struts 1 - exception 처리

Published on: 2009. 7. 2. 00:39 by louis.dev


스트럿츠 1에서는 익셉션 처리 하는 방법이 두가지가 있다.
① Global Exception으로 처리하는 방법
② Action Exception으로 처리하는 방법

1. Global Exception으로 처리하는 방법

1) 에러가 발생되었을때 보여질 jsp 페이지를 생성한다.

-----------------------------------------------------------------------------------------------------
<%@ page contentType="text/html; charset=euc-kr"%>
<%@ page import="org.apache.struts.Globals" %>
<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html"%>
<%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean"%>
 
<html>
 <head>
  <title>예외 처리</title>
 </head>

 <body>
  <center>
    <h3><b>예외 핸들러가 전달한 에러 메시지 목록</b></h3>
   <html:messages id="error">
    <li><bean:write name="error"/></li>
   </html:messages>

   <br/><br/>
   <h3>예외객체에서 가져온 예외 메시지</h3>
   <blockquote style="background: wheat;">
 <%
  Exception ex = (Exception)
                 request.getAttribute(Globals.EXCEPTION_KEY);
     if (ex == null) out.println("ex == null");
     else out.println(ex.getMessage());
 %>

   </blockquote>
  </center>
 </body>
</html>
-----------------------------------------------------------------------------------------------------

2) .properties 파일(메시지 번들) 생성

-----------------------------------------------------------------------------------------------------
# exception messages
exception.global=오류가 발생했습니다.
exception.handler={0} : 오류가 발생했습니다. 오류 메시지 : {1}
exception.register=존재하지 않는 이름이 입력되었습니다.
exception.fileNotFound=업로드 파일이 존재하지 않습니다.

# native2ascii -encoding euc-kr ExceptionMessageResource.properties ExceptionMessageResource_ko.properties
-----------------------------------------------------------------------------------------------------

3) 사용할 struts-config.xml 파일에 <global-exceptions>생성

<global-exceptions>
  <exception type="java.lang.Exception"
                   key="exception.global"
                   path="/exception/exception.jsp"/>
 </global-exceptions>

모든 Exception이 발생했을때 다음의 global-exceptions 를 실행한다.

- type : Exception class 설정
- key : properties 파일에 존재하는 에러 key 선택
- path : 에러 발생시 보여줄 페이지 선언
- handler: exception을 처리할 Handler Class 선언
               Handler Class 는 ExceptioHandler class를 상속 받은 구조여야 한다.(Action Exception으로 exception을 처리할때 선언)


4) config.xml 파일에 message-resources 등록하기(.properties파일 경로 지정)

<message-resources parameter="com.myhome.upload.ExceptionMessageResource"/>

2. Action Exception으로 처리하는 방법

1) ExceptioHandler class를 상속받은 class를 생성하고 ExceptionHandler class의 excute() 메소드를 override 한다.

-----------------------------------------------------------------------------------------------------
package com.myhome.handler;

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

import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.config.ExceptionConfig;
import org.apache.struts.action.ExceptionHandler;
import org.apache.struts.action.ActionMessage;

import java.util.Date;

public class InfoExceptionHandler extends ExceptionHandler {
 
    public ActionForward execute(Exception ex, 
            ExceptionConfig config,
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
               throws ServletException {
   
     
 /* 발생한 예외시간을 포함해서 새로운 문자열로 구성한다.
  * 액션 메시지의 정보를 리소스번들에 지정한 인수로 전달하기 위해 사용된다.
  * . resource bundle
  *   exception.handler={0} : 오류가 발생했습니다.
  *                     오류 메시지 : {1}
  *  arg[0] => {0}로 연결된다.
  *  arg[1] => {1}로 연결된다.                   
  *
  * */

 String [] args = new String[2];
 long currentTimeMillis = System.currentTimeMillis();
 Date currentTime = new Date(currentTimeMillis);
 args[0] = currentTime.toString(); // 현재 시간을 인자로 저장.
 args[1] = ex.getMessage(); // 오류 메시지를 인자로 저장.
 
 // 지정된 키의 메시지를 메시지 리소스 번들에서 가져와
    //{0}, {1}을 지정된 인자로 대체하여 새로운 메시지 구성.
 ActionMessage errorMessage = new ActionMessage(
                            config.getKey(),args);       
       
 // 예외 정보를 가지고 포워딩할 JSP페이지를 찾는다.
 //<exception path=""/>에 지정된 페이지
 ActionForward forward = new ActionForward(config.getPath());
 
 // 예외 사항들을 request에 저장한다.
 storeException(request,
                       config.getKey(),
                       errorMessage,
                       forward,                         
                       config.getScope());
            return forward;
   }
}

-----------------------------------------------------------------------------------------------------
이 클래스는 익셉션이 발생하였을때 이쪽으로 넘어오며 에러메시지를 request 객체에 담아 에러 메시지를 보여줄 페이지로 보내주게 된다.

에러가 발생하게 되면

<exception key="exception.handler"/> 메시지를 가져다가 현재 시간과 ex.getMessage()를 실행하여 예외의 메시지를 합쳐서 ActionMessage 객체를 구성하게 된다.

그리고 config.getPath()를 이용해서

