[Struts] 스트러츠2 설정 struts.xml (interceptor)

2011. 3. 21. 17:13FrameWork/Struts

스트러츠2 가이드 문서 : http://struts.apache.org/2.x/docs/guides.html

 

 

출처 : http://jjaeko.tistory.com

 

 

web.xml
이 파일이 웹 애플리케이션의 배치스크립터(DD) 라는건 다 알고 있는 사실입니다.
Struts2가 요청을 받아들일 수 있도록 DD에 필터를 등록해야 합니다.

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

struts-default.xml
이 파일의 위치는 프레임워크 코어 라이브러리인 struts2-core-버전.jar 안에 포함되어 있습니다.
즉 사용자가 작성해야 하는 파일이 아니고 미리 정의되어 있는 파일입니다. 그렇다면 왜 이 파일을 여기서 언급 하는 걸까요? 그 이유는 사용자가 작성해야 할 struts.xml 파일의 설정을 상당히 줄일 수 있도록 모든 디폴트 값들이 설정되어 있기 때문입니다. 역시 제로 컨피규레이션 지향답습니다.
이 파일의 DTD는 바로 아래에서 소개될 사용자가 설정해야 하는 struts.xml 파일의 DTD와 동일합니다. 
따라서 struts.xml과 설정 방법이 동일 하므로 직접 열어 보면 큰 도움이 됩니다. 설정되어 있는 내용들 중
가장 중요한 것은 struts-default 라는 이름을 가진 패키지 입니다. 
이 파일에 대해선 여기까지만 설명하고 아래 내용들을 보면 이래서 중요하구나 라는걸 느낄수 있을 것 입니다.

struts.xml
이 파일은 웹 애플리케이션내의 처리 흐름을 설정 합니다.
<include />
Struts1에서는 하나의 struts-config.xml 파일만 지원했지만 Struts2에서는 여러개의 설정파일을 역할별로
나눠서 설정할 수 있습니다. 그리고 <include /> 요소를 이용해 하나의 설정파일에 포함 시킵니다.
파일의 위치는 ClassPath상의 경로입니다.
<struts>
    <include file"struts-default.xml" />
    <include file"jjaeko/struts-m1" />
    <include file"jjaeko/struts-m2" />
    
    ...
    
    <include file"jjaeko/struts-m3" />
    <include file"jjaeko/struts-m4" />
</struts>
이 처럼 하나이상의 파일을 포함할 수 있습니다. ... 은 다른 요소이며 순서대로 포함됩니다.
Java 클래스가 묵시적으로 Object 클래스를 상속하듯이 struts.xml 파일도 묵시적으로 struts-default.xml
파일을 포함합니다. 따라서 첫번째 <include file="struts-default.xml" /> 생략 가능 합니다.

<bean />
<bean /> 요소에 설정된 클래스는 프레임워크의 컨테이너에 의해 생성되어 내부 프레임워크 객체에 주입됩니다. 대부분의 애플리케이션에서 이 요소를 사용할 일은 없으므로 이런게 있다는 것만 알고 넘어가겠습니다.

<constant />
이 요소는 상수를 설정할 때 쓰입니다. 상수는 Struts2의 작동 방식을 결정짓는 값 입니다.
상수의 설정은 struts.xml 뿐만 아니라 struts.properties, web.xml 등.. 에서도 할 수 있습니다.
<constant /> 요소의 속성은 다음과 같습니다.
- name : 상수의 이름을 지정 합니다.
- value : 상수의 값을 지정 합니다.
설정 가능한 상수는 struts2-core-버전.jar 의 org.apache.struts2 패키지의 default.properties 파일에 나와 있는데 자세한 상수 설정에 대해서는 Struts2 상수설정 에서 다루겠습니다.

<package />
패키지는 result, interceptor, action 등을 논리적인 단위로 그룹화 하는데 사용 합니다.
struts.xml 파일 설정중에 대부분의 설정은 패키지 안에서 이루어 집니다.
먼저 속성에 대해 알아보겠습니다.
- name(필수) : 패키지를 구분하는 이름입니다. 패키지의 이름은 유일해야 하며 다른 패키지에서 상속할 때
이 이름을 사용 합니다.

- extends(옵션) : 다른 패키지를 상속할 때 해당 상속받을 패키지의 이름을 지정합니다. 상속받게 되면 부모 패키지의 모든 설정을 물려 받고 동일한 설정이 존재하면 오버라이드 합니다. 대부분 Struts2에서 제공하는 디폴트 값을 사용하기 위해 struts-default.xml 파일에 정의되어 있는 strtus-default 패키지를 상속하게 됩니다.

- namespace(옵션) : 네임스페이스는 액션 설정의 고유 접두어로 사용되는데 요청 URL의 중간경로로 생각하면 됩니다. URL 형식 -> http://localhost:8080/[컨텍스트]/[네임스페이스]/[액션]
네임스페이스는 사용자 정의 네임스페이스 외 디폴트 네임스페이스와 루트 네임스페이스 두가지가 있습니다.
디폴트 네임스페이스는 값이 "" 빈문자열이거나 명시를 안할경우 이며 고유 네임스페이스에서 해당 액션을 찾지 못한다면 디폴트 네임스페이스에서 액션을 찾습니다.
루트 네임스페이스는 값이 "/" 이며 루트 네임스페이스에서 액션을 찾지 못하면 디폴트 네임스페이스에서 액션을 찾습니다. 

- abstract(옵션) : 패키지를 추상패키지로 만듭니다. 추상패키지는 액션이 없는 패키지 입니다. 만약
액션이 없고 abstract 속성이 true가 아닐경우 이패키지를 상속하면 에러가 납니다. 따라서 액션이 없는
패키지는 반드시 abstract 속성을 true로 설정해야 합니다. 참고로 사용자가 기본적으로 상속하는 struts-default 패키지도 액션이 없기 때문에 추상패키지로 선언되어 있습니다.

