Extended Query Service

쿼리문이나 객체의 입력만으로 DB 데이터 조작을 가능하게 하는 기존 Query 서비스의 기능을 확장한 서비스이다. Extended Query 서비스는 내부적으로 DataSource 서비스와 기존 Query 서비스를 이용하고 있으므로, DataSource 서비스, Query서비스가 같이 배포되어야 한다.
Extended Query 서비스에 대한 구현체는 1가지이며, 다음은 각 구현체별 사용법이다. 아래 상세 가이드를 참조하면 Extended Query Service를 쉽게 이용할 수 있다.

ExtendedQueryService

다음은 Query 서비스를 사용하기 위해 필요한 설정 정보들이다.
Property Name
Description
Required
Default Value
jdbcTemplate 참조할 jdbcTemplate service의 bean id
Y
N/A
sqlLoader 참조할 sqlLoader service의 bean id
Y
N/A
lobHandler 참조할 lobHandler service의 bean id
Y
N/A
velocityPropsFilename Velocity 실행시 참조하게 될 Velocity 속성 정의 파일의 위치 정의
N
N/A

기존 Query Service와 달리 sqlLoader가 별도의 bean으로 분리되었으며 jdbcTemplate과 lobHandler를 설정하는 것은 동일하다.

다음은 sqlLoader 설정시 필요한 정보들이다.
Tag Name
Attrubute Name
Description
Required
Default Value
Child Tag
config:configuration filename nullcheck
filename 테이블 매핑 정보와 사용할 쿼리문을 정의하고 있는 파일명을 지정하는 요소로 복수 지정 가능하다. filename 요소에 대한 지정은 절대 / 상대적인 파일 경로 지정 방법과 Classpath를 이용한 지정 방식의 2가지가 있다. Classpath를 이용하여 매핑 파일 정보를 지정하고자 할 경우 classpath:로 시작한다.
N
N/A
nullcheck 해당 DB Column의 값이 없는 경우, null value가 리턴되었을 때, 지정한 값으로 변환시켜준다.
N
N/A
property name="skiperror" error 발생 시 skip 여부를 세팅한다.
N

Samples

  • Query Service Configuration
  • 다음은 Query Service에서 사용할 query의 속성을 정의한 applicationContext-extenedquery-general.xml의 일부이다.
    <bean name="queryService" class="anyframe.core.query.impl.ExtendedQueryServiceImpl">
    	<property name="jdbcTemplate">
    		<ref bean="pagingJdbcTemplate"/>
    	</property>		
    	<property name="sqlRepository">
    		<ref bean="sqlLoader"/>
    	</property>	
    	<property name="lobHandler">
    		<ref bean="lobHandler"/>
    	</property>									
    </bean>		
    
    <bean id="pagingJdbcTemplate" class="anyframe.core.query.impl.util.PagingJdbcTemplate">
      <constructor-arg ref="dataSource"/>
    </bean>
    
    <bean name="sqlLoader" class="anyframe.core.query.impl.SQLLoader">
    	<property name="skipError" value="false"/>	
    	<config:configuration>
            <filename>classpath:sql/**/*.xml</filename>
       	    <nullcheck type="VARCHAR" default-value=""/> 
    	</config:configuration>					
    </bean>	
    
    <bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
    	<property name="nativeJdbcExtractor"><ref local="nativeJdbcExtractor"/></property>
    </bean>
    
    <bean id="nativeJdbcExtractor" 
    	class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" 
    	lazy-init="true"/>	
  • 사용 sample
  • Extended QueryService를 사용하기 위해서는 DAO에서 anyframe.core.query.AbstractDAO를 상속 받는다. AbstractDAO클래스에는 argument로 Object대신에 VO를 직접 사용 할 수 있는 method가 추가 되어 있어 개발이 손쉬우며 특히 테이블 단위의 CRUD 개발을 쉽게 할 수 있다.

    AbstractDAO 클래스를 상속 받아 아래 소스코드와 같이 DAO에서 CRUD의 메소드만작성하면 SQL 문은 SYSTEMiER Framework에서 제공하는 이클립스 플러그인(Create Mapping File)을 사용해서 개발자가 직접 작성하지 않고 개발 할 수 있다.

    다음은 AbstractDAO를 이용하여 실 구현한 CustomerDAO.javamapping-extended-query.xml 예제이다.

    CustomerDAO.java
    public class CustomerDAO extends AbstractDAO{
      
      public Page selectCustomerList(CustomerVO vo) throws Exception {
        int pageIndex = vo.getPageIndex();
        int pageSize = vo.getPageSize();
        int pageUnit = vo.getPageUnit();
        return findListWithPaging("selectCustomerList", vo, pageIndex, pageSize, pageUnit );
      }
      
      public int createCustomer(CustomerVO vo) throws Exception {
        return insert("CUSTOMER", vo);
      }
    
      public int updateCustomer(CustomerVO vo) throws Exception {
        return update("CUSTOMER", vo);
      }
      
      public int deleteCustomer(CustomerVO vo) throws Exception {
        return delete("CUSTOMER", vo);
      }
    
      public CustomerVO selectCustomer(String ssno) throws Exception {
        CustomerVO vo = new CustomerVO();
        vo.setSsno(ssno);
        CustomerVO resultVo = (CustomerVO)findByPk("CUSTOMER", vo);
    
        return resultVo;    
      }
      
    }


    mapping-extended-query.xml
    아래 query xml에서 볼 수 있듯이 입력한 테이블명 ("CUSTOMER")과 AbstractDAO에서 제공이 되는 함수명을 prefix로 한 query id가 mapping 되는 것을 알 수 있다.
    ex) 함수명 : insert("CUSTOMER", vo) -> 호출 query id : insertCUSTOMER
    함수명 : update("CUSTOMER", vo) -> 호출 query id : updateCUSTOMER
    <queryservice>
      <queries>
        <query id="findByPkCUSTOMER">
          <statement>
            SELECT * FROM TBL_CUSTOMER WHERE SSNO like :vo.ssno
          </statement>
          <result class="integration.anyframe.services.query.vo.CustomerVO"/>
        </query>  
        <query id="selectCustomerList">
          <statement>
            SELECT * FROM TBL_CUSTOMER  WHERE SSNO like :vo.ssno
          </statement>
          <result class="integration.anyframe.services.query.vo.CustomerVO"/>
        </query>    
        <query id="insertCUSTOMER">
          <statement>
            INSERT INTO TBL_CUSTOMER ( ssno, name, address ) VALUES (:vo.ssno,:vo.name,:vo.addr)
          </statement>
        </query>    
        <query id="updateCUSTOMER">
          <statement>
            UPDATE TBL_CUSTOMER SET ssno = :vo.ssno , name = :vo.name, address = :vo.addr WHERE ssno = :vo.ssno
          </statement>
          <result class="integration.anyframe.services.query.vo.CustomerVO"/>
        </query>
        <query id="deleteCUSTOMER">
          <statement>
            DELETE FROM TBL_CUSTOMER WHERE ssno = :vo.ssno
          </statement>
          <result class="integration.anyframe.services.query.vo.CustomerVO"/>
        </query>
      </queries>
    </queryservice>
    
    앞서 소개된 샘플 테스트 코드를 포함하여 Extended Query Service 소개 페이지에서 제공하는 모든 샘플 테스트 코드는 HSQL DB를 기반으로 실행된다. 단, ※ CallableStatement, LOB의 경우는 Oracle 9i, 10g를 기반으로 함.)

