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을 사용할지를 적어 주면 된다.

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

Published on: 2009. 6. 29. 23:39 by louis.dev


1. LookupDispatchAction




getKeyMethodMap() 메서드를 구현하고 리소스 번들의 키와 메소드명을 매핑한다. 기본적으로 파라미터로 method 이름을 전달하여 그것을 통하여 method를 실행하것으로 DispatchAction과 유사한 방법으로 작동 된다.

작업순서

1)위의 클래스에서 getKeyMethodMap()에서 mapping을 해야 하기 때문에 .properties 로 확장자가 끝나는 메시지번들을 생성한다.

2)LookupDispatchAction Class를 상속받은 Class를 생성하고 LookupDispatchAction Class의 getKeyMethodMap()를 Override 하여 구현한다.

3)struts-config-lookup.xml 파일을 생성한다.

4)web.xml 에 struts-config-lookup.xml파일을 설정한다.

5)LookupDispatchAction 을 사용할 jsp 페이지 에서 DispatchAction에서 했던것과 동일 한방법으로 hidden으로 값을 숨기고 전달한다.


작업 방법
1)mapping을 위한 메시지 번들(.properties)를 생성한다.

-이클립스 자체에서 .properties파일을 생성하면 에러가 발생한다. 물론 플러그인을 추가하여 이클립스를 통해 properties파일을 생성 할 수 있지만 일단 메모장에서 작업하고 가져오는 방법을 취한다.

InfoMessageResource.properties(Original File)
------------------------------------------------------------------------------------------------
# struts1 lookup message bundle
# file name : InfoMessageResource.properties

lookup.register = 등록
lookup.list = 리스트
lookup.query = 쿼리
lookup.update = 갱신
lookup.delete = 삭제

# 국제회(Locale) 표준코드 (Unicode)로 변환
# native2ascii [-encoding 코드값] 원시파일 대상파일
# 코드값 : euc-kr, ksc5601, ms949, utf-16

# natice2ascii -encoding euc-kr InfoMessageResource.properties InfoMessageResource_ko.properties
------------------------------------------------------------------------------------------------
다음의 내용을 메모장을 통해 작성후 eclipse의 패키지에 끌어다 놓는다.
#은 주석이다.

가장 핵심 적인 부분은

lookup.register = 등록
lookup.list = 리스트
lookup.query = 쿼리
lookup.update = 갱신
lookup.delete = 삭제

이부분 인데 나중에 LookupDispatchAction Class를 상속한 파일에서 getKeyMethodMap() 메소드를 오버라이딩 하고 거기서 mapping시킬때 사용한다. 위와 같이 한글로 만들 수 있으며 한글로 저장하고 바로 properties파일을 이클립스에 끌어다 놓으면 한글이 깨진다..

------------------------------------------------------------------------------------------------
# struts1 lookup message bundle
# file name : InfoMessageResource.properties

lookup.register = µî·Ï
lookup.list = ¸®½ºÆ®
lookup.query = Äõ¸®
lookup.update = °»½Å
lookup.delete = »èÁ¦

# ±¹Á¦È¸(Locale) Ç¥ÁØÄÚµå (Unicode)·Î º¯È¯
# native2ascii [-encoding Äڵ尪] ¿ø½ÃÆÄÀÏ ´ë»óÆÄÀÏ
# Äڵ尪 : euc-kr, ksc5601, ms949, utf-16