 <exception path="/exception/exception.jsp"/> 로 지정된 포워딩할 JSP 주소를 얻어다 ActionForward 객체를 구성한다.

최종적으로 storeException()메소드를 실행하여 에러 메시지를 지정된 스코프(config.getScope())에 저장하고는 포워드 객체를 리턴한다.

이제 IOException 이나 NullPointerException이 발생하면 아래와 같은 화면을 보게 된다.




2.struts-config.xml 파일에 <action>태크 밑으로 로컬 exception 영역을 설정한다.

<action path="/upload"
           name="uploadBean"
           scope="request"
           parameter="method"
           unknown="true"
           type="com.myhome.upload.actions.UploadDispatchAction">
         
       <!-- exception handle -->
       <exception key = "exception.handler"
            handler = "com.myhome.handler.InfoExceptionHandler"
            path = "/excetpion.jsp"
            type = "java.lang.NullPointerException">
       </exception>

            <forward name="result"  path="/result.jsp"/>
            <forward name="fail"    path="/fail.jsp"/>
            <forward name="list"    path="/list.jsp"/>
            <forward name="query"   path="/modify.jsp"/>
            <forward name="update"  path="/template.jsp"/>
            <forward name="delete"  path="/template.jsp"/>
       </action>   

type 에 선언된 Action에서 exception이 발생 되었을때 하단의 exception handle에 의해 에러 페이지로 이동한다.

여러종류의 Exception을 처리 할 경우

<exception key="exception.handler"
           handler=“info.handler.InfoExceptionHandler"
           path="/exception/exception.jsp"
           type="java.lang.NullPointerException"/>
<exception  key="exception.handler"
           handler=“info.handler.InfoExceptionHandler"
           path="/exception/exception.jsp"
           type="java.io.IOException"/>

struts1 - Tiles plug-in

Published on: 2009. 7. 1. 21:05 by louis.dev

스트럿츠 1에서는 사용할 수 있는 플러그인은 두개 밖에 없다. validator plug-in과 Tiles plug-in이 그 두가지 이다.
Tiles는 중복되는 웹페이지의 레이아웃을 간단한 설정파일을 통해 쉽게 설정할 수 있고 기존에 include로 페이지를 삽입했을때 보다 유지 보수성이 뛰어나다는 장점을 가지고 있다.

작업 순서
1) strust-tiles-1.3.10.jar파일을 라이브러리에 추가 시킨다.

2)tiles-defs.xml파일을 설정한다.

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

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

<tiles-definitions>
    <definition name=".layout-main"
                path="/tilesModule/classicLayout.jsp">     <!-- 다음과 같은 path로 찾아 들어왔을때 웹페이지의 설정을 한다. 실제 적으로 classicLayout.jsp파일에서 tiles 테그라이브러리를 통해 include할때  아래의 이름으로 include 시키게 된다.-->
        <put name="title"  value="struts framework tiles examples"/>  <!-- title이란이름으로 들어갈 value를 설정 -->
        <put name="header" value="/tilesModule/header.jsp"/>          <!-- jsp페이지에서 header란 이름으로 include했을때 다음의 jsp 페이지를 include 한다. -->
        <put name="menu"   value="/tilesModule/menu.jsp"/>
        <put name="body"   value="/tilesModule/body.jsp"/>
        <put name="footer" value="/tilesModule/footer.jsp"/>
    </definition>
   
    <definition name=".layout-menu1" extends=".layout-main">           <!-- extends: original페이지의 definition 이름을 설정한다. -->
        <put name="body" value="/tilesModule/body-menu1.jsp"/>
    </definition>
   
    <definition name=".layout-menu2" extends=".layout-main">
        <put name="body" value="/tilesModule/body-menu2.jsp"/>
    </definition>
</tiles-definitions>

---------------------------------------------------------------------------------------

3) layout page 생성

---------------------------------------------------------------------------------------
<%@page contentType="text/html; charset=euc-kr"%>
<%@ taglib prefix="tiles" uri="http://struts.apache.org/tags-tiles"%>
<%@ taglib uri="
http://struts.apache.org/tags-html" prefix="html"%>
<!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>
        <html:base/>
    </head>
    <body>
 <h1><tiles:getAsString name="title"/></h1>
    <table border=0 cellpadding=0 cellspacing=1 bgcolor="#a0a0a0" width="100%">
        <tr valign="middle" bgcolor="#ffffff">
            <td colspan=2><tiles:insert attribute="header"/></td>
        </tr>
        <tr height="400" bgcolor="#ffffff">
            <td valign="top"  width="15%">
               <tiles:insert attribute="menu"/>
            </td>
            <td valign="middle" align="center">
               <tiles:insert attribute="body"/>
            </td>
        </tr>
        <tr bgcolor="#ffffff">
            <td colspan=2><tiles:insert attribute="footer"/></td>
        </tr>
    </table>
    </body>
</html>

---------------------------------------------------------------------------------------
위에 처럼 테그라이브러리를 선언하고 tiles 테그라이브러리로 다음의 페이지를 입력할 수 있다.
getAsString은 tiles-defs.xml파일에서 설정한 곳으로 들어가 name을 찾아 스트링을 입력한다.
insert는 tiles-defs.xml파일에서 선언한 jsp페이지를 삽입한다.

4) struts-tilesModule.xml에 plug-in설정
<plug-in className="org.apache.struts.tiles.TilesPlugin">
  <set-property property="definitions-config"  value="/WEB-INF/tiles-defs.xml” /> <!-- tiles-defs파일 위치 설정-->
