struts 2008. 7. 31. 09:20

struts2] struts2 + ibatis 활용한 게시판1-3

         struts2 + ibatis 를 활용한 게시판

* 게시판 글쓰기 및 수정, 파일업로드 기능

1. bbs.xml
      - 글 작성하기 위해 <insert>추가 및 sql문 정의
      - 파라미터를 여러개 받아야 하기 때문에 parameterClass를 객체로 지정한다.
         즉, 여기서는 위에 정의한 alias인 bbsvo로 지정하면 된다.
      - insert에 idx로 이용되는 컬럼명은 sequence로 가져와야하기 때문에
        dual table을 이용해서 미리 시퀀스 값을 가져온다.
      -<selectKey>속성인 resultClass은 실행했을때 리턴되는값을 명시
        keyProperty에 idx가 아래의insert절의 #idx#에 맵핑된다.

2. Bbs.java
      - interface에 메소드 정의

3. BbsImple.java
     - interface에 정의된 메소드를 구현
     - insert절은 insert, delete절은 delete, select은 queryForList 호출
     -

4. struts.xml
     - 1. add 액션추가
     - 2. add_ok action 추가

5.write.jsp
    - action에서 result로 write.jsp를 호출하였기때문에 해당 페이지에서 글작성할수있는 페이지 작성
    - insertForm.jsp페이지를 해당 폼으로 설정
        <s:form action="add_ok" method="post" enctype="multipart/form-data">
            <s:include value="insertForm.jsp"></s:include>
       </s:form>

6. insertForm.jsp
    - struts2의 taglib를 이용해서 글보기시 session에 사용자 및 글제목등 관련 필드 내용을 session에
     등록한다.
     이렇게 하는이유는 insertForm.jsp 하나의 폼을 가지고 delete 및 uptate시에도 동일 폼을 사용하기
     때문에 세션으로부터 그 폼을 가져와서 재활용하려고 하는것이다. 이렇게되면 delete.jsp 같은
     페이지를 동일한 폼을 만들지 않아도 되고 글 상세보기시 session에 폼에 대한 data를 세션에 등록
     한다. 그렇게 되면 수정버튼을 클릭시 db로부터 값을 불러오지 않고  세션에 등록된 값을 가져와서
     글쓴이,제목,내용등을 사용자에게 보여줄수있는 것이다.

7.AddAction 클래스 정의
   - struts.xml에서 정의한 클래스 및 메서드 정의(AddAction.java / clear()) - 1.add action
   - write.jsp에서 action으로 정의한 struts.xml에 action등록 - 2. add_ok action
   - 파일업로드시 File변수명+FileName 이라고 해야 Struts2에서 자동으로 파일명을 인식한다.
           ex> File s_file        파일명얻어내기 : s_fileFileName
   - AddAction클래스가 호출되면 필드로 선언된 변수에 값이 셋팅이 되고 난후에 execute()메서드가
     호출된다.


8.FileService.java
   - 파일업로드를 하기 위한 FileService 파일 작성
   - 아래 fileupload에서 한 예제를 가지고 그대로 사용하면된다.
   



* bbs.xml     
 <insert id="insertBbs" parameterClass="bbsvo">
       <selectKey keyProperty="idx" resultClass="int"> 
         select BBS_idx.NEXTVAL AS idx FROM dual
       </selectKey>
       <!--
        resultClass 이것을 실행했을때 리턴되는것 명시
        keyProperty에 idx가 아래의insert절의 #idx#에 맵핑된다.
       -->
       insert into BBS_T(idx,subject,writer,writedate,contents,s_file,pwd,readhit,ip)
       values (<!-- 아래서 전달되는 변수는 parameterClass에서 찾는다. -->
       #idx#,#subject#,#writer#,sysdate,#contents#,#s_file#,#pwd#,#readHit#,#ip#
       <!-- getSubject(),getWriter()이런 메소드가 호출되면서 파라미터에  맵핑된다. -->
       )
     </insert>

* Bbs.java
      - interface에 메소드 정의
            public void addBbs(BbsVO n);

* BbsImple.java
       public void addBbs(BbsVO n) {
          insert("insertBbs",n);   //insert(ag id값, 넘겨줄인자값)
       }


* struts.xml
      <action name="add" class="action.AddAction" method="clear">
          <result>/write.jsp</result>
      </action>
      
      <action name="add_ok" class="action.AddAction">
          <result name="input">/list.jsp</result>
          <result type="redirect-action" name="success">list</result>
      </action>

*write.jsp
  <%@ taglib prefix="s" uri="/struts-tags" %>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link rel="StyleSheet" href="/css/style.css" type="text/css">
    <link rel="StyleSheet" href="text.css" type="text/css">
    <s:head/> <!-- taglib가 가지고 있는 head값 -->
  </head>

  <body>
    <s:form action="add_ok" method="post" enctype="multipart/form-data">
      <s:include value="insertForm.jsp"></s:include>   //insertForm.jsp를 해당페이지에 폼으로 include
    </s:form>
  </body>
</html>  