# native2ascii -encoding euc-kr InfoMessageResource.properties InfoMessageResource_ko.properties
------------------------------------------------------------------------------------------------
그러므로 맨아래 부분에 처리된 주석과 같이 인코딩 타입을 euc-kr로 변환하는 작업을 해 주어야 하며 jdk/bin폴더 안에 있는 native2ascii 를 통해 변환 할 수 있다.

          [native2ascii를 통해 변환 하는 방법]
          1.콘솔창을 실행하고 맨처음 properties파일을 생성한 위치로 이동을 한다.
 

          2. 이동한 곳에서 native2ascii 사용하여 encoding타입을 euc-kr타입으로 변경한다.
          native2ascii [-encoding] [코드값] [원시파일] [목적파일]
          형식으로 작업하면 된다.
         
          예) native2ascii -encoding euc-kr InfoMessageResource.properties InfoMessageResource_ko.properties

          를 콘솔창에 쓴다.


          그러면 위와 같이 InfoMessageResource_ko.properties파일이 생성 된 것을 볼 수 있고 인코딩 되어 있는 것을 확인 할 수 있다.
          InfoMessageResource_ko.properties
          ----------------------------------------------------------------------------------------
          # struts1 lookup message bundle
          # file name : InfoMessageResource.properties

          lookup.register = \ub4f1\ub85d
          lookup.list = \ub9ac\uc2a4\ud2b8
          lookup.query = \ucffc\ub9ac
          lookup.update = \uac31\uc2e0
          lookup.delete = \uc0ad\uc81c

          # \uad6d\uc81c\ud68c(Locale) \ud45c\uc900\ucf54\ub4dc (Unicode)\ub85c \ubcc0\ud658
          # native2ascii [-encoding \ucf54\ub4dc\uac12] \uc6d0\uc2dc\ud30c\uc77c \ub300\uc0c1\ud30c\uc77c
          # \ucf54\ub4dc\uac12 : euc-kr, ksc5601, ms949, utf-16

          # native2ascii -encoding euc-kr InfoMessageResource.properties InfoMessageResource_ko.properties
          ----------------------------------------------------------------------------------------
          
         ※만약 natice2ascii에 대해서 찾을 수 없다는 에러가 나오면 환경변수중에 path를 설정하지 않은 것이다. path를 설정해 주면 바로 사용해 줄 수        있다.

          3) 만들어진 두개의 파일을 elipse의 원하는 곳으로 복사를 해서 가지고 온다.

          4) config.xml 파일에 .properties파일 경로를 설정해 준다.
          <message-resources parameter="com.myhome.lookup.InfoMessageResource" />

2)LookupDispatchAction Class를 상속한 InfoLookupDispatchAction Class(임의)를 생성한다.

----------------------------------------------------------------------------------------
package com.myhome.lookup;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.LookupDispatchAction;


import com.myhome.info.beans.InfoFormBean;
import com.myhome.info.dao.InfoDAO;
import com.myhome.info.dto.InfoDTO;

public class InfoLookupDispatchAction  extends LookupDispatchAction {
 
 @Override
 protected Map<String,String> getKeyMethodMap() {
  
  Map<String,String> map = new HashMap<String, String>();
  map.put("lookup.register", "register");  //메시지번들에 있는 키와 같아야 한다. 뒤에는 메소드 명이다.
  map.put("lookup.list", "list");
  map.put("lookup.query", "query");
  map.put("lookup.update", "update");
  map.put("lookup.delete", "delete");
  return map;
 }

 public ActionForward register(ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response)
     throws Exception{

 /*form parameter를 bean으로 받는다*/
  InfoFormBean bean = new InfoFormBean();
  bean.setName(request.getParameter("name"));
  bean.setSex(request.getParameter("sex"));
  bean.setTel(request.getParameter("tel"));
  
  /*bean property 를 dto로 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  dto.setWdate(this.getWdate());
  
  /*info table에 연동한다.*/
  
  new InfoDAO().register(dto);
  
  /*result.jsp로 포워드하기 위해 리퀘스트 영역에 dto를 binding한다
  * */
  request.setAttribute("dto", dto);
  
  
  return mapping.findForward("result");
 }
 
 public ActionForward list(ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response)
     throws Exception{
  
  List<InfoDTO> list = null;
  
  list = new InfoDAO().getAllQuery();
  
  request.setAttribute("list", list);
  
  return mapping.findForward("list");
 }
 
 public ActionForward query(ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response)
     throws Exception{
  InfoFormBean bean = (InfoFormBean)form;
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  
  //쿼리된 object를 리퀘스트 영역에 바인딩 한다.
  
  request.setAttribute("dto", new InfoDAO().getQuery(dto));
  
  return mapping.findForward("query");
 }
 
