채은이가 세상에 나온지 벌써 1년이 되었습니다.
많이 많이 축하해 주세요~ ^^

Struts2, Spring, iBatis 사용

1. 다운로드

1-0. Mysql 다운로드

URL : http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-5.0.67-win32.zip/from/pick#mirrors

1-1. Spring 다운로드 : spring-framework-2.5.5.zip

URL : http://www.springframework.org/download
(2008년 9월 현재 최신버젼 2.5.5)

spring-framework-2.5.5-with-dependencies.zip (82M) 라이브러리 + 문서 + common-lib 포함
spring-framework-2.5.5-with-docs.zip (36M) 문서포함
spring-framework-2.5.5.zip (6M) 라이브러리

1-2. iBatis 다운로드 : ibatis-2.3.3.720.zip

URL : http://ibatis.apache.org/javadownloads.cgi
(2008년 9월 현재 최신버젼 2.3.3)

ibatis-2.3.3.720.zip (1.9M) 라이브러리

1-3. Struts 다운로드 : struts-2.0.11.2-lib.zip

URL : http://struts.apache.org/downloads.html
(2008년 9월 현재 최신버젼 2.0.11.2 )

struts-2.0.11.2-all.zip (91M) Full Distribution
struts-2.0.11.2-apps.zip (23M) Example Applications
struts-2.0.11.2-lib.zip (4M) Essential Dependencies Only

1-4. Mysql-Connector 다운로드 : mysql-connector-java-5.0.8.zip

URL : http://dev.mysql.com/downloads/connector/j/5.1.html

mysql-connector-java-5.0.8.tar.gz (8.4M) tar 압축(일반적으로 리눅스)
mysql-connector-java-5.0.8.zip (8.4M) zip 압축

2. 이클립스 프로젝트 생성

  • 환경
    이클립스 3.4 WTP
  • 새 프로젝트 작성
    File >> New >> Project >> Ohter >> Dyanmic Web Project
    Project Name : devTest 입력 >> Finish
  • Output폴더 변경
    Propterties >> Java Build Path >>Source탭 >> 제일 밑에 Default output folder 이 있다.
    Default output folder : devTest/WebContent/WEB-INF/classes

3. 설치

3-0. Mysql 설치

알아서 설치~^^; 윈도우용이라면 .exe 파일을 실행하셔서.
"다음", "다음".... 클릭신공 발휘!!

3-1. Spring 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    (파일을 복사하게 되면 자동으로 이클립스가 라이브러리를 Java Resources: src/Libraries/Web App Libraries 에 등록한다.신기 _!)
    spring-framework-2.5.5
        │  changelog.txt
        │  license.txt
        │  notice.txt
        │  readme.txt
        │  
        └─dist
            │  (V) spring.jar
            │  
            ├─modules
            │      (V) spring-aop.jar
            │      (V) spring-beans.jar
            │      (V) spring-context-support.jar
            │      (V) spring-context.jar
            │      (V) spring-core.jar
            │      (V) spring-jdbc.jar
            │      (V) spring-jms.jar
            │      (V) spring-orm.jar
            │      (V) spring-test.jar
            │      (V) spring-tx.jar
            │      (V) spring-web.jar
            │      (V) spring-webmvc-portlet.jar
            │      (V) spring-webmvc-struts.jar
            │      (V) spring-webmvc.jar
            │      
            ├─resources
            │      spring-aop-2.0.xsd
            │      spring-aop-2.5.xsd
            │      spring-beans-2.0.dtd
            │      spring-beans-2.0.xsd
            │      spring-beans-2.5.xsd
            │      spring-beans.dtd
            │      spring-context-2.5.xsd
            │      spring-form.tld
            │      spring-jee-2.0.xsd
            │      spring-jee-2.5.xsd
            │      spring-jms-2.5.xsd
            │      spring-lang-2.0.xsd
            │      spring-lang-2.5.xsd
            │      spring-tool-2.0.xsd
            │      spring-tool-2.5.xsd
            │      spring-tx-2.0.xsd
            │      spring-tx-2.5.xsd
            │      spring-util-2.0.xsd
            │      spring-util-2.5.xsd
            │      spring.ftl
            │      spring.tld
            │      spring.vm
            │      
            └─weaving
                    spring-agent.jar
                    spring-aspects.jar
                    spring-tomcat-weaver.jar

3-2. iBatis 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    ibatis-2.3.3.720
    │  jar-dependencies.txt
    │  license.txt
    │  notice.txt
    │  release.txt
    │  
    ├─doc
    │      dev-javadoc.zip
    │      user-javadoc.zip
    │      
    ├─lib
    │      (V) ibatis-2.3.3.720.jar
    │      
    ├─META-INF
    │      MANIFEST.MF
    │      
    ├─simple_example
    │  │  README.TXT
    │  │  
    │  └─com
    │      └─mydomain
    │          ├─data
    │          │      Account.xml
    │          │      SimpleExample.java
    │          │      SqlMapConfig.xml
    │          │      
    │          └─domain
    │                  Account.java
    │                  
    └─src
            ibatis-src.zip

3-3. Struts 설치

  • (V) 표시가 되어있는 파일을 이클립스 프로젝트의 /devTest/WebContent/WEB-INF/lib 안에 넣는다.
    struts-2.0.11.2
        │  LICENSE.txt
        │  NOTICE.txt
        │  
        └─lib
                antlr-2.7.2.jar
                commons-beanutils-1.6.jar
                commons-chain-1.1.jar
                (V) commons-logging-1.0.4.jar
                commons-logging-api-1.1.jar
                commons-validator-1.3.0.jar
                (V) freemarker-2.3.8.jar
                (V) ognl-2.6.11.jar
                oro-2.0.8.jar
                struts-core-1.3.5.jar
                struts2-codebehind-plugin-2.0.11.2.jar
                struts2-config-browser-plugin-2.0.11.2.jar
                (V) struts2-core-2.0.11.2.jar
                struts2-jasperreports-plugin-2.0.11.2.jar
                struts2-jfreechart-plugin-2.0.11.2.jar
                struts2-jsf-plugin-2.0.11.2.jar
                struts2-pell-multipart-plugin-2.0.11.2.jar
                struts2-plexus-plugin-2.0.11.2.jar
                struts2-sitegraph-plugin-2.0.11.2.jar
                struts2-sitemesh-plugin-2.0.11.2.jar
                struts2-spring-plugin-2.0.11.2.jar
                struts2-struts1-plugin-2.0.11.2.jar
                struts2-tiles-plugin-2.0.11.2.jar
                tiles-api-2.0.4.jar
                tiles-core-2.0.4.jar
                tiles-jsp-2.0.4.jar
                (V) xwork-2.0.5.jar

3-4. Mysql-Connector 다운로드 : mysql-connector-java-5.1.6.zip

  • 압축을 풀고 mysql-connector-java-5.1.6-bin.jar 파일을 JRE_HOME/lib 안에 복사한다.

4. HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!! HelloWorld!!

4-1. HelloWorld!! Spring!!

Spring을 사용하는 이유? 10가지!!

1. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
2. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
3. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
4. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
5. Spring Provides Better Leverage
적은 노력을 하고도 많은 결과를 줄 수 있다.
6. Spring Enables POJO Programming
Spring은 POJO프로그래밍을 가능하게 한다.
7. Spring Enables POJO Programming
Spring은 POJO프로그래밍을 가능하게 한다.
8. Dependency Injection Helps Testability
DI는 테스트를 용이하게 해준다.
9. Inversion of Control Simplifies JDBC
IoC는 JDBC를 단순화한다.
10. Spring's Community Thrives
Spring 커뮤니티의 번영

4-1-1. Controller + Model 생성 및 테스트

  • hello1 패키지 생성
  • hello1.HelloWorld.java 인터페이스 생성
    HelloWorld.java
    package hello1;
    
    public interface HelloWorld {
    	public String sayHello(String message);
    }
  • hello1.HelloWorldImpl.java 클래스 생성
    hello1.xml에서 message를 설정
    HelloWorldImpl.java
    package hello1;
    
    public class HelloWorldImpl implements HelloWorld {
    
     
        private String message;
    
        public HelloWorldImpl() {
        }
    
        public HelloWorldImpl(String message) {
                this.message = "From Constructor" + message;
        }
    
        public String sayHello(String message) {
                return this.message + message;
        }
    
        public void setMessage(String a) {
                message = a;
        }
    }
  • /src/hello1.xml 생성
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
       <!--  bean 설정 -->
    	<bean id="hello" class="hello1.HelloWorldImpl">
    		<property name="message">
    			<value>HelloWorld!! Spring!!</value>
    		</property>
    	</bean>
    </beans>
    친절한 클립스씨

    이클립스에서 컴파일시 자동으로 /devTest/WebContent/WEB-INF/hello1.xml로 옴겨준다. '친절한것..^^'

  • 테스트를 위한 HelloClient.java 생성
    HelloClient 테스트 (hello1.xml과 HelloWorld연동 테스트)
    package hello1;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    public class HelloClient {
            public static void main(String[] args) {              
                    Resource res = new ClassPathResource("hello1.xml"); // 리소스를 읽어온다.
                                
                    BeanFactory factory = new XmlBeanFactory(res); // 스프링 컨테이너.
                    
                    HelloWorld bean1 = (HelloWorld)factory.getBean("hello"); // hello1.xml에서 입력한 beanID
                    
                    String str = bean1.sayHello("I need you!");
                    
                    System.out.println(str);                
            }
    }
    <결과>
    
    HelloWorld!! Spring!!I need you!

4-1-2. WAS 연동 : 웹으로 사용해보자.

  • HelloWorldServlet.java 생성
    package hello1;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    public class HelloWorldServlet extends HttpServlet {
            public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
                    res.setContentType("text/html; charset=euc-kr");
                    req.setCharacterEncoding("KSC5601");
                    PrintWriter out = res.getWriter();
                    String text = req.getParameter("message");
                    
                    try {                        
                            Resource resource = new ClassPathResource("hello1.xml");
                            BeanFactory factory = new XmlBeanFactory(resource);
                            HelloWorld bean1 = (HelloWorld)factory.getBean("hello");
                            String s = bean1.sayHello(text);
                            out.println(s);                        
                    }
                    catch(Exception e) {
                            
                    }
            }
            
            public void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException
             {
              doGet(req, resp);
             }
    
    }

    컴파일 오류시 tomcat5/common/lib/servlet-api.jar 를 lib 추가한다.

  • 필터를 위한 WebContent/WEB-INF/web.xml 생성
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
    	<!-- 설정 -->
    	<servlet>
    	<!-- hello1.HelloWorldServlet클래스의 서블릿이름은 HelloWorld 이다. -->
    		<servlet-name>HelloWorld</servlet-name>
    		<servlet-class>hello1.HelloWorldServlet</servlet-class>
    	</servlet>
    	
    	<!-- 맵핑 -->
    	<servlet-mapping>
    	<!-- url끝에     /servlet/HelloWorld.ok가 들어오면 서블릿이름이 HelloWorld인것을 연결시켜라 -->
    		<servlet-name>HelloWorld</servlet-name>
    		<url-pattern>/servlet/HelloWorld.ok</url-pattern> 
    	</servlet-mapping>
    </web-app>
  • 입력을 위한 index.html 생성
    <html>
    <body>
    	<form method=post
    		action="http://localhost:8080/devTest/servlet/HelloWorld.ok"><input
    		type=text name="message"> <input type=submit></form>
    </body>
    </html>

