DWR - (1) DWR이란?

Published on: 2010. 12. 29. 11:41 by louis.dev
DWR은 DirectWebRemoting의 약자입니다.

DWR을 사용하기 전 비동기적 서버 통신은 Ajax를 통해서 비동기적인 request를 보내고 서버가 해당하는 데이터를 텍스트(json text도 가능)나, xml을 보내주면 javascript의 callback method를 통해 데이터 데이터를 parsing하여 view에 javascript로 뿌려주는 방식으로 사용하였습니다.

이렇게 web에서 가장 많이 사용하는 비동기 통신은 얼마전까지 ajax가 담당해 왔습니다. 하지만, Ajax를 구현해 보신 분은 아시겠지만, 비동기 통신을 하기 위해선 XMLHttpRequest라는 Object의 인스턴스를 생성해서( 이것도 브라우저마다 지원하는 XMLHttpRequest가 달라 브라우저마다 따로 구현을 해야 합니다.) request를 서버로 날리고 response로 받은 xml이나 text( ajax는 두종류의 return밖에 지원하지 않아요..ㅜㅜ)를 적절히 파싱후 html의 해당 영역에 꽂아 넣어야 하는 엄청 대박 불편한 루틴을 타야 합니다. 

그래서 나온것이 DWR입니다. 이 DWR이란 놈은 Ajax의 XMLHttpRequest를 만들필요 없이, 바로 비지니스로직을 처리하는 JAVA의 class로 직접 접근할 수 있습니다. 그렇기 때문에 request를 날리기 위해 XMLHttpReqeust를 만들 필요가 없을 뿐더러, view에서 자바 method를 call할때 전달 파라미터가 String형이 아닌 Object 형도 가능하다는 장점이 있습니다.

그럼 다음 post에는 실제 DWR을 구현해 보도록 하겠습니다~

*비동기적 통신? 
일반적으로 서버로 request를 보내게 되면 페이지가 이동하면서 서버가 응답을 보내올때까지 먹통이 되었다가,(서버가 응답을 리턴해 줄때까지 기다리다가) 서버가 리턴해준 응답을 통해 다음페이지를 보여주게 됩니다. 이러한 방식이 동기화 방식입니다. 
이와 반대로 비동기적 통신이란 페이지는 이동하지 않은 상태에서 request를 만들어 서버로 요청할수 있고, 그 반응이 올때까지 기다리지 않고 다른 작업을 하다 서버로 부터 응답이 오면 화면에 보여주는 방식을 비동기적이라고 합니다.

Ajax의 비동기 통신에 대해서 얘기 할때 보통 택배의 예를 많이 듭니다. 
만약 택배아저씨가 전달할 물건이 request이고 아저씨가 배달해야 할 집을 server라고 가정하겠습니다. 이때 동기적 통신은 처음 배달하려는 집에 찾아가 문을 두드리고 사람이 없으면 올때까지 기다리는 방식입니다. 정말 비효율 적이겠죠.
반대로 문을 두드렸으나 반응이 없음을 확인한 택배 아저씨는 현관문 앞에 쪽지로 친절하게 "집에 도착했을때 전화주세요" 라고 친절하게 자기의 전화번호를 남겨두고( 실제로 이런 분은 없죠..ㅜㅜ) 다른집의 택배를 열심히 배달하다가, 아까 집에 사람이 없던 곳의 주인이 집에 도착하여 "나 집에 왔어요~" 라고 전화를 주면 다시 택배아저씨는 그집으로 가서 택배를 전달을 합니다.

이처럼 페이지에서 사용자가 서버의 요청을 올때까지 멍하니 하얀 페이지를 보고 있는것이 아니라, 계속 다른 작업을 하면서 서버로부터 response가 도착했을때 처리하는 방식을 비동기적 통신이라고 합니다. (이해가 잘 되셨을지는 잘 모르겠네요..;;;)

Spring - Spring + iBatis 연동시 iBatis Transaction 실행 안되는 문제

