Flex3.0&AS3 2008. 9. 19. 15:09

[combobox]콤보박스를 이용한 모듈로드


<?xml version="1.0"?>
<!-- modules/EventApp.mxml -->
<mx:Application xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml" width="900" height="100%" backgroundGradientAlphas="[0.0, 0.0]">
    <mx:Script>
        <![CDATA[
            [Bindable]
            public var selectedItem1:Object;
        ]]>
    </mx:Script>
    <mx:ComboBox
        width="215"
        labelField="label"
        close="selectedItem1=ComboBox(event.target).selectedItem"
>
        <mx:dataProvider>
            <mx:Object label="Select Coverage"/>       
            <mx:Object
                label="Life Insurance"
                module="insurancemodules/LifeInsurance.swf"
            />
            <mx:Object
                label="Auto Insurance"
                module="insurancemodules/AutoInsurance.swf"
            />         
            <mx:Object
                label="Home Insurance"
                module="insurancemodules/HomeInsurance.swf"
            />
        </mx:dataProvider>
    </mx:ComboBox>

    <mx:Panel width="100%" height="100%">
        <CustomModuleLoader id="mod"
            width="100%"
            url="{selectedItem1.module}"
        />
    </mx:Panel>
    <mx:HBox>
        <mx:Button label="Unload" click="mod.unloadModule()"/>
        <mx:Button label="Nullify" click="mod.url = null"/>
    </mx:HBox> 
</mx:Application>




customModuleLoader.mxml

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- modules/CustomModuleLoader.mxml -->
<mx:ModuleLoader xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" creationComplete="init()">
  <mx:Script>
    <![CDATA[
    public function init():void {
        addEventListener("urlChanged", onUrlChanged);
        addEventListener("loading", onLoading);
        addEventListener("progress", onProgress);
        addEventListener("setup", onSetup);
        addEventListener("ready", onReady);
        addEventListener("error", onError);
        addEventListener("unload", onUnload);

        standin = panel;
       /*  removeChild(standin); */       
    }
   
    public function onUrlChanged(event:Event):void {
        if (url == null) {
            if (contains(standin))
                removeChild(standin);
        } else {
            if (!contains(standin))
                addChild(standin);
        }
        progress.indeterminate=true;
        unload.enabled=false;
        reload.enabled=false;
    }

    public function onLoading(event:Event):void {
        progress.label="Loading module " + url;
        if (!contains(standin))
            addChild(standin);

        progress.indeterminate=true;
        unload.enabled=false;
        reload.enabled=false;
    }
   
    public function onProgress(event:Event):void {
        progress.label="Loaded %1 of %2 bytes...";
        progress.indeterminate=false;
        unload.enabled=true;
        reload.enabled=false;
    }
   
    public function onSetup(event:Event):void {
        progress.label="Module " + url + " initialized!";
        progress.indeterminate=false;
        unload.enabled=true;
        reload.enabled=true;
    }
   
    public function onReady(event:Event):void {
        progress.label="Module " + url + " successfully loaded!";
        unload.enabled=true;
        reload.enabled=true;

        if (contains(standin))
            removeChild(standin);
    }
   
    public function onError(event:Event):void {
        progress.label="Error loading module " + url;
        unload.enabled=false;
        reload.enabled=true;
    }
   
    public function onUnload(event:Event):void {
        if (url == null) {
            if (contains(standin))
                removeChild(standin);
        } else {
            if (!contains(standin))
                addChild(standin);
        }
        progress.indeterminate=true;
        progress.label="Module " + url + " was unloaded!";
        unload.enabled=false;
        reload.enabled=true;
    }
   
    public var standin:DisplayObject;
    ]]>
  </mx:Script>

  <mx:Panel id="panel" width="100%">
    <mx:ProgressBar width="100%" id="progress" source="{this}"/>
    <mx:HBox width="100%">
      <mx:Button id="unload"
        label="Unload Module"
        click="unloadModule()"
      />
      <mx:Button id="reload"
        label="Reload Module"
        click="unloadModule();loadModule()"
      />
    </mx:HBox>
  </mx:Panel>