4-1-3. 실행

4-2. HelloWorld!! iBatis!!

iBatis의 장점 5가지..

적은 노력으로 SQL문을 변경할수 있다.
적은 노력으로 SQL문을 변경할수 있다.
기존 데이터베이스 프로그램 코드의 20%정도만 사용해도 80%이상의 같은 기능을 수행할 수가 있게 된다
코드를 간단(simple)하게 해준다.
코드를 간단(simple)하게 해준다.

4-2-1. SqlMap

  • src/SqlMapConfig.xml 생성
    SqlMapConfig.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" 
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
    <sqlMapConfig>
    	<properties resource="SqlMapConfig.properties" />
    	<settings cacheModelsEnabled="true" enhancementEnabled="true"
    		lazyLoadingEnabled="true" maxRequests="32" maxSessions="10"
    		maxTransactions="5" useStatementNamespaces="false" />
    	<typeAlias alias="Hello" type="hello2.Hello" />
    	<transactionManager type="JDBC">
    		<dataSource type="DBCP">
    			<property name="JDBC.Driver" value="${driver}" />
    			<property name="JDBC.ConnectionURL" value="${url}" />
    			<property name="JDBC.Username" value="${username}" />
    			<property name="JDBC.Password" value="${password}" />
    			<property name="JDBC.DefaultAutoCommit" value="false" />			 
    			
    		</dataSource>
    	</transactionManager>
    	
    	<sqlMap resource="HelloMessage" />
    	<!-- 요런식으로 추가할 수 있다. -->
    	<!-- <sqlMap resource="Comment.xml" />  -->
    	<!-- <sqlMap resource="Message.xml" />  -->
    </sqlMapConfig>
  • settings 엘리먼트의 속성들
    acheModelsEnabled SqlMapClient 를 위한 모든 캐시모델을 가능 유무. Default: true (enabled)
    enhancementEnabled 런타임시 바이트코드 향상을 가능유무. Default: false (disabled)
    lazyLoadingEnabled 모든 늦은(lazy)로딩을 가능유무. Default: true (enabled)
    maxRequests 동시에 SQL문을 수행할 수 있는 쓰레드의 수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 수행을 완료할 때까지 블록 된다. Default: 512
    maxSessions 주어진 시간동안 활성화될 수 있는 세션의 수. Default: 128
    maxTransactions 한꺼번에 SqlMapClient.startTransaction()에 들어갈 수 있는 쓰레드의 최대갯수. 셋팅값보다 많은 쓰레드는 다른 쓰레드가 나올 때까지 블록 된다. Default: 32
    useStatementNamespaces 이 셋팅을 가능하게 하면 당신은 sqlmap이름과 statement이름으로 구성된 전체적인 이름(fully qualified name)으로 맵핑된 statement를 참조해야 한다. 예를 들면: queryForObject("sqlMapName.statementName"); Default: false (disabled)
  • transactionManager 엘리먼트의 별칭
    JDBC com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig
    JTA com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig
    EXTERNAL com.ibatis.sqlmap.engine.transaction.external.ExternalTransactionConfig
  • dataSource 엘리먼트의 별칭
    SIMPLE com.ibatis.sqlmap.engine.datasource.SimpleDataSourceFactory
    DBCP com.ibatis.sqlmap.engine.datasource.DbcpDataSourceFactory
    JNDI com.ibatis.sqlmap.engine.datasource.JndiDataSourceFactory