- externalReferenceResolver : 이건 뭔지 모르겠습니다.

속성뿐 아니라 6개의 하위 요소를 포함하는데 하위 요소로써 포함되는 순서는 다음과 같습니다.
- <result-types />
- <interceptors />
- <default-interceptor-ref />
- <default-action-ref />
- <global-results />
- <global-exception-mappings />
- <action />
이 6개의 요소들은 바로 아래에서 각각 순서대로 알아보도록 하겠습니다. 
각 요소마다 존재하는 하위요소에 대해서도 알아 보겠습니다.

<result-types />
<result-types/> 요소는 하위요소인 <result-type /> 요소를 이용하여 result-type 을 설정할 때 쓰입니다.
그런데 struts-default.xml 파일에 이미 모든 result-type이 정의 되어 있어서 <package /> 요소의 extends 속성으로 struts-default 를 상속받으면 딱히 직접적으로 사용할 일이 없습니다.
다음은 struts-default.xml 의 struts-default 패키지에 정의된 result-type중 일부분 입니다.
여러가지 형태로 클라이언트에게 응답할 수 있군요~ 이것 말고도 엄청 많습니다.
<result-types>
    <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
    <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
    <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
    <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
    <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
    <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
    <result-type name="plaintext" class="org.apache.struts2.dispatcher.PlainTextResult" />
    ...... 이하 여러개의 <result-type> 정의
</result-types>
여기서 눈여겨 볼것은 name이 dispatcher이고 default속성이 true 되어 있는 요소입니다.
default로 정의된 result-type은 <result /> 요소 선언시 type을 명시하지 않을 경우 적용되는 값입니다.
<result /> 요소의 설정방법은 아래의 <action />요소에서 설명하겠습니다.

<interceptors />
Interceptor는 AOP와 같은 개념으로 액션 실행 전후로 실행되는 모듈입니다.
파라미터값을 자동으로 저장, 로깅, 파일 업로드, 유효성 검사, 보안 등 다양한 Interceptor가 존재 합니다.
이 모든 Intercpetor는 struts-default.xml 파일에 모두 정의가 되어 있습니다. 
따라서 <interceptors /> 요소는 <interceptor-stack /> 요소를 이용해 사용자 정의 스택을 구성할 경우를 
제외 하고는 사용할 일이 없으며 단지<interceptor-ref /> 요소를 이용해 가져다 쓰기만 하면 됩니다.
다음은 struts-dafault.xml에 정의된 <interceptors /> 요소중 일부분 입니다.
<interceptors>
    <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
    <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
    <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
    <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
    ...... 이하 여러개의 <intercpetor /> 정의

    <interceptor-stack name="basicStack">
        <interceptor-ref name="exception"/>
        <interceptor-ref name="servletConfig"/>
        ...... 이하 여러개의 <interceptor-ref /> 정의 
    </interceptor-stack>

    <interceptor-stack name="defaultStack">
        <interceptor-ref name="exception"/>
        <interceptor-ref name="alias"/>
        ...... 이하 여러개의 <interceptor-ref /> 정의
    </interceptor-stack>
    
    ...... 이하 여러개의 <interceptor-stack /> 정의 
</interceptors>
<interceptor-stack /> 요소는 <interceptor-ref /> 요소를 이용하여 이미 정의된 인터셉터들을 여러개씩 묶어서 하나의 스택으로 만들 때 쓰입니다. 

<default-interceptor-ref />
다음은 struts-default.xml 의 struts-default 패키지에 정의된 <default-interceptor-ref /> 입니다.
<default-interceptor-ref name="defaultStack"/>
<default-interceptor-ref /> 요소가 하는 역할은 바로 위에서 알아본 Interceptor 를 참조하여
패키지내 Interceptor가 설정되지 않은 액션에 대해서 기본적으로 실행될 Interceptor를 설정 합니다.
예를 들어 기본적으로 사용자의 패키지는 struts-default 패키지를 상속받고 액션에서 아무 Interceptor도 설정하지 않았다면 struts-default 패키지에 정의된 <default-interceptor-ref name="defaultStack"/> 요소에 따라 defaultStack으로 묶인 Interceptor들이 설정 됩니다.

<default-action-ref />
사용자가 요청한 액션이 존재하지 않을 경우 실행될 액션을 설정합니다. 500에러를 방지할 수 있겠네요. 
이 요소는 네임스페이스당 하나만 존재할 수 있습니다.
<package name="sample" extends="struts-default">
    <default-action-ref name="defaultAction">
    
    <action name="defaultAction" class="......" />
</package>

<global-results />
<result /> 요소는 <action /> 요소의 하위에 설정 합니다. 하지만 수많은 <action /> 요소에서 똑같은 <result /> 요소를 설정하고 있을 땐 중복 설정으로 이어질 것 입니다. 예를들어 로그인 페이지나 에러페이지 같은 포워딩을 담당하는 <result /> 설정이 그러한 경우 입니다.  
이럴 때 사용하는 것이 바로 <global-results /> 요소 입니다. 간단한 예를 보겠습니다.
<package name="sample" extends="struts-default">
    <global-results>
        <result name="login">/WEB-INF/jsp/login.jsp</result>
        <result name="error">/WEB-INF/jsp/error.jsp</result>
    </global-results>
        
    <action name="sample" class="jjaeko.SampleAction">
        <result name="SUCCESS">/WEB-INF/jsp/sample.jsp</result>
    </action>
</package>
sample 액션에서는 경우에 따라 login과 error을 리턴할 수 있습니다. 이 때 로컬 액션에서 해당 result를 
찾지 못하면 패키지내 정의된 <global-results />에서 찾게 됩니다.

<global-exception-mappings />