Samples with Velocity Props

  • Query Service Configuration
  • 다음은 Velocity 속성 정의 파일의 위치를 포함한 ExtendedQueryService 속성 정의 파일의 일부이다. ExtendedQueryService의 velocityPropsFilename 속성의 값에 velocity.properties 파일의 위치를 정의해 두면, Dynamic Query를 수행할 때 사용하는 Velocity Engine에서 로그를 남길 때 velocity.properties 파일에 정의된 속성 정보를 참조하게 된다.
    <bean name="extendedQueryService" class="anyframe.core.query.impl.ExtendedQueryServiceImpl">
    	<property name="jdbcTemplate">
    		<ref bean="pagingJdbcTemplate"/>
    	</property>		
    	<property name="sqlRepository">
    		<ref bean="sqlLoader"/>
    	</property>	
    	<property name="velocityPropsFilename" value="src/test/resources/velocity.properties"/>
    </bean>	
    
  • velocity.properties
  • Velocity 내에 Velocity 만을 위한 별도의 Logger를 설정하지 않고, log4j.xml 파일 내에 정의된 logger를 같이 사용하고자 한다면, velocity.properties 파일 내에 Log4j와의 연동을 위한 구현 클래스와 log4j.xml 내에 정의된 logger명을 다음과 같이 정의한다. 다음의 velocity.properties 파일에 의하면, Velocity는 org.apache.velocity라는 logger명을 가진 Logger를 이용하여 로그를 남기게 될 것이다.
    runtime.log.logsystem.class=org.apache.velocity.runtime.log.SimpleLog4JLogSystem
    runtime.log.logsystem.log4j.category=org.apache.velocity
    
  • log4j.xml
  • 다음은 log4j.xml 내에 정의된 logger "org.apache.velocity"의 정의 내용이다.
    <logger name="org.apache.velocity">
        <level value="DEBUG"/>
        <appender-ref ref="console"/>
    </logger> 
    

Resources

  • 다운로드
  • 샘플 테스트 코드를 포함하고 있는 anyframe-extendedquerytest-src.zip 파일을 다운받은 후, 테스트 환경 설정을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다.
    Name
    Download
    anyframe-extenededquerytest-src.zip
    Download