<!-- 여기서 부터 옵션 -->
  <set-property property="definitions-debug" value="2" /> <!--디버그 수위 value=0 사용안함 value = 2보통 value = 5 max -->
  <set-property property="definitions-parser-details" value="2" />
  <set-property property="definitions-parser-validate" value="true" />
</plug-in>

5) struts-tilesModule.xml 에 action-mapping설정
<action path="/main"  forward=".layout-main" />
<action path="/menu1" forward=".layout-menu1" />
<action path="/menu2" forward=".layout-menu2" />

<controller processorClass="info.process.InfoRequestProcessor"/>
※ processortClass는 반드시 TilesRequestProcessor타입이어야 한다.


6) Request processor class생성
package com.myhome.info.processor;

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

import org.apache.struts.tiles.TilesRequestProcessor;
public class InfoRequestProcessor extends TilesRequestProcessor{

 @Override
 /* Action으로 호출하기 전 처리할 내용을 기술하는 부분입니다. */
 protected boolean processPreprocess(HttpServletRequest request,
   HttpServletResponse response) {
  
  //form parameter에 대한 인코딩을 수행한다.
  boolean flag = false;
  try{
   request.setCharacterEncoding("euc-kr");
   flag = true;
  }catch(java.io.UnsupportedEncodingException uee){};
  
  return flag;
 }
 
}
request processor class를 tilesReqeustProcessor가 상속하고 있다.

struts 1 - validator

Published on: 2009. 7. 1. 16:57 by louis.dev


struts1 에서 validator를 수행하는 방법은 두가지가 있다.
① 직접 validator logic을 수행하여 validate하는 방법
② validator plug-in을 통한 방법

1. 직접 validator logic을 수행하여 validate하는 방법


- 클라이언트로 들어온 요청은 ActionServlet으로 들어간다.

- ActionServlet은 config 파일에 있는 <action>을 실행하고 action property중에 validate= true 이면 Request processor에게 ActionForm이 validate() method를 가지고있으니 validate()를 실행해라라는 것을 알려준다.

- Request Processor를 거쳐 들어온 데이터는 ActionForm으로 가고 validate()메소드에서 각각의 validate logic을 수행하고 만약 validate에 문제가 있으면 ActionError에 메시지를 누적 시킨다. ActionForm에서 로직을 수행한 결과는 Request Processor에게 전달된다.

- Request Processor는 전달받은 결과중 ActionError에 에러 메시지가 들어있는지를 확인하고 없으면 Action으로 들어가 비지니스로직을 수행하고 에러메시지가 있다면 바로 Client로 돌려 보낸다.




1) MessageResource.properties파일을 만든다.
----------------------------------------------------------------------------------------
#validator message resource

name.error={0} 이름을 입력하세요!!!
age.error={0} 유효하지 않는 나이입니다.
email.error={0} 메일형식에 맞지 않습니다.
----------------------------------------------------------------------------------------
{0} 는 Action class에서 파라미터로 넘겨준 사용자 정의의 스트링으로 맵핑 시켜준다.
예를 들어 ValidatorFormBean class에서

error.add("age",new ActionMessage("age.error","나이 오류!"));

다음과 같은 파라미터로 넘겨오는 경우 나이오류라는 전달 인자가 age.error={0} 에 맵핑되어 에러메시지는
나이오류! 유요하지 않은 나이입니다.

이라는 에러 메시지를 출력하게 된다. 만약 properties 파일에서
age.error = {0} 유효하지 않은 나이 입니다. {1}
이렇게 선언 되어 있고
error.add("age",new ActionMessage("age.error","나이 오류!","나이를정확히 입력해 주세요"));
이렇게 전달인자를 넘겨 준다면 에러메시지 출력 결과는

나이 오류!
유효하지 않은 나이입니다. 나이를 정확히 입력해 주세요

와 같이 에러가 출력된다.

2) FormBean을 설정한다.
          - ActionForm Class를 상속한 class를 생성한다.
          - ActionForm Class 의 validate() 메소드를 override 한다.
          - 각각의 validate logic을 완성한다.
          - validate() method 안의 logic을 완성하고 error가 있을경우 ActionError 인스턴스에 에러 메시지를 add해준다.

----------------------------------------------------------------------------------------
package com.myhome.validator;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;

/**
 *  user login을 통한 validator 구현
 *  ActionForm class에서 validate()를 통해 구현
 *
 */

@SuppressWarnings("serial")
public class ValidatorFormBean extends ActionForm{
 /* form property fields  */
 private int    age;
 private String name;
 private String email;
 
 /*ActionForm class의 validate()를 overriding한다*/
 
 @Override
 public ActionErrors validate(ActionMapping mapping,
   HttpServletRequest request) {
  ActionErrors error = new ActionErrors();
  if(!isNameValid()){
   error.add("name",new ActionMessage("name.error","이름 오류!!"));
  }
  if(!isAgeValid()){
   error.add("age",new ActionMessage("age.error","나이 오류!"));
  }
  if(!isEmailValid()){
   error.add("email",new ActionMessage("email.error","이메일 오류!"));
  }
  return error;
 }
 
 /*validator logics*/
 //이름은 반드시 두자이상 입력을 요구한다.
 protected boolean isNameValid(){
  if(this.getName() == null) return false;
  else if(this.getName().length() < 2) return false;
  return true;
 }
 