이 요소는 하위 요소인 <exception-mapping /> 를 이용해 글로벌한 예외 매핑 설정을 합니다.
예외 매핑이란 액션에서 예외가 발생하면 특정 result를 수행하도록 하는 것입니다.
액션에서 특정 예외가 발생 했을 때 해당 액션의 <exception-mapping /> 요소를 먼저 찾고 만약 해당 액션의 예외 매핑이 없다면 <global-exception-mapping /> 에서 찾습니다. 
<global-results /> 요소는 <result /> 요소의 글로벌한 설정이듯이 <global-exception-mapping /> 요소는
<exception-mapping /> 요소의 글로벌한 설정입니다.
<package name="sample" extends="struts-default">
    <global-results>
        <result name="error">/WEB-INF/jsp/error.jsp</result>
    </global-results>
        
    <global-exception-mappings>
        <exception-mapping exception="SQLException" result="error"/>
    </global-exception-mappings>
        
    <action name="some" class="jjaeko.SomeAction">
        <result name="error">/WEB-INF/jsp/error.jsp</result>
    </action>
</package>
SomeAction 에서는 SQLException 예외를 던지고 some 액션 내에서 예외 매핑을 찾습니다. 그런데 some 액션에는 예외 매핑이 설정되지 않았으므로 <global-exception-mappings> 요소에서 찾게 됩니다.
일치하는 예외가 있고 result는 error 군요. 여기서 result를 찾을 때 some 액션과 global-results에 모두 error가 존재하는 상황에서 우선순위는 some 액션 입니다.

<action />
패키지에서 가장 핵심이 되는 <action /> 요소는 다음과 같은 설정을 할 수 있습니다.
- URL과 액션 클래스를 매핑
- 액션 수행 전 후로 Interceptor 설정
- result 지정
- 예외 지정

먼저 <action /> 요소의 속성부터 알아보겠습니다.
- name(필수) : 액션 이름을 지정합니다. URL 요청의 마지막 .action 을 제외한 부분이 되겠습니다. 예를들면 http://호스트/애플리케이션이름/[네임스페이스]/액션명.action 에서 액션명을 지명하면 됩니다.

- class(필수) : URL 요청에 따라서 실행될 액션클래스를 지정합니다.

- method(옵션) : 옵션 사항으로 값을 지정하지 않았다면 기본적으로 execute() 메서드를 찾습니다. 만약 하나의 액션 클래스에서 여러개의 액션 메서드를 사용하고자 할 때 각 요청별로 method 속성을 이용해 매핑할 수 있습니다. 

- converter(옵션) : 이건 뭔지 모르겠습니다.

이제 <action /> 요소의 하위 요소에 대해 알아보겠습니다.
<param />
이 요소는 <action /> 요소 뿐만 아니라 <exception-mapping />, <interceptor-ref />, <result /> 요소(default 접두어가 붙은 요소 포함) 의 하위요소로도 사용됩니다.
용도는 각 요소에서 사용되는 클래스의 프로퍼티에 값을 설정하는 것 입니다. 간단한 예를 보겠습니다.
<package name="sample" extends="struts-default">
    <action name="hello" class="jjaeko.HelloAction">
        <param name="message">안녕?</param>
        <result name="k"><param name="location">/WEB-INF/jsp/hello.jsp</param></result>
    </action>
</package>
HelloAction 클래스의 message 프로퍼티에 "안녕?" 이라는 문자열을 설정 합니다.
사용자 요청에 전달된 파라미터와 설정되어 있는 <param /> 요소가 중복될 경우 사용자 요청에 전달된 파라미터가 우선시 됩다. 그런데 <result /> 요소는 뭔가 이상합니다. location 은 무엇일까요? 처음부터 잘 생각해 봅시다.  struts-default에는 dispatcher가 result-type의 디폴트로 설정되어 있기 때문에 <result /> 에서 type을 명시하지 않으면 dispatcher로 설정됩니다. 그리고 location 프로퍼티는 dispatcher 에 존재하는 프로퍼티 입니다. 그동안 <result /> 요소의 하위요소로 <param /> 요소를 사용한적이 없었던 이유는 dispatcher 의 디폴트 프로퍼티가 location 이기 때문 입니다. 따라서 result-type의 디폴트 프로퍼티는 <param />요소를 생략 할 수 있습니다.

<exception-mapping />
이 요소에 대한 설명은 <global-exception-mappings> 에서 했으므로 설명은 생략하고 액션내의 예외 매핑 예제를 바로 살펴보겠습니다.
<package name="sample" extends="struts-default">
    <global-results>
        <result name="error">/WEB-INF/jsp/error.jsp</result>
    </global-results>

    <action name="some" class="jjaeko.SomeAction">
        <exception-mapping exception="SQLException" result="error"/>
        <result name="error">/WEB-INF/jsp/error.jsp</result>
    </action>
</package>
SomeAction 에서 SQLException이 발생하면 some 액션내에 설정되어 있는 예외 매핑을 찾게 되겠습니다.
주의할 것은 예외가 발생되는 액션에서 exception Interceptor 가 설정되어 있어야 합니다.

<interceptor-ref />
액션의 실행 전 후로 실행될 Interceptor 를 지정합니다. 이 요소를 생략할 경우 디폴트로 defaultStack이 설정 됩니다. 각 Interceptor 마다 요구하는 프로퍼티 값이 존재할 수 있는데 위에서 소개한 <param /> 요소를
이용해 프로퍼티명과 값을 설정할 수 있습니다.

<result />
이 요소는 액션 메서드에서 리턴한 문자열의 이름으로 어떠한 형태로 응답을 작성할지 결정 합니다.
- name(옵션) : 액션 메서드에서 리턴한 문자열의 이름을 지정합니다. 디폴트는 success 입니다.
- type(옵션) : struts-default 패키지에 선언된 result-type 을 지정합니다. 디폴트는 dispatcher 입니다.

