앞서 아이바티스를 사용해서 DAO 처리리를 하기위해서 설정을 하는데 시간이 좀 걸렸다. 

하지만 초기에 이렇게 작업을 해놓으면 유지보수에 있어서는 정말 편리할 것이다.

처음에 개발을 빨리 편하게 할려면 이 짓을 할필요가 없지만 

나중에 유지보수에 들어가는 시간과 노력과 짜증을 생각하면 할만하다




이제 실제로 DAO 처리를 함 해보자.... Data Access Object


앞에서 아이바티스가 로드되는 순간은 DAOManager 를 얻어서 구현클래스를 얻는 것이라 했다.

IBATISDAO iBATIS = (IBATISDAO)DAOService.getDao(IBATISDAO.class);


iBATIS 는 IBATISDAO 를 구현한 클래스이다.

(스트럿츠에 대한 설명은 안합니다. DAO 부분만)
일단은 제일 간단하면서 이것 저것 다 해볼 수 있는 게시판 리스트를 만드는 뷰를 처리해보자.




ListAction.java

ArrayList<ItemBean> array = null;

IBATISDAO iBATIS = (IBATISDAO)DAOService.getDao(IBATISDAO.class);

array = iBATIS.getArticles(index  * 10);

액션 클래스에서 구현클래스를 얻고, 그클래스안의 모든글을 다 가져오는 getAtricles() 메소드를 이용해서

모든글을 자바빈인 ItemBean 에 담아서 그놈을 arraylist 에 담아서 리턴받는다.





IBATISDAOimpl.java  ( 구현 클래스 )
public class IBATISDAOimpl extends SqlMapDaoTemplate implements IBATISDAO {

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

	@Override
	public ArrayList getArticles(int index) {
		
		return (ArrayList)queryForList("Allarticles", new Integer(index));
	}

	
코드를 보면 12라인에 queryForList() 메소드가 보인다. ( 구현 클래스에서는 리턴에 대한 작업만 최소한으로 코딩한다)

저 메소드는 SELECT 쿼리를 이용할 때 사용하는 메소드인데, 몇가지가 더있다. 

케이스메소드명
결과세트를 반환할 때 queryForList(), queryForObject()
한개 이상의 결과 객체를 반환할 때(여러개 레코드를 묶어서 받을때 편함) queryForList()
한개의 결과 객체를 반환할 때, 여러개의 레코드가 반환될 때는 에러발생시킴 queryforObject()
결과세트를 반환하지 않거나 OUT 파라미터에 결과세트를 셋팅하지 않을 때 update()


코드 12라인에 보면

첫 번째 파라미터는 "Allarticles" 라고 이름을 지정하고, 2번째는 정수를 파라미터로 주고있다.


이것이 바로 sqlMap 에 정의해놓은 쿼리문들을 부르는 방법이다.

 
쿼리문에 정의되어있는 아이디값과 매핑되는 쿼리문을 실행시키면서 파라미터로 2번째 인자인 정수를 가지고 가는 것이다. 





그럼 이제 매핑되는 sqlMap 파일안의 쿼리를 살펴보자.

Margo.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/dao-2.dtd">

<sqlMap>
<!-- Struts_BBS.ItemBean 클래스를 alias 속성을 줘서 artcle 이라는 이름으로 쓰겠다고 정의 -->
<typeAlias alias="article" type="Struts_BBS.ItemBean"/>

<select          id="Allarticles"         parameterClass="int"            resultMap="getContent">
SELECT * FROM 
(SELECT ROWNUM rnum,A.*  
FROM 
(SELECT * FROM margo ORDER BY article_num DESC) A ) 
WHERE rnum BETWEEN #index#+1 AND #index# + 10
 
</select>