* insertForm.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>

   <%@ taglib prefix="s" uri="/struts-tags" %>
  
        <table width="100%" border="0" cellspacing="0" cellpadding="0">
              <tr>
                <td valign="top">
                  <table width="100%" border="0" cellspacing="0" cellpadding="0">
                    <tr>
                      <td align="center" height="10"></td>
                    </tr>
                    <tr>
                      <td align="center"><u><b>BBS 글쓰기</b></u></td>
                    </tr>
                    <tr>
                      <td align="center" valign="top"><table width="100%" border="0" cellspacing="0" cellpadding="0">
                          <tr>
                            <td>&nbsp;</td>
                          </tr>
                        </table>
                        <table width="556" border="0" cellspacing="0" cellpadding="0">
                          <tr>
                            <td height="2" bgcolor="#C3C3C3"></td>
                          </tr>
                          <tr>
                            <td bgcolor="#E5E5E5"><table width="100%" border="0" cellspacing="1" cellpadding="2">
                                
                                <tr>
                                  <td width="90" height="20" align="center" bgcolor="#669AB3">
                                      <s:text name="작성자"/>
                                 </td>
                                  <td bgcolor="#F2F7F9" align="left">
                                    <s:textfield name="writer" value="%{#session.selectBoard.writer}" cssStyle="width:100px" theme="simple"/>
                                </td>
                                </tr>                              
                                <tr>
                                  <td height="20" align="center" bgcolor="#669AB3"><s:text name="제목"/></td>
                                  <td bgcolor="#F2F7F9" align="left"><s:textfield name="subject" value="%{#session.selectBoard.subject}" cssStyle="width:450px" theme="simple"/></td>
                                </tr>
                                <tr>
                                  <td height="20" align="center" bgcolor="#669AB3"><s:text name="내용"/></td>
                                  <td bgcolor="#F2F7F9" align="left"><s:textarea name="contents" value="%{#session.selectBoard.contents}" cssStyle="width: 450px; height: 200px" theme="simple"/></td>
                                </tr>
        <tr>
                                  <td height="20" align="center" bgcolor="#669AB3"><s:text name="첨부파일"/></td>
                                  <td bgcolor="#F2F7F9" align="left"><s:file name="s_file" cssStyle="width:300px" theme="simple"/>
                                    </td>
                                </tr>
                                <tr>
                                  <td height="20" align="center" bgcolor="#669AB3"><s:text name="비밀번호"/></td>
                                  <td bgcolor="#F2F7F9" align="left"><s:password name="pwd" cssStyle="width:200px" theme="simple"/>
                                    <font color="#0066CC">* 삭제.수정시 필요</font> </td>
                                </tr>
                              </table></td>
                          </tr>
                        </table>
                        <table width="556" border="0" cellspacing="0" cellpadding="0">
                          <tr>
                            <td height="20" valign="middle"><img src="/images/sub_it/point_line.gif" width="556" height="3"></td>
                          </tr>
                          <tr>
                            <td align="right"> <table width="100%" border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                  <td width="315" align="center">
                                       
                                  </td>
                                  <td width="241" align="right"> <s:submit src="images/but_submit.gif" theme="simple"/>
                                  <s:reset  theme="simple"/>
                                    
                                  </td>
                                </tr>
                              </table></td>
                          </tr>
                        </table></td>
                    </tr>
                    <tr>
                      <td height="19"></td>
                    </tr>
                  </table>
                </td>
              </tr>
            </table>


*AddAction.java
package action;

import java.io.File;
import java.util.Map;

import javax.servlet.Servlet;

import org.apache.struts2.ServletActionContext;


import service.FileService;
import vo.BbsVO;

import com.opensymphony.xwork2.ActionContext;

import dao.Bbs;
import dao.DaoService;

public class AddAction {
 
 String writer,subject,contents,pwd;
 File s_file;
 String s_fileFileName,serverFullPath; //s_fileFileName이라고 작성해야 된다.
 
 public String clear() throws Exception{
  /*현재 사용되고 있는 session정보 가져오기*/
  Map<String,BbsVO> map = ActionContext.getContext().getSession();
  map.clear();
  return "success";
 }
 
 public String execute() throws Exception{
 
  /*ibatis의 Dao객체 얻기*/
 
  Bbs bbs = (Bbs)DaoService.getDao(Bbs.class);  
 
  BbsVO vo = new BbsVO();  //ibatis에서 인자로 vo를 받기때문에 값을 셋팅하고 인자로 넣어준다.
  vo.setWriter(writer);
  vo.setSubject(subject);
  vo.setContents(contents);
  vo.setS_file(s_fileFileName);
  vo.setReadHit(0);
  vo.setPwd(pwd);
  vo.setIp(ServletActionContext.getRequest().getRemoteAddr());
  String basePath="D:/jspwork/Struts2_ibatis/WebContent/upload"; //저장할경로 설정
  FileService fs = new FileService(); //서버에 파일을 저장시키위해 객체생성
  serverFullPath = fs.saveFile(s_file, basePath, s_fileFileName); // 서버에 저장(파일객체,저장경로,파일명)
 
  bbs.addBbs(vo); //위에서 셋팅한 vo객체를 ibatis 인자로 넘겨준다(이런방식으로 여러개의 파라미터를 전달할수있다)
 
  return "success";
 }
 // 일반적인 setter//getter 메소드 정의

}



struts 2008. 7. 30. 16:19

struts2] struts2 + ibatis 활용한 게시판1-2

            struts2 + ibatis 를 활용한 게시판

* DB로 부터 글 목록불러오기 및 페이징처리 part