</mx:ModuleLoader>

Flex3.0&AS3 2008. 9. 18. 09:21

[펌]DisplayObejct

1. DisplayObject란 무엇인가? 
AS2까지는 MovieClip이 모든 것을 처리할 수 있었으나 AS3에서는 기존의 MovieClip의 기능을 여러 개의 클래스로 분산해 놓았다. 

1.1. 표시 오브젝트란

표시 오브젝트란 화면에 표시되는 모든 오브젝트라고 할 수 있다. 예를 들면 AS2의 MovieClip도 화면에 표시되므로 표시 오브젝트라고 할 수 있다. String 이나 Sound와 같은 클래스의 오브젝트는 그 자체로 화면에 표시할 수 없는 것들이기 때문에 표시 오브젝트라고 할 수 없다.

AS3에서는 MovieClip을 복수의 클래스에 분산시켰는데 타임 라인 기능이 없는 Sprite과 같이 MovieClip보다 적은 기능을 갖고 있는 클래스도 있고 비트 맵을 표현하는 Bitmap 클래스, 텍스트를 표시하는 TextField 클래스 등이 있다. Sprite와 같은 클래스를 이용하면 MovieClip을 사용하는 것보다는 전체적으로 퍼포먼스를 향상 시킬 수 있다. 이유는 AS3이전에는 MovieClip 자체에서 거의 모든 기능을 포함하고 있었기 때문에 MovieClip 하나만을 보더라도 묵직했지만 그것을 기능별로 분류하여 오브젝트 자체가 가벼워 졌기 때문이다. 실제로 사용하게 되는 표시 오브젝트 클래스들은 아래와 같은 클래스들이 있다. 

AVM1Movie, Bitmap, MorphShape, Shape, StaticText, Video, SimpleButton, TextField, Loader, Sprite, Stage, MovieClip

1.2. 표시 오브젝트 컨테이너란

표시 오브젝트는 “화면에 표시되는 모든 오브젝트” 라고 하였지만 정확하게는 “화면에 표시할 수 있는 모든 오브젝트” 라고 할 수 있다.

new로 만든 표시 오브젝트만으로 화면에 표시되지는 않는다. 표시 오브젝트는 표시 오브젝트 컨테이너에 넣어야만 화면에 표시된다. 아래에서 이야기 하겠지만 표시 오브젝트 컨테이너에 있는 addChild나 addChildAt 메소드 등을 이용해서 컨테이너에 표시 오브젝트를 추가하는 행위로서 화면에 표시된다. 표시 오브젝트 컨테이너가 될 수 있는 클래스는 아래와 같은 클래스들이다.

Loader, Sprite, Stage, MovieClip

여기서 표시 오브젝트 컨테이너는 그 자체가 표시 오브젝트라는 것을 알 수 있다.
AS3의 이전 버전에서 사용하던MovieClip이 상자 구조를 취할 수 있던 것처럼 이러한 클래스도 상자 구조를 취할 수 있다.

1.3. 표시 리스트란
이와 같이 컨테이너 화면에 표시되고 있는 오브젝트의 리스트를 표시 리스트라고 한다. swf 1개의 최상위에는 1개의 Stage 오브젝트가 있다. 이것이 스테이지의 최상위 컨테이너가 된다.

스테이지로부터 표시 오브젝트는 트리 구조를 갖게 되며 컨테이너가 될 수 없는 표시 오브젝트는 리프 노드(그 이상 분기하지 않는 것)이며
컨테이너는 리프 노드, 또는 브랜치 노드(그 이상 분기 가능한)가 된다. 