4-2-2. ibatis

  • 환경
    mysql
    SQL 쿼리
    create table hello(name varchar(10), text varchar(10)); 
    
    insert into hello values("spring", "helloworld 1");
    insert into hello values("ibatis", "helloworld 2");
    insert into hello values("struts", "helloworld 3");
    
    commit;
  • hello2 패키지 생성
  • hello2.Hello.java 생성 (VO)
    Hello.java
    package hello2;
    
    public class Hello {
    	private String name;
    	private String text;
    	
    	public Hello(String name, String text) {	
    		this.name = name;
    		this.text = text;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getText() {
    		return text;
    	}
    	public void setText(String text) {
    		this.text = text;
    	}
    	
    	
    }
  • src/SqlMapConfig.properties 생성
    SqlMapConfig.xml의 $Driver같은 참조를 사용할 속성 정의
    SqlMapConfig.properties
    driver=org.gjt.mm.mysql.Driver
    url=jdbc:mysql://192.168.10.200:3306/swjang
    username=swjang
    password=xxxxxxxx
  • src/HelloMessage.xml 생성
    HelloMessage.xml
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">
    <sqlMap>
    	<select id="getHelloMessage" parameterClass="string" resultMap="Hello">
      <![CDATA[
        select 
          name,
          text
        from userinfo
        where name=#name#
      ]]>
    	</select>
    </sqlMap>
  • hello2.HelloWorld.java 생성
    HelloWorld.java
    package hello2;
    
    import java.io.IOException;
    import java.io.Reader;
    import java.sql.SQLException;
    
    import com.ibatis.common.resources.Resources;
    import com.ibatis.common.util.PaginatedList;
    import com.ibatis.sqlmap.client.SqlMapClient;
    import com.ibatis.sqlmap.client.SqlMapClientBuilder;
    
    public class HelloWorld {
    
    	 
    	@SuppressWarnings("deprecation")
    	public static void main(String[] args) throws SQLException {		
    		Reader reader = null;
    		try {
    			reader = Resources.getResourceAsReader("SqlMapConfig.xml");
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		
    		SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
    		
    		
    		PaginatedList list = (PaginatedList) sqlMap.queryForPaginatedList("getHelloMessage", "struts", 0);
    		
    		for (int i = 0; i < list.size(); i++) {
    			
    			System.out.println(list.getPageIndex());
    			list.nextPage();			  
    		}		
    		
    	}
    	
    }
    org.apache.commons.dbcp.BasicDataSource 클래스가 없다고 징징거릴때는?

    tomcat5/common/lib/nameing-factory-dbcp.jar 추가

그런데... 해도 에러난다?; =ㅅ=;

4-3. HelloWorld!! Spring + iBatis!!

4-3-1. SqlMapConfig.xml(ibatis용) => applicationContext.xml(spring용) 로 변경

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--
		iBATIS SQLMaps의 설정파일 위치를 지정한다. class값은 SQLMaps 1.x버전을 사용할때는
		org.springframework.orm.ibatis.SqlMapFactoryBean SQLMaps 2.x버전을 사용할때는
		org.springframework.orm.ibatis.SqlMapClientFactoryBean 를 사용한다.
	-->
	<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="configLocation">
			<value>WEB-INF/SqlMapConfig.xml</value>
		</property>
	</bean>
	<!--
		dataSource를 사용하는것에 대한 정보를 나타낸다. 여기서 사용될수 있는 dataSource타입은 다른 문서를 참조하길
		바란다. 여기선 apache의 DBCP Connection pooling을 사용하는 것이다.
	-->
		
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName">
			<value>org.gjt.mm.mysql.Driver</value>
		</property>
		<property name="url">
			<value>jdbc:mysql://192.168.10.200:3306/swjang</value>
		</property>
		<property name="username">
			<value>swjang</value>
		</property>
		<property name="password">
			<value>xxxxxxx</value>
		</property>
		<property name="defaultAutoCommit">
			<value>false</value>
		</property>
	</bean>
	<!--
		DB연결에 관련된 설정을 DataSource형태로 지정을 했기 때문에 트랜잭션 관리를
		org.springframework.jdbc.datasource.DataSourceTransactionManager 가
		담당하도록 지정한다.
	-->
	<bean id="myTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="dataSource" />
		</property>
	</bean>  
  
 <!--?? -->
  <!-- 각각의 메소드 별로 트랜잭션관리 속성을 지정한다. -->
	<bean id="guestService"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref local="myTransactionManager" />
		</property>
		<property name="target">
			<ref local="guestTarget" />
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	<!--
		소위 Spring을 사용하게 되는 비지니스 객체의 클래스를 지정하는 부분이다. 즉 여기선
		gikim.dongguk.guestboard.spring.GuestSpringImpl 클래스가 Spring의 여러가지 기능을
		담당하게 되는것이다. 그리고 관리하게 되는 DAO는 guestDAO로 지정한다.
	-->
	<bean id="guestTarget" class="gikim.dongguk.guestboard.spring.GuestSpringImpl">
		<property name="guestDAO">
			<ref local="guestDAO" />
		</property>
	</bean>
	<!--
		DAO에 관련된 셋팅이다. 실제로 iBATIS SQLMaps를 사용하게 되는 클래스를 지정하게 된다. DB정보인
		dataSource값과. iBATIS SQLMaps설정파일의 위치에 해당하는 sqlMapClient를 지정한다.
	-->
	<bean id="guestDAO" class="gikim.dongguk.guestboard.dao.IbatisGuestDAOImpl">
		<property name="dataSource">
			<ref local="dataSource" />
		</property>
		<property name="sqlMapClient">
			<ref local="sqlMapClient" />
		</property>
	</bean>
</beans>

4-3-2. code

spring은 SqlMapClient객체를 대체하는 SqlMapClientTemplate를 제공하는데 이를 생성하는 메소드는 getSqlMapClientTemplate()이다.

Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
user = (User) sqlMap.queryForObject("getUser", id);

사용자 정보를 가져오는 소스가 위와 같다고 할 때 spring의 SqlMapClientTemplate를 사용하면 아래와 같이 될 것이다..

User user = getSqlMapClientTemplate().queryForObject("getUser", id);

눈에 띄게 소스가 간편해진다. 이것밖에 장점이 없을까.? 아니다. 다음의 소스를 보자. spring이 자동적으로 트랜잭션을 처리해 주기 때문에 조금 전 입력예제로 사용되었던 소스가 아래처럼 다시 변경될 수 있다.

getSqlMapClientTemplate().insert("insertMessage", message);
return true;

spring의 트랜잭션 관리를 사용하면 위와 같이 소스가 간단해진다.

이것은 transactionAttributes 속성 하위의 설정값들에 의해 spring의 DI(dependency injection)을 사용하여 가능한 것이지만, 일단 개발자들에게는 SQLMaps로 인해 간단해진 소스가 더욱 심플해졌다는 사실 자체로 행복한 일일 것이다. 이건 개발 프레임워크를 제대로 사용할 때 개발 프레임워크가 개발자에게 주는 혜택이다

4-4. HelloWorld!! Struts + Spring + iBatis!!

5. 결론

이런 프레임워크를 사용하는 이유는...

보다 적은 노력 큰 효과
1) 유연성
2) 간결함
3) 재사용성

6. 참고자료

spring : http://cafe.naver.com/hdjv.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=299
spring의 장점 : http://epro.tistory.com/tag/spring의 장점

ibatis : http://openframework.or.kr/Wiki.jsp?page=SqlmapsOfMaso
ibatis 장점 : http://okjsp.pe.kr/seq/104465

spring + ibatis + struts로 게시판 만들기 : http://blog.naver.com/phcs1219?Redirect=Log&logNo=140044056674

