------------------------------------------------------------
아무래도 현재 사용중인 프레임은 AnyFrame 이라는 것을 이용한 것인가보다...
xml에 #if, #end 같은 조건 분기가 들어가는 것을 보니...
검색해도 잘 나오지 않더니 오늘 우연히 찾았다...
XML에서 #if ~ #elseif ~ #end
검색을 어떻게 더 해야 조건 제어에 대한 내용을 더 찾을 수 있을지....
(쥔장 주석 끝)-----------------------------------------------
#startline====================================================
앞서 소개된 샘플 테스트 코드를 포함하여 Query 서비스 소개 페이지에서 제공하는 모든 샘플 테스트 코드는 HSQL DB를 기반으로 실행된다. ( 단, ※ CallableStatement, LOB의 경우는 Oracle 9i, 10g를 기반으로 함. )
[출처] AnyFrame... http://dev.anyframejava.org/anyframe/doc/core/3.2.1/corefw/guide/query-usecase-dynamic.html
#endline=====================================================
아무래도 현재 사용중인 프레임은 AnyFrame 이라는 것을 이용한 것인가보다...
xml에 #if, #end 같은 조건 분기가 들어가는 것을 보니...
검색해도 잘 나오지 않더니 오늘 우연히 찾았다...
XML에서 #if ~ #elseif ~ #end
검색을 어떻게 더 해야 조건 제어에 대한 내용을 더 찾을 수 있을지....
(쥔장 주석 끝)-----------------------------------------------
#startline====================================================
Query Service - Dynamic Query
Query 서비스는 text 치환, named parameter 형태 등을 통해 Dynamic 쿼리문 정의를 지원한다. 다음과 같은 syntax를 사용하면, 운영 시 입력된 조건 값에 따라 동적으로 쿼리문을 변환할 수 있다.- :ParameterName : 특정 쿼리문에 입력되어야 할 변수를 지정할 때 사용한다.
- {{치환 문자열 키}} : 치환 문자열 키에 해당하는 문자열로 치환되어야 하는 부분에 정의한다.
- #if ~ (#elseif) ~ #end : 조건 분기가 필요한 부분에 정의한다.
- # foreach ~ #end : Loop가 필요한 부분에 정의한다.
- $velocityCount : foreach 구문내의 Loop index를 체크하고자 하는 부분에 정의한다.
Query 서비스 속성 정의 파일 Sample
다음은 Query 서비스를 정의한 applicationContext-query-common.xml 과 Query 서비스에서 읽어들일 매핑 XML 파일의 위치를 정의한 applicationContext-query-sqlloader.xml 파일의 일부이다.<bean id="queryService" class="anyframe.core.query.impl.QueryServiceImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> <property name="sqlRepository" ref="sqlLoader"/> <!-- 중략 --> </bean> <bean id="jdbcTemplate" class="anyframe.core.query.impl.jdbc.PagingJdbcTemplate"> <property name="dataSource" ref="common_datasource" /> </bean> <!-- 중략 -->
<bean name="sqlLoader" class="anyframe.core.query.impl.config.loader.SQLLoader"> <config:configuration> <filename>classpath:/services/query/mappings/mapping-dynamic-query.xml</filename> <!-- 중략 --> </config:configuration> </bean> <!-- 중략 -->
매핑 XML 파일 Sample
다음은 앞서 정의한 Query 서비스를 통해 로드된 mapping-dynaminc-query.xml 로, 여러 유형의 dynamic 쿼리문을 포함하고 있다.<queries> <query id="getLogonIdByNamedParam" isDynamic="true"> <statement> SELECT LOGON_ID FROM TBL_USER WHERE LOGON_ID BETWEEN :lowId AND :highId </statement> <param name="lowId" type="VARCHAR"/> <param name="highId" type="VARCHAR"/> </query> <query id="getEmployeesByTextReplacement" isDynamic="true"> <statement> SELECT LOGON_ID FROM {{schema}} ORDER BY {{sortColumn}} </statement> </query> <query id="getLogonIdByIf" isDynamic="true"> <statement> SELECT LOGON_ID FROM TBL_USER #if ($id && !$id.equals("")) WHERE LOGON_ID like '%' || :logonId || '%' #end ORDER BY {{sortColumn}} </statement> <param name="logonId" type="VARCHAR"/> </query> <query id="getLogonIdByForeach" isDynamic="true"> <statement> SELECT LOGON_ID, NAME FROM TBL_USER WHERE LOGON_ID IN ( #foreach ($logonId in $logonIdList) #if ($velocityCount == 1 ) '$logonId' #else , '$logonId' #end #end ) ORDER BY NAME </statement> </query> </queries>
Query 서비스 테스트 코드 Sample
다음은 앞서 언급한 매핑 XML 파일에 정의된 parameter 값에 따라 동적으로 변경 가능한 쿼리문들을 실행하는 소스 코드 QueryServiceTestDynamic.java 를 구성하고 있는 메소드들이다. dynamic 쿼리문을 사용하면 소스 코드나 매핑 XML 파일을 고치지 않고도 조건에 따라서 원하는 쿼리문을 실행할 수 있다./** * Named Parameter를 이용해서 query id가 'getLogonIdByNamedParam'인 Dynamic 쿼리문을 실행한다. * getLogonIdByNamedParam : key가 lowId, highId인 Named Parameter의 값을 key=value 형태로 Query * 서비스에 전달하면 Query 서비스는 해당 value를 PreparedStatement에 셋팅하고 해당 쿼리문을 실행한다. * 이 메소드에서는 "lowId = a", "highId = z"라는 paramter를 Object[] 형태로 Query 서비스에 전달하고 있으며, * 이 때 실행되는 쿼리문은 다음과 같다. * SELECT LOGON_ID FROM TBL_USER WHERE LOGON_ID BETWEEN 'a' AND 'z' */ public void testDynamicQueryUsingNamedParameter() throws Exception { IQueryService queryService = (IQueryService) context.getBean("queryService"); Object[] iVal = new Object[2]; iVal[0] = "lowId=a"; iVal[1] = "highId=z"; ArrayList rtList = (ArrayList)(queryService.find("getLogonIdByNamedParam", iVal)); if( rtList.size() != 2){ throw new Exception("Dynamic Query Using NamedParameter failed"); } } /** * {{치환문자열키}}를 이용해서 query id가 'getEmployeesByTextReplacement'인 Dynamic 쿼리문을 실행한다. * getEmployeesByTextReplacement : key가 schema, sortColumn인 치환문자열의 값을 key=value 형태로 Query * 서비스에 전달하면 Query 서비스는 해당 value를 문자열로 그대로 치환해서 사용한다. * 이 메소드에서는 "schema=TBL_USER", "sortColumn=NAME"라는 parameter를 Object[] 형태로 Query 서비스에 전달하고 * 있으며, 이 때 실행되는 쿼리문은 다음과 같다. * SELECT * FROM TBL_USER ORDER BY NAME */ public void testDynamicQueryUsingTextreplace() throws Exception { IQueryService queryService = (IQueryService) context.getBean("queryService"); Object[] iVal = new Object[2]; iVal[0] = "schema=TBL_USER"; iVal[1] = "sortColumn=NAME"; ArrayList rtList = (ArrayList)(queryService.find("getEmployeesByTextReplacement", iVal)); if( rtList.size() != 2){ throw new Exception("Dynamic Query Using Text replace failed"); } } /** * 조건분기를 위한 #if를 이용해서 query id가 'getLogonIdByIf'인 Dynamic 쿼리문을 실행한다. * getLogonIdByIf : key가 id인 parameter의 값이 Null이 아니고, 빈 문자열도 아니라면, #if문 내에 * 포함된 WHERE절이 실행될 쿼리문에 포함된다. (#if문이 끝나는 지점에는 반드시 #end를 정의해주어야 함에 * 유의하자.) * 또한, WHERE절 내에서는 '%' || :logonId || '%'와 같은 형태의 문장을 사용하고 있는데 이것은 Named * Parameter의 값에 앞뒤로 %를 붙인 형태의 문자열을 만들어 내기 위함이다. * (이 때, '%', ||, :logonId 사이에는 빈 칸을 두어야 WHERE절이 정상적으로 동작한다. ) * 이 메소드에서는 "id=test", "sortColumn=NAME" 라는 parameter를 Object[] 형태로 Query 서비스에 전달하고 있으며 * 실행되는 쿼리문은 다음과 같다. * SELECT LOGON_ID * FROM TBL_USER * WHERE LOGON_ID like '%test%' * ORDER BY NAME */ public void testDynamicQueryUsingCondition() throws Exception { IQueryService queryService = (IQueryService) context.getBean("queryService"); Object[] iVal = new Object[3]; iVal[0] = "id=yes"; iVal[1] = "logonId=test"; iVal[2] = "sortColumn=NAME"; ArrayList rtList = (ArrayList)(queryService.find("getLogonIdByIf", iVal)); if( rtList.size() != 1){ throw new Exception("Dynamic Query Using Condition failed"); } } /** * Loop를 위한 #foreach를 이용해서 query id가 'getLogonIdByForeach'인 Dynamic 쿼리문을 실행한다. * getLogonIdByForeach : key가 logonIdList인 parameter의 값은 List 형태이며, List에서 순서대로 * 추출된 값들은 내부적으로 logonId라는 변수에 셋팅된다. logonId는 Query 서비스에 전달되어야 하는 입력 * parameter가 아니다. * velocityCount가 1인 경우 즉, 첫번째 Loop일 경우 logonIdList의 첫번째 값이 그대로 추가되고 그 이후부터는 * ,를 붙인 값이 추가되게 된다. (#foreach, #if문이 끝나는 지점에는 반드시 #end를 정의해주어야 함에 유의하자.) * 이 메소드에서는 logonIdList의 값이 "admin", "test"라는 두개의 문자열로 구성된 ArrayList를 Object[] * 형태로 Query 서비스에 전달하고 있으며 실행되는 쿼리문은 다음과 같다. * SELECT LOGON_ID, NAME * FROM TBL_USER * WHERE LOGON_ID IN ('admin', 'test') * ORDER BY NAME */ public void testDynamicQueryUsingLoop() throws Exception { IQueryService queryService = (IQueryService) context.getBean("queryService"); List logonIdList = new ArrayList(); logonIdList.add("admin"); logonIdList.add("test"); Object[] iVal = new Object[]{"logonIdList", logonIdList}; ArrayList rtList = (ArrayList) (queryService.find("getLogonIdByForeach", new Object[]{ iVal })); if (rtList.size() != 1) { throw new Exception("Dynamic Query Using Condition failed"); } }
#endline=====================================================