 //나이는 20세부터 80세 까지만 허용한다.
 protected boolean isAgeValid(){
  if(this.getAge() < 20 || this.getAge() > 80)
   return false;
  return true;
 }
 
 //이메일 형식이 정확한 지 검사한다.
 protected boolean isEmailValid(){
  int delim = this.getEmail().indexOf('@');
  if(delim < 0)
   return false;
  if(this.getEmail().substring(0,delim).length() < 2)
   return false;
  if(this.getEmail().substring(delim).length() < 2)
   return false;
  return true;
 }
 
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
 
 
}

----------------------------------------------------------------------------------------
주황색 부분이 가장 중요한 부분으로 ActionErrors 인스턴스인 error에 add메소드로 validate가 유효하지 않을때 message를 저장하게 된다.
error.add("name",new ActionMessage("name.error","이름 오류!!"));
이부분에서 앞의 name은 그냥 string형이름으로 정하고 name.error 는 앞에 properties파일에 설정된 key를 불러 들여오고 두번째 전달인자인 "이름오류" properties파일의 name.error ={0} 과 대응되어 결국 두메시지가 합쳐진 형태로 에러 메시지를 출력한다.

3)validate DTO를 생성한다. 일반적인 DTO와 다르지 않다.

4) struts-validatorModule.xml 파일을 생성하고 action과 message-resource, form-bean 영역을 설정한다.
----------------------------------------------------------------------------------------
<form-beans>
          <form-bean name="validatorBean" 
                            type="com.myhome.validator.ValidatorFormBean"/>
</form-beans>

<action-mappings>
   <action path="/register"
          name="validatorBean"
          scope="request"
          validate="true"
          input="/register.jsp"
          type="com.myhome.validator.ValidatorRegisterAction">
         <forward name="success" path="/result.jsp"/>
        </action>   
   </action-mappings>

<message-resources parameter="com.myhome.validator.ValidatorMessageResource"/>
----------------------------------------------------------------------------------------
여기서 가장 중요한 부분은 action mapping부분의 validate="true" 이다. 이부분을 true로 놓아야 action Servlet이 request processor에게 actionForm의 validate() 메소드를 실행 시켜야 된다 라는 것을 알려주기 때문이다.


5). web.xml에 struts-validatorModule.xml을 등록한다.
<init-param>
   <param-name>config/validatorModule</param-name>
   <param-value>/WEB-INF/config/struts-validatorModule.xml</param-value>
  </init-param>

6)jsp 페이지 에서 struts 태그를 사용하여 ErrorMessage를 출력한다.

<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html"%>
<%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean"%>
<%@ taglib prefix="logic" uri="http://struts.apache.org/tags-logic"%>

<logic:messagesPresent> <!-- message stack에 에러메시지가 있으면 다음을 실행한다. -->
    <tr height=30 bgcolor="#ffffff">
      <td align="left" colspan="2">
        <html:messages name="error"> <!-- 메시지 id는 임의로 정의하고 -->
         <span style="font-size:10pt; color:red">
          <li><bean:write name="error"/></li> <!-- 메시지 이름이 ERROR인 애를 출력한다. -->
           </span>
         </html:messages>
      </td>
    </tr>
</logic:messagesPresent>

※struts-validatorModule.xml에 설정한 form-bean 이름으로 jsp페이지 까지 넘어 오기 때문에 <form>테그 안의 데이터 들을 그대로 남겨 두려면 EL 테그를 쓰면 된다.
예)
<input type="text" name="email" size=35 value="${validatorBean.email}">
이렇게 하면 데이터를 입력하고 서브밋을 눌러 ActionForm에 갔다가 다시 jsp페이지로 오면 사용자가 입력한 데이터가 다음의 bean에 입력되어 있기때문에 그대로 데이터를 살려 둘 수 있다.


2. validator plug-in을 통한 방법

validator plug-in방식으로 하려면 라이브러리 파일이 필요하지만 struts-core 라이브러리에 있기 때문에 특별히 라이브러리를 추가할 필요가 없다.

작업순서

1)validator Formbean 생성
VaidatorForm class를 상속받은 Formbean class를 작성한다.
----------------------------------------------------------------------------------------
package com.myhome.validator;

import org.apache.struts.validator.ValidatorForm;


@SuppressWarnings("serial")
public class ValidatorPropertyBean extends ValidatorForm implements java.io.Serializable{

 /*Form property fields*/
 private String name;
 private int    age;
 private String email;
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
 
 
}
----------------------------------------------------------------------------------------

2)struts-validatorModule(사용할 xml파일).xml 에 validator plug-in 설정을 한다.

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
         <set-property
              property="pathnames"
              value="/org/apache/struts/validator/validator-rules.xml,
                     /WEB-INF/validation.xml"/><!-- 뒤에 xml은 우리가 만든 validation xml 파일 -->
     </plug-in>

3)struts-validatorModule(사용할 xml파일).xml 에 form-bean설정을 한다.
<form-bean name="propertyBean"
          type="com.myhome.validator.ValidatorPropertyBean"> <!-- validation.xml(사용자가 validate할 옵션을 정해준 xml 파일)에서 사용한 bean 이름과 같아야 한다. -->
      <!-- validatorForm을 상속받은 bean의 property와 똑같이 설정한다 -->
      <form-property name="name"
            type="java.lang.String"/>
      <form-property name="age"
            type="java.lang.Integer"/>
      <form-property name="email"
            type="java.lang.String"/>
     </form-bean> 