Published on: 2010. 12. 13. 17:56 by louis.dev

프로젝트를 진행하다 Transaction을 수행해야 하는 query가 있었습니다. 그때 저는 iBatis의 Transaction을 통해 다음과 같이 구현하였습니다.
(Spring에서 제공하는 SqlMapClientTemplate를 이용하여 iBatis를 사용했습니다)

SqlMapClient sqlClient = template.getSqlMapClient();
try {
	sqlClient.startTransaction();
	template.insert("turotial.dataInsert", data);
	template.insert("tutorial.updateInfo", data);
	sqlClient.commitTransaction();
	return true;
} catch (SQLException e) {
	e.printStackTrace();
	return false;
} finally {
	sqlClient.endTransaction();
}


위와 같이 insert하고 update부분을 iBatis의 transaction으로 묶으려고 하였습니다.

하지만 우연치 않게 iBatis의 Transaction이 먹히지 않는것을 발견하였습니다. 왜이럴까 고민하다가 Spring에서 제공하는 Transaction을 통해 구현해 보기로 하였고, 결국 Transaction이 제대로 동작하는것을 확인 할 수 있었습니다.

저같은 경우는 Spring project를 할때 db연동에 관련한 모든 bean들을 applicationContext-iBatis.xml에 몰아 둡니다.( 관리하기가 더 편하더라구요.. 개인적 생각입니다.^^)

저는 이 ibatis.xml 에 ibatis를 통해 DB에 접근할 dataSource bean을 설정해 두었습니다.

1. transactionManager와 transactionTemplate을 bean으로 등록합니다.
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="java:comp/env/jdbc/tutorial"/>
</bean>
	
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
	<property name="configLocation" "classpath:sqlMapConfig.xml" />
	<property name="dataSource" ref="dataSource" />
</bean>
	
<bean id="template"
          class="org.springframework.orm.ibatis.SqlMapClientTemplate"
          p:sqlMapClient-ref="sqlMapClient"/>
    
<bean id="transactionManager" "org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
    
<bean id="transactionTemplate"  
      class="org.springframework.transaction.support.TransactionTemplate"
      p:transactionManager-ref="transactionManager"/>


위와 같이 transactionManager와 transactionTemplate bean을 dataSource를 통해 생성합니다.

2. transactionTemplate를 사용할 bean에 property로 설정합니다.
<bean id="tutorialDAO" class="tutorial.TutorialDAOImpl">
	<property name="template" ref="template"/>
	<property name="transactionTemplate" ref="transactionTemplate"/>
 </bean>


3. 해당 DAOImpl 클래스에서 field로 transactionTemplate와 setter method를 구현하여 DI가 되도록 작업해 줍니다.

4. 다음과 같이 transactionTemplate를 통해 transaction을 구현합니다.
public boolean transactionTest(final TutirialVO vo ) throws SQLException{
	boolean result = false;
	result = (Boolean)transactionTemplate.execute( new TransactionCallback() {
		public Object doInTransaction(TransactionStatus status) {
			try {
				template.insert("Tutorial.insertData", vo);
				template.insert("Tutorial.updateData", vo);
				return true;
			}catch (Exception e){
				e.printStackTrace();
				status.setRollbackOnly();
				return false;
			}
		}
	});
	return result;
}

위와 같이 transactionTemplate.execute를 실행하고 전달인자로 TransactionCallBack 인스턴스를 전달하는데, 일반적으로 TransactionCallback이 인터페이스 이기 때문에 new로 객체를 생성하고 doInTransaction method를 구현합니다.

iBatis - queryForMap을 사용하여 map 인스턴스 return 받기

Published on: 2010. 12. 13. 17:34 by louis.dev