*ListAction.java
        - execute()메서드에  ibatis에 정의된  Bbs bbs = (Bbs)DaoService.getDao(Bbs.class)를 명시할시
          ListAction클래스가 불려지면서 ibatis와 연동을 시킬수가 있다.
        - execute()메서드안에 db로부터 가져온 결과를 가지고 게시판을 구축하면된다.
        - Paging클래스를 따로 작성해서
         

package action;

import java.util.*;

import page.Paging;
import vo.BbsVO;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import dao.Bbs;
import dao.DaoService;

public class ListAction extends ActionSupport{
  /*
   * pojo기반으로 사용하게되면 session처리하기가 곤란하다.
   * 따라서 ActionSupport를 상속받아 처리한다.
   * */
 
 private ArrayList<BbsVO> arr_list; //모든 게시물
 private List<BbsVO> list;  //현재 페이지에서 보여질 게시물
 private int nowPage = 1;
 private int rowTotal;   // 전체 게시물의 수
 private int blockList;    // 한 페이지당 보여질 게시물의 수
 private int blockPage; // 한번에 보여지는 페이지수
 private String pagingCode;
 private Paging page ; // 페이지 기법을 구현하는 클래스
 
 @Override
 public String execute() throws Exception {
 
  /*
   * 세션객체 구하기
   * 이것은 나중에 게시물 보기시 히트 수를 증가해 주기 위한것으로 이미 한번 읽은것은
   * 히트 수를 증가하지 않도록 하는데 있어 필요하다.
   * */
  Map<String, BbsVO> map = ActionContext.getContext().getSession(); //세션객체를 맵으로 리턴
  map.clear();  //session 청소
 
  /* ibatis를 통한 게시물 받기 위해서는 우선 Dao객체가 필요하다. */
  /*
   * dao.xml에 Bbs라는것이 선언되어있어야하며<dao>에 선언된 interface 호출시 구현된 객체가 생성된다.
   * 리턴받을시 interface 타입의 받기 때문에 BbsImple로 받는것이 아니라 반드시 Bbs로 받아서 캐스팅을 해줘야한다.
   * */
  Bbs bbs = (Bbs)DaoService.getDao(Bbs.class);
  arr_list = bbs.getAllBbs(); //전체 게시물을 불러옴
 
  rowTotal = arr_list.size();
  blockList = 7;
  blockPage = 5;
 
  /*페이징 기법에 의한 현재 보여질 게시물들 결정*/
  page = new Paging(nowPage,rowTotal,blockList,blockPage);
  pagingCode = page.getSb().toString(); //페이징 기법의 HTML문장
 
  /* 현재 페이지에서 보여질 게시물들 선별*/
  int to = rowTotal;
 
  if(page.getEndRow()<rowTotal)
   to = page.getEndRow()+1;
 
  list = arr_list.subList(page.getStartRow(), to);
 
  return SUCCESS;
 }
 //  그외에 일반적으로 필드에 선언된 setter/getter 메서드 정의

}
*Paging.java
        - paging처리하는 클래스

package page;

public class Paging {
 
  private boolean isPrevPage,isNextPage;
  private int nowPage,rowTotal,blockList,blockPage,totalPage,startPage,endPage,startRow,endRow;
 
  private StringBuffer sb;

  //페이징 기법을 총괄해서 계산하는 생성자
  public Paging(int nowPage, int rowTotal, int blockList, int blockPage) {
   /* 각종 플래그를 초기화*/   
   isPrevPage = false;
   isNextPage = false;
   
   /* 입력된 전체 게시물의 수를 통하여 전체 페이지 수를 구한다.*/

   /* 아래 코드와 ceil을 이용한 전체페이지수를 구하는것은 같은 코드이다.   
   totalPage = rowTotal/blockList;
   if(rowTotal%blockList !=0)
    totalPage++;
   */
   
   /* Math.ceil메서드는 인자의 수를 가지고 가장 가까운 값으로 올림을 한다. */
   totalPage = (int)Math.ceil((double)rowTotal/(double)blockList);
   
   
   /* 현재 페이지가 전체페이지수 보다 클경우 전체페이지 수로 할당 */
   if(nowPage > totalPage)
     nowPage = totalPage;
   
   /* 현재 페이지에 따른 시작 행의 정보와 끝 행의 정보 */

   startRow = (nowPage -1)*blockList;
   endRow = startRow + blockList -1;
   
   /* 시작 페이지와 마지막 페이지 값을 구한다.*/
   startPage = (int)((nowPage -1) / blockPage)*blockPage+1 ;
   endPage = startPage + blockPage -1 ;
   
   /* 마지막 페이지 값이 전체 페이지 수보다 클 경우*/
   if(endPage > totalPage)
    endPage = totalPage;
   
   /* 시작 페이지가 1보다 클 경우 이전 페이징 기능을 활성화 있도록 flag 설정*/
   if(startPage>1)
     isPrevPage = true;
   
   /* 마지막 페이가 전체 페이지 수보다 작을 경우 다음 페이징 기능을 활성화*/
   if(endPage<totalPage)
     isNextPage = true;
   
   /*멤버 변수에 값 저장*/
   this.nowPage = nowPage;
   this.rowTotal = rowTotal;
   this.blockList = blockList;
   this.blockPage = blockPage;
   
   /*HTML문장 만들기*/
   sb = new StringBuffer();
   if(startPage < blockPage)
     sb.append("<img src='images/button/but_prev.gif' width='30' height='9'>");
   else{
     sb.append("<img src='images/button/but_prev.gif' width='30' height='9' ");
     sb.append("onclick='location.href=\"list.action?nowPage=");
     sb.append(nowPage-blockPage);
     sb.append("\"' style='cursor:hand'>");
   }
   
   sb.append("|");
   for(int i = startPage; i<=endPage ; i++){
    if( i < totalPage)
     break;
    if(i == nowPage){
     sb.append("&nbsp;<b><font color='#91B7EF'>");
     sb.append(i);
     sb.append("</font></b>");        
    }else{
     sb.append("%nbsp;<a href='list.action?nowPage=");
     sb.append(i);
     sb.append("'>");
     sb.append(i);
     sb.append("</a>");    
    }
   }
   sb.append("&nbsp;|");
   
  if(startPage < totalPage)
    sb.append("<img src='images/button/but_next.gif' width='30' height='9'>");
  else{
    sb.append("<img src='images/button/but_next.gif' width='30' height='9' ");
    sb.append("onclick='location.href=\"list.action?nowPage=");
    sb.append(nowPage+blockPage);
    sb.append("\"' style='cursor:hand'>");
   }
}
 //  그외에 일반적으로 필드에 선언된 setter/getter 메서드 정의
}