문서에 대하여

Struts Recipes의 공동 저자 George Franciscus는 또 다른 Struts 통합 레시피를 가지고 돌아왔다. 이번에는 Struts 애플리케이션을 Spring 프레임웍으로 반입한다. Struts 액션을 Spring의 빈 처럼 관리할 수 있다. Spring AOP의 효과를 쉽게 누릴 수 있다.

Inversion of Control (IOC) 디자인 패턴에 대해서는 누구나 한번쯤은 들어봤을 것이다. Spring 프레임웍을 사용했다면 그 실행 원리도 알 것이다. Struts 애플리케이션을 Spring 프레임웍으로 반입할 때 IOC 패턴이 큰 힘을 발휘한다.

Struts 애플리케이션을 Spring 프레임웍으로 통합할 때의 이점은 많이 있다. 우선, Spring은 JEE의 문제들, 이를 테면 복잡성, 낮은 퍼포먼스, 테스트 같은 문제들을 해결하기 위해 설계되었다. 두 번째로 Spring 프레임웍에는 aspect 지향 기술을 일반 객체 지향 코드에 적용할 수 있는 AOP 구현이 포함되어 있다. 세 번째로 Spring 프레임웍은 Struts가 핸들하는 것 보다 Struts를 더 잘 다룬다. 하지만 이것은 견해의 문제이고, Struts 애플리케이션을 Spring 프레임웍으로 통합하는 세 가지 접근방식을 설명할 때 여러분 스스로 판단해 보기 바란다.

내가 설명하는 접근 방식들은 비교적 실행하기에 간단하지만 각기 다른 효과를 갖고 있다. 따라서 각각의 방식을 완전히 이해할 수 있도록 작동 예제도 따로 만들었다. 다운로드 섹션에서 전체 예제의 소스 코드를 참조하기 바란다. Struts MVC와 Spring 프레임웍 다운로드는 참고자료를 참조하라.

Spring의 장점은 무엇인가?

Spring 창시자 Rod Johnson은 Java™ Enterprise 소프트웨어 개발에 비평적인 시각을 갖고 있었고, 많은 기업들 문제가 IOC 패턴을 전략적으로 사용하여 해결될 수 있다는 것을 제안했다. Rod와 오픈 소스 개발자 팀이 그의 이론을 실행에 옮겼고, 그 결과가 Spring 프레임웍이였다. 간단히 말해서 Spring은 경량의 컨테이너로서 외부 XML 설정 파일을 사용하여 객체들을 함께 와이어링 하기 쉽도록 한다. 각 객체는 JavaBean 속성을 노출함으로서 종속 객체에 대한 레퍼런스를 받으면서 XML 설정 파일에서 "이것을 와이어링"하는 간단한 태스크를 여러분의 몫으로 남겨놓는다.

IOC와 Spring

IOC는 애플리케이션 로직을 노출하여 클라이언트 코드로 투입되도록 하는 디자인 패턴이다. IOC와 인터페이스에 대한 프로그래밍 사용을 결합하면 Spring 프레임웍과 마찬가지로 클라이언트가 구현 스팩의 로직에 덜 의존하는 아키텍쳐를 만들어 낸다.(참고자료)

의존성 삽입(Dependency injection)은 강력한 기능이지만, Spring 프레임웍은 그 이상을 제공한다. Spring은 플러거블 트랜잭션 매니저를 지원하여 광범위한 트랜잭션 핸들링 선택권을 준다. 영속 프레임웍을 통합하면서 일관성 있는 예외 계층을 제공한다. Spring은 또한 aspect 지향 코드를 일반 객체 지향 코드에 적용하는 간단한 메커니즘도 제공한다.

Spring AOP는 여러분이 인터셉터를 사용하여 한 개 이상의 실행 포인트에서 애플리케이션 로직을 인터셉트 할 수 있도록 한다. 인터셉터는 로깅에 광범위하게 사용된다. 인터셉터의 애플리케이션의 로깅 로직은 보다 가독성 있는 함수적 코드 기반이라는 결과를 만든다. 곧 알게 되겠지만 Spring AOP에는 크로스커팅 문제를 다루는 인터셉트가 함께 제공되고 직접 작성할 수도 있다.




위로


Struts와 Spring 통합

Struts와 마찬가지로 Spring 역시 MVC 구현으로서의 기능을 한다. 두 프레임웍 모두 장점과 단점을 갖고 있다. MVC에 관해서라면 Struts가 여전히 우세하다는 것에는 동의할 것이다. 많은 개발팀들은 엄격한 데드라인 하에 양질의 소프트웨어를 구현할 수 있는 토대로서 Struts에 의존해야 한다고 배워왔다. Struts 뒤에 너무나 많은 탄력으로 Spring 프레임웍의 기능을 통합하고 싶은 개발 팀 조차도 Spring MVC로 전환하기를 꺼려한다. 좋은 소식은 여러분은 그럴 필요가 없다는 것이다. Spring 아키텍쳐에서 여러분은 웹 프레임웍으로서 Struts를 Spring 기반의 비즈니스 및 영속 레이어에 연결할 수 있다.

이제부터 Struts MVC를 Spring 프레임웍과 통합하는 세 가지 방법을 설명한다. 각 레시피의 장단점을 설명하겠다. 세 가지 모두 작동하는 것을 일단 설명한 다음 내가 개인적으로 선호하는 방식을 설명하겠다.




위로


세 가지 레시피

