Programming2011. 7. 29. 12:12

Struts2 + ibatis 연동을 하는 방법에 알아보도록 하자.

요즘 많이 사용하는 방법으로는 Struts2 + Spring2 + ibatis 를 이용을 하는 경우가 많다.

하지만 난..;;; Struts2 + ibatis에서 spring에서 필요한 부분만 빼와서 사용하거나

Spring2.5 + ibatis에서 Struts에서 필요한 부분만 사용했다.

아직 저렇게 3개를 연동하여 사용해본적이 없으므로 일단 위에것만 해보도록 하자.;;;

무튼 일단 필요한 lib 부터 챙기도록 하자. 필자가 말하는 lib는 꼭 필요한 lib이므로 하나라도 빼먹으면 아니된다.

참고로 난 어제 commons-pool.jar 이거 넣었는지 알고 빼먹었다가 2시간 캐삽질했다.

- Struts2 관련 lib

commons-fileupload.jar
commons-io.jar
freemarker.jar
ognl.jar
struts2-core.jar
xwork.jar

- ibatis 및 DB, odbc, pool dbcp 등 기타 lib

commons-dbcp.jar
commons-logging.jar
commons-pool.jar
ibatis-commons.jar
ibatis-dao.jar
ibatis-sqlmap.jar

다운 받았는가?

(* 참고 - eclipse에서 Dynamic Web Project를 생성하여 작업을 진행하고 있다.)

일단 다운 받은 lib들을 WebContent/WEB-INF/lib 폴더안에 싸그리 몽땅 넣어 버리자. ㅎㅎㅎ;;;

일단 Struts2 관련 한 것들 부터 천천히 차근차근히 해보도록 하자.

WEB-INF/Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>Struts2_sample</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>

이 파일에서 struts2를 기동시키기 위한 자동필터 작업이 이루어지게 된다.