흔히 iBatis를 사용하면 SqlMapClient의 queryForListqueryForObject를 많이 사용하게 됩니다.
queryForList는 select문을 통하여 여러 row를 가져올때 iBatis가 List형태로 리턴해 주고, queryForObject는 select의 where조건을 통해 하나의 row만 가져오게 됩니다.
하지만 SqlMapClient에는 이들 메소드 만큼 유용한 메소드를 지원해 주는데, 그 메소드가 바로 queryForMap입니다. SqlMapClient의 queryForMap은 select문을 통해 검색된 데이터를 map형태로 리턴해 주는 아주 유용한 메소드 입니다.

Map형태로 데이터를 가져올때 약 2가지의 방법이 있습니다.

1. column을 key로 데이터를 value로 가질때
만약 select query를 통해 검색된 데이터가 다음과 같다고 가정하겠습니다.

ex)select * from test_tb where idx = 1
 idx  name  title  contents  read_count
 1  전근재  이건뭔가요?  아..모르겠다..ㅜㅜ  100

다음과 같이 검색 되었다고 할때 key값으로는 column(idx,name, title, contents, read_count)이고 각 값들은 검색된 값(1, 전근재, 이건뭔가요?, 아 모르겠다..ㅜㅜ, 100)으로 하고 싶으면 다음과 같이 작업하면 됩니다.

<SPAN id=tx_marker_caret><?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="tutorial">
     <resultMap id="tutorialMap" class="java.util.HashMap">
          <result column="idx" property="idx"/>
          <result column="name" property="name"/>
          <result column="title" property="title"/>
          <result column="contents" property="contents"/>
          <result column="read_count" property="readCount" javaType="int"/>
     </resultMap>

     <select id="getBoardItem" parameterClass="int" resultMap="tutorialMap">
          SELECT *
          FROM test_tb
          WHERE idx = #idx#
     </select>
</sqlMap></SPAN>


위와 같이 설정한후 queryForObject객체로 데이터를 가져 오면 됩니다.
ex)return (Map<String,Object>) getSqlMapClient().queryForObject( "tutorial.getBoardItem", idx);

위의 result의 property속성이 map의 key가 됩니다. 즉 return을 통해 map을 받았으면, map.get("read_count") 가 아니라 map.get("readCount")로 데이터를 가져옵니다.

또한 resultMap의 read_count에는 javaType으로 int형이 선언되어 있는데, 만약 이렇게 지정하지 않으면, iBatis가 숫자형을 BigDecimal로 지정하여 나중에 타입형변환을 하면 문제를 일으킵니다.(BigDecimal은 int형으로 형변환 할수 없다.. 뭐 이렇게 나오죠... 이거때문에 많이 삽질했습니다..ㅜㅜ)


2. 특정 column의 데이터를 key로 또 다른 특정 column을 value로 지정 할때
다음과 같은 select query가 있다고 하겠습니다.

ex) select name, ssn from test_tb;
 name  ssn
 태연  111111-2222222
 김태희  222222-3333333
 이민정  333333-4444444
로 데이터가 검색 되었다고 가정 하겠습니다.

만약 name의 값들을 key로 사용하고 ssn의 값들을 value로 사용하려고 하면, queryForMap을 사용하면 됩니다.
<?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="tutorial">
     <select id="getUserMap" resultClass="java.util.HashMap">
          SELECT name,ssn
          FROM test_tb
     </select>
</sqlMap>

위와 같이 select문을 구성합니다.
그리고 dao에서 SqlmapClient 인스턴스의 queryForMap 메소드를 이용하여 map을 return 받습니다.

ex) return (Map) getSqlMapClient.queryForMap("tutorial.getUserMap", null, "name", "ssn");
이라고 하면 됩니다.
null은 query 문으로 전달할 파라미터가 없음으로 null을 넣은 것이고, 널 다음의 인자가 key를 나타내는 column, 그 다음인자가 value를 나타내는 column 명을 입력하시면 됩니다.

