본문 바로가기

Java/Java

Using IntelliJ File Template

Using IntelliJ FileTemplate.


프로젝트를 진행하다 보면, 동일한 Template의 파일을 여럿 작성하게 된다.

예를 들면, 아래와 같은 경우이다.

공통 코드를 조회하는 RestController이다.

CommonCodeRestController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import project.pilot.api.common.base.BaseController;
@RestController
public class CommonCodeRestController extends BaseRestController {
private final CommonCodeService commonCodeService;

@Autowired
public CommonCodeController(CommonCodeService commonCodeService) {
this.commonCodeService = commonCodeService;
}
}

프로젝트내의 모든 RestController가 위의 코드를 기본으로 하여 만들어진다.

동일한 프로젝트에서 게시글을 조회하는 RestController는 아래와 같이 만들어진다.

BoardRestController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import project.pilot.api.common.base.BaseController;
@RestController
public class BoardRestController extends BaseRestController {
private final BoardService boardService;

@Autowired
public BoardRestController(BoardService boardService) {
this.boardService= boardService;
}
}

두개의 파일에서 다른점을 찾아보면 딱 한개의 단어뿐이다.

CommonCode가 Board로 바뀌었을뿐이다.

IntelliJ에서는 이런 경우 해당 Template을 저장하여 파일을 만들어낼때마다 불러 쓸 수 있는 기능을 제공한다.

바로 FileTemplate이다.

File-Settings-Editor-File and Code Template

File and Code Template

“+”를 클릭하여 새 Template을 만든다.

이름은 RestController, 확장자는 java로 한다.

add new File template

이제 아래의 검은색 빈칸에 Template을 등록하자.

먼저, Class파일을 살짝 컨닝해보도록 하자.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
public class ${NAME} {
}

Java Class의 Template은 여기서부터 시작한다.

먼저, RestController와 Autowired에 대한 import를 지정한다.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#parse("File Header.java")
public class ${NAME} {
}

이번엔 RestController Annotation을 추가한다.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#parse("File Header.java")
@RestController
public class ${NAME} {
}

이번에는 서비스 클래스에 대한 정보를 추가해보자.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#parse("File Header.java")
@RestController
public class ${NAME} {
private final ${SERVICE_NAME} ${SERVICE_NAME};

@Autowired
${NAME} (${SERVICE_NAME} ${SERVICE_VAR_NAME}) {
this.${SERVICE_VAR_NAME} = ${SERVICE_VAR_NAME};
}
}

${SERVICE_NAME} 이라는 값을 추가했는데, 이렇게 되면 파일을 만들때 사용자에게 해당 값을 입력받게 된다.

이제 지금까지 만든 Template을 등록하고 작성해보자.

좌측의 Project Window에서 파일을 생성할 폴더를 선택하고, Alt+Insert를 누르면 아래와 같은 메뉴가 나온다. 등록한 파일 Template의 이름은 RestController를 선택해보자.

그럼 위 그림과 같이, SERVICE NAME을 입력 받게 된다.

각 필드에 값을 입력하고, OK를 클릭하면 아래 파일이 만들어진다.

문제가 하나 보인다.

변수로 선언된 TestService값을 testService로 바꿔줘야할 것 같다.

IntelliJ의 FileTemplate은 Velocity Template languge를 사용한다.

이말인 즉슨, String Class가 가지고 있는 Method나, Velocity에서 제공하는 StringUtils를 사용할 수 있다는 말이다.

Template에서 사용자 정의값을 설정할 수 있다. Velocity에서 설정하는 방법과 같다.

#set ($SERVICE_VAR_NAME = $SERVICE_NAME.substring(0,1).toLowerCase() + $SERVICE_NAME.substring(1))

위의 구분을 넣으면, ${SERVICE_VAR_NAME}에 맨 앞자리 문자를 소문자로 변경한 값을 할당하게 된다.

안타깝게도 Velocity의 StringUtils에는 맨앞자리 를 대문자와 하는 capitalizeFirstLetter(java.lang.String) Method를 제공하지만, 반대의 경우는 없는 듯하다.

만약 소문자로 입력받은 값의 맨앞자리만을 대문자로 변경하고 싶다면 아래와 같이 설정할 수 있다.

#set ($CAP_SERVICE_NAME = ${StringUtils.capitalizeFirstLetter($SERVICE_NAME)})

자, 그럼 설정한 값을 포함하여 다시 Template을 설정하자.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#set ($SERVICE_VAR_NAME = $SERVICE_NAME.substring(0,1).toLowerCase() + $SERVICE_NAME.substring(1))
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#parse("File Header.java")
@RestController
public class ${NAME} {
private final ${SERVICE_NAME} ${SERVICE_VAR_NAME};
    @Autowired
${NAME} (${SERVICE_NAME} ${SERVICE_VAR_NAME}) {
this.${SERVICE_VAR_NAME} = ${SERVICE_VAR_NAME};
}
}

그리고 다시 TestRestController를 생성해보자.

어떤가?

별것 아니지만, 참 멋진 기능 아닌가?


이렇게 추가하여, 최종적으로 완성한 나의 RestController Template은 아래와 같다.

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

#if (${
Included_Service_Name_-_optional} && ${Included_Service_Name_-_optional} != "")
#set ($SERVICE_NAME = ${StringUtils.capitalizeFirstLetter($Included_Service_Name_-_optional)} + "Service")
import org.springframework.beans.factory.annotation.Autowired;
#end
import org.springframework.web.bind.annotation.RestController;

import project.pilot.api.common.base.BaseRestController;

#parse("File Header.java")
@RestController
public class ${NAME}RestController extends BaseRestController {
#if (${Included_Service_Name_-_optional} && ${Included_Service_Name_-_optional} != "")
#set ($SERVICE_VAR_NAME = $SERVICE_NAME.substring(0,1).toLowerCase() + $SERVICE_NAME.substring(1))
private final ${SERVICE_NAME} ${SERVICE_VAR_NAME};

@Autowired
${NAME}RestController (${SERVICE_NAME} ${SERVICE_VAR_NAME}) {
this.${SERVICE_VAR_NAME} = ${SERVICE_VAR_NAME};
}
#end
}