struts 2008. 7. 30. 15:59

struts2] Interceptor

                             Interceptor

개념
  - 액션 단위의 작업을 수행할 때 기존 액션 처리 전과 후에 추가적인 작업을 지원하기 위한 방법을 제공

flow
  - FliterDispatcher 실행후 Interceptor 호출 -> Action -> Interceptor -> FilterDispatcher

종류
  - param : 요청파라미터를 액션에 저장
  - prepare : 액션이 Preparable 인터페이스를 구현하였다면 prepre()메소드 호출
  - model-driven : 액션이 ModelDriven인터페이스를 구현하였다면 getModel() 메소드 호출


간단한 interceptor활용 예

1. struts 환경구성
     - struts.xml에 action 및 interceptor정의
      -struts.properties 정의


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

<!DOCTYPE struts PUBLIC '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'
'http://struts.apache.org/dtds/struts-2.0.dtd'>
<struts>
    <package name="defalut" extends="struts-default" namespace="">
   
       <interceptors>
         <interceptor name="MyInterceptor" class="interceptors.MyInterceptor"></interceptor>
       </interceptors>
           
    <action name="f3">
         <result>/ex1/form3.jsp</result>
     </action>
      
    <action name="form3" class="ex1.FormAction3">
      <interceptor-ref name="prepare"/><!--1첫째수행됨, 사용자가 원하는 객체를 생성 -->
      <interceptor-ref name="modelDriven"/><!--2번째 수행됨, 위의 객체를 ValueStack에 적재 -->
      <interceptor-ref name="params"/><!-- 3번째 수행됨,ValueStack에 가장 위에 있는 객체에 파라미터를 저장 -->
      <result>/ex1/res3.jsp</result>
    </action>
     
    <action name="myInter" class="ex1.InterTestAction">
        <interceptor-ref name="MyInterceptor"/>
        <interceptor-ref name="logger"/>
        <result>/ex1/res4.jsp</result>
    </action>
      
    </package>
</struts>

* struts.xml
# To change this template, choose Tools | Templates
# and open the template in the editor.
struts.i18n.reload=true
struts.devMode=true
struts.configuration.xml.reload=true
struts.continuations.package=org.apache.struts2.showcase
struts.custom.i18n.resources=globalMessages
struts.url.http.port=9000
struts.action.extension=action
struts.serve.static=true
struts.serve.static.browserCache=false
struts.mulipart.maxSize=2097252

* form3.jsp
     - struts.xml에 정의한 action name인 f3.action 실행시 form3.jsp페이지 호출
     - form3.jsp호출후 action안에 정의한 interceptor실행
           interceptor실행순서  :  prepare -> modelDriven -> params
     - interceptor가 모두 수행되면 action 실행

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<body>
  <s:form action="form3" method="post" theme="simple">
    Name : <s:textfield name="name"/><br/>
    Phone : <s:textfield name="phone"/><br/>
    <s:submit value="Send"/>
  </s:form>
</body>


*FormAction3.java
     - interceptor에 정의한 params에 의해서 폼으로 부터 넘겨온 파라미터값을 valuestack에 올림
     - 따라서 Action클래스가 불려질때 form으로 부터 파라미터값들이 넘어옴

package ex1;

import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;

public class FormAction3 implements Preparable,ModelDriven{
   String msg;
   Personal p;
   
   public String getMsg() {
    return msg;
   }
   public void setMsg(String msg) {
    this.msg = msg;
   }
   public Personal getP() {
    return p;
   }
   public void setP(Personal p) {
    this.p = p;
   }
   
   public String execute() throws Exception{
    msg = p.getName()+" 정보를 DB저장 완료"; 
             //interceptor 에서 이미 객체를 valuestrack올렸기때문에 여기서 p.getName()으로 호출이 가능
    return "success";
   }
   
   public void prepare() throws Exception {
    /*
     * prepare는 내가 원하는 객체를 생성하는것이 목적
     * execute()가 불려지기 전에 prepare()메서드가 먼저 불려진다.
     */
    p = new Personal();
   }
   @Override
   public Object getModel() {
     /*
      * 여기서 반환되는 객체가 ValueStack에 올라간다.
      * */
    return p;
   }
 }


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