 select 문에 해당하는 id 가 자바코드에서 부른것과 동일한 엘리먼트로 parameterClass="int"  값을 가지면서
온다. 이 값을 이용하는 부분은 이 게시물 아래 다른글에 보면 있다. (http://winmargo.tistory.com/104)


↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

SELECT 엘리먼트 속성을 보면 id, parameterClass, resultMap 이렇게 되어있는데

id 는 얘기했듯이  자바코드에서 insert(), queryForList(), delete(), update() 등 여러 DB관련 메소드에서

부를때 키값으로 매핑되는 이름이다. 이 메소드들은 SqlMapDaoTemplate 를 상속 받았기 때문에

쓸 수 있는 것이다. 



parameterClass 는 인자로 달고오는 값이고, 이 값들은 프리미티브 타입일수도있고, 클래스일수있다.

resultMap 은 resultClass 와 두가지중 하나를 쓸수 있는데

resultMap 은 자바빈과 DB Column 명을 미리 매핑시켜놓고, 자동으로 불러쓸수있는 방법이다.

이방법에 대해서 자세한건 ( http://winmargo.tistory.com/107 )


동작되는 방식은 queryForList() 이기 때문에 자동으로 ArrayList 로 반환한다.

실렉트 쿼리로인해서 다수의  레코드들이 튀어나올것이다.

이렇게 나온 코드를 resultMap 이나, resultClass 가 받아서  클래스들을 ArrayList 에 넣어서 

result 값을 만들어준다.



저 위에 코드 12라인을 보면 return (ArrayList<ItemBean>)queryForList("Allarticles", new Integer(index));

ArrayList 를 리턴하고 있다. 


여기까지가 DaoManager 를 이용해서 구현클래스를 얻은다음 , 수행메소드를 이용해서

DB에서 참조해서 가져올 값을 넘겨서, result 를 얻어오기 까지의 수행과정이다. 



IBATIS DAO 수행방법 간단요약


1. DAO Manager 로부터 DAO 처리 메소드들이 담긴 구현클래스를 얻어온다.


2. 메소드에서 sqlMap 에 정의된 쿼리문을 매핑되는 "ID"를 통해서 부른다.
      관련된 메소드 본체와     구현한 클래스(iBATISDAOimpl.java)를 는 아래에 따로 정리해놓았다.


3. sqlMap 에 정의된 쿼리에서 파라미터값을 이용해서 쿼리를 수행한 후
    리턴처리가 있으면 리턴값을 생성후에 리턴한다. 

 




Statement 처리를 위한 메소드 정리

SqlMapClient API를 통해 statement를 수행하기.
 
SqlMapClient는 이것에 관련된 모든 맵핑된 statement를 수행하기 위한 API를 제공한다. 그 메소드들은 다음과 같다. 

 
public int insert(String statementName, Object parameterObject)
throws SQLException
 
public int update(String statementName, Object parameterObject)
throws SQLException
 
public int delete(String statementName, Object parameterObject)
throws SQLException
 
public Object queryForObject(String statementName,Object parameterObject)
throws SQLException
 
public Object queryForObject(String statementName,Object parameterObject, Object resultObject)
throws SQLException

public List queryForList(String statementName, Object parameterObject)
throws SQLException
 
public List queryForList(String statementName, Object parameterObject,int skipResults, int maxResults)
throws SQLException
 
public List queryForList (String statementName,Object parameterObject, RowHandler rowHandler)
throws SQLException
 
public PaginatedList queryForPaginatedList(String statementName,Object parameterObject, int pageSize)
throws SQLException
 
public Map queryForMap (String statementName, Object parameterObject,String keyProperty)
throws SQLException
 
public Map queryForMap (String statementName, Object parameterObject,String keyProperty, String valueProperty)
throws SQLException




위 메소드들의 설명 

각각의 경우에 맵핑된 statement의 이름은 첫번째 파라미터로 넘겨진다. 이 이름은 위에서 서술된 <statement>요소의 
name속성에 대응된다. 추가적으로 파라미터객체는 옵션적으로 전달할수 있다. null파라미터객체는 만약 기대되는 파라미
터가 없다면 전달될수 있다. 행위의 남겨진 차이점은 아래에서 간단하게 설명된다. 

 
insert(), update(), delete() : 이 메소드들은 update statement를 위해 특별히 의미된다. 밑의 쿼리 메소드중에 하나를 사용
해서 update statement를 수행하는 것은 불가능하다. 어쨌든 이것은 애매한 의미이고 드라이버에 의존적이다. 
 
executeUpdate()의 경우에 statement는 간단하게 수행되고 영향을 받는 많은 수의 row가 반환된다. 
 
 
queryForObject() : executeQueryForObject()의 두가지 버전이 있다. 하나는 새롭게 할당된 객체를 반환하는 것이고 다른 
하나는 파라미터처럼 전달된 미리할당된 객체를 사용하는것이다. 후자의 경우 하나의 statement보다 많은 수에 의해 생성되
는 객체에 유용하다. 
 
queryForList() : queryForList()에는 세가지 버전이 있다. 첫번째는 쿼리를 실행하고 쿼리로부터 모든 결과를 반환하는것이
고 두번째는 스킵되는 결과물의 수(이를 테면 시작지점)를 지정할수 있고 반환되는 레코드의 최대갯수도 지정할수 있다. 이것
은 전체데이터를 반환하고 싶지 않은 굉장히 큰 데이터셋과 작업을 할 때 가치가 있다. 마지막으로 세번째는 row핸들러를 가
진다. 이 메소드는 대개의 칼럼과 rows보다 result객체를 사용해서 row에 의해 결과를 처리하도록 한다. 이 메소드는 전형적인 
이름과 파라미터 객체를 넘기지만 RowHandler를 가진다. row핸들러는 RowHandler인터페이스를 구현하는 클래스의 인스턴
스이다. RowHandler인터페이스는 다음처럼 오직 하나의 메소드만 가진다. 
public void handleRow (Object object, List list); 
이 메소드는 데이터베이스로부터 반환되는 각각의 row를 위한 RowHandler에서 호출될것이다. 이것은 쿼리결과를 처리하기 
위해 깔끔하고 간단하며 확장가능한 방법이다. RowHandler의 사용법 에제를 위해 아래 섹션의 예제를 보라. 리스트 파라미터
는 queryForList()메소드로부터 반환될 List인터페이스의 인스턴스이다. 당신은 리스트의 result객체의 아무것도, 몇몇 또는 모
든 것을 추가할수도 있다. 만약 당신이 100만개의 row로 작업을 한다면 리스트에 그것들을 모두 넣는 것은 좋은 생각이 아니
다. 
 
queryForPaginatedList(): 이것은 이전, 다음 버튼으로 데이터를 탐색할 때 데이터의 일부를 관리할수 있는 리스트를 반환
하는 매우 유용한 메소드이다. 이것은 쿼리로부터 반환된 레코드의 일부만을 표시하는 사용자 인터페이스를 구현하는데 유용
하다. 10,000개의 필드를 반환하는 검색엔진이 있지만 한번에 100개만 표시해야 하는 예제가 있다. PaginatedList인터페이스
는 페이지를 통한 탐색(nextPage(), previousPage(), gotoPage())과 페이지의 상태를 체크(isFirstPage(), isMiddlePage(), 
isLastPage(), isNextPageAvailable(), isPreviousPageAvailable(), getPageIndex(), getPageSize())하는 메소드를 포함한다. 유효
한 레코드의 총 개수가 PaginatedList인터페이스로부터 접근가능하지 않더라도 이것은 기대되는 결과갯수를 세는 두번째 
statement를 간단히 수행함으로써 쉽게 달성할 수 있을 것이다. 반면에 PaginatedList를 사용하면 지나친 부하가 발생할수도 
있다. 
 
queryForMap(): 이 메소드는 리스트로 결과의 collection을 로드하는 대안을 제공한다. 대신에 이것은 keyProperty처럼 전달
된 파라미터에 의해 결과를 키(key)화된 map으로 로드한다. 예를 들면 만약 Employee객체의 collection을 로드한다면 당신은 
그것들을 employeeNumber프라퍼티에 의해 키(key)화된 map으로 로드할것이다. Map의 값은 전체 employee객체가 될수도 
있고 valueProperty라고 불리는 두번째 파라미터내 정의된 employee개체로 부터의 다른 프라퍼티가 될수도 있다. 예를들면 당
신은 employee숫자에 의해 키(key)화된 employee이름의 map을 원할지도 모른다. result객체처럼 Map타입을 사용하는 개념을 
사용하는 메소드를 혼란스러워하지 마라. 이 메소드는 result객체가 자바빈즈나 Map인지에따라 사용될수 있다. 


출처 : IBATIS SQL Maps 개발자 가이드 (번역 : 이동국)

 


iBATISDAOimpl.java
package Struts_BBS;

import java.util.ArrayList;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.template.SqlMapDaoTemplate;

public class IBATISDAOimpl extends SqlMapDaoTemplate implements IBATISDAO {

	// 생성이되면서, 
	// 저렇게 설정해놓은 IBATISDAOimpl 클래스가 인자로 들어온다
	public IBATISDAOimpl(DaoManager daoManager) {
		super(daoManager);
		// TODO Auto-generated constructor stub
	}

	@Override
	public ArrayList getArticles(int index) {
		// TODO Auto-generated method stub
		return (ArrayList)queryForList("Allarticles", new Integer(index));
	}

	
	
	@Override
	public int getArticleCount(){
		
		return (Integer)this.queryForObject("getCount");
	}
	
	
	
	@Override
	public ItemBean getContent(int contentNum){
		
		return (ItemBean)this.queryForObject("getContent", new Integer(contentNum));
	}
	
		
	
	@Override
	public Object setContent(ItemBean itemBean){
		
		return (String)insert("setContentTest", itemBean);
	}
	
	
	
	@Override
	public int checkID(String id, String password){
	
		int state = 3;
		String tmp= null;
		
		tmp = (String)this.queryForObject("checkID", id);
			
		if(tmp == null) return state;
			
		if(tmp.equals(password)) {
			
			return 1;
			
		}else return 0;
		
	}
	
	
	
	@Override
	public int setReply(ItemBean itemBean){
			
		int firstNumber = itemBean.article_num - 1;
		
		itemBean.setArticle_num(firstNumber);
			
		//글 번호 정리
		this.update("reply_articleNumControl", firstNumber);
		
		//댓글 입력
		this.insert("setReply", itemBean);
				
		return 0;
	}
	
	
	
	@Override
	public int deleteContent(int number, String password){
		
		int state = 3;
		
		String tmp = (String)this.queryForObject("checkPASS", new Integer(number));
		
		
		if(tmp == null) return state;
		
		
		if(tmp.equals(password)) {
			
			this.delete("deleteContent", new Integer(number));
			
			return 1;
			
		}else return 0;
		
	}
	
	
	
	@Override
	public int editContent(ItemBean itemBean){
		
		this.update("editContent", itemBean);
		
		return 0;
	}
	
}





YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST