티스토리 뷰

728x90
iBatis가 구동되는 순서(Struts와 연동)
※ 톰캣이 구동되면서 init에서 실행되는 것이 아니라 각 기능별 클래스에서 Dao Manager를 통해 호출하는 순간 실행

○ DAOManager가 DaoManagerBuilder.builderDaoManager(Dao.xml) 통해서 
    SqlMapConfig와 실제 모든 DAO 작업을 처리할 인터페이스와 그것을 구현한 실제클래스를 설정해 놓은 
    dao.xml 파일을 로드
    사용 예) BbsDao bbs = (BbsDao)DaoService.getDao(BbsDao.class);

○ 로드된 dao.xml 파일에 설정되어 있는 
    SqlMapConfig 파일과 실제 작업을 수행하는 클래스파일(IBATISDAOimpl.java) 읽음

○ SqlMapConfig
    디비접속 정보와, 쿼리들을 처리할 쿼리문들이 코딩되어 있는 SqlMap 파일을 읽어들여서
    SqlMap 안의 ELEMENT 들을 쓸 수 있게  자동으로 처리하여, 
    자바코드에서 ELEMENT ID 를 key 값으로 부르면 사용 가능하도록 처리

○ 인터페이스를 구현한 실제 수행 클래스(여기서는 BbsDaoImpl.java)
    이 클래스는 DAO 기능을 수행할 자바코드를 모아놓은 클래스이다.
    여기까지가  iBatis가 DAO 수행을 위해서 설정 파일들이 로드되는 과정

출처 : http://winmargo.tistory.com/109



1. Dao Config

[dao.xml]

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE daoConfig PUBLIC "-//ibatis.apache.org//DTD DAO Configuration 2.0//EN" "http://ibatis.apache.org/dtd/dao-2.dtd">

<daoConfig>

<context id="sqlmap">

<transactionManager type="SQLMAP">
<property name="SqlMapConfigResource" value="sql_map_config.xml" />
</transactionManager>

<dao interface="Struts_MVC.BbsDao" implementation="Struts_MVC.BbsDaoImpl" />

</context>

</daoConfig>


- SqlMapConfig 파일 지정
- Dao Interface 파일 지정(구현할 파일 지정)



2. Dao Service

[DaoService.java]

package Struts_MVC;

import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.dao.client.*;

public class DaoService {
private static DaoManager daoManager;
private static DaoManager getDaoManager() {
String daoXmlResource = "dao.xml";
Reader reader = null;
if(daoManager == null) {
try {
reader = Resources.getResourceAsReader(daoXmlResource);
daoManager = DaoManagerBuilder.buildDaoManager(reader);
} catch (Exception e) {
e.printStackTrace();
}
}
return daoManager;
}
public static Dao getDao(Class inter) {
return getDaoManager().getDao(inter);
}
}


- Dao Config 파일 지정
- Dao Service를 어디서든지 불러다 쓸수 있도록 static 선언


3. SqlMapConfig