만약 이때 이 key, value의 column명이 AS를 통해 다른이름으로 붙여 졌다면, 해당이름으로 queryForMap을 call해야 합니다.
ex) SELECT name AS n, ssn AS s FROM test_tb
라면 queryForMap("tutorial.getUserMap", null, "n", "s"); 로 실행해야 제대로 데이터를 받을 수 있습니다.

이렇게 queryForMap으로 데이터를 받으면, 해당 map에서 map.get("김태희") 는 222222-3333333 이 나올 것입니다.


자주는 아니지만 map형식으로 받을 일이 종종 있기 때문에 알아두면 다 피가되고 살이되는 정보 입니다~^^

iBatis - 기본 설정 & 게시판 만들기

Published on: 2010. 10. 26. 19:51 by louis.dev

IBatisTutorial.war



얼마전 iBatis 프로젝트가 myBatis라는 이름으로 변경되면서 apache 사이트에서 code.google로 이동하였습니다. myBatis 프로젝트로 변경되면서 많은 설정 부분이 변경되었지만, 일단 많이 사용하는 iBatis2 버전을 가지고 진행 하겠습니다.

본 설정법은 Eclipse + Tomcat 6.0 그리고 MySql 5 버전을 통해 진행하도록 하겠습니다.

iBatis란?
iBatis는 DBMS와 Java 객체간의 자동 맵핑 프레임웍 입니다.
즉, iBatis에서 select 쿼리를 수행하여 검색 된 쿼리가 다음과 같고
 idx  category  title  regDate  readCount
 1  질문  질문합니다.  2010-10-26  0

자바 객체의 property 명이 검색된 쿼리문의 column의 이름과 같다면
package net.tutorial.ibatis.vo;

import java.util.Date;

public class IbatisBoardVO {
	private int idx;
	private String category;
	private String title;
	private String contents;
	private Date regDate;
	private int readCount;
	private String writer;
}

각각의 검색된 column 명에따라 자동으로 객체에 저장이 됩니다.

이렇듯 iBatis는 쉽게 DB의 데이터를 제어할 수 있는 DBMS-JAVA 객체간의 맵핑 프레임웍입니다.

iBatis 설정방법
1. iBatis 라이브러리와 MySQL Connector 라이브러리 다운
자바 프로그래밍의 시작은 늘 라이브러리의 추가입니다~^^

iBatis-2.3.4.726 을 다운로드 후, lib안의 ibatis-2.3.4.726.jar 
MySQL Java용 Connector 다운로드 후, mysql-connectgor-java-5.1.13-bin.jar
위의 두 파일을 이클립스에서 생성한 웹프로젝트 안의 webContent\WEB-INF\lib 디렉토리에 추가합니다.

2. 게시판에 사용될 DB와 Table을 생성합니다.(콘솔에서 접근하여 DB를 생성해도 되고, 다른 어플리케이션을 통해서 테이블을 생성하셔도 상관없습니다. 전 개인적으로 SQLGate라는 프로그램을 사용해서 개발합니다.^^)

MySQL DB생성과 권한 설정 방법

-DB 생성 쿼리
CREATE DATABASE board_db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

-Table 생성 쿼리
CREATE TABLE `ibatis_board_tb` (
  `idx` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category` char(30) DEFAULT NULL,
  `title` text,
  `contents` text,
  `reg_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `read_count` int(10) DEFAULT NULL,
  `writer` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`idx`),
  UNIQUE KEY `idx` (`idx`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

위와 같은 스크립트로 board_db 라는 데이터 베이스와 ibatis_board_tb 라는 테이블을 생성했습니다.

3. 생성된 테이블과 맵핑될 Value Object를 생성해 줍니다.
- IbatisBoardVO
package net.tutorial.ibatis.vo;

import java.util.Date;

public class IbatisBoardVO {
	private int idx;
	private String category;
	private String title;
	private String contents;
	private Date regDate;
	private int readCount;
	private String writer;
	public int getIdx() {
		return idx;
	}
	public void setIdx(int idx) {
		this.idx = idx;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContents() {
		return contents;
	}
	public void setContents(String contents) {
		this.contents = contents;
	}
	public Date getRegDate() {
		return regDate;
	}
	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
	public int getReadCount() {
		return readCount;
	}
	public void setReadCount(int readCount) {
		this.readCount = readCount;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("IbatisBoardVO [category=");
		builder.append(category);
		builder.append(", contents=");
		builder.append(contents);
		builder.append(", idx=");
		builder.append(idx);
		builder.append(", readCount=");
		builder.append(readCount);
		builder.append(", regDate=");
		builder.append(regDate);
		builder.append(", title=");
		builder.append(title);
		builder.append(", writer=");
		builder.append(writer);
		builder.append("]");
		return builder.toString();
	}
}


4. DB를 사용할때 필요한 설정파일을 생성합니다.
1) db.properties
이 파일은 DB Connection을 맺기 위한 driver, url, username, password 등을 저장하는 파일입니다.
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/생성한DB이름?characterEncoding=utf-8
username=DB에접근아이디
password=DB접근패스워드


2) iBatis 설정을 할 SqlMapConfig.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>
	<!-- 하단의 DataSource 설정을 위해 위에서 생성한 db.properties 파일 위치 설정 -->
	<properties resource="net/tutorial/ibatis/sqlmap/db.properties" />
	<!-- 
		iBatis사용을 위한 설정입니다. 아래 설정내용은 
		useStatementNamespaces="false"를 true로 변경한것 빼고는 Default 설정입니다.
	-->
	<settings
		cacheModelsEnabled="true"
		enhancementEnabled="true"
		lazyLoadingEnabled="true"
		maxRequests="32"
		maxSessions="10"
		maxTransactions="5"
		useStatementNamespaces="true"
	/>
	<!-- properties태그로 properties 파일 위치 경로를 선언하면 
	     ${properties파일에 선언한 이름} 으로 접근하여 데이터를 가져 올수 있습니다.
	     properties 파일을 생성하지 않고 ${driver} 대신 바로 "com.mysql.jdbc.Driver"
	     와 같이 직접 넣을 수도 있습니다.
	-->
	<transactionManager type="JDBC" >
		<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 태그는 실제 쿼리문이 들어갈 xml파일입니다. -->
	<sqlMap resource="net/tutorial/ibatis/sqlmap/BoardSqlMap.xml" />
</sqlMapConfig>


3) 사용할 쿼리문을 정의할 BoardSqlMap.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">
<!--
 	SqlMapConfig.xml 파일에서 namespace사용을 true로 변경하였기 때문에 이 XML의 네임스페이스를 
 	IbatisBoard로 정의합니다.
-->
<sqlMap namespace="IbatisBoard">
	<!--
		typeAlias태그는 type에 선언된 클래스 파일을 짧은이름으로 치환해 주는 역할을 합니다.
		즉 net....IbatisBoardVO란 java파일을 이 xml에서는 Board란 이름으로 사용하겠다는 뜻입니다
	-->
	<typeAlias alias="Board" type="net.tutorial.ibatis.vo.IbatisBoardVO"/>
	
	<!-- 
		실제 사용할 쿼리 문입니다.
		select 시에는 select,
		delete 시에는 delete
		update 시에는 update 태그를 사용하여 쿼리문을 생성합니다.
		이때 id는 필수 요소 입니다. 이 아이디를 통해 쿼리문을 접근할 수 있습니다.
		resultClass="Board" 는 아래 쿼리문을 통해 select된 데이터를 Board 클래스에 자동으로 저장하겠다는 뜻이고, 이 Board클래스는 상단의 typeAlias를 통해 alias시킨 것임으로 결국 IbatisBoardVO에 자동으로 저장될 것입니다.
		 
	-->
	<select id="getTotalBoardList" resultClass="Board">
		SELECT
			idx, category, title, reg_date AS regDate, read_count AS readCount, writer
		FROM
			ibatis_board_tb
		ORDER BY idx DESC
	</select>