4)validation.xml(validation할 설정이 들어있는 xml) 생성

required – 폼 데이터가 입력되지 않을 때 검증한다.
minlength – 폼 데이터의 최소길이를 설정하여 검증한다.
maxlength – 폼 데이터의 최대길이를 설정하여 검증한다.
mask – 필요한 문자만 입력되었는 지 검증한다.
intRange – 폼데이터에서 정수의 범위를 설정하여 검증한다.
email – 이메일 형식에 맞게 입력되었는 지 검증한다.

http://struts.apache.org/1.3.8/faqs/validator.html 가면 더 확인 할 수 있다.

----------------------------------------------------------------------------------------
<?xml version="1.0" encoding="euc-kr" ?>
<!DOCTYPE form-validation PUBLIC
     "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN"
     "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd">

<form-validation>
  <formset>
 <form name="propertyBean">  <!-- struts-validatorModule에서 form-bean 이름과 같아야 함 -->
     <field property="name" depends="required,minlength,mask">   <!--property : form-bean에 설정되어 있는 property, depends: 미리 설정되어 있는 옵션들을 석어 준다 -->
        <arg key="propertyBean.name"/>    <!-- form-bean 이름이 propertyBean인곳의 property중 name을 가지고 아래의 validation을 처리하겠다. -->
        <arg name="minlength" key="${var:minlength}" resource="false" position="0"/> 
     <arg name="mask" key="${var:mask}" resource="false" position="1"/>
<!--
      name: 윗쪽에 기술된 미리 작성된 validation을 하기 위한 정의된 것을 가져와서 쓴다
      key: 아래의 <var>태그에 선언된 value를 가져와서 validation에서 사용한다.
      position: 먼저 validation 되는 순서를 정한다. 아래의 경우 글자 수가 2개 이상이 아니거나 한글이 들어오지 않을 경우 체크하는것으로서
                   .properties 설정된 것이 로딩되어 경고 메시지를 출력한다.
-->         
           <var>
              <var-name>minlength</var-name>
              <var-value>2</var-value>
           </var>
           <var>
              <var-name>mask</var-name>
              <var-value>^[&#44032;-&#55203;]*$</var-value> <!-- 한글 외에 다른것을 다 걸러준다 -->
           </var>
     </field>
    
     <field property="age" depends="required,integer,intRange">
        <arg key="propertyBean.age" position="0" />
        <arg name="intRange" key="${var:min}" position="1" resource="false"/>
        <arg name="intRange" key="${var:max}" position="2" resource="false"/>
        <var>
         <var-name>min</var-name>
         <var-value>20</var-value>
        </var>
        <var>
         <var-name>max</var-name>
         <var-value>80</var-value>
       </var>
        </field>

     <field property="email" depends="required,email">
          <arg key="propertyBean.email"/>
     </field>
 </form>
  </formset> 
</form-validation>
----------------------------------------------------------------------------------------
5) struts-validatorModule.xml 에 action-mapping을 선언한다.
<action path="/register"
          name="propertyBean"
          scope="request"
          validate="true"
          input="/register.jsp"
          type="com.myhome.validator.ValidatorRegisterAction">
         <forward name="success" path="/result.jsp"/>
        </action> 
validate는 반드시 true로 설정해 주어야 한다.

6) properties 파일 생성과 선언

errors.required=필수 입력항목입니다.
errors.minlength=최소 2자이상 입력해야합니다.
errors.email=메일형식이 맞지 않습니다.
errors.invalid=사용할 수 없는 문자가 입력되었습니다.
errors.range=등록할 수 없는 나이입니다.
----------------------------------------------------------------------------
앞의 errors는 임의로 아무거나 설정할 수 있으나 뒤의 string은 validator plug-in에 있는것으로만 설정해야 한다.
다음을 입력하고 properties 파일로 저장한다. 그리고 struts-validatorModule.xml에 message-resource를 등록한다.

<message-resources parameter="com.myhome.validator.ValidatorMessageResource"/>

7)jsp 페이지 설정
<logic:messagesPresent> <!-- message stack에 에러메시지가 있으면 다음을 실행한다. -->
    <tr height=30 bgcolor="#ffffff">
      <td align="left" colspan="2">
        <html:messages name="error"> <!-- 메시지 id는 임의로 정의하고 -->
         <span style="font-size:10pt; color:red">
          <li><bean:write name="error"/></li> <!-- 메시지 이름이 ERROR인 애를 출력한다. -->
           </span>
         </html:messages>
      </td>
    </tr>
</logic:messagesPresent>

struts 1 - File Uplod & File Download

Published on: 2009. 7. 1. 16:06 by louis.dev

1. File Upload

-업로드는 FormFile class로 처리한다.
-DB테이블은 FormFile class 자체가 들어갈 수 없음으로 파일의 정보를 담을 것들(크기,이름..)을 COLUMN으로 생성한다. 여기서는 파일의 이름과 크기를 COLUMN으로 설정한다.

File Upload에는 3가지 해야 할 것이 있다.
① 저장할 디렉터리 위치를 어디로 할 것 인가?
② 용량 제한은 얼마로 할 것 인가?
③ 중복파일에 대해서 해결책은 어떻게 할 것인가?
        - 1/1000초 로 계산하여 파일 이름 변경
        - 파일 명 뒤에 숫자 붙여서 저장 - 많이 사용한다.

작성방법

