'Java/Struts2'에 해당되는 글 4건
- 2009.03.29 Struts2 에서 확장자 제거하기
- 2009.03.26 <bean /> 선언시 주의할 점
- 2009.03.24 struts2 커스텀태그 개발자가이드
- 2009.03.23 struts2 Result Types
Struts2에서 Action의 기본확장자는 action이다.
REST의 관점에서 보면 URL은 Resource를 가리키고 있을 뿐이어서 action이란 접미어가 붙는 것은 restful 하지 않아 보인다.
그래서 struts.properties의 struts.action.extension에 아무것도 할당하지 않으면 간단히 확장자를 제거 할 수 있다.
struts.action.extension=
struts.properties
하지만, 이렇게 하면 welcome-file을 사용할 수 없고, *.jsp, *.gif, *.jpg등 struts action이 아닌 resource들은 접근 할 수도 없다. 그래서 다음과 같이 간단한 필터를 만들어 보았다.
- package filters;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.struts2.dispatcher.FilterDispatcher;
- public class StrutsRedirectFilter implements Filter {
- FilterDispatcher dispatcher = new FilterDispatcher();
- @Override
- public void doFilter(ServletRequest req, ServletResponse res,
- FilterChain chain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) req;
- String uri = request.getRequestURI();
- // 확장자가 있는 경우
- if (uri != null
- && (uri.equals(request.getContextPath().concat("/")) || uri
- .substring(uri.indexOf("/")).indexOf(".") > -1)) {
- chain.doFilter(req, res);
- // 아닌 경우 struts로 넘긴다.
- } else {
- dispatcher.doFilter(req, res, chain);
- }
- }
- @Override
- public void destroy() {
- dispatcher.destroy();
- }
- @Override
- public void init(FilterConfig config) throws ServletException {
- dispatcher.init(config);
- }
- }
StrutsRedirectFilter.java
이 필터를 org.apache.struts2.dispatcher.FilterDispatcher 대신 web.xml 에 넣어주면 된다.
- <?xml version="1.0"?>
- <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd">
- <web-app>
- <display-name>My Application</display-name>
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>filters.StrutsRedirectFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
Struts2는 WebWork와 통합되어 있다는 사실은 누구나 알고 있습니다.
WebWork는 XWork를 기반으로한 Web MVC 프레임워크 라는 사실 또한 누구나 알고 있을 것 입니다.
여기서 XWork는 IoC 컨테이너 입니다. 스프링2.5에서 @Autowire 애노테이션으로 의존성을 주입하듯이
XWork에서는 @Inject 라는 애노테이션으로 의존성을 주입합니다.
Struts2는 WebWork와 적절히 통합되어 있습니다.
Struts2의 API 대부분의 setter 메서드에서는 @Inject 애노테이션이 사용 되어지고 있습니다.
@Inject 애노테이션의 속성은 value 와 required 두 가지 입니다.
value는 XWork Container에 존재하는 인스턴스의 이름을 지정하는 속성이며 기본 값은 "default" 라는 문자열 입니다. required 속성은 필수여부인데 true일 경우 Contanier내에 반드시 존재해야 합니다. 만약 존재하지 않으면
예외를 뿜어냅니다.
여기까지가 기본적으로 알고 있어야 하는 간단한 지식이고 이제 본론으로 들어가서...
struts-default.xml 에 보면 Struts2 에서 사용되는 객체들을 <bean /> 요소로 아주 많이 선언해 두었습니다.
모든 핵심 클래스들이 선언되어 있죠... 그리고 위에서 밝혔듯이 Struts2 API는 @Inejct 애노테이션이 마구마구
사용되어 지고 있는 상태 입니다. Struts2가 구동시 <bean /> 요소로 선언된 클래스들을 생성하고 필요한 곳에
주입 됩니다. 아래 몇 가지 예가 있습니다.
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="composite" class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful" class="org.apache.struts2.dispatcher.mapper.RestfulActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="restful2" class="org.apache.struts2.dispatcher.mapper.Restful2ActionMapper" />
그 밖에도 다른 <bean /> 요소로 선언된 것 중에서 역시 name 속성이 "struts" 인 것만 사용 됩니다.
그래서 저는 추측 했습니다.
개발자가 별도로 <bean /> 요소로 선언할 때 name 속성을 "struts"로 줘야 하는구나...
그리고 ActionEventListener를 당장 만들어서 선언한 뒤 name 값을 "struts"로 주었습니다.
하지만 이 객체는 DefaultActionProxy 에 주입되지 않았습니다.
당연한 결과 였습니다. DefaultActionProxy에는 단지 @Ineject(required=false) 로만 선언되어 있었기 때문에
name 속성이 "struts"로 되어있는 ActionEventListener 객체를 찾지 못하는 것 이었습니다.
(@Inject() 애노테이션의 value 속성의 기본값은 "default" 이기 때문에 "default" 로 찾습니다.)
그런데 뭔가 이상 합니다.
분명 struts-default.xml 에 수많은 <bean /> 요소들의 name 속성은 "struts"로 되어 있고
그 객체들을 필요로 하는 곳에서는 단지 @Inejct() 로만 요청하고 있는데 name 값이 틀림에도 불구하고
어떻게 정상적으로 의존성 주입이 되는 것일까...
처음에 디버깅 할 때는 객체를 찾아오는 부분에서 시작했습니다. 여기서 대부분의 시간을 보냈지만 답을 찾을 수 없었습니다. 그래서 초심으로 돌아가서 FilterDispatcher의 init() 메서드부터 차근차근 보았습니다.
디버깅을 하면서 XWork의 초기화 과정을 발견 했는데 Struts2에서 XWork를 초기화 할 때
XWork의 생명주기 관련 인터페이스인 ConfigurationProvider 의 구현체들을 등록하는 것을 발견 했습니다.
그 중에서 BeanSelectionProvider 가 있는데 이 클래스가 해답 이었습니다.
XWork의 초기화 과정에서 BeanSelectionProvider.register() 메서드가 호출 되는데 이 메서드에서
특정 타입이면서 name 값이 "struts"인 객체들의 name 값을 "default" 로 바꿔 주는 것 입니다.
그래서 정상적으로 의존성 주입이 되고 있었던 것 입니다.
특정 타입의 목록은 다음과 같습니다.
XWorkConverter.class
TextProvider.class
ActionProxyFactory.class
ObjectTypeDeterminer.class
ActionMapper.class
MultiPartRequest.class
FreemarkerManager.class
VelocityManager.class
위 타입 이외에 것들은 (UnknownHandler, ActionEventListener)
<bean /> 요소로 선언 할 때 name 속성은 무턱대고 "struts" 로 지정할 경우 정상적으로 작동 되지 않습니다.
그냥 name 속성을 생략 하거나 동일한 타입이 여러개일 경우 주입하고자 하는 <bean /> 요소에 name 속성을
"default" 로 설정 하면 됩니다.
가장 사용이 많은 경우는 두가지 구문으로 분할된다. 첫번째, application's 상태를 변경하거나 query한다. 그리고 application의 view를 갱신하여 표현하기를 필요로한다. Action class는 application의 상태를 관리하고, Result type은 view를 관리한다.
미리 정의된 Result Types
framework은 자신의 application을 개발할 준비가 된 com.opensymphony.xwork2.Result interface의 몇몇 implementation들을 제공한다.
Chain Result | Action Chaining을 위해 사용된다. |
Dispatcher Result |
JSP통합을 포함한 web resource통합 을 위해 사용된다. |
FreeMarker Result |
FreeMarker 통합을 위해 사용된다. |
HttpHeader Result |
특정 HTTP가동을 제어하기 위해 사용된다. |
Redirect Result |
다른 URL(web resouece)에 redirect하기 위해 사용된다. |
Redirect Action Result |
다른 action mapping에 redirect하기 위해 사용된다. |
Stream Result |
browser로 Inputstream을 stream하기 위해 사용된다.(일반적으로 파일 다운로드를 위해) |
Velocity Result |
Velocity통합을 위해 사용된다. |
XSL Result |
XML/XSLT 통합을 위해 사용된다. |
PlainText Result |
특정 page(i.e , jsp , HTML) 에 raw content를 display하기 위해 사용된다. |
Tiles Result |
Tiles통합을 위해 사용된다. |
Optional
JasperReports Plugin은 Third-party plugin인 JasperReports Tutorial 을 선택적으로 통합하기 위해 사용된다. 추가적인 Result type은 생성 할 수 있으며, com.opensymphony.xwork2.Result interface를 implement하여 application에 plug될 수 있다.
Custom Result Type들은 email , JMS message, image 생성, 기타 등등 들을 포함한다.
Default Parameters
최소한의 설정으로는 , Result는 parameter안에 변환된 single value로 설정 할 수 있고, 각 Result는 어떤parameter가 값으로 설정되는지 묘사한다.
예를 들어, 다음 예제는 Default parameter를 사용하여 XML안에 정의된 결과 이다:
<result type="freemarker">foo.fm</result>
That is the equivalent to this:
<result type="freemarker"><param name="location">foo.vm</param></result>
대 개 application 의 95% 여러 parameter들을 포함한 결과를 필요로 하지 않기 때문에 이 간단한 중요한 많은 양의 작업 비용을 줄여준다. 또한 Default parameter를 열거할 경우 특별한 이름의 paremeter를 위해 동일 parameter들을 설정할 필요가 없다.
Registering Result Types
모든 Result Type들은 Result Configuration을 통해 plug된다.
Open Framework의 대중화를 위해 : jsHan
[출처] struts2 Result Types (한양IT Education) |작성자 오키도키