다음의 통합 기술들(또는 레시피)은 장점도 갖고 있고 단점도 있다. 나는 이들 중 한 가지를 선호하기는 하지만, 이들 모두를 이해하는 것이 바람직하다. 또한 다양한 시나리오를 다루는 광범위한 시나리오도 소개 할 예정이다. 레시피는 다음과 같다.

  • Spring의 ActionSupport 클래스를 사용하여 Struts와 통합하기
  • Struts의 RequestProcessor를 Spring의 DelegatingRequestProcessor로 오버라이드 하기
  • Struts Action 관리를 Spring 프레임웍에 위임하기

애플리케이션 컨텍스트 로딩하기

어떤 기술을 사용하든지 Spring의 ContextLoaderPlugin을 사용하여 Spring 애플리케이션 컨텍스트를 Struts ActionServlet에 로딩해야 한다. struts-config.xml 파일에 플러그인을 추가한다.

<plug-in className=
  "org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property=
      "contextConfigLocation" value="/WEB-INF/beans.xml"/>
 </plug-in>

앞에서도 언급했지만 아래 다운로드섹션에서 예제 애플리케이션의 소스를 다운로드 할 수 있다. 각각의 예제는 Struts와 Spring을 통합하는 방식을 다르게 보여주고 있다. 이 글의 예제는 기본적인 부분만 다르기 때문에 애플리케이션을 다운로드하여 전체를 다 보는 것도 좋다.




위로


레시피 1. Spring의 ActionSupport 사용하기

Spring 컨텍스트를 직접 만드는 것은 Struts와 Spring 통합에 있어서 가장 매력적인 방법이다. 더 쉽게 하기 위해 Spring은 도움말도 제공한다. org.springframework.web.struts.ActionSupport 클래스는 getWebApplicationContext()메소드를 제공하여 Spring 컨텍스트를 쉽게 얻을 수 있도록 한다. 여러분은 그저 Struts의 Action 클래스 대신 Spring의 ActionSupport에서 액션을 확장하면 된다. (Listing 1)


Listing 1. ActionSupport를 사용하여 Struts 통합하기
package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends ActionSupport {   |(1)


  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    DynaActionForm searchForm = (DynaActionForm) form;
    String isbn = (String) searchForm.get("isbn");
		
    //the old fashion way
    //BookService bookService = new BookServiceImpl();
		
    ApplicationContext ctx = 
      getWebApplicationContext();    |(2)
    BookService bookService = 
      (BookService) ctx.getBean("bookService");   |(3)
        
  Book book = bookService.read(isbn.trim());

    if (null == book) {
      ActionErrors errors = new ActionErrors();
      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
        ("message.notfound"));
      saveErrors(request, errors);
      return mapping.findForward("failure") ;
  }

    request.setAttribute("book", book);
    return mapping.findForward("success");
  }
}

어떤 일이 일어나는지 보자. (1)에서 Struts Action 클래스가 아닌 Spring ActionSupport 클래스에서 확장하여 Action 을 만든다. (2)에서 getWebApplicationContext() 메소드를 통해 ApplicationContext 를 얻었다. 비즈니스 서비스를 얻으려면 (2)에서 획득한 컨텍스트를 사용하여 (3)에서 Spring 빈을 검색하면 된다.

이 기술은 간단하고 이해하기 쉽다. 불행히도 이것은 Struts 액션을 Spring 프레임웍에 연결한다. Spring 말고 다른 것을 사용해야 한다면 코드를 다시 작성해야 한다. 더욱이 Struts 액션은 Spring의 제어를 받지 않기 때문에 Spring AOP의 혜택을 누릴 수도 없다. 이 기술은 다중의 독립적인 Spring 컨텍스트를 사용할 때 유용하지만 대부분의 경우는 바람직하지 못하다.




위로


레시피 2. RequestProcessor 오버라이드

Struts 액션에서 Spring을 분리하는 것도 좋은 방법이다. 한 가지 방법은 Struts RequestProcessor 프로세서를 org.springframework.web.struts.DelegatingRequestProcessor로 오버라이드 하는 것이다.


Listing 2. Spring의 DelegatingRequestProcessor
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
 <form-beans>
    <form-bean name="searchForm" 
      type="org.apache.struts.validator.DynaValidatorForm">
               <form-property name="isbn"    type="java.lang.String"/>
    </form-bean>
  
  </form-beans>

 <global-forwards type="org.apache.struts.action.ActionForward">
     <forward   name="welcome"                path="/welcome.do"/>
     <forward   name="searchEntry"            path="/searchEntry.do"/>
     <forward   name="searchSubmit"           path="/searchSubmit.do"/>
 </global-forwards>

 <action-mappings>
    <action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
    <action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
    <action    path="/searchSubmit" 
               type="ca.nexcel.books.actions.SearchSubmit"
               input="/searchEntry.do"
               validate="true"
               name="searchForm">
              <forward name="success" path="/WEB-INF/pages/detail.jsp"/>
              <forward name="failure" path="/WEB-INF/pages/search.jsp"/>
    </action>  

 </action-mappings>

 <message-resources parameter="ApplicationResources"/>

 <controller processorClass="org.springframework.web.struts.
   DelegatingRequestProcessor"/> |(1)

 <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property property="pathnames" 
      value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
 </plug-in>


 <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/>
 </plug-in>
 
</struts-config>

여기에서 <controller> 태그를 사용하여 디폴트 Struts RequestProcessorDelegatingRequestProcessor로 오버라이드 했다. 그런 다음, Spring config 파일에 액션을 등록한다. (Listing 3)


Listing 3. Spring config 파일에 액션 등록하기
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
  "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

  <bean name="/searchSubmit" 
    class="ca.nexcel.books.actions.SearchSubmit"> |(1)
     <property name="bookService">
        <ref bean="bookService"/>
     </property>
  </bean>
</beans>