와일드카드 매핑
<action /> 요소의 method 속성을 이용할 경우 하나의 액션 클래스에 여러개의 메서드를 정의할 수 있습니다.
하지만 동일한 액션 클래스를 사용하는 <action /> 요소를 메서드 수 만큼 선언해야 하는 단점이 있습니다.
하지만 와일드 카드 매핑을 이용하면 단번에 해결 됩니다.
<action name="*User*" class="jjaeko.UserAction" method="{1}User">
    <result>/{2}/{1}User.jsp</result>
</action>
와일드카드(*) 는 여러개를 지정할 수 있으며 method 에서 순서에 따라 {순서} 형태로 설정합니다.
<result /> 요소에서도 역시 {순서} 형태로 설정 할 수 있습니다.
Insert_User_Admin.action 이라는 요청이 오면 UserAction 에서 InsertUser 라는 메서드가 실행 됩니다.
그후 "success" 를 리턴하면 Admin/InsertUser.jsp 페이지로 포워드 됩니다.

디폴트 와일드카드 매핑
액션 클래스가 없는 뷰를 응답해야 할 때 사용 합니다. 단 패키지의 가장 마지막에 존재해야 합니다.
<action name="*">
    <result>/WEB-INF/jsp/{1}.jsp</result>
</action>


 

 

스트러츠 상수 설정

 

상수는 프레임워크의 작동 방식에 대한 환경 설정 요소입니다.

default.properties

이 파일은 struts2-core-버전.jar 파일의 org.apache.struts2 패키지에 존재하며 모든 환경 설정 기본값이 설정 되어 있습니다. 따라서 설정 파일들을 통해 설정을 변경 하고자 하는 프로퍼티만 변경 하면 됩니다.
설정 항목들에 대해서는 이 파일을 참조하면 됩니다.

struts.properties 에서 설정
이 파일은 default.properties 와 설정 방법이 동일하며 ClassPath 루트에 위치해야 합니다.

struts.xml 에서 설정

<struts>
    <constant name="프로퍼티명" value="프로퍼티값" />
    ......
</struts>


web.xml 에서 설정

<web-app ......>
    <filter>
        <filter-name>struts</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <init-param>
       <param-name>프로퍼티명</param-name>
       <param-value>프로퍼티값</param-value>
    </init-param>
</web-app>


여러 파일에서 환경 설정을 할 수 있듯이 Struts2가 환경 설정 값을 찾는 순서도 있습니다.
나중에 찾는 설정중에 이전의 중복된 설정이 있다면 나중에 찾는 설정이 오버라이드 됩니다.
struts-default.xml -> struts-plugin.xml -> struts.xml -> struts.properties -> web.xml

 

 

 

==========================================================================================================================

==========================================================================================================================

 

 

16.5 interceptor

 

[1] 개요

스트럿츠 2에 도입된 중요한 요소 중에 하나로 Action 객체가 실행하기 전/후에 호출된다.

 

■ 개요

⋅ 액션 단위의 작업을 수행할 때 기존 액션 처리 전과 후에 추가적인 작업을 지원한다.

⋅ 모든 액션 요청(Action Request)에 대해 공통적으로 적용되어야 하는 공통 기능들을 제공하는 모듈

⋅ 인터셉터의 시작은 ActionInvocation 이 담당한다. ActionInvocation 은 인터셉터 스택에 정의된 인터셉터로 구성된 맵을 가지고 있다.

⋅ 액션 프록시가 ActionInvocation 의 invoke() 메서드를 호출 할 때 인터셉터의 실행이 시작된다.

⋅ 인터셉터의 작업이 끝나면, 또 다시 ActionInvocation 의 invoke() 메서드를 다시 호출한다. invoke() 에서드는 실행할 추가 인터셉터가 존재하는지 조사한 후 실행할 인터셉터가 존재한다면, 그 인터셉터의 interceptor() 메서드를 호출하는 식으로 인터셉터 체인을 형성한다. 만약 더 실행할 인터셉터가 존재하지 않는다면, 액션을 호출한 후 리절트를 실행한다.

⋅ 사용자가 자신만의 인터셉터를 작성하여 적용할 수 있다.

⋅ 스트럿츠2가 자체적으로 기본적인 인터셉터들은 제공하고 있으며, 디폴트 XML(struts-default.xml) 파일에 정의되어 있다.

 

■ 용도

⋅ 값의 검증

⋅ 사용자 인증처리

⋅ 예외처리

⋅ 파라미터 설정 및 변경

⋅ 복잡한 연산의 감춤

 

■ 인터셉터 스택

⋅ 다수의 인터셉터들을 묶어 정의함으로서, 하나 이상의 인터셉터들이 일괄적으로 적용되도록 해준다.

⋅ 인터셉터는 정의된 순서대로 적용 된다.

⋅ 기본적인 인터셉터 스택은 디폴트 XML(struts-default.xml) 파일에 정의되어 있다.

⋅ 사용자만의 인터셉터 스택을 정의하여 사용할 수 있다.

⋅ 패키지별 액션별로 적용될 수 있다.

 

또한 Struts2에서는 많은 스택들을 준비해 놓고 있다.

 

가장 많이 사용하는 것은 params 인터셉터로 요청할 때 넘어온 파라미터 값을 해당 Action에 설정하는 일을 한다. 파라미터 이름이 'name' 이라면 Action 객체의 setName() 메서드를 호출하여 파라미터 값을 할 당하며 이름이 'employee.id' 이면 Action객체에 대해 getEmployee().setId() 메서드를 호출한다.

 