원래 저기 url parttern에 보면 struts1에서는 /*do 였나? 암튼 jsp.do 이런식으로 struts를 기동시켰다면

struts2에서는 jsp.action으로 기동을 시킨다.

src/struts.properties 파일 생성 및 작성

struts.i18n.reload=true
struts.devMode=false
struts.configuration.xml.reload=true
struts.continuations.package = org.apache.struts2.showcase
struts.custom.i18n.resources=globalMessages
struts.url.http.port = 8080
struts.serve.static=true
struts.serve.static.browserCache=false
struts.multipart.maxSize=10000000000

저기 위에 보면 devMode라고 있는데 false라고 꼭 해야 한다.

true라고 하니까 에러도 이상한 에러 뱉어내고 짜증난다.-_ -++

src/struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="sample" extends="struts-default">
<action name="sample" class="sample.sampleAction" method="sample_test">
<result>/sample/sample.jsp</result>
</action>
</package>
</struts>

음~여기서 jsp와 action 클래스와의 연동을 시켜주는 부분인데. 대충 설명을 하자고 하면 sample이라는 pakage에 있는

sampleAction이라는 클래스를 불러와서 그 안에 있는 sample_test라는 메소드를 참조 하겠다는 말이다.

그 결과는 어디로 주느냐!?!? result라고 되어 있는 sample폴더의 sample.jsp에 던져주겠다.라고 되어 있다. 그리고

action name. 이 부분이 이제 실제 url에서 구동시키는 부분이다. 여기서는 sample이라고 되어 있으니까 예를 들어

http://localhost:8080/sample(프로젝트명)/sample(jsp폴더명)/sample.action 이라고 하면 딱 된다는 말이지.

만약에 action name이 test였다면 당연히 test.action으로 해주어야 한다.!

그럼 일단 struts2 설정이 잘 되었나 확인을 해보도록 하자.

WebContent/sample/sample.jsp 생성 및 작성

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>sample page</title>
</head>
<body>
hello sample <s:property value="test"/>
</body>
</html>

저기 taglib 보이는가. 저게 스트럿츠 태그를 사용하도록 지정을 하는것이다.

그리고 action에서 얻어온 값을 <s:property value="test"/> 이런식으로 뱉어내게 된다.

근데 값에 왜 test가 들어 갔냐고? 아래 파일을 작성하다보면 쉬이 이해가 되리라.

src/sample/sampleAction.java

package sample;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;

public class sampleAction extends ActionSupport {

private String test;
public String sample_test() throws Exception{
test = "Good Struts2";
return SUCCESS;
}
public String getTest() { return test; }
public void setTest(String test) { this.test = test; }
}

저기 보면 ActionSupport를 상속받아서 스트럿츠2를 사용하게 될 수 있게 되었다.

그 결과를 보면 return SUCCESS 이 구절이 에러가 안나게 되는것이지.

test를 하나 만들어서 거기 Good Struts2라고 저장을 하자. 그리고 get set를 해서 던진다.

던질때의 내부 struts2 로직은 어떻게 되는지는 잘 모르나 저렇게 하면 넘어 간단다. 뭐 이정도만 알면 되는거 아이가.!ㅎㅎㅎ

음~요까지 했으면 일단 jsp로 접속을 하자. 우리가 만든 jsp는 sample 프로젝트의 sample 폴더에 sample.jsp이다.

아. sample이 너무 많이 겹치네. 암튼. http://localhost:8080/sample/sample/sample.jsp 에 접속을 하면

sample page의 타이틀에 hello sample 이라는 바디가 출력이 될것이다.

이제 struts2가 잘 되엇는지 확인한다. http://localhost:8080/sample/sample/sample.action 에 접속을 하게 되면

타이틀은 같을 것이고. hello sample Good Struts2 가 바디에 출력이 될 것이다.

struts2 성공! ㅋㅋ 이렇게 하면 쉽게 구현을 할 수 있지만 나름 힘든점이 많았다.

lib가 없어서 에러가 나고...struts.xml에 경로나 namespace같은 설정 때문에 어려움이 따랏다. 짜증나게.

무튼 이렇게 한번 하고 나니 쉽게 생각이 드는데 처음 하는 사람들은 나름 짜증 날 수도 있다.

설정 가르쳐 주는건 많은데 파일을 어느 경로에 생성해야 하고 그런걸 모르니까. 짜증이 나지. 암튼

다음 번에 ibatis를 연동하는 것으로 돌아 오겟다.

to be continue...

이 전페이지에서는 struts2를 설정을 해보았다면

여기서는 설정해 놓은 struts2에 ibatis를 연동을 한다.

일단 ibatis를 사용하면 dao라는 것도 사용하고 sqlmap, sqlmapconfig 뭐 등등 사용을 한다.

나름 복잡한듯보이지만 나중에 되면 엄청 간편하고 간결하게 코딩이 되어 진다.

암튼 잡소리 다 집어 치우고 바로 돌입한다.

이 전페이지에서 했던 것에 바로 하는 것이니 참고 하기 바람.

src/sample/dao.xml 파일 생성 및 작성

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

<daoConfig>
<context>
<transactionManager type="SQLMAP">
<property name="SqlMapConfigResource" value="sample/sql-map-config.xml"/>
</transactionManager>

<dao interface="sample.sampleDao" implementation="sample.sampleDaoImpl"/>
</context>
</daoConfig>

요기서 sqmlmapconfig를 참조함과 동시에 Dao를 각 클래스마다 잡아준다.

죠기 보이지~dao interface.... 등등. 저기서.

지금은 없지만 차차 Dao와 DaoImpl 파일을 만들게 될 것이다.

src/sample/sql-map-config.xml 파일 생성 및 작성

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings
cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
maxRequests="256"
maxSessions="64"
maxTransactions="16" />

<transactionManager type="JDBC">
<dataSource type="DBCP">
<property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:orcl"/>
<property name="JDBC.Username" value="test"/>
<property name="JDBC.Password" value="test"/>
<property name="JDBC.DefaultAutoCommit" value="true"/>
<property name="Pool.MaximumActiveConnection" value="10"/>
<property name="Pool.MaximumIdleConnection" value="5"/>
<property name="Pool.MaximumCheckoutTime" value="120000"/>
<property name="Pool.TimeToWait" value="500"/>
</dataSource>
</transactionManager>

또 다른 DB 연동 방법
<!-- <transactionManager type="JDBC" commitRequired="false">
<dataSource type="JNDI">
<property name="DataSource" value="jdbc/wsp"/>
</dataSource>
</transactionManager> -->

<!-- sample -->
<sqlMap resource="sample/sample.xml"/>
</sqlMapConfig>

여기서는 DB를 연동하는 것인디~뭐 저기서 보고 자기 DB설정 관련해서 착착 넣어주면 될듯하다.

그리고 마지막에 보면 sqlMap resource가 있는데 현재는 없지만 흔희 말하는 sqlmap을 만들게 되면 여기에 등록을

해놓아야 사용을 할 수 있다. ㅇㅋ??

src/sample/DaoConfig.java 파일 생성 및 작성

package sample;
import com.ibatis.common.resources.Resources;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.DaoManagerBuilder;
public class DaoConfig {
public static DaoManager getDaomanager(){
return daoManager;
}
private static final DaoManager daoManager;
static {
try{
String resource = "/sample/dao.xml";
java.io.Reader reader = Resources.getResourceAsReader(resource);
daoManager = DaoManagerBuilder.buildDaoManager(reader);
}catch(Exception e){
throw new RuntimeExㅂception("Could not initialize DaoConfig. Cause: " + e);
}
}
}

ibatis 설정 확인 및 Struts2 연동 테스트

순차적으로 Action >> Model >> Service >> SeriveImpl >> Dao >> DaoImpl >> sqlMap >> jsp 으로 작성을 진행한다.

src/sample/sampleAction.java 수정

package sample;

import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
public class sampleAction extends ActionSupport {

private String test;
private List sampleList;
private sampleService ss;

public String sample_test() throws Exception{
test = "Good Struts2";
ss = new sampleServiceImpl();
sampleModel sm = new sampleModel();
sampleList = ss.sample_test(sm);

return SUCCESS;
}

public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public List getSampleList() {
return sampleList;
}
public void setSampleList(List sampleList) {
this.sampleList = sampleList;
}
}

Action에서 서비스를 호출하고 model에 정의해놓은 값들을 이용한다.

src/sample/sampleModel.java 생성 및 작성

package sample;

public class sampleModel {
private String test1;
private String test2;

public String getTest1() {
return test1;
}
public void setTest1(String test1) {
this.test1 = test1;
}
public String getTest2() {
return test2;
}
public void setTest2(String test2) {
this.test2 = test2;
}
}

여기서는 모델 클래스에서는 실제 DB의 걸럼 명들과 같게 만들어 준다. 여기가 spring에서 보면 DTO라는 곳과 같은 곳이다.

나중에 sqlmap에서 result 또는 param으로 이것을 사용하기 때문이다.

src/sample/sampleService.java

package sample;

import java.util.List;
public interface sampleService {
public List sample_test(sampleModel sm);
}

service interface부분. 뭐 이렇다.ㅋㅋ

src/sample/sampleServiceImpl.java

package sample;

import java.util.List;
import com.ibatis.dao.client.DaoManager;

public class sampleServiceImpl implements sampleService{

private DaoManager daoManager;
public sampleServiceImpl() {
daoManager = DaoConfig.getDaomanager();
}

private sampleDao dao;
/** DAO를 설정한다. */
private sampleDao getDao() {
if(dao == null) {
dao = (sampleDao)daoManager.getDao(sampleDao.class);
}
return dao;
}

