目次

Migration From struts application to JSF application

Struts Framework로 개발된 application을 JSF application으로 이관하는 과정을 소개한다.
처음으로 해야 할 일은 적절한 라이브러리들을 설정하는 것이다.

1.Struts-Faces 라이브러리를 애플리케이션에 추가: Struts-Faces 라이브러리는 Struts-faces.jar라고 하는 JAR파일에 포함돼있다.
Struts-Faces 배포판으로부터 이 파일을 애플리케이션의 WEB-INF/lib 디렉토리에 복사하기 바란다.

2.JSF 라이브러리를 애플리케이션에 추가 : 참조 구현체(Sun RI)의 경우에는 jsf-api.jar와 jsf-impl.jar를 사용하면 된다.
이 두 파일을 애플리케이션의 WEB-INF/lib 디렉토리에 복사하기 바란다.

3.JSTL 라이브러리를 애플리케이션에 추가: 이 라이브러리는 공식 JSTL 배포 사이트 또는 JSF 구현체로부터 얻을 수 있다.
JSTL JAR 파일들(jstl.jar 및 standard.jar)을 애플리케이션의 WEB-INF/lib 디렉토리에 복사하기 바란다.

4.JSF 컨트롤러 서블릿을 웹 애플리케이션 배치 설명자(WEB-INF/web.xml)에 추가: 이 단계는 다른 JSF 애플리케이션에서도 필요하다.

<servlet>
   <servlet-name>Faces Servlet</servlet-name>
   <servlet-class>
     javax.faces.webapp.FacesServlet
   </servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>

FacesServlet이 가장 먼저 로드되도록 <load-on-startup>을 1로 설정한 것을 유의하기 바란다. FacesServlet이 처음 로드돼야 하므로 struts servlet인 ActionServlet은 두 번째 또는 더 나중에 로드돼도록 해야 한다. 이는 ActionServlet을 정의한 부분에서 <load-on-startup>요소를 생략하거나, 값을 2이상으로 설정하면 된다.

<servlet>
   <servlet-name>Struts Servlet</servlet-name>
   <servlet-class>
     org.apache.struts.action.ActionServlet
   </servlet-class>
   <load-on-startup>2</load-on-startup>
</servlet>

5.JSF 컨트롤러 서블릿을 위한 서블릿 맵핑을 웹 어플리케이션 배치 설명자(WEB-INF/lib)에 추가: 4단계의 경우와 마찬가지로 이는 일반적인 JSF 설정 작업에 해당한다.

<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

이는 접두어 맵핑의 예이지만, 접미어 맵핑을 사용할 수도 있다.

6.Struts-Faces의 RequestProcessor를 Struts 설정 파일(WEB-INF/struts-config.xml)에 추가: <controller> 요소를 추가하면 된다. 만약 Tiles를 사용하지 않는다면 FacesRequestProcessor 클래스를 사용하기 바란다. 1)

  <controller>
    <set-property property="processorClass" value="org.apache.struts.faces.application.FacesRequestProcessor">
  </controller>

만약 Tiles를 사용하지 않는다면 FacesTilesRequestProcessor를 사용하면 된다.

  <controller>
    <set-property property="processorClass" value="org.apache.struts.faces.application.FacesTilesRequestProcessor">
  </controller>

Example of Struts-JSF Integration

Struts application을 JSF로 이관하는 과정을 이해하기 위해 간단한 logon화면을 보여주는 jsp를 살펴보자. 현재의 struts버전은 대략 다음과 같은 모습이다.

Listing 1: A simple Struts-based logon JSP

<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
 
<html:html>
<head>
<title><bean:message key="logon.title"/></title>
</head>
<body>
<html:errors/>
<html:form action="/logon"/>
<table border="0">
  <tr>
    <td align="right">
      <bean:message key="prompt.username"/>
    </td>
    <td align="left">
      <html:text property="username"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <bean:message key="prompt.password"/>
    </td>
    <td align="left">
      <html:password property="password"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <html:submit value="Log On"/>
    </td>
    <td align="left">
      <html:reset/>
    </td>
  </tr>