interceptor 는 "Stack" Interceptor 를 만들어서 함께 연결될 수 있다. 만약 Action 에서 client의 신뢰성을 체크하고, Action 을 로그 처리하고, 시간을 측정하는 등 이러한 일반적인 기능을 수행하고 자한다면, 동일한 Interceptor Stack 을 만들어 사용할 수 있다.

 

interceptor 는 자바 클래스로 구현되며, 각 Interceptor 는 그 이름이 유일해야 한다. Interceptor 를 쉽게 만들어 사용하고자 한다면, Framework 에 등록하고, 간단한 이름으로 등록하여 사용할 수 있다.

 

<interceptors>

<interceptor name= "security" class= "com.company.security.SecurityInterceptor" />

<interceptor-stack name= "secureStack" >

<interceptor-ref name= "security" />

<interceptor-ref name= "defaultStack" />

</interceptor-stack>

</interceptors>

 

개개의 Interceptor 와 Interceptor Stack 은 Interceptor Stack 에 정의된 모든 순서에 맞게 함께 사용되어 질 수 있다. Struts 2 Framework 은 Stack 에 정의된 순서대로 각 Interceptor 를 호출할 것이다.

 

대부분의 어플리케이션은 default Interceptor Stack 을 정의한다.

 

<default-interceptor-ref name="secureStack"/>

하지만 각 Action 은 자신의 local stack 을 정의할 수 있습니다.

 

<action name= "VelocityCounter" class= "org.apache.struts2.example.counter.SimpleCounter" >

<result name= "success" > ... </result>

<interceptor-ref name= "defaultComponentStack" />

</action>

 

디폴트 환경설정(struts-default.xml) 에서 default Interceptor Stack 을 설정하며, 대부분의 어플리케이션에서 잘 동작을 한다.

 

[2] interceptor 관련 태그

■ <interceptors>

⋅ package를 시작할 때는 그 package에 소속된 action들이 사용할 interceptor를 먼저 정의하는데 이를 <interceptors>안에 기술한다.

⋅ <interceptors>안에는 Configuring Interceptor는 <interceptor>tag로, Stacking Interceptor는 <interceptor-stack>를 사용한다.

 

■ <interceptor>

⋅ 인터셉터 스택에서 참조할 인터셉터를 등록하는 태그이다.

⋅ attribute

name: 인터셉터 ID

class: 인터셉터의 소스파일의 경로, 만약 struts-default.xml에 등록되어있는 interceptor 라면 class를 쓸 필요가 없다.

 

■ <interceptor-stack>

⋅ 여러개의 인터셉터는 하나의 스택으로 만드는 태그이다.

⋅ <interceptor-ref>를 사용하여 등록된 인터셉터를 stack 화 한다.

⋅ attribute

name: 인터셉터 스택 ID

 

■ <interceptor-ref>

⋅ <interceptor-stack>태그 안에서는 <interceptor-ref>를 사용하여 등록된 인터셉터를 stack 화 한다.

⋅ <action>태그에서 실제로 인터셉터가 사용될때는 <interceptor-ref>에 name에 위에서 등록한 인터셉터나 인터셉터-스택 이름을 등록한다.

 

[3] 정의된 interceptor

 

Interceptor 명

설 명

alias 요청 사이에 서로 다른 이름을 가진 비슷한 파라미터들을 컨버팅 한다.
chain 이전 액션의 프로퍼티들을 현재 액션에서 사용 할 수 있게 한다. 이전 액션 정의에서 <result type="chain"> 과 함께 사용한다.
conversionError ActionContext에서 액션의 필드 오류로 변환한다.
createSession 자동으로 HttpSession을 생성한다. Token Interceptor와 같이 HttpSession이 적절하게 작동하도록 요구하는 인터셉터들에 유용하다.
debugging 페이지 뒷단에 데이터를 출력할 수 있는 몇몇 디버깅 화면을 제공한다.
externalRef  
execAndWait 백그라운드에서 액션을 실행하고 대기 상태 페이지를 사용자에게 즉각적으로 보낸다.
exception exception들을 결과(Result)에 매핑 한다.
fileUpload 파일 업로드를 쉽게 할 수 있게 지원한다.
i18n 사용자 세션에 대한 지역정보를 기억한다.
logger 액션의 이름을 출력한다.
modelDriven 액션이 ModelDriven 인터페이스를 구현하였다면 getModel() 결과를 ValueStack에 넣어 준다.
scopedModelDriven 액션이 ScopedModelDriven 인터페이스를 구현하였다면 인터셉터는 스코프로부터 Interceptor driven 모델을 저장 처리하고, setModel()을 호출하여 액션에 저장한다.
params 요청 파라미터들을 액션에 저장한다.
params 인터셉터는 요청 파라미터를 읽어서 request.getAttribute(key) 역할을 수행하여 key 값과 동일한 이름을 가진 Form 클래스 멤버의 setter 메서드를 호출하여 값을 넣어준다.
<input name="name"> 의 값을 Form 클래스의 setName() 메서드를 호출하여 name 멤버에 값을 넣어주는 역할을 한다.
prepare 액션이 Preparable 인터페이스를 구현하였다면 prepare() 메서드를 호출한다.
staticParams struts.xml에 정의된 파라미터 값들을 액션에 저장한다. <action> 태그 의 직속 자식으로 <param> 태그가 있다.
정적으로 변하지 않는 파라미터를 넘길경우(꼭 들어가야하는값) 사용자가 지정할 수 있다.
    1. Parameterizable을 구현한다
    2. Bean 객체 생성후 집어넣음 
        예) DTO dto = new DTO();
             dto.setName(params.get("name").toString());
            여기서 params는 사용자가 선언한 Map객체 "name"은 xml에 정의
    3. xml 매핑
        예) <action name="staticParams" class="staticParams.ParameterizableAction">
                 <param name="name">aaa</param>
                 <param name="age">bbb</param>
                 <param name="email">ccc</param>
                 <interceptor-ref name="staticParams"></interceptor-ref>
                 <result>/ch4/createSuccess.jsp</result>
              </action>
