Ibatis 라이브러리를 이용한 VO,DAO의 구현
전에 JDBC를 이용하여 VO, DAO설계를 해보았습니다. 그러다 보니 많은 부분 불필요한 소스가 생겨나고 생산성이 떨어지는 것을 경험하였을 것입니다. 이를 해결하기 위하여 Ibatis라는 라이브러리를 사용해 보겠습니다.
Ibatis는 JDBC를 대체하는 것이 아니라 JDBC를 효율적으로 사용하는 라이브러리라 할 수 있습니다. 그 핵심에는 DI(Dependency injection)패턴이 있습니다. 각종 프레임워크에서는 이 DI를 적극적으로 활용하고 있으며 특히 Java 1.5부터는 Annotation을 활용하여 DI가 기본을 이루고 있습니다. DI패턴과 Annotation은 나중에 알아 보고요.
우선은 ibatis를 활용하여 vo와 dao를 구현해보겠습니다.
테이블과 vo, dao인터페이스는 기존 생성은 기존과 같습니다.
package org.power.vo; import java.util.Date; public class BbsVO { private int bbsno; private String title; private String writer; private int hits; private String content; private Date regdate; public int getBbsno() { return bbsno; } public void setBbsno(int bbsno) { this.bbsno = bbsno; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getWriter() { return writer; } public void setWriter(String writer) { this.writer = writer; } public int getHits() { return hits; } public void setHits(int hits) { this.hits = hits; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Date getRegdate() { return regdate; } public void setRegdate(Date regdate) { this.regdate = regdate; } } |
package org.power.dao; import org.power.vo.BbsVO; public interface BbsDAO { public void insert(BbsVO vo) throws Exception; public BbsVO select(int bbsno) throws Exception; public void update(BbsVO vo) throws Exception; public void delete(int bbsno) throws Exception; } |
자 그럼 Ibatis 라이브러리를 활용하여 구현을 해볼까요? 우선 공통적으로 Ibatis 환경설정 부분을 Abstract Class로 빼 보았습니다. 그냥 구현해도 되지만 확장성을 고려해서 빼보겠습니다.
package org.power.dao; import java.io.IOException; import java.io.Reader; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; public abstract class AbstractIbatis { protected static SqlMapClient sqlMapper; static { try { Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml"); sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader); reader.close(); } catch (IOException e) { // Fail fast. throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e); } } } |
SqlMapConfig.xml 환경설정 파일은 아래와 같습니다. 여기서 JDBC Connection 정보를 설정하는 곳이 보입니다.
즉, Ibatis는 JDBC를 쉽게 사용하기 위한 툴입니다. 여기서 확인해 두어야 할 것은 sqlMap 테그 부분으로 SQL문장을따로 xml형태로 읽어들여 사용한다는 것입니다.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <transactionManager type="JDBC" commitRequired="false"> <dataSource type="SIMPLE"> <property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" /> <property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@127.0.0.1:1521:ORCL" /> <property name="JDBC.Username" value="tony" /> <property name="JDBC.Password" value="1234" /> </dataSource> </transactionManager> <sqlMap resource="BBS.xml" /> </sqlMapConfig> |
BBS.xml의 내용을 보면 아래와 같다.
<?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> <insert id="insertBBS" parameterClass="org.power.vo.BbsVO"> <![CDATA[ INSERT INTO TBL_BBS (bbsno, title, content, writer, hits) VALUES (SEQ_BBS_NO.NEXTVAL, #title#, #content#, #writer#, #hits#) ]]> </insert> <select id="selectBBS" resultClass="org.power.vo.BbsVO"> <![CDATA[ SELECT bbsno, title, content, writer, hits, regdate FROM TBL_BBS WHERE bbsno = #bbsno# ]]> </select> <update id="updateBBS" parameterClass="org.power.vo.BbsVO"> <![CDATA[ UPDATE TBL_BBS SET title=#title#, content=#content#, writer=#writer#, hits=#hits#, regdate=#regdate# where bbsno=#bbsno# ]]> </update> <delete id="deleteBBS" parameterClass="java.lang.Integer"> <![CDATA[ DELETE FROM TBL_BBS WHERE bbsno=#bbsno# ]]> </delete> </sqlMap> |
SQL문이 기술되어 있습니다. 여기서 중요한 것이 ParameterClass와 resultClass입니다. 이는 Ibatis에서 SqlMapClient에서 매개변수로 넘기는 데이터 형태를 말합니다. 여기서 #bbsno#등과 같이 ##로 묶여있는 것은 Ibatis에서 자동으로
맵핑을 시켜줍니다. 즉 SELECT문의 #bbsno#와 getBbsno() 메소드와 맵핑을 시킵니다. 그러므로 해당 필드들은 대소문자를 구분합니다.
자 그럼 BbsDAOImpl 클래스를 한번 만들어보겠습니다.
package org.power.dao; import org.power.vo.BbsVO; public class BbsDAOImpl extends AbstractIbatis implements BbsDAO { @Override public void insert(BbsVO vo) throws Exception { sqlMapper.insert("insertBBS", vo); } @Override public BbsVO select(int bbsno) throws Exception { return (BbsVO) sqlMapper.queryForObject("selectBBS", bbsno); } @Override public void update(BbsVO vo) throws Exception { sqlMapper.update("updateBBS", vo); } @Override public void delete(int bbsno) throws Exception { sqlMapper.delete("deleteBBS",bbsno); } } |
자 그럼 Junit을 통해 단위테스트를 해보겠습니다. 해당 코드는 아래와 기존과 동일합니다.
package org.power.test; import org.power.dao.BbsDAO; import org.power.dao.BbsDAOImpl; import org.power.vo.BbsVO; import junit.framework.TestCase; public class BbsDAOTest extends TestCase { private BbsDAO bbsDao; protected void setUp() throws Exception { super.setUp(); bbsDao = new BbsDAOImpl(); } public void testInsert() { BbsVO vo = new BbsVO(); try { vo.setTitle("Ibatis사용 새로운 글을 등록합니다.(타이틀)"); vo.setContent("Ibatis사용 새로운 글을 내용을합니다."); vo.setHits(100); vo.setWriter("S002"); bbsDao.insert(vo); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void testSelect() { BbsVO vo = new BbsVO(); try { vo = bbsDao.select(200); System.out.println(vo.getBbsno()); System.out.println(vo.getTitle()); System.out.println(vo.getContent()); System.out.println(vo.getWriter()); System.out.println(vo.getRegdate()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void testUpdate() { BbsVO vo = new BbsVO(); try { vo = bbsDao.select(300); vo.setTitle("300번 글 타이틀 수정입니다."); vo.setContent("300번 글 내용 수정한 내용입니다"); vo.setHits(0); bbsDao.update(vo); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void testDelete() { try { bbsDao.delete(150); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
testInsert() 테스트 결과
testSelect() 테스트 결과
Ibatis를 테스트 할 경우 하나의 메소드만 테스트를 하여도 전체 xml을 테스트하므로 에러메시지를 확인하여야 합니다.
자 기존의 소스와 비교하였을 때 매우 간단하게 구현하는 것을 볼 수 있으며 보다 확장성이 좋아진 것을 볼 수 있습니다.
즉, SQL을 수정 또는 추가시 기존 소스를 수정해야 하는 부분이 많이 줄어 들었으며 결과를 return하는 것도 ibatis에서 자동으로 설정하여 반환하므로 개발자는 거의 신경을 안써도 됩니다.
그런데 만약에 여러게의 게시판이 있다고 생각해봅시다. 각 게시판마다 이런 동일한 코드를 작성해야 할 까요.
다음번에는 좀 더 확장성이 좋게 VO, DAO를 설계해 보도록 해보겠습니다.
[출처] http://blog.naver.com/byebird
'Programming > Java' 카테고리의 다른 글
Generic을 사용한 VO, DAO의 구현 (0) | 2011.07.19 |
---|---|
JDBC를 이용한 VO,DAO의 구현 (0) | 2011.07.19 |