spring의 장점 중하나는 다양한 데이타베이스 모델에 대한 자체적인 api를 가지고 있다는 것이다. 하나의 프레임워크 만을 사용하면 확장성에 문제가 있기 때문에 필요에 따라 다양한 프레임워크를 사용한다.



■ spring library 다운 받기.

 http://www.springsource.org/  에서 다운로드로 이동 후 Spring Framework 2.5.6.SEC01 is the current production release (requires Java 1.4+) 아래 Download 를 클릭 한다. 페이지 이동 후 Download Now를 클릭한다.
 페이지 이동 후에 More를 클릭하여 2.5.6 을 클릭하면 spring-framework-2.5.6-with-dependencies.zip spring-framework-2.5.6-with-docs.zip 파일을 다운로드 한다. (개인 정보를 입력하는 부분이 나오면 대충 입력해도 된다.)


 다운로드 받은 파일을 압축을 해제하고 spring-framework-2.5.6-with-dependencies\dist(여기가 spring의 핵심 부분) 으로 간다. dist 폴더에 보이는 spring library 파일을 프로젝트의 lib 폴더에 추가한다.
 다시 spring-framework-2.5.6-with-dependencies\dist\modules 폴더로 이동해서 spring-aop, spring-beans, spring-core, spring-jdbc, spring-orm, spring-tx, spring-web, spring-webmvc, spring-webmvc-struts 라이브러리 파일을 추가한다.
 마지막으로 spring-framework-2.5.6-with-dependencies\lib\log4j 폴더에서 log4j-1.2.15 라이브러리를 추가한다.

 그리고 Struts2 library에서 struts-2.0.14\lib 폴더에 있는 struts2-spring-plugin-2.0.14 라이브러리를 추가 한다.(Strust1에서는 Spring으로 가는 플러그인이 없다)

■ applicationContext.xml 을 만들어서 작업을 진행하는 동안 계속 추가해 난간다.

작업 내용이 추가된 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans  
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
      
 
  <!-- DataSource JDBC type -->
  <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        p:driverClassName="oracle.jdbc.driver.OracleDriver"
        p:url="jdbc:oracle:thin:@localhost:1521:XE"
        p:username="user01"
        p:password="user01" />
 
  <!-- iBatis SQL-Map config -->
  <bean id="sqlMapClient" <!-- 아이디는 임으로 지어낸다 -->
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
        p:dataSource-ref="dataSource" <!-- dataSource 참조 -->
        p:configLocation="classpath:SqlMapConfig.xml" /> <!-- default 경로는 scr 이고, src 하위 아무 디렉토리나 참조하기 위해서는 classpath를 써주는게 좋다 --<
  
  <bean id="template"
        class="org.springframework.orm.ibatis.SqlMapClientTemplate"
        p:sqlMapClient-ref="sqlMapClient"/>
       
  <bean id="scheduleDao"
    class="com.myhome.schedule.model.ScheduleDAOImpl"
    p:template-ref="template"/> <!-- p는 property다.-->
    <!-- <property name="template" ref="template"/> 이렇게 써도 된다. 같은 방법  bean id="template"가 p:template-ref="template"의 template다 -->
                 
  <bean id="service"
        class="com.myhome.service.ScheduleServiceImpl"
        p:scheduleDao-ref="scheduleDao"/>
    
  <bean id="dto" class="com.myhome.schedule.model.ScheduleDTO"/>
 
   <bean id="scheduleModel"
        class="com.myhome.schedule.api.ScheduleModel"/>    
</beans>

※ DB와 연동하기 위해 여기서는 SqlMapClientTemplate 을 사용하는데 bean 주입을 이용한다. iBatis에서 SqlMapConfig.xml 트랜잭션을 정의한 부분이 applicationContext.xml으로 온다. 
 
 SqlMapConfig.xml을 참조하고 있는 bean이 필요한데, 이런 객체들을 컨테이너가 가지고 있다가 서비스를 한다. 