scope 액션 상태 값을 세션 또는 애플리케이션 스코프에 저장하는 간단한 메커니즘
servletConfig HttpServletRequest와 HttpServletResponse를 다루는 맵을 엑세스할 수 있게 한다.
timer 인터셉터와 뷰 처리를 포함하여 액션의 작업 처리 시간을 출력한다.
token 액션 내에 유효한 토큰이 존재하는 지 검사하고 폼을 이중으로 submit 하는 것을 방지한다.
tokenSession Token Interceptor와 같다, 그러나 유효하지 않은 토큰을 가지고 있을 때 세션 내에 submit 된 데이터를 저장한다.
validation action-validation.xml 내에 정의된 validator를 사용하여 유효성 검사를 한다.
workflow 액션 클래스 내의 validator() 메서드를 호출한다. 액션에서 오류가 발생했다면 그것은 input 뷰로 리턴 한다.
Validateable 인터페이스의 메소드 validate() 메서드를 호출 하여 유효성 검사를 진행한다. 즉 유효성 검사 부분은 validate() 메서드를 구현하여 검증 실패 시  addFieldError 로 해당하는 파라미터의 메시지를 넣어주면 workflow 인터셉터는 hasError() 메서드를 호출하여 에러가 있으면 자동적으로 return INPUT 을 호출하여 result와 매핑 시켜 준다. 
workflow 로 통해 넣은 에러 메시지는 jsp 페이지의 fieldErrors 의 파라미터명으로 메시지를 표출 가능하다.
store 인터페이스를 구현한 액션에 대한 액션 메시지 / 오류, 필드 오류을 저장하고 처리한다.
checkbox 체크되지 않은 체크박스를 감지할 수 있는 코드를 자동으로 추가하고 디폴트 값(보통(false)을 가진 파라미터들로 그들을 추가한다. submit 되지 않은 체크박스를 감지하기 위해서 특별한 이름을 가진 히든(hidden) 필드를 사용한다.
checkbox 인터셉터는 체크하지 않은 체크박스에 기본값을 지정해서 파라미터로 사용하게 할 수 있다. 원래 체크박스는 체크한것만 넘어간다.
    예) <action name="checkbox" class="checkBox.CheckboxAction">
             <interceptor-ref name="checkbox">
                 <param name="uncheckedValue">false</param>
             </interceptor-ref>
             <interceptor-ref name="params"></interceptor-ref>
             <result>/checkbox/checkboxSuccess.jsp</result>
         </action>
profiling 파라미터를 통해서 프로파일링을 작동시킨다.
roles 사용자가 올바른 JAAS 권한을 가진다면 액션은 실행된다.
cookie 액션에 설정가능한 '이름/값'을 가지는 쿠키 삽입(2.0.7부터 추가)
autowiring  
sessionAutowiring  

 

[4] Prepare Interceptor

프리페이 인터셉터는 Preparable 인터페이스를 구현한 액션의 prepare() 메서드를 호출하는 기능을 제공한다. 이 인터셉터는 액션 메서드를 호출하기 전에 수행해야 할 비지니스 로직을 수행할 필요가 있을 때 매우 유용하다.

 

<action name="someAction" class="ex1.SomeAction">

<interceptor-ref name="params" />

<interceptor-ref name="prepare" />

<interceptor-ref name="basicStack" />

<result>/ex1/res.jsp</result>

</action>

 

[5] Model-Driven Interceptor

모델 드리븐 인터셉터는 ModelDriven 인터페이스를 구현한 액션 클래스를 지켜본 후 액션의 getModel() 메서드를 호출하여 getModel() 메서드가 반환하는 객체의 프로퍼티를 valueStack 에 저장한다. 모델 드리븐 인터셉터로 파라미터를 모델에 적용하려면 Stack Parameters Interceptor 와 Parameters Interceptor 전에 위치해야 한다.

 

만약 모델이 널 값이 아니라면 스택에 저장한다. 또한 모델 드리븐 액션을 생성하려면 액션 클래스가 ModelDriven 인터페이스를 구현하고, Object 타입의 model 프로퍼티를 생성하거나 최소한 public Object getModel() 메서드를 만들어야 한다.

 

<action name="someAction" class="ex1.SomeAction">

<interceptor-ref name="modelDriven" />

<interceptor-ref name="basikStack" />

<result>/ex1/res.jsp</result>

</action>

 

[6] Parameter Interceptor

파라미터 인터셉터는 모든 파라미터를 밸류 스택에 저장한다. 이 인터셉터는 ActionContext의 getParameter() 메서드로 모든 파라미터를 얻은 후 ValueStack의 setValue(String, Object) 메서드를 호출하여 valueStack 에 저장한다.

 

<action name="someAction" class="ex1.SomeAction">

<interceptor-ref name="params" />

<result>/ex1/res.jsp</result>

</action>

 

[7] fileupload Interceptor

파일 업로드 인터셉터의 역할은 폼의 enctype 속성이 "multipart/form-data" 값으로 설정된 페이지에 <s:file /> 태그를 사용하여 파일을 첨부하여 포스트 방식으로 submit 했을 때 요청으로부터 멀티 파트 래퍼 (MultiPartWrapper) 클래스 객체를 생성한다. 멀티 파트 래퍼 클래스로부터 포함된 각 파일의 파라미터의 파일 내용, 컨텐츠 타입, 파일 이름을 액션 컨텍스트의 파라미터 객체에 저장한다.

호출한 <s:file name="upload" /> 태그는 액션 클래스의 프로퍼티의 javaio.File 타입의 프로퍼티 'upload'와 매핑한다.

 

