Skip to content
KwonNam Son edited this page Nov 26, 2015 · 37 revisions

freemarker-dynamic-ql-builder 시작하기

freemarker-dynamic-ql-builder 를 사용하면 Java에서 동적으로 SQL, JPQL, HQL 등을 생성하고 JDBC 쿼리 파라미터를 바인딩해줄 수 있다. 이제부터 나오는 QL은 SQL, JPQL, HQL 등을 의미한다.

이렇게 생성한 쿼리 문자열과 바인딩 파라미터 리스트(혹은 배열)을 Plain PreparedStatementSpringFramework JdbcTemplate, jDBI, JPA, Hibernate 등에서 Native 혹은 JPQL/HQL을 실행하는 용도로 사용할 수 있다.

요구사항

  • Java 6+
  • 의존성이 freemarker 2.3.23+와 slf4j 단 두개뿐인 가벼운 동적 쿼리 생성 툴이다.

Gradle 의존성 설정

compile 'kr.pe.kwonnam.freemarkerdynamicqlbuilder:freemarker-dynamic-ql-builder:0.2'

Maven 의존성 설정

<dependency>
    <groupId>kr.pe.kwonnam.freemarkerdynamicqlbuilder</groupId>
    <artifactId>freemarker-dynamic-ql-builder</artifactId>
    <version>0.2</version>
</dependency>

Builder 객체 설정

먼저 프리마커 Configuration 객체를 입맛대로 생성하고, 이를 사용하여 FreemarkerDynamicQlBuilder 객체를 생성한다.

최종 생성된 FreemarkerDynamicQlBuilder 객체를 SpringFramework Bean으로 등록해서 Spring과 함께 사용하면된다. FreemarkerDynamicQlBuilder는 Thread Safe 하다. 단 Configuration 객체를 한 번 설정한 이후 변경해서는 안된다.

import freemarker.template.Configuration;
import kr.pe.kwonnam.freemarkerdynamicqlbuilder.FreemarkerDynamicQlBuilder;
import kr.pe.kwonnam.freemarkerdynamicqlbuilder.FreemarkerDynamicQlBuilderFactory;

// ...

// 자신이 원하는 대로 Freemarker 설정을 해준다.
Configuration freemarkerConfiguration = new Configuration(Configuration.VERSION_2_3_23);
freemarkerConfiguration.setClassForTemplateLoading(AbstractFreemarkerDynamicQlBuilderTest.class, "/META-INF/dynamicqls");
freemarkerConfiguration.setDefaultEncoding("UTF-8");

// 숫자형을 쉼표없이 숫자만 출력하게 포미팅
freemarkerConfiguration.setNumberFormat("0.######");
// 템플릿 파일 변경 체크 주기를 1시간으로 설정
freemarkerConfiguration.setTemplateUpdateDelayMilliseconds(3600000L); // ms 단위
// 성능 향상을 위한 캐시 설정
freemarkerConfiguration.setCacheStorage(new MruCacheStorage(500, 5000));

// Freemarker 설정을 가지고 FreemarkerDynamicQlBuilder 객체를 생성한다.
FreemarkerDynamicQlBuilder qlDynamicBuilder = new FreemarkerDynamicQlBuilderFactory(freemarkerConfiguration)
		// 중간에 기타 설정들..
		.getFreemarkerDynamicQlBuilder();

가장 간단한 Dynamic QL Template의 생성 살펴보기

동적으로 QL을 생성하려면 프리마커 Configuration 에서 지정한 경로상에 디렉토리를 만들고 파일을 확장자가 .ql.ftl로 끝나게 생성해준다.

위의 설정에서는 CLASSPATH 내의 /META-INF/dynamicqls 디렉토리를 템플릿 홈으로 지정하였으므로 /META-INF/dynamicqls/users/select.ql.ftl 을 생성했다고 간주하면,

SELECT *
FROM somewhere
<@ql.where>
    <#if user.name?has_content>
    name = ${param(user.name)}
    </#if>
    <#if user.birthyear gt 0>
    AND birthyear = ${param(user.birthyear)}
    </#if>
    <#if user.employeeType??>
    AND employeeType = ${param(user.employeeType, 'enumToName')}
    </#if>
    <#list userIds!>
    AND userId IN (<#items as userId>${param(userId)}<#sep>,</#sep></#items>)
    </#list>
</@ql.where>

ORDER BY userId
LIMIT 10

이제 Java 코드상에서는

User user = new User();
user.setName(""); // empty on purpose
user.setBirthyear(2015);
user.setEmployeeType(EmployeeType.FULLTIME);

Map<String,Object> dataModel = new HashMap<String,Object>();
dataModel.put("user", user);
dataModel.put("userIds", new int[]{100, 200, 300});


DynamicQuery dynamicQuery = = qlDynamicBuilder.buildQuery("users/select", dataModel);
// dynamicQuery 에 생성된 QL과 파리머터 목록이 들어 있다.

이 명령을 실행하고나서 dynamicQuery 객체를 살펴보면 쿼리 실행에 필요한 SQL 문자열과, Positional Parameter(물음표, ?)에 바인딩 될 파라미터 객체들의 리스트 혹은 배열을 얻을 수 있게 된다.

dynamicQuery.getQueryString() 
==> String
"SELECT *
FROM somewhere
WHERE birthyear = ?
    AND employeeType = ?
    AND userId IN (?,?,?)
ORDER BY userId
LIMIT 10"

dynamicQuery.getParameters()
==> List<Object> : [2015, FULLTIME, 100, 200, 300] 

dynamicQuery.getQueryParameterArray()
==> Object[] : [2015, FULLTIME, 100, 200, 300] 

이제 이것을 가지고 PreparedStatement에 배열을 for문 돌면서 바인딩하거나 아래와 같이 간편하게 바인딩 할 수 도 있다.

PreparedStatement psmt = connection.prepareCall(dynamicQuery.getQueryString());
dynamicQuery.bindParameters(psmt);

ResultSet rs = psmt.executeQuery();
// ...

Plain JDBC가 아닌 SpringJdbcTemplate이나 jDBI, Hibernate, JPA 등에 쿼리와 바인딩할 파라미터를 넘겨서 쿼리를 실행할 수도 있다.

If you find any incorrect sentence or invalid information, please feel free to edit.

Clone this wiki locally