1) apache.org -> commons -> IO 와 FileUpload library를 다운 받고 추가한다.

2) 데이터를 담을 DTO를 생성한다.
----------------------------------------------------------------------------------------------------
package com.myhome.upload.dto;

public class UploadDTO{
 
 /*entity property*/
 private int    num;
 private String name;
 private String sex;
 private String tel;
 private String wdate;
 private String fileName;
 private long   fileSize;

 
 
 public int getNum() {
  return num;
 }
 public void setNum(int num) {
  this.num = num;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getSex() {
  return sex;
 }
 public void setSex(String sex) {
  this.sex = sex;
 }
 public String getTel() {
  return tel;
 }
 public void setTel(String tel) {
  this.tel = tel;
 }
 public String getWdate() {
  return wdate;
 }
 public void setWdate(String wdate) {
  this.wdate = wdate;
 }
 public String getFileName() {
  return fileName;
 }
 public void setFileName(String fileName) {
  this.fileName = fileName;
 }
 public long getFileSize() {
  return fileSize;
 }
 public void setFileSize(long fileSize) {
  this.fileSize = fileSize;
 }
 
 
}

----------------------------------------------------------------------------------------------------
DB에는 FormFile 자체가 들어가지 못하기 때문에 파일의 이름과 크기를 저장할 property를 설정한다.

3) ActionForm을 상속받은 bean class를 생성하고 각각의 property들을 설정한다.

UploadFormBean Class

----------------------------------------------------------------------------------------------------
package com.myhome.upload.beans;

import org.apache.struts.action.ActionForm;
import org.apache.struts.upload.FormFile;

@SuppressWarnings("serial")
public class UploadFormBean extends ActionForm implements java.io.Serializable{
 /*form property*/
 private int    num;
 private String name;
 private String sex;
 private String tel;
 private String wdate;
 
 /*upload property*/
 private FormFile file;

 public int getNum() {
  return num;
 }

 public void setNum(int num) {
  this.num = num;
 }

 public String getName() {
  return name;
 }

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

 public String getSex() {
  return sex;
 }

 public void setSex(String sex) {
  this.sex = sex;
 }

 public String getTel() {
  return tel;
 }

 public void setTel(String tel) {
  this.tel = tel;
 }

 public String getWdate() {
  return wdate;
 }

 public void setWdate(String wdate) {
  this.wdate = wdate;
 }

 public FormFile getFile() {
  return file;
 }

 public void setFile(FormFile file) {
  this.file = file;
 }
 
}

----------------------------------------------------------------------------------------------------
위에서 가장 중요한 부분은 FormFile로 file 을 선언하고 getter 와 setter를 생성한다는 점이다. jsp에서 넘어온 파일이 저 FormFile class에 담기게 된다.

4)저장하기 위해 SqlMap.xml을 생성한다.

5)DAO를 설정해 DB에 접근하게 한다.


----------------------------------------------------------------------------------------------------
package com.myhome.upload.dao;

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

 

import com.myhome.manager.SQLManager;
import com.myhome.upload.dto.UploadDTO;

public class UploadDAO extends SQLManager{
 
 public void insert(UploadDTO dto) throws SQLException{
  this.getSqlMap().insert("uploadInsert",dto);
 }
 @SuppressWarnings("unchecked")
 public List<UploadDTO> list() throws SQLException{
  return (List<UploadDTO>)this.getSqlMap().queryForList("uploadList");
 }
}
----------------------------------------------------------------------------------------------------

6) web.xml 에 struts-uploadModul.xml 의 init-param을 설정한다.
----------------------------------------------------------------------------------------------------
<init-param>
   <param-name>config/uploadModule</param-name>
   <param-value>/WEB-INF/config/struts-uploadModule.xml</param-value>
  </init-param>
----------------------------------------------------------------------------------------------------

7.) struts-uploadModul.xml에서 ActionForm을 사용하기 때문에 Form-bean설정과 <action></action>설정을 해준다.
----------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="euc-kr" ?>

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

<struts-config>

   <!-- Form Bean Definitions -->
   <form-beans>
      <form-bean name="uploadBean" type="com.myhome.upload.beans.UploadFormBean"/>
   </form-beans>


   <!-- Global Exception Definitions -->
 <global-exceptions>
  <exception type="java.lang.Exception"
       key="exception.global"
       path="/exception/exception.jsp"/>
 </global-exceptions>

   <!-- Global Forward Definitions -->
    <global-forwards>
    </global-forwards>


   <!-- Action Mapping Definitions -->
    <action-mappings>
       <action path="/toModule"
               type="org.apache.struts.actions.SwitchAction"/>
      
       <action path="/index"
          type="org.apache.struts.actions.ForwardAction"
          parameter="/register.jsp"/>
       
       <action path="/upload"
            name="uploadBean"
          scope="request"
          parameter="method"
          unknown="true"
          type="com.myhome.upload.actions.UploadDispatchAction">
         
       <!-- exception handle -->
       <exception key = "exception.handler"
            handler = "com.myhome.handler.InfoExceptionHandler"
            path = "/excetpion.jsp"
            type = "java.lang.NullPointerException">
       </exception>
           <forward name="result"  path="/result.jsp"/>
           <forward name="fail"    path="/fail.jsp"/>
           <forward name="list"    path="/list.jsp"/>
           <forward name="query"   path="/modify.jsp"/>
           <forward name="update"  path="/template.jsp"/>
           <forward name="delete"  path="/template.jsp"/>
       </action>   
      
       <action path="/download"
            type="com.myhome.upload.actions.FileDownloadAction">
       </action>
    
      
          
    </action-mappings>

   <!-- Controller Processor Definition -->
   <controller processorClass="com.myhome.info.processor.InfoRequestProcessor"/>

   <!-- Message Resources Definitions -->
 <message-resources parameter="com.myhome.upload.ExceptionMessageResource"/>
   <!-- Plug Ins Configuration -->
      <!-- Tiles plugin -->
      <!-- Validator plugin -->
    