업로드한 파일의 로컬 파일명은 특정 명명 규칙에 의한 String 타입의 프토퍼티가 액션 클래스에 정의되어 있을 경우 자동으로 그 프로퍼티에 저장한다.

 

⋅ <s:file /> 태그의 name 속성 명= " 액션 클래스의 java.io.File 타입 프로퍼티 명"

⋅ 로컬파일명을 저장할 프로퍼트 명= " 액션 클래스의 java.lang.String 타입 프로퍼티 명 " + "FileName"( ex :-> uploadFileName)

⋅ 컨텐츠 타입을 저장할 프로퍼티 명= "액션 클래스의 java.lang.String 타입 프로퍼티 명 " + "ContentType" ( ex : upload -> uploadContentType)

 

 

 

 

 

======================================================================================================================

======================================================================================================================

 

 

 

구동원리

  1. Servlet Container 에 요청전달
  2. 표준 필터 체인을 통과
    1. ActionContextCleanUp (선택) 필터
    2. 기타 필터들 호출
    3. FilterDispatcher 필터 호출
      1. Action에 대한 요청인지 알아보기 위해 ActionMapper에게 문의
      2. ActionMapper는 요청을 Action 객체가 처리해야 하는지 결정
      3. Action이 처리해야 한다면, ActionProxy에 제어권을 위임
  3. ActionProxy
    1. 프레임웍 설정 파일(struts.xml) 매니저에게 문의
    2. ActionInvocation 생성
  4. ActionInvocation
    1. 인터셉터 스택 실행
    2. Action 호출
    3. Action 실행
      1. 결과를 만들 담당자 이름을 리턴
    4. struts.xml에서 해당 이름의 '결과 생성 담당자(JSP, FreeMarker 등)'를 조회
    5. result 실행
    6. 인터셉터 스텍을 꺼꾸로 실행
  5. 클라이언트에 결과 리턴
  6. FilterDispatcher
    1. ActionContextCleanUp 필터가 있다면, ThreadLocal ActionContext 삭제하지 않습니다.
    2. 없다면, 모든 ThreadLocal들을 삭제합니다.

아키텍처에 있는 모든 구성요소는(Action, Result, Interceptor 등) ObjectFactory가 생성합니다. Struts에 내장된 ObjectFactory 대신 다른 인기있는 ObjectFactory(예: Spring)을 사용할 수 있습니다.

단, struts.properties 파일에 해당 이름을 설정해야 합니다.
struts.properties:

struts.objectFactory=foo.bar.MyCustomObjectFactory

사용자 정의 ObjectFactory 클래스 예:

public class MyCustomObjectFactory extends ObjectFactory {
    .....
}

2 주요 요소

예제) struts.xml

<struts>
    <!-- Configuration for the default package. -->
    <package name="default" extends="struts-default">

        <!-- Default interceptor stack. -->
        <default-interceptor-ref name="paramsPrepareParamsStack"/>
        
        <action name="index" class="com.aurifa.struts2.tutorial.action.EmployeeAction" method="list">
            <result name="success">/WEB-INF/jsp/employees.jsp</result>
            <!-- we don't need the full stack here -->
            <interceptor-ref name="basicStack"/>
        </action>

        <action name="crud" class="com.aurifa.struts2.tutorial.action.EmployeeAction" method="input">
            <result name="success" type="redirect-action">index</result>
            <result name="input">/WEB-INF/jsp/employeeForm.jsp</result>
            <result name="error">/WEB-INF/jsp/error.jsp</result>
        </action>
    </package>
</struts>


위의 예에서 'index' Action의 'success'이름의 result 타입은 기본적으로 DispatcherResult 입니다. 그냥 단순히 employees.jsp 로 포워딩 하는 것입니다.

'crud' Action의 경우 좀더 복잡한데, 'success' 결과의 타입을 보면 redirect-action 입니다. 즉, 단순히 index라는 이름을 가진 Action으로 redirect 하라는 의미입니다.

Package

Action, result, interceptor, interceptor-stack을 하나의 논리적 설정 단위로 묶는 방법입니다.


Interceptor

스트럿츠 2에 도입된 중요한 요소 중에 하나입니다. Action 객체가 실행하기 전/후에 호출될 것입니다.

  • 용도
    • 값의 검증
    • 사용자 인증처리
    • 예외처리
    • 파라미터 설정 및 변경
    • 복잡한 연산의 감춤

Struts2에서는 많은 스택들을 준비해 놓고 있습니다.

가장 많이 사용하는 것은 params 인터셉터 입니다. 요청할 때 넘어온 파라미터 값을 해당 Action에 설정하는 일을 합니다. 파라미터 이름이 'name' 이라면 Action 객체의 setName() 메소드를 호출하여 파라미터 값을 할 당할 것입니다. 이름이 'employee.id' 이면 Action객체에 대해 getEmployee().setId() 메소드를 호출할 것입니다.


Action 매핑

Action은 프레임웍의 기본적인 작업 단위입니다. 클라이언트의 요청을 처리할 Action을 정의하는 것입니다.

Result

Result 요소는 Action이 실행한 후에 클라이언트에게 보낼 결과를 만드는 객체를 설정합니다. 결과는 JSP파일, Freemarker 템플릿 랜더링, 차트 생성, XML 출력 등이 될 수 있습니다. 
>> 의미

  • 결과 생성 객체의 논리적 이름 제공.
    • Action은 클라이언트 요청에 대해 작업을 수행한 후, 이 이름을 사용하여 클라이언트에게 어떤 결과를 보낼 것인지 지정하게 됩니다. 보통 결과를 지정하기 위해 "success", "error", "input" 등의 단순한 문자열을 사용할 것입니다.
  • result type 설정
    • 프레임웍에 미리 정의된 Result 타입 외에 사용자 정의 Result 타입을 만들수 있습니다.
    • com.opensymphony.xwork2.Result 인터페이스를 구현하면 됩니다.
    • 예) 이메일 생성, JMS 메시지 생성, image 생성 등.