*MyInterceptor.java
      - interceptor를 사용자가 만들어서 아래와 같은 방법으로 사용할수있다.
      - 사용자가 만들시에는 AbstractInterceptor 클래스를 상속받아야하고 intercept(ActionInvocation ai)
         메서드를 재정의 하면된다.


package interceptors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class MyInterceptor extends AbstractInterceptor{

 private  static Log log = LogFactory.getLog(MyInterceptor.class);
 @Override
 public String intercept(ActionInvocation ai) throws Exception {
   
   log.info("실행전");
   String res = ai.invoke();  // 16행
   /*
    * 현재 인터셉터가 마지막 인터셉터라면 이때  Action이 호출된다.
    * 결국 invoke()메서드를 중심으로 해서 16행전을 [전처리부] 16행 이후를 후처리부라 한다.
    * */
   log.info(res+"실행후");
  return res;
 }
}


*InterTestAction.java
   - 테스트용 action 클래스

package ex1;

public class InterTestAction {
  private String msg;

  public String getMsg() {
   return msg;
  }
 
  public String execute() throws Exception{
   msg = "Just Do It";
   return "success";
  }
}

struts 2008. 7. 30. 10:35

struts2] struts2 + ibatis 활용한 게시판1-1

           struts2 + ibatis 를 활용한 게시판


사용자 삽입 이미지

- struts2 framework 와 ibatis를 연동한 게시판 구축
- struts2 action클래스와 paging처리하는부분은 2페이지에 걸쳐 작성



1. 환경설정
    - struts2,ibatis,oracle library 등록(web-inf/lib)

2. struts.xml
    - aciton 등록