</struts-config>


----------------------------------------------------------------------------------------------------


8) 업로드할때 쉽게 사용하기 위해 업로드 파일의 최대값과 저장 폴더를 설정한 UploadUtil class를 생성한다
----------------------------------------------------------------------------------------------------
package com.myhome.upload.util;

public final class UploadUtil {

 public static final String SAVE = "D://JAVA/Java Web2/edu/upload/";
 
 public static final String SIZE = "1024*1024*20";
}
----------------------------------------------------------------------------------------------------
- SAVE : 업로드된 파일을 저장하는 위치를 지정한다. 각 폴더 구조는 역슬레쉬(\)가 아닌 슬래쉬(/)로 표현한다
- SIZE : 업로드 파일의 최대를 설정한 것으로 20MB를 지정하고 있다.

9) 비지니스 로직을 구현하기 위해 각각의 Action 클래스를 상속받은 Action Class를 구현한다.
----------------------------------------------------------------------------------------------------
package com.myhome.upload.actions;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

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

import org.apache.commons.beanutils.BeanUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.upload.FormFile;

import com.myhome.upload.beans.UploadFormBean;
import com.myhome.upload.dao.UploadDAO;
import com.myhome.upload.dto.UploadDTO;
import com.myhome.upload.util.UploadUtil;

public class UploadDispatchAction extends DispatchAction{
 
 public ActionForward register(ActionMapping mapping,
          ActionForm form,
          HttpServletRequest request,
          HttpServletResponse response)
          throws Exception{
  
  UploadFormBean bean = (UploadFormBean)form;
  UploadDTO dto = new UploadDTO();
  BeanUtils.copyProperties(dto, bean);
  if(bean.getFile() != null){
   this.upload(bean.getFile());
   dto.setFileName(bean.getFile().getFileName());
   dto.setFileSize(bean.getFile().getFileSize());
  }else{
   dto.setFileName("");
   dto.setFileSize(0L);
   new NullPointerException("파일을 올려주세요!!");
  }
  dto.setWdate(this.getWdate());
  
  new UploadDAO().insert(dto);
  request.setAttribute("dto", dto);
  return mapping.findForward("result");
 }
 public void upload(FormFile ff) throws Exception {
     InputStream is = ff.getInputStream();
     OutputStream os = new FileOutputStream(UploadUtil.SAVE + ff.getFileName());
     byte buffer[] = new byte[8192];
     int n = 0;
     while((n = is.read(buffer,0,8192)) != -1){
          os.write(buffer, 0, n);
     }
    
     is.close();
     os.close();
 }
 
 /*리스트 부분*/
 public ActionForward list(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws Exception{
  
  request.setAttribute("list", new UploadDAO().list());
  
  return mapping.findForward("list");
 }
 
 protected String getWdate(){
  return new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date());
 }

}
----------------------------------------------------------------------------------------------------
가장중요한 부분은 보라색으로 색칠 해놓은 곳이다.(register method는 현재 등록만 한다고 생각한다.)
upload method의 버퍼 크기는 2의 n승으로 커지고 보통 2의 10승부터 사이즈를 적는다.
10) jsp 페이지에서 form 테그는 enctype=“multipart/form-data” 다음과 같이 변경한다.


<form method="post"   name="regform" action="toModule.do?prefix=/uploadModule&page=/upload.do" enctype="multipart/form-data">
          <input type="file" name="file">
</form>




2. File Download

다운로드시에는 struts 1 library에 포함되어있는 DownloadAction class를 상속 받아 getStreamInfo()를 override하여 File Download를 구현한다.

작업순서
1) struts-uploadModule.xml 에 <action></action>에 다운로드에 대한 Action을 선언한다.

<action path="/download"
            type="com.myhome.upload.actions.FileDownloadAction">
</action>

2) DownloadAction class를 상속받은 class를 만든다.
----------------------------------------------------------------------------------------------
package com.myhome.upload.actions;

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

import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;

/*download*/
import org.apache.struts.actions.DownloadAction;
import java.io.File;
import com.myhome.upload.util.UploadUtil;


public class FileDownloadAction extends DownloadAction {
 