 public ActionForward update(ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception{
  /*form parameter를 InfoFormBean으로 받는다*/
  
  /**
  *  ActionForm의 역할
  *   Form parameter의 정보를 참조하기 위해
  *   ActionForm의 객체를 초기화 한다 - reset()
  * 
  *   form parameter의 정보를 받아 유효성 검사를 실시한다 - validate()
  * 
  *   참조한 폼 정보를 form-bean에 설정도니 bean으로 전달한다.
  * */
 
  InfoFormBean bean = (InfoFormBean)form;
  
  /*bean의 객체를 Entity(DTO)로 property를 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  
  new InfoDAO().update(dto);
  
  
  return mapping.findForward("update");
 }
 
 public ActionForward delete(ActionMapping mapping,
      ActionForm form,
      HttpServletRequest request,
      HttpServletResponse response)
      throws Exception{
 
  InfoFormBean bean = (InfoFormBean)form;
  
  /*bean의 객체를 Entity(DTO)로 property를 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  new InfoDAO().delete(dto);
  return mapping.findForward("delete");
 }
 protected String getWdate(){
  return new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date());
 }

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

이 클래스 에서 가장 중요한 부분은 getKeyMethodMap() 부분이다.
Map을 한개 선언한 뒤에 위의 properties에서 선언한 대로 map에 집어 넣으면 된다.

  map.put("lookup.register", "register");  
  map.put("lookup.list", "list");
  map.put("lookup.query", "query");
  map.put("lookup.update", "update");
  map.put("lookup.delete", "delete");

앞의 lookup.~~ 는 properties파일에 정의된 부분과 같아야 되며 뒤에는 실행될 메소드 이름이다.


3)struts-config-lookup.xml 을 생성한다.

-----------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!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>
 <action-mappings>
  <action path = "/lookupIndex"
    type = "org.apache.struts.actions.ForwardAction"
    parameter="/lookup/register.jsp"/>
  
  <!--
   unknown은 input속성을 대체하기 위한 속성이다.
   입력폼이 여러개 발생할 때 사용된다.
   template.jsp는 list.do로 보내면 어디로 가야 할지 모르기때문에
  -->
  
  <action path = "/lookup"
    name = "bean"
    scope = "request"
    unknown = "true"
    parameter = "method"
    type = "com.myhome.lookup.InfoLookupDispatchAction">
   
   <forward name="result" path = "/lookup/result.jsp"/>
   <forward name="list" path = "/lookup/list.jsp"/>
   <forward name="query" path = "/lookup/modify.jsp"/>
   <forward name="update" path = "/lookup/template.jsp"/>
   <forward name="delete" path = "/lookup/template.jsp"/>
  
  </action>
 </action-mappings>
 
 <!-- Message Resources Definitions -->
 <!-- .property 파일을 설정 -->
 <message-resources parameter="com.myhome.lookup.InfoMessageResource" />
 
</struts-config>
-----------------------------------------------------------------------------------------
가장 핵심적인 부분은 굵은 선의 <action></action>이 핵심이다. DispatchAction 과 같은 형태로 선언 되어 있으며 jsp 페이지 에서 hidden name이 method인 것을 value를 받아 type로 선언된 class로 이동하여 getKeyMethodMap() 를 실행하고 mapping을통해 메소드가 실행된다.

4. web.xml에 config파일을 등록한다

-----------------------------------------------------------------------------------------
<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>
-----------------------------------------------------------------------------------------

5. jsp페이지에서 hidden값으로 넘겨준다.

<input type="hidden" name="method" value="등록">

이렇게 선언을 하고 submit이 되면
properties파일을 거쳐 lookup.register = 등록 과 같은 맵핑을 수행하게 된다. 이렇게 맵핑된 것은 LookupDispatchAction class의 getKeyMethodMap() 부분에서 map.put("lookup.register", "register"); 를 통해 register method가 실행 되게 된다.

           

Struts 1 & iBatis : 회원 등록 & CRUD

Published on: 2009. 6. 26. 17:21 by louis.dev

1. iBatis JNDI를 사용
2. struts 기본 설정및 각종 Action Class사용
3. ActionForm 사용

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

Published on: 2009. 6. 26. 17:16 by louis.dev

1. ForwardAction Class


만약 기본타입처럼 Request Process를 거치지 않고 바로 뷰 페이지를 요청 할때는 다음과 같이 선언 할 수 있다.

<action path = "/index"  forward = "/info/register.jsp"/>

하지만 이렇게 action을 설정 하게 되면 위의 그림에서 보듯이 ActionServlet 에서 들어와서 Request processor를 거쳐 바로 ViewPage로 이동 하게 된다. 하지만 ForwardAction 을 쓰게 되면 Request Processor에서 ActionForm으로 넘어가 모든 로딩을 거쳐 ViewPage를 요청하게 할 수 있다.

<action path="/index"
          type = "org.apache.struts.actions.ForwardAction"
          parameter = "/info/register.jsp"/>

- type : 여기서 struts에서 제공하는 ForwardAction Class를 설정한다.
- parameter : 보여줄 view page의 경로를 설정 한다.

2.IncludeAction Class


defalte를 사용하면 Action에서 로직을 실행한후 ActionMapping을 통해 ActionForward로 이동후 Request Processor로 이동한후 view Page로 이동하는데 IncludeAction Class를 사용하면 ActionForward 에서 RequestProcessor를 거쳐서 View Page로 이동하는 것이아니라 바로 View Page로 이동할 수 있다.

- 장점 : ViewPage로 빠른 이동이 가능하다(검색 등에 사용)
- 단점 : Request Prcessor를 거쳐 가지 않기 때문에 processe method에서 실행하는 page Encoding이라 던가 validator를 사용할 수 없다.

예)
<action path="/index"
          type = "org.apache.struts.actions.IncludeAction"
          parameter = "/info/register.jsp"/>

3. DispatchAction Class
일반적으로 Action class를 상속받아 사용하게 되면 하나의 로직당 하나의 Class만을 생성 해야 하기 때문에 Class Over Head가 발생하기 쉽다. 이럴때는 Action Class를 상속 받지 않고 DispatchAction Class를 상속받고 그안에 메소드 형식으로 구현 하기 때문에 클래스 한개에서 모두 처리 할 수 있다.
하나의 클래스에서 이름이 다른 여러개의 ActionForward를 사용 할 수 있다.


다음 그림과 같이 jsp 페이지 에서는 form 태그 안에 hidden 으로 사용할 method 이름을 value로 넘겨 준다. value가 DispatchAction 을 상속 받은 클래스의 method 와 이름이 같아야 클래스에서 method가 실행 된다.

다음으로는 struts-config.xml 파일의 <action mapping>안의 내용이다
여기서 눈여겨 볼 내용은 type 과 parameter 이다.

- type : DispatchAction을 상속 받은 클래스의 위치를 지정
- parameter : jsp page의 hidden 태그의 name과 parameter 의 값과 같아야 한다.

즉 jsp페이지에서 히든으로 넘겨주는 value가 각각의 메소드 이름일때 다음의 것들이 실행 된다는 것이다.

ex)struts-config.xml

<struts-config>
 <action-mappings>
  <action path = "/dispatchIndex"
    type = "org.apache.struts.actions.ForwardAction"
    parameter="/dispatch/register.jsp"/>
  
  <!--
   unknown은 input속성을 대체하기 위한 속성이다.
   입력폼이 여러개 발생할 때 사용된다.
   template.jsp는 list.do로 보내면 어디로 가야 할지 모르기때문에
  -->
  
  <action path = "/dispatch"
    name = "bean"
    scope = "request"
    unknown = "true"
    parameter = "method"
    type = "com.myhome.dispatch.InfoDispatchAction">
   
   <forward name="result" path = "/dispatch/result.jsp"/>
   <forward name="list" path = "/dispatch/list.jsp"/>
   <forward name="query" path = "/dispatch/modify.jsp"/>
   <forward name="update" path = "/dispatch/template.jsp"/>
   <forward name="delete" path = "/dispatch/template.jsp"/>

  
  </action>
  
 </action-mappings>

위와 같이 forward 이름이 각 method마다 달라야 한다.


구현은 jsp 페이지 에서

1) DispatchAction을 상속 받은 클래스 생성
EX)
package com.myhome.dispatch;

import java.util.List;

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.action.DynaActionForm;
import org.apache.struts.actions.DispatchAction;

import com.myhome.info.beans.InfoFormBean;
import com.myhome.info.dao.InfoDAO;
import com.myhome.info.dto.InfoDTO;

 

public class InfoDispatchAction extends DispatchAction{
 
 public ActionForward register(ActionMapping mapping,
          ActionForm form,
          HttpServletRequest request,
          HttpServletResponse response)
          throws Exception{
  
  /*form parameter를 bean으로 받는다*/
  InfoFormBean bean = new InfoFormBean();
  bean.setName(request.getParameter("name"));
  bean.setSex(request.getParameter("sex"));
  bean.setTel(request.getParameter("tel"));
  
  /*bean property 를 dto로 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  dto.setWdate(this.getWdate());
  
  /*info table에 연동한다.*/
  
  new InfoDAO().register(dto);
  
  /*result.jsp로 포워드하기 위해 리퀘스트 영역에 dto를 binding한다
   * */
  request.setAttribute("dto", dto);
  
  
  return mapping.findForward("result");
 }
 
 public ActionForward list(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws Exception{
  
  List<InfoDTO> list = null;
  
  list = new InfoDAO().getAllQuery();
  
  request.setAttribute("list", list);

  return mapping.findForward("list");
 }
 
 public ActionForward query(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws Exception{
  InfoFormBean bean = (InfoFormBean)form;
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  
  //쿼리된 object를 리퀘스트 영역에 바인딩 한다.
  
  request.setAttribute("dto", new InfoDAO().getQuery(dto));

  return mapping.findForward("query");
 }
 
 public ActionForward update(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws Exception{
  /*form parameter를 InfoFormBean으로 받는다*/
  
  /**
   *  ActionForm의 역할
   *   Form parameter의 정보를 참조하기 위해
   *   ActionForm의 객체를 초기화 한다 - reset()
   * 
   *   form parameter의 정보를 받아 유효성 검사를 실시한다 - validate()
   * 
   *   참조한 폼 정보를 form-bean에 설정도니 bean으로 전달한다.
   * */
  
  InfoFormBean bean = (InfoFormBean)form;
  
  /*bean의 객체를 Entity(DTO)로 property를 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  
  new InfoDAO().update(dto);
  

  return mapping.findForward("update");
 }
 
 public ActionForward delete(ActionMapping mapping,
         ActionForm form,
         HttpServletRequest request,
         HttpServletResponse response)
         throws Exception{

  InfoFormBean bean = (InfoFormBean)form;
  
  /*bean의 객체를 Entity(DTO)로 property를 복사한다.*/
  InfoDTO dto = new InfoDTO();
  BeanUtils.copyProperties(dto, bean);
  new InfoDAO().delete(dto);
  return mapping.findForward("delete");
 }
 protected String getWdate(){
  return new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date());
 }
 
}


4.MappingDispatchAction Class

DispatchAction은 각 사용할 method를 hidden값으로 받아서 xml에서 세팅 해주어야 한다. 그리고 DispatchAction을 사용하면 input 테그에서 데이터를 받을때 다양한 값을 받을 수 없기 때문에 MappingDispatchAction을 사용한다.

1)MappingDispatchAction을 상속받아 클래스를 생성한다.
(DispatchAction Class와 다를 것이 없다)

2)xml을 설정한다.
<action-mappings>
  <action path="/mappingIndex"
    type = "org.apache.struts.actions.ForwardAction"
    parameter="/mapping/register.jsp" />
  