3. web.xml
   - struts환경에서는 사용자가 action요청시 가장 먼저 FilterDispatcher가 호출되고 위에 그림처럼
      배치관리자로 인해 struts.xml 파일과 struts.properties 파일이 자동으로 호출되게 된다

    <filter>
      <filter-name>struts2</filter-name>
      <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
   </filter>
   
   <filter-mapping>
      <filter-name>struts2</filter-name>
      <url-pattern>/*</url-pattern>
   </filter-mapping>

4. DaoService.java
    - 데이타베이스 접속하기위한 DaoManager 를 반환하는 DaoService클래스 작성
    - 싱글턴패턴으로 만들어서 하나의 DaoManager를 공유



* struts.xml
     - 반드시 src 기본경로에 존재하여야 struts에서 인식할수있다.
     - web.xml에서 등록한 필터가 읽혀진후 해당 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="defalut" extends="struts-default" namespace="">
      <action name="list" class="action.ListAction">
       <result>/list.jsp</result>
      </action>
    </package>
</struts>


* DaoService.java
          - DaoService는 한번만 읽혀져서 하나만 생성되어 DaoManager는 한개만 생성된다.


package dao;

import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.dao.client.Dao;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.DaoManagerBuilder;

public class DaoService {
  private static DaoManager daoManager;
 
  private static DaoManager getDaoManager(){
   String daoXmlResouce  = "dao.xml";  //src폴더에 dao.xml
   Reader reader = null;
   
   if(daoManager ==null)  //static으로 선언되어있기때문에 null 체크를 해서 null일경우만 생성
    try {
      reader = Resources.getResourceAsReader(daoXmlResouce);     //dao.xml파일로부터 읽음
      daoManager = DaoManagerBuilder.buildDaoManager(reader);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return daoManager;
  } 
 
  //실제 서버에서 dao객체가 필요할 경우 호출하는 메서드
  public static Dao getDao(Class inter){
   return getDaoManager().getDao(inter);
  }
}



* dao.xml
     - 사용하고자하는 dao interface 및  dao를 구현하고 있는 dao 를 명시

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

<daoConfig>
 <context id="sqlMap">
  <transactionManager type="SQLMAP">
   <property name="SqlMapConfigResource" value="config/SqlMapConfig.xml"/> 
  </transactionManager>
  <dao interface="dao.Bbs" implementation="dao.BbsImpl"/>
 </context>
</daoConfig>



* SqlMapConfig.xml
     - 사용하는 database 환경설정이 필요한 파일이다(여기서는 oracle을 사용)

<!DOCTYPE sqlMapConfig PUBLIC '-//ibatis.apache.org/DTD SQL Map Config 2.0//EN'
'http://ibatis.apache.org/dtd/sql-map-config-2.dtd'>
<sqlMapConfig>
    <properties resource="config/sqlMapConfig.properties" />
    <transactionManager type="JDBC" commitRequired="false">
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="${driver}" />  //라이브러리(odbc14.jar)파일이 필요
            <property name="JDBC.ConnectionURL" value="${url}" />
            <property name="JDBC.Username" value="${user}" />
            <property name="JDBC.Password" value="${pwd}" />
        </dataSource>
    </transactionManager>
 <sqlMap resource="config/bbs.xml" />
</sqlMapConfig>



* SqlMapConfig.properties
     - 보안을 위해 db접속정보를 따로 파일로 만들어둠

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:ORCL
user=SCOTT
pwd=TIGER


* Bbs.java(Interface)
     - 사용자가 호출할수 있는 기능적요소들을 명시

package dao;

import java.util.ArrayList;

import vo.BbsVO;

public interface Bbs {
  public ArrayList<BbsVO> getAllBbs();
}


* BbsImpl.java
     - 위의 인터페이스를 구현하고 SqlMapDaoTemplate 를 상속받는 클래스
     - 반드시 디폴트 생성자만 있으면 안되고 반드시 SqlMapDaoTemplate를 상속받고
        DaoManager를 인자로 받는 생성자를  만들어야 한다.
     - struts환경에서 여기에 정의된 메소드를 호출하게되면 결과를 받을수 있게 된다.
         ex> getAllBbs()
    
* BbsVO.java
     - DataBase에 있는 컬럼명과 동일한이름으로 멤버 변수로 정의
     - 정의된 멤버변수의 setter/getter 메서드를 정의


* bbs.xml
     - SqlMapConifg.xml 안에 <sqlMap>에 정의된 xml문서
     - 이 안에 정의된 <select> 요소의 속성 id는 값은 BbsImple.java클래스의 queryForList("") 이안에
       들어가는 인자값(String)과 동일해야 한다.  ex> select id="selectAllBbs"

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC '-//ibatis.apache.org//DTD SQL Map 2.0//EN' 'http://ibatis.apache.org/dtd/sql-map-2.dtd'>

<sqlMap namespace="memo">
     <typeAlias alias="bbsvo" type="vo.BbsVO"/>
    
     <select id="selectAllBbs" resultClass="bbsvo">
           select * from bbs_t order by idx desc
     </select>
</sqlMap>


* ListAction.java
     - struts 액션 클래스로서 ActionSupport를 상속
     - pojo기반으로 사용하게되면 session처리하는데 어려움이 있기때문에 ActionSupport를 상속
     - ListAction에서 ibatis DaoService에 정의된 메소드를 호출하게되면 해당 객체를 얻어낼수있다.
          ex>  Bbs bbs = (Bbs)DaoService.getDao(Bbs.class);


           


struts 2008. 7. 29. 15:53

struts2] Download

                            Download

1. web.xml
      - 필터등록(위에서 설정한 부분과 동일)

2.  struts.properties
      - struts환경설정 파일 (위에서 설정한 부분과 동일)


3. struts.xml
      - result type에   결과를 stream으로 받기 때문에 stream으로 설정
      - param 요소에 mimeType,원 자원의 길이, 컨텐츠헤더값, inputStream이름, 버퍼크기 설정

<?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="defalut" extends="struts-default" namespace="">
    
     <action name="fileList" class="ex1.FileListAction">
   <result>/ex1/fileList.jsp</result>
  </action>
    
     <action name="fileDownload" class="ex1.FileDownLoadAction">
   <result type="stream">
         <param name="contentType">bynary/octet-stream</param>  // mimeType
         <param name="contentLength">${contentLength}</param> // 원자원의 길이
         <param name="contentDisposition">${contentDisposition}</param>
       <!-- 파일의 이름을 설정하기 위한 컨텐츠헤더값 지정-->
         <param name="inputName">input</param> // inputStream 이름
         <param name="bufferSize">4096</param> // 버퍼 크기
   </result>
  </action>
    </package>
</struts>


4. fileList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
  <h2>파일 목록</h2>
  <s:property value="basePath"/>
  <s:iterator value="fileList" status="stat">
     /*
          FileListAction 클래스로부터 받은 basePath를  param에 등록하고, fileName에 파일명을 등록
          url에 해당 param을 등록하고 href요소에 url id를 맵핑시켜 사용자가 파일클릭시
          fileDownload Action클래스를 수행하게하여 파일 다운로드가 수행되게 된다.
       */
    <s:url id="download" action="fileDownload">
       <s:param name="basePath" value="basePath"/>    
       <s:param name="fileName" >
           <s:property value="fileList[#stat.index].name"/>
       </s:param>
    </s:url>
    <li><s:a href="%{download}">
       <s:property value="fileList[#stat.index].name"/>
      </s:a>
    </li>
  </s:iterator>


5. FileListAction.java
         - ActionSupport를 상속받는 action 클래스 등록
         - properties파일에서 읽어올시 액션 파일명과 동일하게 작성하여 동일위치에 생성

package ex1;

import java.io.File;
import java.util.ArrayList;

import com.opensymphony.xwork2.ActionSupport;

public class FileListAction extends ActionSupport {
 
  private ArrayList<File> fileList = new ArrayList<File>();
  private String basePath;
 
//  필드에 선언된 setter/getter 메서드 정의
 
  @Override
  public String execute() throws Exception {
    basePath = getText("path"); //프로퍼티파일에서 읽혀짐
    //basePath = "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
    /*
       파일들이 저장되어 있는 폴더를 File객체로 생성한다.
       이유는 그렇게 해야 그안에 있는 파일들을 가져와서 ArrayList에 저장할 수 있다.
       내부의 모든 요소들을 반복하여 파일인지 아닌지를 비교하고 비교후 파일일경우 list에 추가
     */
    File dir = new File(basePath);
    File[] files = dir.listFiles();
    if(files!=null && files.length>0)
     for(File f : files)
        if(f.isFile())  
           fileList.add(f);
 
    return SUCCESS;
  }
}


6. FileDownLoadAction.java
         - 사용자가 파일명클릭시 수행되는 ActionClass(다운로드가 수행되는 ActionClass)
         - struts.xml에 등록한것처럼 결과를 steam으로 전달하여 파일다운로드가 이루어짐