(1)에서, struts-config 액션 매핑 이름과 매치하는 이름 애트리뷰트를 사용하여 빈을 등록했다. SearchSubmit 액션은 JavaBean 속성을 노출하기 때문에 Spring이 이 속성을 런타임 시 파퓰레이트 할 수 있다. (Listing 4)


Listing 4. JavaBean 속성을 가진 Struts 액션
package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends Action {
	
  private BookService bookService;
  public BookService getBookService() {
    return bookService;
  }

  public void setBookService(BookService bookService) { | (1)
    this.bookService = bookService; 
  } 

  public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws IOException, ServletException {

    DynaActionForm searchForm = (DynaActionForm) form;
    String isbn = (String) searchForm.get("isbn");
		
  Book book = getBookService().read(isbn.trim());  |(2)

    if (null == book) {
      ActionErrors errors = new ActionErrors();
      errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
      saveErrors(request, errors);
      return mapping.findForward("failure") ;
  }

      request.setAttribute("book", book);
      return mapping.findForward("success");
  }

}

Listing 4에서 Struts 액션의 구현 방법이 나온다. (1)에서 JavaBean 속성을 만든다. 이 속성은 DelegatingRequestProcessor에 의해 자동으로 파퓰레이트 된다. 이 디자인은 Struts 액션이 Spring에 의해 관리된다는 사실을 모르도록 한다. 이와 동시에 여러분은 Spring의 액션 관리 프레임웍을 충분히 활용하게 되는 것이다. Struts 액션이 Spring의 존재를 모르기 때문에 Struts 코드를 리팩토링 하지 않고도 제어 역행 컨테이너를 위해 Spring을 교환할 수 있다.

DelegatingRequestProcessor 방식이 첫 번째 방식 보다 나은 것은 분명하지만, 문제점도 있다. 다른 RequestProcessor를 사용한다면 Spring DelegatingRequestProcessor를 직접 통합해야 한다. 추가된 코드는 관리상의 장애가 될 수 있고 애플리케이션의 유연성도 떨어트린다. 더욱이 Struts RequestProcessor를 명령어 체인으로 대체한다는 이야기도 있다. 그와 같은 변화는 이 솔루션에 부정적인 영향을 끼친다.




위로


레시피 3. 액션 관리를 Spring에 위임하기

Struts 액션 관리를 Spring 프레임웍으로 위임하는 훨씬 더 나은 솔루션이 있다. struts-config 액션 매핑에 프록시를 등록한다. 이 프록시는 Spring 컨텍스트에서 Struts 액션을 관찰한다. 이 액션이 Spring의 제어를 받기 때문에 이것은 이 액션의 JavaBean 속성들을 파퓰레이트하고, Spring의 AOP 인터셉터 같은 기능들도 적용할 수 있는 여지도 마련해 준다

Listing 5에서, Action 클래스는 Listing 4와 같다. 하지만 struts-config가 약간 다르다.


Listing 5. 위임 방식의 Spring 통합
<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
 <form-beans>
    <form-bean name="searchForm" 
      type="org.apache.struts.validator.DynaValidatorForm">
               <form-property name="isbn"    type="java.lang.String"/>
    </form-bean>
  
  </form-beans>

 <global-forwards type="org.apache.struts.action.ActionForward">
     <forward   name="welcome"                path="/welcome.do"/>
     <forward   name="searchEntry"            path="/searchEntry.do"/>
     <forward   name="searchSubmit"           path="/searchSubmit.do"/>
 </global-forwards>

 <action-mappings>
    <action    path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
    <action    path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
    <action    path="/searchSubmit" 
             type="org.springframework.web.struts.DelegatingActionProxy" |(1)
             input="/searchEntry.do"
             validate="true"
             name="searchForm">
             <forward name="success" path="/WEB-INF/pages/detail.jsp"/>
             <forward name="failure" path="/WEB-INF/pages/search.jsp"/>
    </action>  

 </action-mappings>

 <message-resources parameter="ApplicationResources"/>


 <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
    <set-property 
    property="pathnames" 
    value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
 </plug-in>


 <plug-in 
    className="org.springframework.web.struts.ContextLoaderPlugIn">
    <set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
 </plug-in>

 
</struts-config>

Listing 5는 한 가지 작은 차이를 제외하고는 전형적인 struts-config.xml 파일이다. DelegatingActionProxy 액션의 클래스 이름을 밝히는 대신 Spring의 프록시 클래스 이름을 등록한다.(1) 클래스는 액션 매핑 이름을 사용하여 Spring 컨텍스트에서 액션을 관찰한다. 이것은 ContextLoaderPlugIn로 선언된 컨텍스트이다.

Struts 액션을 Spring 빈으로서 등록하는 것은 매우 단순하다.(Listing 6) <bean> 태그의 이름 애트리뷰트 (이 경우 "/searchSubmit")를 사용하여 이 액션 매핑의 이름을 사용하는 빈을 만든다. 이 액션의 JavaBean 속성들은 여느 Spring 빈 처럼 파퓰레이트 된다.


Listing 6. Spring 컨텍스트에 Struts 액션 등록하기
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
 "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

  <bean name="/searchSubmit"   
        class="ca.nexcel.books.actions.SearchSubmit">
     <property name="bookService">
        <ref bean="bookService"/>
     </property>
  </bean>

</beans>




위로


액션 위임의 효과

액션-위임 솔루션은 세 방식 중에서 최고이다. Struts 액션은 Spring을 인식할 수 없고, 코드를 변경하지 않고도 비 Spring 애플리케이션에서 사용될 수 있다. 이것은 RequestProcessor의 변경에 영향을 받지 않고, Spring의 AOP 기능을 활용할 수 있다.