<bean id="sqlMapClient
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
        p:dataSource-ref="dataSource
        p:configLocation="classpath:SqlMapConfig.xml" /> 

 이 부분에서 SqlMapConfig.xml 을 id가 참조하도록 지시한다. 이게 바로 bean 주입 방식이다. 개발자가 객체를 만들지 않고 bena에서 id만 정의 해주면 컨테이너가 이 객체를 다 가지고 있다. 그리고 컨테이너에 의해서 객체 서비스가 이루어 진다.

 그리고(예를 들어) DAOImpl Class 에서 

/*setter injection*/
 private SqlMapClientTemplate template; //이게 bean 주입 방식 으로, applicationContext.xml(빈설정문서 프로퍼티가 동일해야 된다)를 로딩해서 이 template 객체를 만들어 준다.
 public void setTemplate(SqlMapClientTemplate template){
  this.template = template;
 }

이런 식으로 사용한다. 이렇게 다른 곳에서 객체가 필요할 때도 이런 방법으로 만들어 낸다.
 
■ struts.properties

# struts2 + spring Factory
   struts.objectFactory=org.apache.struts2.spring.StrutsSpringObjectFactory
//applicationContext.xml을 가지고 있는게 factory다. 여기서 스트럿츠가 스프링으로 간다는 것을 알려주고 연결한다. objectFactory를 설정해 주면 applicationContext를 이 factory가 갖게 된다. DI를 할 때, 인위적으로 applicationContext를 로드해서 리소스를 읽어 id를 참조해서 만들지 않는다. 
   struts.objectFactory.spring.autoWire=type // applicationContext.xml에 들어있는 각각의 bean 들을 설정하는데 그 bean은 autoWire 라는 뜻으로 우리가 설정하는 타입데로 알아서 처리하라는 뜻.

(이 때 factory를 적용하기 위해서는 struts가 spring으로 간다는 것을 알려주어야 하는데 이때 필요한 library가 struts2-spring-plugin-2.0.14 이다.)

이 두줄을 struts.properties 에 추가한다. 


■ web.xml

<!-- spring scope (context parameter) -->

<!-- applicationContext.xml을 로딩하는 역할을 한다. -->

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value> 
  </context-param>

  <listener>
     <listener-class>
        org.springframework.web.context.ContextLoaderListener
     </listener-class>
  </listener>
 
  <!-- spring scope ended -->

이 부분 까지 Strut2 + Spring + iBatis 연결 설정 부분에 대한 간략한 설명이다.

Spring에서 Simpleformbankingobject

JSP에서 데이타를 입력해서 보여주는게 아니라. Action에서 데이터를 제공해 주는 것으로 데이타를 보호 할 수 있다.

- IndexAction.java

package person.actions;

import java.util.List;
import java.util.ArrayList;
import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class IndexAction extends ActionSupport {
 
 private List<String> list;
 
 @Override
 public String execute()throws Exception {
  list = new ArrayList<String>();
  list.add("서울");
  list.add("부산");
  list.add("대구");
  list.add("대전");
  list.add("광주");
  list.add("인천");
  list.add("울산");
  return SUCCESS;
 }
 
 public List<String> getList(){
  return list;
 }

}

* list에있는 서울, 부산, 대구, 대전, 광주, 인천, 울산 데이터를 JSP 페이지에 보여줄 것이다.

- write.jsp

<%@ page language="java"
         contentType="text/html; charset=EUC-KR"
         pageEncoding="EUC-KR"%>