</sqlMap>


4) iBatis를 사용하기 위한 자바 객체인 SqlMapClient를 생성하는 SQLManager class를 생성합니다.
package net.tutorial.ibatis.manager;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import java.io.IOException;

public abstract class SQLManager{
	private SqlMapClient sc;

    public SQLManager(){
        sc = null;
        try{
            sc = SqlMapClientBuilder.buildSqlMapClient(Resources.getResourceAsReader("net/tutorial/ibatis/sqlmap/SqlMapConfig.xml"));
        }
        catch(IOException ie){
            ie.printStackTrace();
        }
    }

    public SqlMapClient getSqlMap(){
        return sc;
    }

}


SQLMapClient객체는 SqlMapConfig.xml파일을 읽어서 생성하게 되고, getSqlMap method를 통해 SqlMapClient객체를 전달 하게 됩니다.
이 클래스는 DB접근을 위한 클래스인 DAO(Data Access Object)에서 상속받아 사용하면됩니다.

여기까지 iBatis 사용을 위한 설정이 끝났습니다. 이제 이 설정을 통해 iBatis사용 하도록 해보겠습니다.
저는 html테그를 사용할 jsp - 비지니스로직을 처리할 service class - iBatis를 사용해서 DB에 접근하기 위한 DAO class를 만들어 MVC패턴으로 진행하도록 하겠습니다.

5. SQLManager를 상속받은 DAO class를 생성합니다.
package net.tutorial.ibatis.dao;

import java.sql.SQLException;
import java.util.List;

import net.tutorial.ibatis.manager.SQLManager;
import net.tutorial.ibatis.vo.IbatisBoardVO;

public class IbatisBoardDAO extends SQLManager {
	@SuppressWarnings("unchecked")
	public List<IbatisBoardVO> getTotalBoardList(){
		try {
			return getSqlMap().queryForList("IbatisBoard.getTotalBoardList");
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}
}


getTotalBoardList란 method는 select Query를 통해 게시판 테이블의 내용을 모두 가져와 List형태로 리턴해 주는 method입니다.
이부분에서 중요하게 봐야 할부분은 두군대 인데요

첫번째. SQLManager를 상속받고 getSqlMap method로 SqlMapClient 객체를 가져옵니다.
이때 SqlMapClient객체를 통해 호출 할수 있는 method는 여러가지가 있는데 5가지 정도만 살펴보겠습니다.(제일 많이 사용하는 method이기도 합니다)
① queryForList : Select를 통해 데이터를 가져올때 사용합니다. 만약 Select를 통해 얻어오는 데이터가 여러 행일경우, iBatis는 자동으로 List형태로 변환하여 전달해 줍니다.
② queryForObject : Select를 통해 데이터를 가져올때 사용합니다. 만약 select를 통해 얻어오는 데이터가 1개일 경우(where 조건문을 통해서) queryForObject 를 사용합니다.
③ insert : insert를 할때 사용합니다.
④ update : update를 할때 사용합니다.
⑤ delete : delete를 할때 사용합니다.

두번째. queryForList메소드(queryForObject, insert, update, delete 모두 동일)의 파라미터로 IbatisBoard.getTotalBoardList 로 전달하는데 앞의 IbatisBoard는 BoardSqlMap.xml의 namespace이고, 뒤의 getTotalBoardList는 BoardSqlMap.xml의 select태그 ID입니다.
이렇게 하면 IbatisBoard 라는 네임스페이스를 갖는 xml에서 getTotalBoardList라는 아이디를 갖는 쿼리를 실행하겠단 뜻이 됩니다.

6. 비지니스 로직을 처리할 Service class인 IbatisBoardServlce class를 생성합니다.
package net.tutorial.ibatis.service;

import java.util.List;

import net.tutorial.ibatis.dao.IbatisBoardDAO;
import net.tutorial.ibatis.vo.IbatisBoardVO;

public class IbatisBoardService {
	private IbatisBoardDAO ibatisBoardDAO = new IbatisBoardDAO();
	