액션 위임의 효과는 여기서 멈추지 않는다. 일단 Struts 액션을 Spring이 제어하도록 하면 Spring은 더욱 많은 일을 해낸다. 예를 들어, Spring 없이 모든 Struts 액션들은 "쓰레드 안전" 액션이 된다. <bean> 태그의 한 애트리뷰트를 "false"로 설정하면 애플리케이션은 각 요청에 대해 새롭게 만들어진 액션 객체를 갖게 된다. 또한 Spring의 라이프 사이클 메소드를 활용할 수 있다. 예를 들어, <bean>태그의 init-method 애트리뷰트는 Struts 액션이 인스턴스화 될 때 메소드를 실행한다. 이와 비슷하게 destroy-method 애트리뷰트는 빈이 컨테이너에서 삭제되기 전에 메소드를 실행한다. 이 메소드들은 값비싼 객체들을 관리할 수 있는 좋은 방법이다.




위로


Struts 인터셉트

앞서 언급했던 것 처럼, Struts와 Spring을 결합할 때의 가장 큰 장점 중 한 가지는 Spring의 AOP 인터셉터를 Struts 액션에 적용할 수 있다는 점이다. Spring 인터셉터를 Struts 액션에 적용함으로서 크로스-커팅 문제를 해결할 수 있다.

Spring엔 빌트인 인터셉터를 제공한다. 하지만 여기에서는 여러분 스스로 인터셉터를 구현하여 Struts 액션에 적용하는 방법을 설명하겠다. 인터셉터를 사용하기 위해서는 다음과 같이 한다.

  1. 인터셉터를 만든다.
  2. 이를 등록한다.
  3. 이것이 코드를 교차하는 곳을 선언한다.

매우 간단하지만 강력하다. Listing 7에서 Struts 액션에 대한 로깅 인터셉터를 만들었다. 이 인터셉터는 메소드가 호출되기 전에 문장을 프린트한다.


Listing 7. 로깅 인터셉터
package ca.nexcel.books.interceptors;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class LoggingInterceptor implements MethodBeforeAdvice {

   public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("logging before!");
    }
}

이 인터셉터는 매우 간단하다. before() 메소드는 인터섹션의 모든 메소드에 앞서 실행된다. 이 경우 이것은 문장을 프린트하지만 다른 것도 수행할 수 있다. 그런 다음 Spring 설정 파일에 인터셉터를 등록한다. (Listing 8)


Listing 8. 설정 파일에 인터셉터 등록하기
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
  "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
  <bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

  <bean name="/searchSubmit" 
        class="ca.nexcel.books.actions.SearchSubmit">
     <property name="bookService">
        <ref bean="bookService"/>
     </property>
  </bean>

  <!--  Interceptors --> 
  <bean name="logger"    
    class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1)

  <!-- AutoProxies -->
  <bean name="loggingAutoProxy" 
        class="org.springframework.aop.framework.autoproxy.
          BeanNameAutoProxyCreator"> |(2)
    <property name="beanNames">
          <value>/searchSubmit</valuesgt; |(3)
    </property>
    <property name="interceptorNames">
        <list>
          <value>logger</value> |(4)
        </list>
    </property>
   </bean>

</beans>

이미 눈치챘겠지만 Listing 8은 Listing 6을 확장하여 인터셉터를 추가했다.

  • (1) 에서 인터셉터를 등록한다.
  • (2) 에서 인터셉터가 사용되는 방법을 설명하는 빈 이름 autoproxy를 만든다. 인터섹션을 정의하는 다른 방법들도 있지만 이 방법이 일반적으로 사용된다.
  • (3) 에서 Struts 액션을 인터셉트 될 빈으로 등록한다. 다른 Struts 액션을 인터섹트 하려면 추가 <value> 태그를 "beanNames" 아래에 만든다.
  • (4) 에서 인터셉트가 발생할 때 (1)에서 만들었던 인터셉터 빈의 이름을 실행한다. 여기에 나열된 모든 인터셉터들이 "beanNames" 에 사용된다.

다 되었다. Struts 액션을 Spring 프레임웍의 제어를 받도록 하면 Struts 애플리케이션을 핸들 할 때 새로운 옵션들을 사용할 수 있다. 이 예제에서 액션 위임을 통해 Spring 인터셉터를 Struts 애플리케이션에서 쉽게 활용할 수 있었다.




위로


결론

이 글에서 Struts 액션을 Spring 프레임웍에 통합할 수 있는 세 가지 레시피를 배웠다. Spring의 ActionSupport를 사용하여 Struts를 통합하는 것은 빠르고 쉬운 방식이지만 Struts 액션들이 Spring 프레임웍에 연결한다. 이 애플리케이션을 다른 프레임웍에 포팅해야 하다면 코드를 재작성 해야 한다. 두 번째 솔루션인 RequestProcessor를 위임하는 것은 코드를 확실히 분리하지만 Struts RequestProcessor가 명령어 체인으로 개정된다면 오래가지 못한다. 세 번째 방식이 가장 낫다. Struts 액션을 Spring 프레임웍에 위임하면 Struts 애플리케이션에서 Spring의 기능들을 활용할 수 있다.

이 세 가지 Struts-Spring 통합 레시피들 모두 완전한 애플리케이션으로 구현되었다. 아래 다운로드 섹션을 참조하기 바란다.





위로


다운로드 하십시오

설명 이름 크기 다운로드 방식
ActionSupport sample code j-sr2-actionsupport.zip 5 MB  FTP
RequestProcessor sample code j-sr2-requestprocessor.zip 5 MB  FTP
Delegate sample code j-sr2-delegate.zip 5 MB  FTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기

토론


필자소개

George Franciscus: 회장, Nexcel


Tag // spring, Struts