<%@ taglib prefix="s" uri="/struts-tags"%>        
<!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=EUC-KR">
<title>struts2::interceptor</title>
<style type="text/css">
     td {font-size: 11pt; text-decoration: none; color: #000000}
    </style>
</head>
<body>
  <center>
    <br /><br />
    <h3><b>struts2 interceptor(checkbox)</b></h3>
    <form method="post" name="myform" action="write.action">
      <table border=0 cellpadding=0 cellspacing=1
             bgcolor="#000000">
        <tr height=30 bgcolor="#ffffff">
          <td bgcolor="#f0f0f0" width=100 align="center">성명</td>
          <td width=300 align="left">&nbsp;
            <input type="text" name="name">
          </td>
        </tr>    
        <tr height=30 bgcolor="#ffffff">
          <td bgcolor="#f0f0f0" width=100 align="center">이메일</td>
          <td width=300 align="left">&nbsp;
            <input type="text" name="email">
          </td>
        </tr> 
        <tr height=30 bgcolor="#ffffff">
          <td bgcolor="#f0f0f0" width=100 align="center">주소</td>
          <td width=300 align="left">&nbsp;
            <select name="addr">
              <s:iterator value="list">
                <option value="<s:property />">
                  <s:property/>
                </option>
              </s:iterator>
            </select>
          </td>
        </tr> 
        <tr height=30 bgcolor="#ffffff">
          <td bgcolor="#f0f0f0" width=100 align="center">취미</td>
          <td width=300 align="left">&nbsp;
            <input type="checkbox" name="travel" value="여행" checked>여행
            <input type="checkbox" name="climbing" value="등산" >등산
            <input type="checkbox" name="game" value="게임">게임
          </td>
        </tr>
        <tr height=30 bgcolor="#ffffff">
          <td bgcolor="#f0f0f0" width=100 align="center">성별</td>
          <td width=300 align="left">&nbsp;
            <input type="radio" name="sex" value="남" checked>남
            <input type="radio" name="sex" value="여">여
          </td>
        </tr>
        <tr height=30 bgcolor="#f0f0f0">
          <td align="right" colspan=2>
            <input type="submit" value="등록...">&nbsp;
          </td>
        </tr>
      </table>       
    </form>
  </center>
</body>
</html>

* 아래 부분에서 IndexAction.java 의 리스트 부분의 데이타를 보여 줄 수 있다.

<select name="addr">
    <s:iterator value="list">
           <option value="<s:property />">
              <s:property/>
           </option>
      </s:iterator>
 </select>

■ Interceptor의 종류



■ Checkbox Interceptor, Parameters Interceptor.

체크되지 않는 값을 다 막아내고 그 값을 출력하더라고 비어있기 때문에 빼버린다.

- checkbox.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="interCheckbox" namespace="/checkbox" extends="struts-default">
   <!-- 자신이 만든 interceptor은 action 밖에서 사용하고, 존재하는 interceptor의 사용은 action에서 사용한다 -->
   
      <action name="index"
              class="person.actions.IndexAction">
        <result>/person/write.jsp</result>
      </action>
   
      <action name="write"
              class="person.actions.WriteAction">
         
          <param name="name">홍길동</param>
          <interceptor-ref name="staticParams"/> <!-- param을 가질 수 없기 때문에 위로 뺀다. -->
                          
<!-- Checkbox Interceptor 부분 -->
             <interceptor-ref name="checkbox">
              <param name="uncheckedValue">false</param>
<!-- uncheckedValue 예약어다. 체크하지 않은 값은 오지 않는다.-->            
             </interceptor-ref>
             <interceptor-ref name="prepare"/> <!--세개를 써주는게 좋다. default라서 안써도 되지만.-->
             <interceptor-ref name="modelDriven"/>
             <interceptor-ref name="params"/>
         <result>/person/result.jsp</result>
      </action>
     
   </package>

- WriteAction.java

package person.actions;

import person.model.PersonVO;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.interceptor.ParameterNameAware; //특정 파라메터의 값을 받지 않을 경우
import com.opensymphony.xwork2.interceptor.NoParameters; //Interface NoParameters클라이언트가 보내주는 파라미터를 다 차단하겠다.

@SuppressWarnings("unchecked")
public class WriteAction implements Action,
         Preparable,
         ModelDriven,
         ParameterNameAware //Parameters Interceptor 부분 : 특정 파라미터를 안받을 경우
         //NoParameters //Parameters Interceptor 부분 : 모든 파라미터를 안받을 경우
         {
 private String name;
 private PersonVO vo;
 
 //비즈니스 로직 수행 부분
 @Override
 public String execute()throws Exception { //Ation은 execute 메소드를 가지고 있다
  //business logic
  return SUCCESS;
 }
 
 //폼 요청이 들어오면 파라메터의 값을 받기 위해 객체를 생성하고, 각 파라메터의 값을 프로퍼티에 저장한다.
 @Override
 public void prepare() { //preparable, 객체의 초기와 생성
  vo = new PersonVO();
    }

 //execute 메소드를 수행하고 결과를 Result로 전달하는 부분
 @Override
    public Object getModel() { //ModelDriven 데이타를 result로 객체를 넘기는 역할
  return vo;
    }

 //특정 파라메터를 받지 않기 위해 설정한다.
// @Override
 public boolean acceptableParameterName(String parameterName) {
  
  if("name".equals(parameterName)){ //name과 같은 property가 넘어오면 값을 받지 않겠다.
   return false;
  }

  
  return true;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

}

- 결과 보기

테이터를 입력 한다.


ParameterNameAware 을 사용하여 name 을 받지 않은 경우.


NoParameters 를 사용하여 모든 데이터를 받지 않은 경우.


■ Exception Interceptor.

- upload.xml

 exception 에는 알 수없는 action에서 error가 발생했을 때 잡는 global exception과, 특정 action에서 error가 발생했을 잡아주는 local Interceptor exception이 있다.

<?xml version="1.0" encoding="euc-kr"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="upload" namespace="/upload" extends="struts-default">
     
  <!-- 알 수 없는 action에서 error가 발생 했을 경우 global exception을 발생한다. -->
     <!-- global exception은 action 위에서 는다. -->

    <global-results>
          <result name="exception">/exception/exception.jsp</result>
    </global-results>
     
     <global-exception-mappings> <!-- 여기서 exception이 발생하면 result name의 exception을 요구하고 위의 name 이 exception 인 result 페이지로 이동한다 -->
      <exception-mapping result="exception" exception="java.lang.Exception"/> <!-- exception 잡을 때 최상위를 잡는게 좋다 -->
     </global-exception-mappings>
     
     <action name="index" class="com.myhome.upload.actions.UploadIndexAction">
                  <result>/WEB-INF/upload/register.jsp</result>
     </action>
     
     <action name="register"
       class="com.myhome.upload.actions.UploadMultiAction"
       method="register">

       <!-- local interception exception은 action 안에서 잡는다. -->
      <!-- 특정 액션에서 예외가 발생할 때 인터셉터를 적용한다. -->

      <exception-mapping result="exception" exception="java.lang.NullPointerException"/> <!-- 여기서는 직접 구현한 익셉션을 사용하는게 좋다 -->
      
       <result name="success" type="dispatcher">/WEB-INF/upload/result.jsp</result>
      <result name="input" type="dispatcher">/WEB-INF/upload/register.jsp</result>
      <result name="error" type="dispatcher">/WEB-INF/upload/register.jsp</result>
      <result name="exception">/exception/exception.jsp</result>
     </action>

... 생략 ...

* UploadMultiAction 에 설정해 놓은 NullPointerException 이 발생 할 경우 result name이 exception인 곳으로 데이터를 보내고 exception.jsp에서는 <s:actionerror/>, <s:actionmessage/>, <s:fielderror/>, ${exception.message}, ${exceptionStack} 이런 식으로 데이타를 보여준다.

- exception.jsp

<%@ page contentType="text/html; charset=EUC-KR"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!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=EUC-KR">
 <title>exception page</title>
  </head>
 
  <body>
 <h2>예기치 않는 오류 발생</h2>
    <p>
              현재 많은 접속자로 인해  시스템의 과부하가 발생하였습니다.
             잠시 후 다시 접속을 시도해 주십시오.
    </p>
    <p>        
             문의사항이 있으시면 admin@myhome.com으로 메일을 보내주십시오.              
    </p>
    <hr/>
     <h3>에러 메시지</h3>
      <s:actionerror/> <!-- action에서 알 수 없는 error 가 걸렸을 때 보기위해 찍는다. -->
      <s:actionmessage/>
      <s:fielderror/>
      <p>
       ${exception.message}
      </p>
    <hr/>
    <h3>에외 상세정보</h3>
    <p>
      ${exceptionStack}
    </p>
 </body>
</html>

- action class

 action class 안에서 다음과 같이 error message 를 추가 할 수 있다.

/*exception handle*/
this.addActionMessage(bean.getName() + " 님이 파일 오류를 발생하였음"); //이렇게 에러 메세지 추가가 가능하다.
throw new NullPointerException("파일을 올려주셈~~");

■ Servlet Config Interceptor


 HtteServletRequest와 HttpServletResponse를 다루는 맵을 엑세스할 수 있게 한다. 

 Servlet-Config Interceptor는 액션들의 Servlet API에서 다양한 객체들을 주입하는 좋은 방법을 제공한다. Struts2는 Servlet API를 제공하지 않기 때문에 servlet 객체에 접근하기 위해 Map을 사용한다. Map의 종류로는 

 ServletContextAware  : ServletContext 객체를 받을 수 있다.

 ServletRequestAware  : HttpServeltRequest 객체를 받을 수 있다.

 ServletResponseAware : HttpServeltResponse 객체를 받을 수 있다.

 ParameterAware       : Parameter Map을 받을 수 있다.

 RequestAware         : Request Map을 받을 수 있다.

 SessionAware         : Session Map을 받을 수 있다.

 ApplicationAware     : Application Map을 받을 수 있다.

맵을 받기 위해서는 각각의 Aware 인터페이스를 구현해야 한다.


- LoginAction.java


package servletConfig.action;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.apache.struts2.interceptor.RequestAware;

import org.apache.struts2.interceptor.ServletRequestAware;

import org.apache.struts2.interceptor.SessionAware;

import servletConfig.dao.LoginDAO;

import servletConfig.interceptor.LoginDAOAware;

import servletConfig.model.UserInfo;

import com.opensymphony.xwork2.Action;

import com.opensymphony.xwork2.ModelDriven;

import com.opensymphony.xwork2.Preparable;


public class LoginAction implements Action, 

                     Preparable, 

     ModelDriven, 

     LoginDAOAware, 

     SessionAware, 

     ServletRequestAware, 

     RequestAware {


    //도메인 오브젝트

    UserInfo userInfo;

    LoginDAO dao;

    Map sessionMap;

    Map requestMap;

    HttpServletRequest request;

    Log log = LogFactory.getLog(LoginAction.class);


    public String execute() throws Exception {

     if (dao.loginChk(userInfo)) {

           sessionMap.put("userInfo", userInfo);

           log.info("----> requestURI : " + request.getRequestURI());

           log.info("----> request ID : " + requestMap.get("id").toString());

           log.info("----> request PWD : " + requestMap.get("pwd").toString());

           return SUCCESS;

        } else {

           return LOGIN;

        }

    }

    

    //Preparable인터페이스의 prepare 구현

    public void prepare() throws Exception {

        userInfo = new UserInfo();

    }

           

    //ModelDriven 인터페이스의 getModel 구현

    public Object getModel() {

        return userInfo;

    }


    //LoginDAUInterceptor에서 LoginDAO를 주입한다.

    public void setLoginDAO(LoginDAO loginDAO) {

        this.dao = loginDAO;

    }


    //SessionAware의 setSession 구현

    public void setSession(Map session) {

        this.sessionMap = session;

    }


    //RequestAware의 setRequest 구현

    public void setRequest(Map requestMap) {

        this.requestMap = requestMap;

    }


    //ServletRequestAware의 serServletRequest 구현

    public void setServletRequest(HttpServletRequest request) {

        this.request = request;

    }


}


- interServletConfig.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="interServlet" namespace="/login" extends="struts-default">

<!-- <interceptors>는 자신이 만든 interceptor를 사용하기 위해 정의하는 부분이다. -->

<!-- 더 필요한 정보가 없을 경우 <interceptor-ref name="servletConfig"/> 만 써도 된다. -->

<interceptors>

<interceptor name="loginDao" class="servletConfig.interceptor.LoginDAOInterceptor"/>

</interceptors>

<action name="login" class="servletConfig.action.LoginAction">

<interceptor-ref name="prepare"/>

<interceptor-ref name="modelDriven"/>

<interceptor-ref name="params"/>

<interceptor-ref name="loginDao"/>

<interceptor-ref name="servletConfig"/>

<result>/login/logout.jsp</result>

<result name="login">/login/login.jsp</result>

</action>

<action name="logout" class="servletConfig.action.LogoutAction">

<result>/login/login.jsp</result>

</action>

</package>

</struts>


- LoginDAO.java

package servletConfig.dao;

import servletConfig.model.UserInfo;

public class LoginDAO{

public boolean loginChk(UserInfo userInfo){

//login을 할 때, 아이디를 test로 넣어주어야 홍길동이라는 이름을 보내준다. (test로 넣어주어야 홍길동을 쿼리 해오겠다는 의미)

if("test".equals(userInfo.getId())){

userInfo.setName("홍길동");

return true;

}else{

return false;

}

}

}


- LoginDAOAware.java

package servletConfig.interceptor;

import servletConfig.dao.LoginDAO;

public interface LoginDAOAware{

public void setLoginDAO(LoginDAO loginDAO);

}


- LoginDAOInterceptor.java


package servletConfig.interceptor;

import servletConfig.dao.LoginDAO;

import com.opensymphony.xwork2.ActionInvocation;

import com.opensymphony.xwork2.interceptor.Interceptor;


@SuppressWarnings("serial")

public class LoginDAOInterceptor implements Interceptor{

LoginDAO loginDAO;

//인터셉터는 라이프 사이클을 가지고 있다.

@Override

public void init() {

loginDAO = new LoginDAO(); //객체 생성

}

@Override

public void destroy() {

loginDAO = null; //객체 소멸

}


//로그인을 셋팅 해주는 과정

@Override

public String intercept(ActionInvocation invocation) throws Exception {

               Object action = invocation.getAction(); //오브젝트로 액션을 얻어 온다.

if(action instanceof LoginDAOAware){ //instanceof는 이게 어느 클래스의 인스턴스인지를 물어볼때 쓰는 키워드이다.

LoginDAOAware loginDAOAware = (LoginDAOAware)action;

loginDAOAware.setLoginDAO(loginDAO);

}

//System.out.println("***************" + invocation.invoke()); //성공시 success를 return 한다.

return invocation.invoke();

}

}


- 실행 모습

http://localhost:8989/Struts2_ServletConfigInterceptor/login/login.action 으로 접속한다.



test라는 아이디를 넣고 로그인을 한다.


그러면 홍길동 이라는 이름으로 로그인 한 모습을 볼 수 있다. LoginDAO.java 에서 test라는 아이디로 들어오면 홍길동이라는 이름을 리턴하게 구현하였기 때문이다. 다른 아이디를 입력 하면 로그인이 되지 않을 것이다.



자세한 내용은 파일을 참조 한다.






 Struts2에서 차트 예제를 실행 하기위해서 freemarker-2.3.8.jar와 ognl-2.6.11.jar library가 필요한 합니다.
 무슨 library 인지 알고 써야 할 것 같아 찾아 봤습니다.(왠지 이 모를 궁금함과 찜찜함...^^;)

 freemarker-2.3.8.jar 는 "template engine"으로 템플릿 기반으로 테스트 결과물을 만들어네는 일반적인 툴 이라고 합니다. 템플릿 파일과 자바 객체들이 FreeMarker를 통과하면 텍스트 결과물을 만들어 내는 그림을 볼 수 있습니다. 그리고 Strtus 에서는 Struts 태그의 output을 생성하는데 사용된다고 하네요.


freemarker 사이트 주소는
http://freemarker.org/  입니다. 참고 하세요.

ognl-2.6.11.jar 의 OGNL - Object Graph Navigation Library 의 약자로 Object-Graph Navigation Language의 표준으로, OGNL은 자바 오브젝트의 프로퍼티들을 get, set 하기위한 표현 언어라고 합니다.
OGNL은 Struts2 태그가 속성을 읽고 계산하기 위한 기능을 제공한다고 합니다.

그리고 이것들을 검색하다 특이한 사이트 하나를 찾았습니다. findJAR 이라고 JAR search engine 이라고 하네요. 참고하세요.

 

Tiles에 대한 자세한 내용은

http://tiles.apache.org/

참조 한다.

■ Tiles를 사용하는 이유.

 1. 매 페이지마다 include를 시키게 되면 나중에 그 파일이 변경 됐을 때 문제가 발생한다. 다 뜯어 고쳐야 한다. 그래서 따로 설정문서에다가 include 파일들을 준비해두고 필요시 가져다 쓰라는 것이다. 나중에 페이지 include할 파일 이름이 바뀔 경우 설정문서에서 만 바꿔주면 된다.
 2. 레이아웃을 지원해 준다. 레이아웃패턴을 이용해서 Tiles를 사용할 수 있도록 지원해 준다.

■ Tiles의 진행 순서.



 Action에서 결과를 전달하는데 Result가 tiles로 가라고 알려준다. 그럼 Interceptor에서 Plugin인 web.xml에 정의 되어있는 listener에게 알려준다. 그럼 listener는 현재 tiles.xml을 받아서 Plugin에게 알려준다. 그럼 그 Plugin은 tiles.xml 에 정의 되어 있는 각각의 정의 문서를 통해서 적절할 페이지로 이동시킨다. 그러기 위해서는 web.xml에서 tiles-definitions으로 정의하고 있는 그 문서를 참조하기 위한 event listener를 반드시 정의해줘야 한다.

■ 필요한 library

Struts2 library의 lib 폴더(struts-2.0.14\lib) 에서 아래 네개 파일을 추가한다.

struts2-tiles-plugin-2.0.14, tiles-api-2.0.4, tiles-core-2.0.4, tiles-jsp-2.0.4

■ web.xml

<!-- title plug in listener 리스너를 정의 해준다.-->
 <listener>
  <listener-class>
   org.apache.struts2.tiles.StrutsTilesListener
  </listener-class>
 </listener>

■ tiles.xml(정의문서 : web.xml과 같은 위치에 있다)

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

<tiles-definitions>
    <definition name="index" template="/tiles/classicLayout.jsp"> <!-- index를 요구하면 이 페이지로 전달하겠다. -->
        <put-attribute name="title"  value="Struts2 Tiles Example"/> 
        <put-attribute name="menu"   value="/tiles/menu.jsp"/>
        <put-attribute name="header" value="/tiles/header.jsp"/>
        <put-attribute name="body"   value="/tiles/body.jsp"/>
        <put-attribute name="footer" value="/tiles/footer.jsp"/>
    </definition>
   
    <definition name="menu1" extends="index">
        <put-attribute name="body"   value="/tiles/body-menu1.jsp"/> <!-- "/tiles/body.jsp"/ 이 페이지를 /tiles/body-menu1.jsp"/ 페이지로 바꿔라 -->
    </definition>
 
 <definition name="menu2" extends="index">
        <put-attribute name="body"   value="/tiles/body-menu2.jsp"/>
    </definition>
</tiles-definitions>

*  즉 include해야할 파일을 설정 문서에다가 설정해두고 각각의 페이지에서는 그 속성의 이름만을 쓴다.
 
■ classicLayout.jsp

<%@ page contentType="text/html; charset=euc-kr"%>
<%@ taglib prefix="tiles"  uri="http://tiles.apache.org/tags-tiles"%> <!-- tiles 태그를 사용하겠다고 정의 -->

<!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><tiles:getAsString name="title" /></title> <!-- 문자열을 가져올 때 -->
    </head>
    <body>

    <table border=0 cellpadding=0 cellspacing=1 bgcolor="#a0a0a0" width="100%">
        <tr height=100 valign="middle" bgcolor="#ffffff">
            <td colspan=2><tiles:insertAttribute name="header"/></td> <!-- 페이지를 가져올 때 -->
        </tr>
        <tr height="670" bgcolor="#ffffff">
            <td width="15%" valign="top"><tiles:insertAttribute name="menu"/></td>
            <td width="85%" align="center"><tiles:insertAttribute name="body"/></td>
        </tr>
        <tr bgcolor="#ffffff">
            <td colspan=2><tiles:insertAttribute name="footer"/></td>
        </tr>
    </table>
    </body>
</html>

* title, header, menu, body 등의 속성은 tiles.xml(정의문서)에 꼭 정의가 되어있어야 한다.

■ tiles.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="tiles" namespace="/tiles" extends="struts-default,tiles-default"> <!-- tiles-default이게 정의 되어 있어야 type에서 tiles를 인식한다 -->
        <action name="index">
            <result type="tiles">index</result>
        </action>
        <action name="menu1">
            <result type="tiles">menu1</result>
        </action>
        <action name="menu2">
            <result type="tiles">menu2</result>
        </action>
    </package>
</struts>   

* Client가 index을 요구하면 tiles.xml(정의문서)에서 정의하고 있는 index라고 정의 되어있는 속성 이름을 전달하겠다고 알려준다.

파일 참조



Struts2 에서 Tiles Plugin 사용하기 끝!


+ Recent posts