public List sample_test(sampleModel sm){
List list = getDao().sample_test(sm);
return list;
}
}

저기 위에 보면 daoManager를 이용하는게 보일것이다. 저게 아까 DaoConfig를 만든 이유라고나 할까.?

암튼 DaoManager를 이용하면 트랜잭션 처리가 훨씬 간편해진다. 그리고 Dao를 설정 후 Dao를 호출하는것.

src/sample/sampleDao.java

package sample;

import java.util.List;
import com.ibatis.dao.client.Dao;

public interface sampleDao extends Dao{
public List sample_test(sampleModel sm);
}

Dao interface 부분


src/sample/sampleDaoImpl.java

package sample;

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

public class sampleDaoImpl extends SqlMapDaoTemplate implements sampleDao{

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

public List sample_test(sampleModel sm) {
return ((List)queryForList("sample.getSample", sm));
}
}
실제로 Service에서 호출한 곳. 여기서 이제 DB. 음 그러니까 쿼리문 날리는 sqlmap을 호출한다.

간편하게 여기서는 일반적인 List형식의 queryForList를 사용한다. 이 부분은 나중에 보면 다른 여러가지가 있다.

그리고 뒤에 인자는 sqlmap 이름.

src/sample/sample.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 namespace="sample">
<typeAlias alias="sampleModel" type="sample.sampleModel"/>