	public List<IbatisBoardVO> getTotalBoardList() {
		return ibatisBoardDAO.getTotalBoardList();
	}
}

크게 로직을 처리하는 부분은 아직까지 없음으로 결과값만 return해 주는 역할만 하겠습니다.

7. 데이터를 보여줄 웹페이지(board_list.jsp)를 만들겠습니다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@page import="java.util.List"%>
<%@page import="net.tutorial.ibatis.vo.IbatisBoardVO"%>
<%@page import="net.tutorial.ibatis.service.IbatisBoardService"%>
<%
	IbatisBoardService boardService = new IbatisBoardService();
	List<IbatisBoardVO> boardList = boardService.getTotalBoardList();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IBatis 게시판 tutorial</title>
</head>
<body>
	<table border="1" cellpadding="0" cellspacing="0" width="800" align="center">
		<tr>
			<td>글번호</td>
			<td>카테고리</td>
			<td>제목</td>
			<td>작성자</td>
			<td>등록일</td>
			<td>조회수</td>
		</tr>
		<% for(IbatisBoardVO board : boardList ) { %>
		<tr>
			<td><%=board.getIdx() %></td>
			<td><%=board.getCategory() %></td>
			<td><%=board.getTitle() %></td>
			<td><%=board.getWriter() %></td>
			<td><%=board.getRegDate() %></td>
			<td><%=board.getReadCount() %></td>
		</tr>	
		<%} %>
	</table>
</body>
</html>


위와 같이 작업하시면 결과 페이지를 확인 하실수 있습니다. 단. DB에 글 데이터는 들어있어야 겠죠~?^^

iBatis - iterate 태그로 동적 Query를 생성해 보자

Published on: 2010. 10. 6. 13:44 by louis.dev
Query문 중 가끔 동적으로 어떠한 쿼리를 생성해야 할 경우가 있습니다.. 
예를 들면 어떠한 리스트에 있는 값을 통해 쿼리문을 생성한다던지 하는 경우 iBatis에서는 iterate 태그로 for문과 같은 역할을 하여 동적 쿼리를 생성 할 수 있습니다.

<select id="getData" parameterClass="java.util.List" resultClass="int">
	SELECT
		count(0)
	FROM data_tb
	<iterate prepend="WHERE id IN" open="(" close=")" conjunction="," >
        	#[]#
     	</iterate>
</select>

위와 같이 parameterClass를 java의 List형태로 전달해 주면 동적쿼리를 생성할수 있습니다. 만약 list에 1,2,3,4 의 데이터가 들어가 있으면 결과적으로
다음과 같은 쿼리가 실행되는 것과 같습니다.
<select id="getData" parameterClass="java.util.List" resultClass="int">
	SELECT
		count(0)
	FROM data_tb
	WHERE id IN (1,2,3,4)
</select>
이렇게  iterate를 사용하여 동적으로 쿼리문을 생성할 수 있습니다.

또한 parameterClass가 list형태가 아닌 Map이 List를 가지고 있는 형태도 iterate의 property 속성을 통해 접근할 수 있습니다.
만약 HashMap에 paramList라는 이름으로 list형이 들어가 있다고 가정하면
예)
 HashMap<String, Object> paramMap = new HashMap<String, Object>();
List<Integer> paramList = new ArrayList<Integer>();
paramMap.put("paramList", paramList);
<select id="getData" parameterClass="HashMap" resultMap="myResult">
	SELECT
		*
	FROM data_tb
	<iterate property="paramList" prepend="WHERE id IN" open="(" close=")" conjunction="," >
                #paramList[]#
     	</iterate>
 </select>

위와 같이 HashMap에 들어있는 list는 iterate의 property 속성을 통해 List를 가져 옵니다. ##사이는 HashMap에 put했던 list이름을 넣어주셔야 작동합니다.