 @Override
 protected StreamInfo getStreamInfo(ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {
  
        String filename = request.getParameter("clip");
       
        File file = new File(UploadUtil.SAVE + filename);
       
        /*한글파일일 경우 헤더타입이 다르므로 변경한다.*/
        String contentType = "application/octet-stream";
        response.setContentType(contentType);

       
        
        /*txt, image파일들은 브라우저가 직접 결과를 전달한다.  
         * 다음과 같이 설정하지 않을 경우 text파일 같은 경우는 브라우져에서
         * 해석이 가능함으로 브라우져에서 바로 열린다. 이것을 처리해 주면
         * 무조건 다운로드 된다.
         * */

       
        response.setHeader("Content-disposition",
                     "attachment;filename="+
                     toEng(file.getName()));
        response.setHeader("Content-Length", ""+file.length());
     
        return new FileStreamInfo(contentType, file);
   }
 
   public String toKor(String data){
     if(data == null)return null;
     String temp = "";
     try{
     temp = new String(data.getBytes("ISO8859_1"),"EUC-KR");
     }catch(java.io.UnsupportedEncodingException uee){}
     return temp;
   }
 
   public String toEng(String data){
     if(data == null)return null;
     String temp = "";
     try{
     temp = new String(data.getBytes("MS949"),"ISO-8859-1");
     }catch(java.io.UnsupportedEncodingException uee){}
     return temp;
   }

}
----------------------------------------------------------------------------------------------

Struts 1 - 스트럿츠 1의 다양한 Action Class 들 part 3

Published on: 2009. 6. 30. 00:05 by louis.dev


1.SwitchAction




Context 내에 여러 개의 모듈이 있을 때  현재 작업중인 모듈에서 다른 모듈로 전환하고 새로운 모듈내의 포워드 하는 일을 수행한다. struts1 의 가장 핵심적인 Action중의 하나라고 할 수 있다.

[struts1의 Groupping 과 Module]
struts1에서의 그룹핑을 사용해서 하는 방법이 가장 쉬운 방법 중에 하나다 . web.xml에
-----------------------------------------------------------------------------------------------
<init-param>
  <param-name>config</param-name>  
  <param-value>
   /WEB-INF/struts-config.xml,
   /WEB-INF/struts-config-dispatch.xml,
   /WEB-INF/struts-config-mapping.xml,
   /WEB-INF/struts-config-lookup.xml  
  </param-value>  
 </init-param>
-----------------------------------------------------------------------------------------------
다음과 같은 방법으로 xml 파일을 모아두면 그룹핑 방식으로 struts를 구성하는 것이다. 또한 module로 나누는 방식은
web.xml에서
-----------------------------------------------------------------------------------------------
<init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/config/struts-config.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/dispatchModule</param-name>
   <param-value>/WEB-INF/config/struts-dispatchModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/lookupModule</param-name>
   <param-value>/WEB-INF/config/struts-lookupModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/mappingModule</param-name>
   <param-value>/WEB-INF/config/struts-mappingModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/uploadModule</param-name>
   <param-value>/WEB-INF/config/struts-uploadModule.xml</param-value>
  </init-param>
-----------------------------------------------------------------------------------------------
이런식으로 한번에 선언하지 않고 나누어 선언 할 수 있다.

특징:
그룹핑을 하면 각 설정xml파일안의 이름들이 같으면 안되나 module별로 나누면 같은 이름이 있어도 된다.
즉 그룹핑 에서는 <action path="">의 path명이 모든 xml 파일이 같으면 안되나 module방식에서는 같아도 상관이 없다.

작성방법
1)web.xml 에 module별로 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>struts1</display-name>
 
  <servlet>
   <servlet-name>action</servlet-name> <!-- 아무이름이나 하면 된다. -->
   <servlet-class>  <!-- 클래스 지정 -->
    org.apache.struts.action.ActionServlet
   </servlet-class>
   

 <!-- switch Action module types -->
  <init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/config/struts-config.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/dispatchModule</param-name>
   <param-value>/WEB-INF/config/struts-dispatchModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/lookupModule</param-name>
   <param-value>/WEB-INF/config/struts-lookupModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/mappingModule</param-name>
   <param-value>/WEB-INF/config/struts-mappingModule.xml</param-value>
  </init-param>
  <init-param>
   <param-name>config/uploadModule</param-name>
   <param-value>/WEB-INF/config/struts-uploadModule.xml</param-value>
  </init-param>

  
   </servlet>
 
  <servlet-mapping> <!-- url 패턴 설정 -->
   <servlet-name>action</servlet-name> <!-- *.do로 들어오면 servlet-name이 action 실행 -->
   <url-pattern>*.do</url-pattern>
  </servlet-mapping>
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
-----------------------------------------------------------------------------------------------
모듈화를 위해 다음과 같이 모듈로 설정한다.

여기서 중요한 부분은

<init-param>
   <param-name>config</param-name>
   <param-value>/WEB-INF/config/struts-config.xml</param-value>
  </init-param>
이부분과 같지 config는 기본적으로 있어야 하며

<init-param>
   <param-name>config/dispatchModule</param-name>
   <param-value>/WEB-INF/config/struts-dispatchModule.xml</param-value>
  </init-param>
위의 빨간색 이름은 동일해야 한다. 또한 param-name의 빨간색 부분은 jsp페이지의 이름이 prefix인 hidden값으로 보내는 value와 같아야 해당 모듈이 실행된다.

2) 각각의 config.xml파일을 생성한다.

<action path="/toModule"
                type="org.apache.struts.actions.SwitchAction"/>

이부분은 각각의 config.xml파일에 모두 존재해야 한다.

3) jsp페이지에서 name 이 prefix와 page인 hidden값을 생성하고 각각을 파라미터로 넘겨준다.

<input type="hidden" name="prefix" value="/mappingModule">
<input type="hidden" name="page"   value="/register.do">


prefix로 전달되는 value는 web.xml파일에 설정된 mappingModule을 사용하겠다는 것이고 page는 그 모듈안에 있는 어떠한 action을 사용할지를 적어 주면 된다.