1.4. 표시 오브젝트의 실체
표시 오브젝트는 보통 변수 같아서 하나의 표시 오브젝트의 실체는 오로지 하나다. 표시 오브젝트를 복수의 컨테이너에 addChild 할 수 없으며 동일 컨테이너에 addChild 했을 경우에도 컨테이너에서는 한 번 삭제되어(이동했다는 표현이 더 적절하겠다) 컨테이너의 맨 위(depth)에 추가된다. 표시 오브젝트 컨테이너에는 addChild와 반대의 기능을 하는removeChild라는 메소드를 가지고 있다. 이것은 이름대로 컨테이너로부터 표시 오브젝트를 삭제하는 메소드다. removeChild 메소드는 컨테이너(표시 리스트)로부터 지정한 표시 오브젝트를 제외할 뿐, 메모리에서 제거되는 것이 아니라는 것을 잊어서는 안 된다. 표시 오브젝트를 더 이상 사용하지 않을 경우에는 removeChild와 함께 별도로 delete 연산자로 표시 오브젝트를 삭제하여야만 가비지 컬렉터에 의해 메모리 회수 대상이 될 수 있다.

2. DisplayObject 클래스와 DisplayObjectContainer 클래스의 관계

표시 오브젝트의 개념을 토대로 표시 오브젝트의 기본이 되는 2개의 클래스를 보면서 좀 더 구체적으로 이야기하면 다음과 같다.

2.1. DisplayObject 클래스 개략
모든 표시 오브젝트는 DisplayObject 클래스를 상속하고 있다.(자세한 상속 관계는 레퍼런스를 참조) 간단하게 말하면 모든 표시 오브젝트에 공통의 성질(프롭퍼티나 메소드)은 DisplayObject 형을 갖고 있는 것이다. 예를 들면 x 나 y ,height ,alpha 등은 공통 항목으로서 DisplayObject 클래스가 가지고 있는 것이다.

MovieClip을 잘 다루기 위해서 레퍼런스를 보는 경우 AS2 까지는 MovieClip만을 보면 되었으나 AS3부터는 기본이 되는 DisplayObject의 프롭퍼티와 메소드를 알아 둘 필요가 있다. 반대로 말하면 DisplayObject의 취급을 알아 두면 모든 표시 오브젝트를 컨트롤 할 수 있다. (DisplayObject 속성에 한하여) 레퍼런스를 참조할 때는 DsplayObject의 항목을 우선적으로 확인해 볼 필요가 있다. DisplayObject 자체는 표시를 위한 기능을 가지고 있지 않으므로 사용자 클래스를 만드는 경우는 DisplayObject의 서브 클래스를 확장하여 사용하면 된다. 

2.2. DisplayObjectContainer 클래스 개략
Sprite나 MovieClip은 컨테이너가 될 수 있다고 이야기 했는데 그것들은 DisplayObjectContainer 클래스를 상속하고 있기 때문이다. 컨테이너를 조작하는 메소드나 프롭퍼티(addChild등)는 DisplayObjectContainer 클래스가 공통으로 가지고 있는 기능이다. 물론 DisplayObjectContainer 클래스는 DisplayObject 클래스를 상속하고 있다.
「심도」의 취급에 대해서도 DisplayObjectContainer (프롭퍼티•메소드)로 관리하게 된다. Sprite나 MovieClip을 취급하는 경우는 이러한 클래스 레퍼런스를 참조할 필요가 있다. 

2.3. AS3에서의 심도 관리는 어떻게 되나
AS3 이전의 액션스크립트에서는 depth나 getNextHighestDepth을 자주 사용하였지만AS3에서는 이러한 메소드는 사라졌다. 하지만「심도」와 같은 개념은 남아 있는데, AS3에서는 해당 컨테이너가 몇 번째에 위치해 있는가를 나타낼 때 “인덱스 위치” 라는 개념으로 설명할 수 있다.

인덱스 위치는 0에서 부터 시작해 증가하는데 0은 가장 안쪽(아래)이 되며 수치가 큰 만큼 앞(위)에 표시된다.

