지난 프로젝트에서 iBatis를 사용하면 어베이터(Abator 1.0.0-238)라는 코드 생성기를 함께 활용했었다(abator는 얼마전에 공식 명칭이 iBATOR로 변경되었다).
iBatis용 코드 생성기는 abator 말고도 몇가지가 더 있는데, 이왕이면 iBatis에서 권장하는 툴을 사용하는 것이 좋지 않겠나 하는 생각이 있었고 abator를 제외한 툴들은 더이상 업데이트가 안되고 있었는 것도 abator를 선택한 이유였다.
관련 코드를 자동으로 생성해주는 것 까진 좋았는데, 필드 및 메서드 마다 붙어버리는 abator 관련 주석들이 코드를 지저분하게 만들고 가독성을 떨어뜨리는 단점이 있다. 그리고 기본적인 CRUD를 제외한 쿼리들과 Stored Procedure의 경우는 어쩔 수 없이 수동으로 편집을 해야했기 때문에, 프로젝트 말미엔 abator의 활용도가 많이 떨어지지 않았었나 싶다.
누가 abator를 사용함으로써 개발 효율이 높아졌느냐고 물어본다면, 직접 써보고 판단하라고 얘기하고 싶다. 아무튼 득실을 따진다면 사견이지만, 잃을 건 없다라는 것.
아래는 개발자들을 위해서 작성했던 간단한 소개 자료를 첨삭한 내용이다.
Abator
Abator는 iBATIS를 위한 코드 생성기이다. Abator는 데이터베이스의 테이블에 접근하기 위한 iBATIS 연관 코드들인 Object와 환경 설정 파일(configuration file)을 생성하며, 기본적인 CRUD(Create, Retrieve, Update, Delete) 쿼리를 포함한다.
Abator 설치를 위한 특별한 의존성은 없지만 다음 조건을 만족해야 한다.
- JRE 1.4 이상.
- DatabaseMetaData 인터페이스를 구현하는 JDBC 드라이버가 필요하다.
Abator가 생성하는 코드(파일) 목록은 다음과 같다.
- 테이블 구조에 매치되는 자바 POJOs
- iBATIS 호환 SQL Map XML 파일들
- DAO 인터페이스와 구현 클래스들
Abator 사용
1. 설정 파일 작성 - abatorConfig.xml
적절한 설정 파일을 생성한다. 설정은 적어도 다음 요소들을 포함하여야 한다(Abator 사이트 참고).
다음은 abatorConfig.xml의 예제이다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE abatorConfiguration
PUBLIC "-//Apache Software Foundation//DTD Abator for iBATIS Configuration 1.0//EN"
"http://ibatis.apache.org/dtd/abator-config_1_0.dtd">
<!-- ===================================================================== -->
<!-- Abator Config File -->
<!-- XXX Project, Kyungseo.Park@gmail.com, 2007.10 -->
<!-- ===================================================================== -->
<abatorConfiguration>
<abatorContext id="SybaseTables" generatorSet="Java5">
<!-- ================================================================= -->
<!-- jdbcConnection -->
<!-- ================================================================= -->
<jdbcConnection driverClass="com.sybase.jdbc3.jdbc.SybDriver"
connectionURL="jdbc:sybase:Tds:192.168.1.5:3000/sybdb"
userId="sybdb"
password="sybdb">
<classPathEntry location="jconn3.jar" />
</jdbcConnection>
<!--
<jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver"
connectionURL="jdbc:oracle:thin:@129.110.30.30:1521:oradb"
userId="oradb"
password="oradb">
<classPathEntry location="classes12.jar" />
</jdbcConnection>
-->
<!-- ================================================================= -->
<!-- javaTypeResolver -->
<!-- ================================================================= -->
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- ================================================================= -->
<!-- javaModelGenerator -->
<!-- ================================================================= -->
<javaModelGenerator targetPackage="xxx.business.sys.domain"
targetProject="XxxProject\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
<property name="rootClass" value="xxx.framework.base.BaseObject" />
</javaModelGenerator>
<!-- ================================================================= -->
<!-- sqlMapGenerator -->
<!-- ================================================================= -->
<sqlMapGenerator targetPackage="xxx.resources.sql.sys"
targetProject="XxxProject\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- ================================================================= -->
<!-- daoGenerator -->
<!-- ================================================================= -->
<daoGenerator type="IBATIS" targetPackage="xxx.business.sys.dao"
targetProject="XxxProject\src">
<property name="enableSubPackages" value="true" />
<property name="rootInterface" value="xxx.framework.base.BaseDao" />
</daoGenerator>
<!-- ================================================================= -->
<!-- table -->
<!-- ================================================================= -->
<table tableName="TM_XXX_ROLE" domainObjectName="Role" >
<property name="useActualColumnNames" value="true"/>
</table>
</abatorContext>
</abatorConfiguration>
2. Abator 실행(Run)
커맨드 라인을 열고 다음과 같이 입력하여 Abator를 실행할 수 있다. 단, 설정 파일에 정의된 targetProject의 대상 디렉토리는 반드시 미리 존재해야 한다.
java -jar abator.jar abatorConfig.xml false
java -jar abator.jar abatorConfig.xml true
java -cp abator.jar org.apache.ibatis.abator.api.AbatorRunner abatorConfig.xml false
java -cp abator.jar org.apache.ibatis.abator.api.AbatorRunner abatorConfig.xml true
여기서 파라미터의 의미는 다음과 같다.
- 첫번째 파라미터: 환경 파일의 경로
- 두번째 파라미터: 파일이 이미 존재할 경우 overwrite 여부
abator 실행을 위한 간단한 배치 파일을 만들어 놓으면 편하다. 예를 들어 “abator.bat” 파일을 만들어 다음과 같이 편집한다.
java -jar abator.jar abatorConfig.xml true
3. Abator 실행 후 작업
다음과 같은 마무리 작업이 필요하다.
- SqlMapConfig.xml 파일을 생성하거나 편집한다.
- iBATIS DAO Framework를 사용할 경우, dao.xml 파일을 생성하거나 편집한다.
Abator로 생성된 코드 예제
1. Java Model Classes
Domain Class
package xxx.business.sys.domain;
import xxx.framework.base.BaseObject;
import java.util.Date;
public class Role extends BaseObject {
/**
* This field was generated by Abator for iBATIS.
* This field corresponds to the database column TM_XXX_ROLE.role_nmbr
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
private Integer role_nmbr;
/**
* This field was generated by Abator for iBATIS.
* This field corresponds to the database column TM_XXX_ROLE.role_nm
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
private String role_nm;
...
// member field 들에 대한 setter 및 getter
...
}
Domain Example Classes
package xxx.business.sys.domain;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RoleExample {
/**
* This field was generated by Abator for iBATIS.
* This field corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
private String orderByClause;
/**
* This field was generated by Abator for iBATIS.
* This field corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
private List<Criteria> oredCriteria = new ArrayList<Criteria>();
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
public String getOrderByClause() {
return orderByClause;
}
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007.
*/
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
...
}
2. SQL Map Files
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap namespace="TM_XXX_ROLE" >
<resultMap id="abatorgenerated_RoleResult" class="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
<result column="role_nmbr" property="role_nmbr" jdbcType="INTEGER" />
<result column="role_nm" property="role_nm" jdbcType="VARCHAR" />
<result column="rmrk" property="rmrk" jdbcType="VARCHAR" />
<result column="sys_mngm_ysno" property="sys_mngm_ysno" jdbcType="CHAR" />
<result column="rgsr" property="rgsr" jdbcType="CHAR" />
<result column="rgsr_dttm" property="rgsr_dttm" jdbcType="TIMESTAMP" />
<result column="amnd" property="amnd" jdbcType="CHAR" />
<result column="amnd_dttm" property="amnd_dttm" jdbcType="TIMESTAMP" />
</resultMap>
<sql id="abatorgenerated_Example_Where_Clause" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
<iterate property="oredCriteria" conjunction="or" prepend="where" removeFirstPrepend="iterate" >
(
<iterate prepend="and" property="oredCriteria[].criteriaWithoutValue" conjunction="and" >
$oredCriteria[].criteriaWithoutValue[]$
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithSingleValue" conjunction="and" >
$oredCriteria[].criteriaWithSingleValue[].condition$
#oredCriteria[].criteriaWithSingleValue[].value#
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithListValue" conjunction="and" >
$oredCriteria[].criteriaWithListValue[].condition$
<iterate property="oredCriteria[].criteriaWithListValue[].values" open="(" close=")" conjunction="," >
#oredCriteria[].criteriaWithListValue[].values[]#
</iterate>
</iterate>
<iterate prepend="and" property="oredCriteria[].criteriaWithBetweenValue" conjunction="and" >
$oredCriteria[].criteriaWithBetweenValue[].condition$
#oredCriteria[].criteriaWithBetweenValue[].values[0]# and
#oredCriteria[].criteriaWithBetweenValue[].values[1]#
</iterate>
)
</iterate>
</sql>
<select id="abatorgenerated_selectByPrimaryKey" resultMap="abatorgenerated_RoleResult" parameterClass="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
select role_nmbr, role_nm, rmrk, sys_mngm_ysno, rgsr, rgsr_dttm, amnd, amnd_dttm
from TM_XXX_ROLE
where role_nmbr = #role_nmbr:INTEGER#
</select>
<select id="abatorgenerated_selectByExample" resultMap="abatorgenerated_RoleResult" parameterClass="xxx.business.sys.domain.RoleExample" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
select role_nmbr, role_nm, rmrk, sys_mngm_ysno, rgsr, rgsr_dttm, amnd, amnd_dttm
from TM_XXX_ROLE
<isParameterPresent >
<include refid="TM_XXX_ROLE.abatorgenerated_Example_Where_Clause" />
<isNotNull property="orderByClause" >
order by $orderByClause$
</isNotNull>
</isParameterPresent>
</select>
<delete id="abatorgenerated_deleteByPrimaryKey" parameterClass="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
delete from TM_XXX_ROLE
where role_nmbr = #role_nmbr:INTEGER#
</delete>
<delete id="abatorgenerated_deleteByExample" parameterClass="xxx.business.sys.domain.RoleExample" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
delete from TM_XXX_ROLE
<include refid="TM_XXX_ROLE.abatorgenerated_Example_Where_Clause" />
</delete>
<insert id="abatorgenerated_insert" parameterClass="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated Wed Nov 28 17:31:32 KST 2007.
-->
insert into TM_XXX_ROLE (role_nmbr, role_nm, rmrk, sys_mngm_ysno, rgsr, rgsr_dttm, amnd,
amnd_dttm)
values (#role_nmbr:INTEGER#, #role_nm:VARCHAR#, #rmrk:VARCHAR#, #sys_mngm_ysno:CHAR#,
#rgsr:CHAR#, #rgsr_dttm:TIMESTAMP#, #amnd:CHAR#, #amnd_dttm:TIMESTAMP#)
</insert>
<update id="abatorgenerated_updateByPrimaryKey" parameterClass="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
update TM_XXX_ROLE
set role_nm = #role_nm:VARCHAR#,
rmrk = #rmrk:VARCHAR#,
sys_mngm_ysno = #sys_mngm_ysno:CHAR#,
rgsr = #rgsr:CHAR#,
rgsr_dttm = #rgsr_dttm:TIMESTAMP#,
amnd = #amnd:CHAR#,
amnd_dttm = #amnd_dttm:TIMESTAMP#
where role_nmbr = #role_nmbr:INTEGER#
</update>
<update id="abatorgenerated_updateByPrimaryKeySelective" parameterClass="xxx.business.sys.domain.Role" >
<!--
WARNING - This element is automatically generated by Abator for iBATIS, do not modify.
This element was generated on Wed Nov 28 17:31:32 KST 2007.
-->
update TM_XXX_ROLE
<dynamic prepend="set" >
<isNotNull prepend="," property="role_nm" >
role_nm = #role_nm:VARCHAR#
</isNotNull>
<isNotNull prepend="," property="rmrk" >
rmrk = #rmrk:VARCHAR#
</isNotNull>
<isNotNull prepend="," property="sys_mngm_ysno" >
sys_mngm_ysno = #sys_mngm_ysno:CHAR#
</isNotNull>
<isNotNull prepend="," property="rgsr" >
rgsr = #rgsr:CHAR#
</isNotNull>
<isNotNull prepend="," property="rgsr_dttm" >
rgsr_dttm = #rgsr_dttm:TIMESTAMP#
</isNotNull>
<isNotNull prepend="," property="amnd" >
amnd = #amnd:CHAR#
</isNotNull>
<isNotNull prepend="," property="amnd_dttm" >
amnd_dttm = #amnd_dttm:TIMESTAMP#
</isNotNull>
</dynamic>
where role_nmbr = #role_nmbr#
</update>
</sqlMap>
3. Java DAO Classes(optional)
DAO Interface
package xxx.business.sys.dao;
import xxx.business.sys.domain.Role;
import xxx.business.sys.domain.RoleExample;
import xxx.framework.base.BaseDao;
import java.util.List;
public interface RoleDAO extends BaseDao {
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007
*/
void insert(Role record);
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007
*/
int updateByPrimaryKey(Role record);
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Thu Dec 13 16:43:17 KST 2007
*/
int updateByPrimaryKeySelective(Role record);
...
}
DAO Implement
package xxx.business.sys.dao;
import xxx.business.sys.domain.Role;
import xxx.business.sys.domain.RoleExample;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.template.SqlMapDaoTemplate;
import java.util.List;
public class RoleDAOImpl extends SqlMapDaoTemplate implements RoleDAO {
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007
*/
public RoleDAOImpl(DaoManager daoManager) {
super(daoManager);
}
/**
* This method was generated by Abator for iBATIS.
* This method corresponds to the database table TM_XXX_ROLE
*
* @abatorgenerated Wed Nov 28 17:31:32 KST 2007
*/
public void insert(Role record) {
insert("TM_XXX_ROLE.abatorgenerated_insert", record);
}
...
}
참고 사이트
"Development Story" 카테고리의 다른 글
Comments
포스트에 붙인 "Framework와 관련 용어"는, 팀 세미나에서 발표한 "아키텍처 및 프레임워크 구축의 일반적 사항과 오픈 소스의 활용"이란 문서의 일부입니다. 자료를 작성할 때 참고한 레퍼런스들을 하단에 덧붙이려고 했는데, 아쉽게도 당장 찾을 수가 없네요. ^^;
Framework , Library, Design Pattern , Architecture...
@.@ 이때까지 확실한 개념이 안잡힌 상태에서 썻던 용어들이네요. ^^;;;
대충 감으로만 이런거겠지 생각해서 헷갈렸던 용어들인데
글을 읽고 조금 개념이 잡히는것 같아요..^^
모르는건 그때 그때 확실히 개념을 알아봐야 겠어요 ^^
좋은 정보 감솨합니다.^^ 과장님 저는 본사로 복귀해서 대기중이에요..ㅋ
하루하루 평화로운 나날들이에요 ^^
어라, 본사 들어갔었군.
평화로운 나날이라... 부럽네! ㅋ~
조만간 보자고. ^^
그때의 열강이 생각나는군요~~
비록 많은 부분 놓치긴했지만요~ ㅋ
기억해주니 고맙네... ^^