</table>
</html:form>
</body>
</html:html>

Step 1: Change the tag library declarations 제일 처음에 해야 할 작업은 tag library 선언부를 Struts-JSF tag library로 바꾸는 것이다.
그리고 모든 컴포넌트 태그를 <f:view> 태그로 둘러싼다.

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
 
<f:view>
<s:html locale="true">

Step 2: Modify declarations for localized messages 두번째 단계는 <s:loadMessage> 태그를 사용하여 basename으로 지정되어 있는 ResourceBundle을 로드하는 것이다.
basename을 지정하지 않으면 기본으로 저장되어있는 application의 기본 MessageResources 번들이 로드된다.

<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>

일단 로드되면 모든 컴포넌트로부터 messages를 키로 JSF Expression language형식으로 접근할 수 있다.
다음은 title을 ResourceBundle을 이용하여 지역화한 예이다.

<title>
  <h:outputText value="#{messages['logon.title']"/>
</title>

Step 3: Change tags for error and form components 세번째는 validation error를 보여주는 <s:errors> 태그와 <html:form> 태그를 <s:form> 태그로 교체하는 것이다.

<s:errors/>
<s:form action="/logon">

Step 4: Using JSF EL for input fields 네번째 단계는 Struts form tag를 해당 JSF form tag로 교체하는 작업이다. logonForm이라는 이름으로 ActionForm이 struts-config.xml에 저장돼있다고 가정한다.

<h:inputText id="username" value="#{logonForm.username}"/>
...
<h:inputSecret id="password" value="#{logonForm.password}"/>

Step 5: Change tags for submit and reset buttons 마지막으로 button 의 label을 지역화한다. 이때 HtmlCommandButton 컴포넌트에 action속성이 지정되있지 않는 것에 눈여겨 보기 바란다. 이는 버튼이 클릭되면 <s:form> 요소와 연결돼있는 struts Action이 실행되기 때문이다.

지금까지의 교체작업으로 바뀐 완성된 JSP는 다음과 같다.

Listing 2: Example logon JSP after migration using the Struts-Faces Integration Library

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
<f:view>
<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>
<s:html locale="true">
<head>
<title><h:outputText value="#{messages['logon.title']"/></title>
</head>
<body>
<s:errors/>
<s:form action="/logon"/>
<table border="0">
  <tr>
    <td align="right">
      <h:outputText value="{messages['prompt.username']"/>
    </td>
    <td align="left">
      <h:inputText id="username" value="#{logonForm.username}"/>
    </td>
  </tr>
  <tr>
    <td align="right">
      <h:outputText value="#{messages['prompt.password']"/>
    </td>
    <td align="left">
      <h:inputSecret id="password" value="#{logonForm.password}"/>
    </td>
  </tr>
  <tr>
    <td align="right">
        <h:commandButton id="submit" type="SUBMIT" value="#{messages['button.logon']"/>
    </td>
    <td align="left">
      <h:commandButton id="reset" type="RESET" value="#{messages['button.reset']"/>
    </td>
  </tr>
</table>
</s:form>
</body>
</s:html>
</f:view>

Reference

  1. JSF In Action, Kito D. Mann
  2. http://www.oracle.com/technology/pub/articles/masterj2ee/j2ee_wk8.html : The Best of Both Worlds: Integrating JSF with Struts in Your J2EE Applications
1)
만약 여러분만의 RequestProcessor를 개발했다면, 그 클래스가 적절한 Struts-Faces의 RequestProcessor를 상속받도록해야 한다. 또한 다른 JSF특정적인 처리작업에 지장을 주지 않도록 주의해야 한다. (Struts-Faces의 클래스 소스를 먼저 파악하기 바란다.)물론 그런 다음에는 struts-config.xml의 <controller> 엔트리도 알맞게 변경해야 한다.