인덱스 위치는 기존에 사용하던 심도의 개념처럼 고정된 것이 아니다. 컨테이너 내에서 표시 오브젝트가 추가되거나 위치가 조정 되면 다른 자식 오브젝트도 자동적으로 인덱스 위치가 조정된다. 심도와는 달리 인덱스 위치는 불연속적인 성격을 가지지 않으며 절대적으로 연속적이다. 
만약 0, 1,2라는 인덱스 위치를 가지고 있는 3개의 오브젝트가 하나의 컨테이너 안에 있을 경우 인덱스 1에 있는 오브젝트를 인덱스 0으로 이동할 경우 AS3 이전의 스크립트에서는 0 뎁스 위치에 있는 오브젝트가 삭제되고 1뎁스에 있는 오브젝트가 0뎁스로 이동하고 기존의 1뎁스는 소멸하면서 중간에 1뎁스에는 오브젝트를 갖고 있지 않은 불연속적인 성격을 갖고 있었으나 AS3부터는 인덱스 1위치를 0위치로 이동할 경우 자동적으로 0위치에 있던 오브젝트는 인덱스 1위치로 이동하게 되므로써 연속적인 위치를 유지하게 된다.

2.4. 컨테이너의 조작
좀 더 구체적으로 이야기 하기 위해서 DisplayObjectContainer의 메소드나 프롭퍼티를 몇 개 소개하면 다음과 같다. (자세한 것은 레퍼런스 참조)

•addChild / addChildAt 메소드
컨테이너에 표시 오브젝트를 추가한다. addChild는 항상 맨 위에 자식 오브젝트를 추가한다.(인덱스 위치의 마지막) addChildAt을 사용하면 특정 인덱스 위치를 지정할 수 있다.

•setChildIndex / swapChildren / swapChildrenAt 메소드
컨테이너의 자식 오브젝트의 인덱스 위치를 변경한다. swapChildren, swapChildrenAt은 2개의 자식 오브젝트를 지정하고 위치를 바꾼다. 전자는 인수로서 2개의 오브젝트를 지정하고 후자는 2개의 인덱스 위치를 지정해서 바꿀 수 있다.

•removeChild / removeChildAt 메소드
컨테이너로부터 표시 오브젝트를 삭제한다. removeChild는 직접 오브젝트를 삭제하고(표시 리스트에서 제거)  removeChildAt은 인덱스 위치를 통해 삭제한다. 표시 오브젝트의 실체는 삭제되지 않으며 어디까지나 컨테이너로부터 제거될 뿐이다.(메모리 영역은 유지된다.)

•getChildAt / getChildByName 메소드
지정한 오브젝트를 돌려준다. getChildAt은 인덱스 위치를 통해 돌려주고 getChildByName은 오브젝트명을 통해서 지정한 오브젝트를 돌려준다. getChildByName의 경우는 해시검색을 진행하기 때문에 getChildAt 쪽이 getChildByName보다 처리속도가 빠르다.

•getChildIndex 메소드
지정한 오브젝트의 인덱스 위치를 돌려준다. 

•contains 메소드
컨테이너 내에 지정한 오브젝트가 있을지를 조사하여 Boolean 값(true/false)를 돌려준다.
import flash.display.Sprite;
var sprite1:Sprite = new Sprite();
var sprite2:Sprite = new Sprite();
var sprite3:Sprite = new Sprite();
var sprite4:Sprite = new Sprite();

sprite1.addChild(sprite2);
sprite2.addChild(sprite3);

trace(sprite1.contains(sprite1)); // true
trace(sprite1.contains(sprite2)); // true
trace(sprite1.contains(sprite3)); // true
trace(sprite1.contains(sprite4)); // false
•numChildren 프롭퍼티
컨테이너에 포함되는 자식 오브젝트의 수를 돌려준다. (컨테이너명.numChildren - 1)로 하면 컨테이너의 맨 위의 인덱스 위치를 지정할 수 있다.
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";
  }
}