  <action path="/mappingRegister"
    parameter="register"
    type="com.myhome.dispatch.InfoMappingDispatchAction">
   <forward name="result" path="/mapping/result.jsp"/>
  </action>
  
  <action path="/mappingList"
    parameter="list"
    type="com.myhome.dispatch.InfoMappingDispatchAction">
   <forward name="list" path="/mapping/list.jsp"/>
  </action>
  
  <action path="/mappingQuery"
    parameter="query"
    type="com.myhome.dispatch.InfoMappingDispatchAction"
    name="bean"
    scope="request"
    input="/mapping/modify.jsp">
   <forward name="query" path="/mapping/modify.jsp"/>
  </action> 
  
  <action path="/mappingUpdate"
    parameter="update"
    type="com.myhome.dispatch.InfoMappingDispatchAction"
    name="bean"
    scope="request"
    input="/mapping/modify.jsp">
   <forward name="update" path="/mappingList.do" redirect="true"/>
  </action>
  
  <action path="/mappingDelete"
    parameter="delete"
    type="com.myhome.dispatch.InfoMappingDispatchAction"
    name="bean"
    scope="request"
    input="/mapping/modify.jsp">
   <forward name="delete" path="/mappingList.do" redirect="true"/>
  </action>

  
 </action-mappings>

-paramether : MappingDispatchAction Class의 method 이름이다.

이렇게 구현하면 jsp 페이지에서 hidden으로 넘겨줄 필요가 없다.