package ex1;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;

import com.opensymphony.xwork2.ActionSupport;

public class FileDownLoadAction extends ActionSupport{
 
  private String basePath,fileName,contentType,contentDisposition;
  private InputStream input;
  private long contentLength;
 
     //  필드에 선언된 setter/getter 메서드 정의
   
  @Override
  public String execute() throws Exception {
     /* jsp페이지에서 taglib에 설정된 param name(value값)이 전달됨 */
    String path  = basePath + System.getProperty("file.separator") + fileName;
    File f = new File(path);
    setContentLength(f.length());
    setContentDisposition("attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));
    setInput(new FileInputStream(path));
   
   return SUCCESS;
  }
 
 
}


 

struts 2008. 7. 29. 14:41

struts2] multi upload

                      Multi Upload


1. web.xml 필터 등록
       - singleupload에서 설정한것과 동일  

2.struts.xml / struts.properties 설정

<?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="defalut" extends="struts-default" namespace="">
        <action name="multiUpload"> 
            <result>/ex2/multiUpload.jsp</result>
         </action>
      <action name="multiUpload_ok" class="ex2.MultiUploadAction">
          <result name="input">/ex2/multiUpload.jsp</result>
          <result>/ex2/multiUploadResult.jsp</result>
      </action>

  </package>
</struts>


3. FileService.java
    - 파일에 관한 처리가 이루어지는 클래스(저장폴더 생성 및 파일저장작업이 이루어지는 메서드정의)


package ex1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class FileService {
 
/*
    파일들이 저장될 폴더를 생성하는 메서드
    폴더가 존재하지않을경우 폴더생성
*/

 public void makeBasePath(String n){  
   File dir = new File(n);
   if(!dir.exists())  
    dir.mkdirs();    
  }
 
/*
      File, 저장경로(basePath),파일명을 인자로 받는 메서드
*/

  public String saveFile(File file, String basePath, String fileName) throws Exception{
   
   if(file == null || file.getName().equals("")||file.length()<1)
      return null;
   
   makeBasePath(basePath);  // 저장될 폴더 생성! 폴더존재시 수행하지않음
   
   String serverFullPath = basePath + System.getProperty("file.separator") + fileName; //파일명이 포함된 절대경로
 
   FileInputStream fis = new FileInputStream(file);  // 저장할 파일에 스트림 생성
   
   /*
      이제 위에 있는 스트림을 통해 읽은 자원을 저장할 스트림 생성
      FileOutputStream은 경로만 존재한다면 그 위치에 파일이 있든 없든 무조건 파일을 만든다.
    */
   FileOutputStream fos = new FileOutputStream(serverFullPath);  
   
   /*
     위에서 생성한 빈파일이 서버측에 생성되었으므로 준비된 스트림을 통하여 채워넣는다.
    */
   int readSize = 0 ;
   byte[] buf = new byte[1024];
   while((readSize = fis.read(buf))!=-1){
    fos.write(buf, 0, readSize); //준비된 스트림을 통해 쓴다.    
   }
   
    fos.close();
    fis.close();    
   return serverFullPath;
  }
}


4. multiUpload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"   pageEncoding="UTF-8"%>

<%@ taglib  prefix="s" uri="/struts-tags"%>
  <s:actionerror/>
  <font color="red"><s:fielderror/></font><!-- 유효성 검사 오류시 표현 -->
  <s:form method="post" action="multiUpload_ok" enctype="multipart/form-data" theme="simple">
   <b>멀티 파일 업로드 </b><hr>
    File 1 : <s:file name="upload"/><br>  //파일명을 동일하게 설정
    File 2 : <s:file name="upload"/><br>
    File 3 : <s:file name="upload"/><br>
    <s:submit/>  
  </s:form>



5. MultiUploadAction.java
      - ActionSupport 클래스를 상속받은 action클래스
      - action클래스 (일반적인 setter/getter, execute()메소드로 구성됨)
      - jsp페이지에서 action클래스가 불려질때 폼에서 전달된 값과 함께 자동적으로 execute()메서드가 호출됨


package ex2;

import java.io.File;

import com.opensymphony.xwork2.ActionSupport;

import ex1.FileService;

public class MultiUploadAction extends ActionSupport {
 
  private File[] upload;    // 멀티 업로드의 경우 배열로 받아 처리
  private String[] uploadFileName,uploadContentType,serverFullPath;

public String execute() throws Exception{
  serverFullPath = new String[upload.length];
  //String basePath = getText("upload_folder");  //아래에 설정한 properties파일에서 내용을 가져옴
  String basePath =  "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
  FileService fileService = new FileService();
 
  for(int i =0 ; i<upload.length; i++){
    serverFullPath[i] = fileService.saveFile(upload[i], basePath, uploadFileName[i]);
  }
   return SUCCESS;
 }
}


6. MultiUploadAction.properties
    - properties파일을 이용하여 값을 받아오게 설정할수 있다.
      (action클래스명.xml 형식으로 작성시 struts에서 자동으로 호출됨)
   
upload_folder = D:/jspwork/struts2_FileUpload/WebContent/fileUpload


7. multiUploadResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MultiUpload</title>
</head>
<body>
   <h2> 멀티 파일 업로드 결과 </h2>
   <s:iterator value="upload" status="stat">
      /*
          <s:property>선언시 자동적으로 action클래스에 getter메서드가 호출됨
           배열로 받기 때문에 iterator를 이용하여 출력
      */
    <li>파일 <s:property value="%{#stat.index+1}"/></li>  
    <li>컨텐츠 타입<s:property value="%{uploadContentType[#stat.index]}"/></li>
    <li>로컬 파일 이름<s:property value="%{uploadFileName[#stat.index]}"/></li>
    <li>서버 전체 경로<s:property value="%{serverFullPath[#stat.index]}"/></li>
    <li>임시 파일 이름<s:property value="%{upload[#stat.index]}"/></li>
    <hr>
   </s:iterator>  
</body>
</html>

struts 2008. 7. 29. 14:25

struts2] single upload

                      Single Upload


1. web.xml 필터 등록

    <filter>
         <filter-name>struts2</filter-name>
         <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
   </filter>
   
   <filter-mapping>
         <filter-name>struts2</filter-name>
         <url-pattern>/*</url-pattern>
   </filter-mapping>
   

2.struts.xml / struts.properties 설정

<?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="defalut" extends="struts-default" namespace="">
       <action name="singleUpload">
           <result>/ex1/singleUpload.jsp</result>
       </action>      

      <action name="singleUpload_ok" class="ex1.SingleUploadAction">
           <result name="input">/ex1/singleUpload.jsp</result>
           <result>/ex1/singleUploadResult.jsp</result>
      </action>
   </package>
</struts>


3. FileService.java
    - 파일에 관한 처리가 이루어지는 클래스(저장폴더 생성 및 파일저장작업이 이루어지는 메서드정의)


package ex1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class FileService {
 
/*
    파일들이 저장될 폴더를 생성하는 메서드
    폴더가 존재하지않을경우 폴더생성
*/

 public void makeBasePath(String n){  
   File dir = new File(n);
   if(!dir.exists())  
    dir.mkdirs();    
  }
 
/*
      File, 저장경로(basePath),파일명을 인자로 받는 메서드
*/

  public String saveFile(File file, String basePath, String fileName) throws Exception{
   
   if(file == null || file.getName().equals("")||file.length()<1)
      return null;
   
   makeBasePath(basePath);  // 저장될 폴더 생성! 폴더존재시 수행하지않음
   
   String serverFullPath = basePath + System.getProperty("file.separator") + fileName; //파일명이 포함된 절대경로
 
   FileInputStream fis = new FileInputStream(file);  // 저장할 파일에 스트림 생성
   
   /*
      이제 위에 있는 스트림을 통해 읽은 자원을 저장할 스트림 생성
      FileOutputStream은 경로만 존재한다면 그 위치에 파일이 있든 없든 무조건 파일을 만든다.
    */
   FileOutputStream fos = new FileOutputStream(serverFullPath);  
   
   /*
     위에서 생성한 빈파일이 서버측에 생성되었으므로 준비된 스트림을 통하여 채워넣는다.
    */
   int readSize = 0 ;
   byte[] buf = new byte[1024];
   while((readSize = fis.read(buf))!=-1){
    fos.write(buf, 0, readSize); //준비된 스트림을 통해 쓴다.    
   }
   
    fos.close();
    fis.close();    
   return serverFullPath;
  }
}


4. singleUpload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"   pageEncoding="UTF-8"%>

<%@ taglib  prefix="s" uri="/struts-tags"%>
  <s:actionerror/>
      <font color="red"><s:fielderror/></font><!-- 유효성 검사 오류시 표현 -->
 
  <s:form method="post" action="singleUpload_ok" enctype="multipart/form-data">
   <b>파일업로드 </b><hr>
    <s:file name="upload"/>
    <s:submit/>
  </s:form>  



5. SingleUploadAction.java
      - ActionSupport 클래스를 상속받은 action클래스
      - action클래스 (일반적인 setter/getter, execute()메소드로 구성됨)
      - jsp페이지에서 action클래스가 불려질때 폼에서 전달된 값과 함께 자동적으로 execute()메서드가 호출됨


package ex1;

import java.io.File;

import com.opensymphony.xwork2.ActionSupport;

public class SingleUploadAction extends ActionSupport {
 
  private File upload;
  private String uploadFileName,uploadContentType,serverFullPath;

    public String execute() throws Exception {
    String basePath = "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
    FileService fileService = new FileService();
    serverFullPath = fileService.saveFile(upload, basePath, uploadFileName);
    return SUCCESS;    
  } 
}


6. SingleUploadAction-validation.xml
    - validation 설정을 하는 부분(action클래스명-validation.xml 형식으로 작성시 struts에서 자동으로 호출됨)
   
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC '-//OpenSymphony Group //XWork Validator 1.0.2//EN' 'http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd'>

<validators>
    <field name="upload">
        <field-validator type="fieldexpression">
            <param name="expression">
                <![CDATA[
                upload.length() > 0
                ]]>
            </param>
            <message>
                업로드할 파일을 선택하십시오.
            </message>
        </field-validator>
    </field>
</validators>


7. SingleUploadResult.jsp

<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
   <h2> 단일 파일 업로드 결과 </h2>
   <li>컨텐츠 타입<s:property value="uploadContentType"/></li>
   <li>로컬 파일 이름<s:property value="uploadFileName"/></li>
   <li>서버 전체 경로입<s:property value="serverFullPath"/></li>
   <li>임시 파일 이름<s:property value="upload"/></li>  
</body>
</html>