>> Predefined result names (in ActionSupport base class)

String SUCCESS = "success";
String NONE    = "none";
String ERROR   = "error";
String INPUT   = "input";
String LOGIN   = "login";

>> Predefined Result Types: com.opensymphony.xwork2.Result 인터페이스 구현한 클래스들

Chain ResultUsed for Action Chaining
Dispatcher ResultUsed for web resource integration, including JSP integration
FreeMarker ResultUsed for FreeMarker integration
HttpHeader ResultUsed to control special HTTP behaviors
Redirect ResultUsed to redirect to another URL (web resource)
Redirect Action ResultUsed to redirect to another action mapping
Stream ResultUsed to stream an InputStream back to the browser (usually for file downloads)
Velocity ResultUsed for Velocity integration
XSL ResultUsed for XML/XSLT integration
PlainText ResultUsed to display the raw content of a particular page (i.e jsp, HTML)
Tiles ResultUsed to provide Tiles integration

>> Optional

JasperReports PluginUsed for JasperReports Tutorial integration Optional, third-party plugin

각 패키지 별로 default result type을 설정할 수 있습니다. 즉, result element에 특별히 result type 속성이 설정되어 있지 않으면 default result type이 사용됩니다. 
>> default result type:

<result-types>
   <result-type name="dispatcher" default="true"
                class="org.apache.struts2.dispatcher.ServletDispatcherResult" />
</result-types>

Result 요소의 name 속성 값이 없다면, default로 "success" 이름을 갖게 됩니다.


>> result type 지정하기

<result name="success" type="dispatcher">
    <param name="location">/ThankYou.jsp</param>
</result>


>> default result type 사용하기

<result>
    <param name="location">/ThankYou.jsp</param>
</result>


>> default result type 사용하기 + param 요소 생략

<result>/ThankYou.jsp</result>


>> 여러개의 result 설정

<action name="Hello">
    <result>/hello/Result.jsp</result>
    <result name="error">/hello/Error.jsp</result>
    <result name="input">/hello/Input.jsp</result>
</action>


>> 여러 Action에서 사용할 수 있는 Global result 설정

<global-results>
    <result name="error">/Error.jsp</result>
    <result name="invalid.token">/Error.jsp</result>
    <result name="login" type="redirectAction">Logon!input</result>
</global-results>


>> 실시간에 result 결정하기
Action 클래스 일부:

private String nextAction;

public String getNextAction() {
    return nextAction;
}

설정:

<action name="fragment" class="FragmentAction">
    <result name="next" type="redirectAction">${nextAction}</result>
</action>

WEB-INF/classes/struts.properties

예)

struts.custom.i18n.resources=guest

이 파일은 Struts 2의 특정 설정 정보를 포함합니다. 예를들면, 사용할 IoC컨테이너, 파일 업로더, 템플릿 등.

위의 예제는 'guest.properties' i18n 파일을 지정하는 문장입니다.


3 Interceptor

3.1 I18n Interceptor

세션의 로케일 설정을 다루는 인터셉터 입니다. 특정한 HTTP 요청 파라미터를 조사하여 값에 따라 세션 범위에서 사용할 로케일을 설정합니다.

Action에 "request_locale"에 해당하는 setter 메소드가 없음이 확인되면, 이 인터셉터는 실행하는 동안 로케일 파라미터를 제거합니다.

예를들어 foo.action?request_locale=en_US 요청이 들어오면, 사용자 세션에 US English로 로케일 정보를 저장하고, 앞으로 모든 요청은 이 로케일이 사용될 것입니다.

  • Parameters
    • 파라미터 명(선택): request_locale
      • 로케일을 바꾸고자 할 때 사용하는 요청 파라미터 이름.
    • 속성 명(선택): WW_TRANS_I18N_LOCALE
      • 세션에 로케일 정보를 저장할 때 사용하는 key 이름.

4 Localization

4.1 개요

프레임웍은 아래의 항목에서 internationalization(i18n)을 지원합니다.

  • UI tags
  • ValidationAware 인터페이스에서 Message 나 Error에 대해
  • ActionSupport를 상속받은 Action 클래스 (getText()를 사용하면 됩니다)

4.2 리소스 번들 파일 탐색 순서

다음 순서로 리소스 번들 파일을 찾습니다.

  1. ActionClass.properties
  2. BaseClass.properties
  3. Interface.properties
  4. ModelDriven's model
  5. package.properties
  6. i18n message key 계층
  7. global resource properties

4.3 예제

메시지 리소스를 사용하는 방법

  • 태그에서 getText() 사용하기
<s:property value="getText('some.key')" />
  • text 태그 사용하기: default 리소스 번드로 부터 메시지 꺼내기
<-- Fourth Example -->
<s:text name="some.key" />

<-- Fifth Example -->
<s:text name="some.invalid.key" >
   The Default Message That Will Be Displayed
</s:text>
  • i18n 태그 사용하기
<s:i18n name="some.package.bundle" >
     <s:text name="some.key" />
</s:i18n>
  • UI 태그의 key 속성 사용하기

대부분 UI 태그들은 key 속성을 사용하여 리소스 번들 메시지를 꺼낼 수 있습니다.

<s:textfield key="some.key" name="textfieldName"/>

4.4 Global Resources 지정

struts.properties 파일에 설정. 글로벌 리소스도 locale과 마찬가지로 프로그램적으로 설정될 수 있다. 

[출처] Struts 2|작성자 윤병현

'FrameWork > Struts' 카테고리의 다른 글

[Struts2] 스트럿츠 액션뒤에 jsessionid 붙을때 해결법  (0) 2011.08.11
[Struts] Struts 란?  (0) 2010.04.28