<select id="sample.getSample" resultClass="sampleModel">
SELECT * FROM TEST
</select>
</sqlMap>

여기서 namesapce를 설정해주고. 이건 왠만하면 파일 이름으로 하는게 제일 좋다.

그리고 typeAlias 를 모델을 사용했는데 다른 사람들은 여기에 resultMap을 만들어서 resultMap에 DB에서 가져온 값을

저장해서 들고 가더라. 그런 2중 일은 피하도록 하기 위하여 바로.!!Model을 resultClass하여 사용한다.!

뭐 나중에 값을 들고 와서 where에서 이것저것 따질대 paramClass를 사용할 수 도 있지만 이때는 Model Class를 전체

들고 오는 것보다 그 부분만 들고 오는게 더 효율적일 것이다. 흠흠 무튼 이렇게 하고

WebContent/sample/sample.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>sample</title>
</head>
<body>
hello sample <s:property value="test"/>

<s:iterator value="sampleList" status="stat">
<s:property value="test1"/>
<s:property value="test2"/>
</s:iterator>
</body>
</html>

이 부분에서 <s:iterator value="sampleList" status="stat"> 이렇게 되어 있는데 Action에서 sampleList를 넘겨 주엇다.

대충 보앗다면 못 보앗을테지.-_ -;;;무튼 그게 List형식이니 for문을 돌려서 빼던가 해야 할텐데 struts2 이놈께서

편하게 하시라고 iterator라는 놈을 사용하여 자동으로 하게 해준다. "

<s:property value="test1"/>
<s:property value="test2"/> 요놈들은 Model에 있던 놈들. 만약에 DB에서 값을 받아 온놈이 test1만이였다면

test2는 굳이 안써도 되겠지.

무튼 이제 실행을 시킬차례.

http://localhost:8080/sample/sample/sample.action 실행을 해보자.

어떻게 나왔는가.

hello sample Good Struts2

Struts2 iBatis Good TEST SUCCESS

라고 나왓다. 첫줄은 이 전 게시물에서 struts2 셋팅하면서 했던것이고 2번째 줄은 DB에서 가져 온값이다.

아참.!! 내 프로젝 폴더를 포여줘야겠군. 이런게 궁금한 사람들도 엄청 많을 수 있으니.

대략 이정도로 되어 있다. 나는 지금 sample 이라는 곳에 다 밀어 넣엇지만 저건 안좋은 방법이다.

나중에 sample이라는 한 로직을 돌린다고 한다면 sample 패키지에 sampleAction, sampleModel, sampleService, sampleServiceImpl, sampleDao, sampleDaoImpl로 sample과 같은 경로에 db라는 패키지를 만들어서 그 곳에

daoConfig, dao, sql-map-config.xml을 지정하고 sample.xml과 같은 sqlmap은 패키지를 따로 만들어서

sql맵들만 싸그리 모아놓는 것이 효율적일 것이다. 뭐 말로 하면 어려운데 막상 지금 하려고 하니 귀찮다;;;

무튼 쉽다고 하면 쉽지만 쉽지 않은게 환경설정이다. 사소한것 하나때문에 계속 에러가 날 수도 있고.

철자하나 틀려서 에러가 미친듯이 날 수도 있다. 그래도 어쩌랴. 해야만 하는 것임에 틀림없는것을...

오늘도 우리 동종업종의 많은 분들은 컴퓨터와 씨름을 하고 있겠군하.

아 우리 개발자들.! 프로그래머들.!! 화이팅이다.!!

Posted by 신의물방울