[sql_map_config.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>

<properties resource="sql_map_config.properties" />
<transactionManager type="JDBC" commitRequired="false">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="${driver}" />
<property name="JDBC.ConnectionURL" value="${url}" />
<property name="JDBC.Username" value="${userName}" />
<property name="JDBC.Password" value="${password}" />
</dataSource>
</transactionManager>
<sqlMap resource="GGoReb.xml" />
</sqlMapConfig>


- 속성들이 저장될 Property 파일 지정
- Property에 저장된 내용을 넘겨받는 부분(DB 접속에 필요한 정보들)
- Query가 저장될 파일 지정



4. SqlMapConfig Property

[sql_map_config.properties]

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1522:ORCL
userName=seorab
password=dkagh



5. SqlMap

[GGoReb.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>
<typeAlias alias="ARTICLE" type="Struts_MVC.BoardBean" />
<typeAlias alias="UPDATE" type="Struts_MVC.BoardBean" />
<typeAlias alias="NUMBER" type="Struts_MVC.NumberBean" />

<resultMap id="bbsResult" class="ARTICLE">
<result property="articleNumber" column="article_number" />
<result property="id" column="id" />
<result property="title" column="title" />
<result property="content" column="content" />
<result property="password" column="password" />
<result property="hitNumber" column="hit_number" />
<result property="depth" column="depth" />
<result property="writeDate" column="write_date" />
<result property="fileName" column="file_name" />
</resultMap>
<sql id="SELECT_ALL_SQL">
SELECT * FROM article_model2
</sql>
<sql id="WHERE_IDX">
WHERE article_number=#articleNumber#
</sql>
<select id="ALL_ARTICLES" resultClass="ARTICLE" resultMap="bbsResult">
<include refid="SELECT_ALL_SQL" />
ORDER BY article_number DESC
</select>
<select id="ARTICLE_COUNT" resultClass="int">
SELECT count(article_number) FROM article_model2
</select>
<update id="SET_HIT_NUMBER" parameterClass="int">
UPDATE article_model2 SET hit_number=hit_number+1 WHERE article_number=#articleNumber#
</update>
<select id="GET_CONTENT" resultClass="ARTICLE" resultMap="bbsResult">
<include refid="SELECT_ALL_SQL" />
<include refid="WHERE_IDX" />
</select>
<insert id="SET_ARTICLE" parameterClass="ARTICLE">
<selectKey keyProperty="articleNumber" resultClass="int">
SELECT article_model2_sequence.NEXTVAL AS article_number FROM DUAL 
</selectKey>
INSERT INTO article_model2 
(article_number, id, title, content, password, hit_number, depth, write_date, file_name) 
VALUES 
(#articleNumber#, #id#, #title#, #content#, #password#, #hitNumber#, #depth#, SYSDATE, #fileName#)
</insert>
<delete id="SET_DELETE" parameterClass="int">
DELETE FROM article_model2 WHERE article_number=#articleNumber#
</delete>
<update id="SET_MODIFY" parameterClass="UPDATE">
UPDATE article_model2 SET title=#title#, content=#content#, password=#password#, write_date=SYSDATE, file_name=#fileName# WHERE article_number=#articleNumber#
</update>
<select id="SET_REPLY_NUMBER_CHANGE1" parameterClass="NUMBER" resultClass="int">
SELECT article_number FROM article_model2 WHERE article_number BETWEEN #startNumber# AND #endNumber# ORDER BY article_number ASC
</select>
<update id="SET_REPLY_NUMBER_CHANGE2" parameterClass="int">
UPDATE article_model2 SET article_number=#num#-1 WHERE article_number=#num#
</update>
<insert id="SET_REPLY" parameterClass="ARTICLE">
INSERT INTO article_model2 
VALUES 
(#articleNumber#, #id#, #title#, #content#, #password#, 0, #depth#, SYSDATE, null)
</insert>
<select id="CHECK_LOGIN" parameterClass="String" resultClass="String">
SELECT password FROM article_model2_member WHERE id=#id#
</select>
</sqlMap>


- Sql 쿼리 사용을 잘 못해서 상당히 길게 비효율적으로 되어 있다
- SET_REPLY_NUMBER_CHANGE1과 2 부분은 하나로 합친 형태
  :  <update id="SET_REPLY_NUMBER_CHANGE" parameterClass="NUMBER">
UPDATE
                    article_model2
                SET
                    article_number=article_number-1
                WHERE
                    article_number BETWEEN #startNumber# AND #endNumber#
</update>
        이렇게 간단하게 끝낼수 있는 것을 쿼리 두문장으로 써놨었다.. -_-
- 현재 SET_REPLY_NUMBER_CHANGE 는 클래스에서 계산된 결과값을 받아서 쿼리문을 보내고 있으나
   단순히 게시물 번호만 보내서 계산하게 할 수도 있다
   :  <update id="SET_REPLY_NUMBER_CHANGE" parameterClass="int">
UPDATE 
                    article_model2 
                SET 
                    article_number=article_number-1 
                WHERE 
                    article_number
                BETWEEN (FLOOR((#article_number#-1)/1000)*1000+1) AND #article_number#-1
</update>
        오라클에서의 작성 예 이다 
        이런식으로 SQL 에서 제공하는 함수를 이용해서 값을 넣는것도 가능하다


6. Dao Interface

[BbsDao.java]

package Struts_MVC;

import java.util.ArrayList;

public interface BbsDao {
public ArrayList<BoardBean> getArticles(int startNumber, int endNumber);
public int getArticleCount();
public void setHitNumber(String articleNumber);
public BoardBean getContent(String articleNumber);
public void setArticle(BoardBean boardBean);
public void setReplyNumberChange(int articleStartNumber, int articleEndNumber);
public void setReply(BoardBean boardBean);
public void setModify(BoardBean boardBean);
public void setDelete(String articleNumber);
public int checkLogin(String id, String password);
}



7. Dao Interface 구현 클래스

[BbsDaoImpl.java]

package Struts_MVC;

import java.util.ArrayList;

import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.template.SqlMapDaoTemplate;

public class BbsDaoImpl extends SqlMapDaoTemplate implements BbsDao {

public BbsDaoImpl(DaoManager daoManager) {
super(daoManager);
}

@Override
public ArrayList<BoardBean> getArticles(int startNumber, int endNumber) {
return (ArrayList<BoardBean>)queryForList("ALL_ARTICLES", startNumber, endNumber);
}
@Override
public int getArticleCount() {
return (Integer)queryForObject("ARTICLE_COUNT");
}

@Override
public void setHitNumber(String articleNumber) {
update("SET_HIT_NUMBER", Integer.parseInt(articleNumber));
}

@Override
public BoardBean getContent(String articleNumber) {
return (BoardBean)queryForObject("GET_CONTENT", Integer.parseInt(articleNumber));
}

@Override
public void setArticle(BoardBean boardBean) {
insert("SET_ARTICLE", boardBean);
}

@Override
public void setReplyNumberChange(int articleStartNumber, int articleEndNumber) {
ArrayList articleNumberList = new ArrayList();
NumberBean numberBean = new NumberBean();
numberBean.setStartNumber(articleStartNumber);
numberBean.setEndNumber(articleEndNumber);
articleNumberList = (ArrayList)queryForList("SET_REPLY_NUMBER_CHANGE1", numberBean);
System.out.println("list size : " + articleNumberList);
for(int i = 0; i < articleNumberList.size(); i++) {
System.out.println("num : " + articleNumberList.get(i));
update("SET_REPLY_NUMBER_CHANGE2", articleNumberList.get(i));
}
}

@Override
public void setReply(BoardBean boardBean) {
insert("SET_REPLY", boardBean);
}

@Override
public void setModify(BoardBean boardBean) {
update("SET_MODIFY", boardBean);
}

@Override
public void setDelete(String articleNumber) {
delete("SET_DELETE", Integer.parseInt(articleNumber));
}

@Override
public int checkLogin(String id, String password) {
String pass = (String)queryForObject("CHECK_LOGIN", id);
if(pass.equals(password)) {
return 0;
}
return 1;
}

}


- SqlMapDaoTemplate 상속
- queryForList, queryForObject, update, insert, delete 등 각 기능에 맞는 메소드 사용
  ㆍ각 메소드는 여러가지 형태로 오버로딩 되어 제공되고 있으므로 상황에 맞게 골라쓰면 된다


여기까지가 실제 동작을 가능하게 해주는 파일들이다

이제 각 상황에 맞는 기능 클래스들을 구현해주면 된다

아래는 글 목록에서 제목을 클릭했을때 내용을 가져오는 ReadAction.java 의 코드 예이다

[ReadAction.java]

package Struts_MVC;

public class ReadAction {
String articleNumber;
String pageNumber;
BoardBean boardBean;
public String execute() {
BbsDao bbs = (BbsDao)DaoService.getDao(BbsDao.class);
bbs.setHitNumber(articleNumber);
boardBean = bbs.getContent(articleNumber);
return "success";
}

public String getArticleNumber() {
return articleNumber;
}

public void setArticleNumber(String articleNumber) {
this.articleNumber = articleNumber;
}

public String getPageNumber() {
return pageNumber;
}

public void setPageNumber(String pageNumber) {
this.pageNumber = pageNumber;
}

public BoardBean getBoardBean() {
return boardBean;
}

public void setBoardBean(BoardBean boardBean) {
this.boardBean = boardBean;
}
}


- 이런 형태로 iBatis를 로드시키고 미리 정의된 메소드를 불러오기만 하면 작업 끝이다