Whiteship's Note


2장 컴포넌트 식별자와 클라이언트 식별자

JSF/JSF in Action : 2010.01.13 15:21


- UI 컴포넌트는 서버에서는 컴포넌트 트리로 살고 클라이언트쪽에서는 여러 형태의 뷰 표현체로 존재한다.
- 서버쪽에서는 컴포넌트 식별자로 컴포넌트를 참조한다.
- 클라이언트에서는 클라이언트 식별자를 사용해서 컴포넌트를 참조한다.
- 컴포넌트 식별자를 이용해서 클라이언트 식별자를 생성한다.
- 컴포넌트 식별자는 반드시 문자 또는 언더바(_)로 시작한다.
- 컴포넌트 식별자를 생략하면 JSF가 자동으로 만들어 준다.
- Naming container: 하위 컴포넌트들이 모두 유일한 식별자를 가지고 있는 컴포넌트.
- 예를 들어 HtmlDataTable, HtmlForm의 하위 컴포넌트트 식별자에는 이 컴포넌트의 식별자를 이용해서 클라이언트 식별자를 만든다.

top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 6. 응답 보여주기

JSF/JSF in Action : 2010.01.11 20:58


Render Response

- 최종적으로 사용자에게 응답을 보낸다.
- 뷰 상태를 저장하여 '뷰 복원하기' 단계에서 재사용할 수 있게 한다.
- 특정 뷰 기술에 종속적이지 않다.
- 컨트롤러의 인코딩 메서드 결과만을 뷰에서 사용할 수 있다.
- 컨트롤러의 인코딩 메서드 결과를 마크업을 만드는 애플리케이션에서 통합할 수 있다.
- 컨트롤러의 인코딩 메서드 결과를 정적인 템플릿에 통합할 수 있다.
- 컨트롤러의 디코딩 메서드 결과를 JSP 같은 동적 리소스에 통합할 수 있다.
- 각각의 컨트롤러 인코딩 과정 중에 변환기(Conveter)를 사용하여 컴포넌트의 값을 문자열로 변환한다.
- 이 단계가 JSF 요청 처리 생명주기의 마지막 단계다.
top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 5. 애플리케이션 호출하기

JSF/JSF in Action : 2010.01.08 21:49


Invoke Application

- 이 단계에서 등록되어 있는 리스너로 이벤트를 전파한다.
- '요청값 적용하기' 단계에서 만든 액션 이벤트를 여기서 전파한다.
- 컴포넌트에 등록된 액션 리스너 EL을 평가하여 백빈의 특정 메서드(액션 리스너 메서드)를 실행한다.
- 액션 리스너 메서드는 컴포넌트의 actionListener 속성으로 설정한다.
- 액션 리스너 메서드 실행이 끝나면 모든 컴포넌트에 자동으로 등록되는 기본 리스너를 실행한다.
- 기본 리스너는 컴포넌트에 등록되어 있는 액션 메서드를 호출한 뒤 해당 메서드의 논리적인 이름을 통해 랜더링할 뷰를 찾는다.
- 액션 메서드는 컴포넌트의 action 속성을 설정한다.
- 액션 메서드가 없는 경우 기본 액션 리스너가 현재뷰를 랜더링 한다.
- 액션 리스너 메서드나, 액션 메서드에서는 직접 응답을 랜더링 할 수도 있고, 애플리케이션 메시지를 추가할 수도 있고, 이벤트를 만들 수도 있고, 애플리케이션 로직을 실행할 수도 있고, 그냥 뷰 랜더링 단계로 건너뛸 수도 있다.
- 모든 리스너 실행이 끝나면 뷰를 랜더링 할 준비가 된 것이다.


top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 4. 모델 값 변경하기

JSF/JSF in Action : 2010.01.07 20:38


Update Model Values

- JSF EL 표현식을 통해서 모델 또는 백빈의 속성 값을 설정한다.

<h:inputText id="helloInput" value="#{helloBean.numControls}" 
             required="true"> 
... 
</h:inputText> 

1. helloBean이라는 키를 가지고 있는 빈을 찾아온다.
2. helloBean의 numControls 속성에 값을 해당 컴포넌트의 로컬 값으로 설정한다.

- 이 단계가 끝나면 관련 리스너에 이벤트를 보내고, 여태까지 그랬던것처럼 리스너에서는 응답을 직접 출력하거나  Render Response 단계로 건너뛸수도 있다.



top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 3. 검증하기

JSF/JSF in Action : 2010.01.07 20:26


Process Validation

- 이 단계에서 JSF는 컴포넌트 트리를 순회하면서 각각의 컴포넌트에게 자신의 값을 수용할 수 있는지 확인하도록 요청한다.
- '요청 값 적용하기' 단계에서 입력 컴포넌트들이 갱신되기 때문에 이 단게에서는 사용자가 입력한 최신값을 가지고 있다.
- 검증을 하기전에 변환기에 의해 값이 변환된다.
- 변환기와 검증기를 무사히 거치고 나면 해당 값을 서브밋하고 다음 단계로 넘어간다.
- 그렇치 않은 경우 '응답 보여주기' 단계로 넘어간다.

<h:inputText id="helloInput" value="#{helloBean.numControls}" 
             required="true"> 
<f:validateLongRange minimum="1" maximum="500"/> 
</h:inputText> 

1. required 속성이 true가 입력한 값이 있는지 검사한다.
2. 컨버터가 입력한 값을 int로 바꾼다.
3. validateLongRange 검증기가 값의 범위를 검증한다.

- submitted value가 변환과 검증이 끝나면 그 값을 기반으로 로컬 값을 세팅하는데 이때 value change event가 발생하고 그에 따른 적절한 리스너가 실행된다. 이 리스너들에 의해 직접 응답을 출력하거나 Render Repsponse 단계로 넘어갈 수 있다.
- 모든 submitted value가 유효하다면 다음 단계로 넘어간다.


top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 2. 요청 값 적용하기

JSF/JSF in Action : 2010.01.06 20:42


Apply Request Values

- 사용자 입력을 받는 컴포넌트들은 사용자가 입력한 원래 데이터를 나타내는 submitted value를 가지고 있다.
- 프레임워크가 요청의 매개변수를 기반으로 submitted value를 설정해준다.
- 이 과정을 decoding이라 부른다.
- 각 컴포넌트는 자신의 id와 자신을 감싸고 있는 컴포넌트의 id를 이용해서 client identifiter를 만든다.
- 이 단계에서 컴포넌트의 요청에 자신의 client id에 해당하는 매개변수가 있는지 확인하여 있다면 그 매개변수의 값으로 설정한다.
- 컴포넌트의 immediate 속성을 true로 설정하면 검증 단계에서 하지않고 그 즉시 검증을 실행한다.
- 이 단계에서 액션 이벤트를 만들 수도 있다. 만들어진 이벤트는 FacesContext에 추가되고 나중에 '애플리케이션 호출' 단계에서 사용된다.
- 이 단계가 끝난뒤 존재하는 이벤트를 관련 리스너로 전달한다.
- 모든 랜더러, 컴포넌트, 리스너는 생명주기를 단축시켜 이 단계를 건너뛰거나 바로 최종단계로 넘어갈 수도 있다.
- 또는 각각의 입력 컴포넌트가 적절하게 디코딩된 속성을 가지고 현재 요청에 기반한 최신 값을 가지고 있을 것이다.



top

Write a comment.


2장 JSF 요청 처리 생명주기 - Phase 1. 뷰 복원하기

JSF/JSF in Action : 2010.01.05 21:37


Restore View

- 뷰는 특정 페이지를 구성하는 모든 컴포넌트를 나타낸다. 
- 브라우저 위에 히든 필드를 이용해서 클라이언트에 저장될 수도 있고, 세션을 이용해서 서버에 저장될 수도 있다. 서버에 저장되는게 기본값이다.
- 각각의 뷰는 컴포넌트 트리로 구성되며 고유의 식별자를 가지고 있다. 그 식별자를 "뷰 식별자"라고 한다. View identifier
- 뷰 식별자는 요청에서 특수한 경로에 해당한다. 서블릿 경로 이후의 값이 뷰 식별자가 된다. 예) http://spirngsprout.org/study/35.do 에서 /study/35.do
- 폼을 보여준 페이지와 동일한 페이지로 다시 포스팅 요청을 하는 것을 포스트백(postback)이라고 한다.
- 기존의 프레임워크와 차이: "이 액션을 수행하라." VS "사용자가 이 명령을 실행했다.", "사용자가 이 컨트롤의 값을 변경했다."
- 이때 중요한 것은 최종 페이지가 어떤 것이며, 그곳에서 어떤 이벤트가 발생했는냐 이다.
- 현재 뷰를 찾아서 사용자가 입력한 내용을 거기에 적용하는 것이 이 단계의 주요 작업 중 하나이다. 
- 세션에서 뷰를 찾아 본 뒤에 뷰가 있으면 그것을 가져와서 FacesContext에 저장하고, 없으면 새로 요청한 뷰 식별자를 기반으로 새로운 뷰를 만들어서 FacesContext에 저장한다.
- 뷰를 복원하는 단계에서 컴포넌트의 값은 물론이고 그와 관련된 이벤트 리스너, 검증기, 변환기도 복원됐는지 확인한다.
- 백빈의 속성에 바인딩되어 있는 컴포넌트의 경우에는 이 단계에서 백빈의 속성과 컴포넌트가 동기화된다.
- 브라우저가 보낸 HTTP 요청의 헤더를 통해 뷰에 사용할 언어를 설정한다.
- 요청이 포스트백일 경우에는 다음 단계로 넘어가고, 그외의 경우에는 처리할 사용자 입력이 없기 때문에 응답 랜더링(Render Response) 단계로 넘어간다.

 
top

Write a comment.


2장 JSF 기본 - 요청 처리 생명주기

JSF/JSF in Action : 2010.01.04 18:11


뷰 복원하기(restore view) - 선택한 뷰에대한 컴포넌트 트리를 찾거나 만드는 단계.  HtmlCommandButton 같은 컴포넌트에서 액션 이벤트를 발생 시킨다.

요청 값 적용하기(Apply Request Values) - 컴포넌트의 값들을 요청에 담겨있는 값과 동일하게 맞춘다. 이 과정에서 변환기(Converter)가 사용될 수 있으며,  변환시 에러가 발생하면 변환 에러를 추가한다.

검증 수행(Process Validations) - 모든 컴포넌트가 각자 검증을 수행하도록 지시한다. 검증 에러 메시지가 보고될 수 있다.

모델 값 갱신(Update Model Values) - 컴포넌트에 연결된 백빈(backing bean) 또는 모델 객체의 값을 갱신한다.  변환 에러가 보고 될 수 있다.

애플리케이션 호출(Invoke Application) - 등록된 액션 리스너를 호출한다. 

응답 랜더링(Render Response) - 선택한 뷰를 보여준다.



top

Write a comment.


SWF 12장 JSF 통합



12.1. 도입

스프링 Faces는 스프링의 JSF 통합 모듈로 스프링에서 JSF 사용을 간편하게 해준다. JSF UI 컴포넌트 모델을 스프링 MVC와 스프링 웹 플로우 컨틀로러와 함께 사용할 수 있게 해준다.

스프링 Faces는 또한 Ajax와 클리이언트쪽 검증 기능을 제공하는 자그마한 Facelets도 제공한다. 이 컴포넌트 라이브러리는 스프링 자바스크립트를 기반으로 만들었다. 스프링 자바스크립트는 Dojo를 기반 UI 툴킷으로 통합한 자바스크립트 추상화 프레임워크드다.

12.2. 스프링-중심 통합 방법

스프링 Faces는 JSF의 UI 컴포넌트 모델 장정을 스프링의 컨트롤러와 설정 모델 장점과 결합해준다. 아무런 약점없이 JSF의 모든 장점을 활용할 수 있다.

스프링 Faces는 표준 JSF 기능에 다음과 같은 강력한 보완재를 제공한다.

  1. managed bean facility
  2. scope management
  3. event handling
  4. navigation rules
  5. easy modularization and packaging of views
  6. cleaner URLs
  7. model-level validation
  8. client-side validation and UI enhancement
  9. Ajax partial page updates and full navigation
  10. progressive enhancement and graceful degradation

이 기능을 사용하면 faces-config.xml에 필요한 설정 분량을 현격하게 줄여줄 것이며 뷰와 컨트롤러 계층을 보다 깔끔하게 분리해주며 애플리케이션의 기능 책임 모듈화를 보다 잘 지원한다. 이 기능들의 사용법은 다음 절에서 살펴보겠다. 이 기능들 대부분은 스프링 웹 플로우의 플로우 정의 언어를 기반으로 한다. 여러분이 플로우 정의하기에 나와있는 기본을 이해하고 있다고 가정한다.

12.3. web.xml 설정하기

스프링 Faces를 사용하는 첫 번째 단계는 요청을 web.xml 파일에 있는 DispatcherServlet으로 라우팅하는 것이다. 이번 예제에서, 우리는 /spring/으로 시작하는 모든 URL을 서블릿으로 맵핑한다. 서블릿을 설정해야 한다. init-param을 사용하여 서블릿에 contextConfigLocation을 넘겨준다. 이 것은 애플리케이션의 스프링 설정 파일 위치다.

<servlet>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/web-application-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
   
<servlet-mapping>
    <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
    <url-pattern>/spring/*</url-pattern>
</servlet-mapping>
       
JSF를 적절하게 동작시키려면, FacesServlet을 web.xml에 설정해야 한다. 스프링 Faces를 사용할 때는 그것을 사용하여 요청을 라우팅할 필요가 없다.

<!-- Just here so the JSF implementation can initialize, *not* used at runtime -->
<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
   
<!-- Just here so the JSF implementation can initialize -->
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>
       
스프링 Faces  컴포넌트를 사용할 때에도 스프링 자바스크립트 ResourceServlet을 설정하여 컴포넌트에서 CSS와 자바스크립트 리소스를 제대로 출력할 수 있게 할 필요가 있다. 이 서블릿은 반드시 /resources/*로 맵핑해야 컴포넌트에서 랜더링한 URL에 대해 제대로 동작한다.

<!-- Serves static resource content from .jar files such as spring-faces.jar -->
<servlet>
    <servlet-name>Resource Servlet</servlet-name>
    <servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
</servlet>
       
<!-- Map all /resources requests to the Resource Servlet for handling -->
<servlet-mapping>
    <servlet-name>Resource Servlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
</servlet-mapping>
       
스프링 Faces 컴포넌트는 JSP 대신에 Facelet을 사용해야 한다. 따라서 이들 컴포넌트를 사용하려면 일반적인 Facelet 설정을 반드시 추가해야 한다.

!-- Use JSF view templates saved as *.xhtml, for use with Facelets -->
<context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
</context-param>
       
12.4. JSF 뷰 랜더링 하도록 웹 플로우 설정하기

The next step is to configure Web Flow to render JSF views. To do this, in your Spring Web Flow configuration include the faces namespace and link in the faces flow-builder-services :

다음 단계는 JSF 뷰를 랜더링 하도록 웹 플로우를 설정하는 것이다. 그렇게 하려면 스프링 웹 플로우 설정에 faces 네임스페이스를 추가하고

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns:faces="http://www.springframework.org/schema/faces"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
           http://www.springframework.org/schema/faces
           http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">

    <!-- Executes flows: the central entry point into the Spring Web Flow system -->
    <webflow:flow-executor id="flowExecutor" />

    <!-- The registry of executable flow definitions -->
    <webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices" base-path="/WEB-INF">
        <webflow:flow-location-pattern value="**/*-flow.xml" />
    </webflow:flow-registry>

    <!-- Configures the Spring Web Flow JSF integration -->
    <faces:flow-builder-services id="facesFlowBuilderServices" />

</beans>
       
faces:flow-builder-services 태그는 JSF 환경에 적절한 다른 기본 값들도 설정한다. 특히 Unified EL을 기본 EL로 설정한다.

완전히 동작하는 예제는 배포판에서 swf-booking-faces 레퍼런스 애플리케이션을 참고하라.

12.5. faces-config.xml 설정하기

faces-config.xml에 유일하게 설정할 필요가 있는 것은 Facelet 사용에 대한 것이다. 만약 스프링 Faces 컴포넌트를 사용하지 않고 JSP를 사용하고 있다면, 어떠한 스프링 Faces 관련 설정도 faces-config.xml에 추가하지 않아도 된다.

<faces-config>
    <application>
        <!-- Enables Facelets -->
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> 
    </application>
</faces-config>
       
12.6. JSF가 관리하는 빈 기능 교체하기

스프링 Faces는 JSF가 관리하는 빈 기능을 플로우가 관리하는 변수와 스프링이 관리하는 빈으로 완전히 교체할 수 있게 해준다. 그렇게 하여 여러분이 관리하는 객체를 잘 정의되어 있는 초기화 후크와 도메인 객체 실행 후크로 생명 주기를 보다 잘 관리할 수 있다. 게다가, 여러분이 이미 비즈니스 계층에서 스프링을 사용해봤다는 가정한다면, 두 개의 다른 빈 관리 모델을 유지하는 것에 대한 개념적인 오버헤드를 줄일 수 있다.

순수 JSF 개발을 할 떄는 request 스코프로는 복잡한 이벤트-기반 뷰를 다루는 대화형 모델 객체를 저장하기에는 적당하지 않다는 것을 금방 알 수 있을 것이다. 오직 사용할 수 있는 옵션은 session 스코프에 모든 것들을 넣는 것이다. 애플리케이션의 다른 뷰 또는 기능적인 부분을 처리할 때 객체들을 청소해줘야 한다는 추가 작업이 생긴다. 정말로 필요한 것은 request와 session 스코프 중간 쯤 되는 어떤 스코프가 필요하다. 우누 좋게도 웹 플로우는 그러한 확장 기능을 제공한다.

12.6.1. 플로우 변수 사용하기

가장 간단하고 자연스럽게 모델을 선언하고 관리하는 것은 플로우 변수를 사용하는 것이다. 이 변수들을 플로우 시작시에 선언할 수 있다.

<var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>
           
그런 다음 이 변수를 플로우 중 어떤 JSF 뷰 템플릿에 EL을 통해서 참조한다.

<h:inputText id="searchString" value="#{searchCriteria.searchString}"/>
           
(좀 더 구체적일 필요가 있다면 그렇게 할 수도 있지만)템플릿에서 변수를 참조할 때 그 스코프로 접두어를 붙이지 않아도 된다는 것에 주목하라. 표준 JSF 빈으로 대응하는 변수에 대해 모든 사용 가능한 스코프에서 찾아볼 것이다. 따라서 EL 표현식을 수정하지 않고도 플로우 정의에서 그것을 참조하는 변수의 스코프를 변경할 수 있다.

또한 뷰 인스턴스 변수를 현재 뷰로 범위를 제한하고 다른 뷰로 이동하면 자동으로 비워버리게 정의할 수 있다. 이렇게 하는 것은 보통 페이지 내에서 다른 뷰로 전이하기 전에 여러 여러 요청에 걸쳐 이벤트를 처리하는 JSF 뷰에서 매우 유용하다.

뷰 인스턴스 변수를 정의할때 var 엘리먼트를 view-state 정의 내부에서 사용할 수 있다.

<view-state id="enterSearchCriteria">
    <var name="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria"/>
</view-state>
           

12.6.2. 스코프를 가진 스프링 빈 사용하기

비록 자동 연결 플로우 인스터스 변수가 괜찮은 모듈화와 가독성을 제공하지만 가끔 여러분은 AOP 같은 스프링 컨테이너의 기능을 활용하고 싶을 수 있다. 그런 경우 여러분은 스프링 애플리케이션컨텍스트 내부에 있는 빈에 특정 웹 플로우 스코프를 줄 수 있다.

<bean id="searchCriteria" class="com.mycompany.myapp.hotels.search.SearchCriteria" scope="flow"/>
           
이런 접근 방법의 가장 큰 차이점은 EL 표현식에 의해 접근될 때 비을 초기화 한다는 것이다. EL을 통한 이런 종류의 생성 지연은 JSF가 관리하는 빈이 할당되는 것과 매우 비슷하다.

12.6.3. 모델 조작하기

뷰 랜터링 하기 전에 (데이터베이스에서 영속 엔티티를 로딩하는 것 같은)모델 초기화가 필요한 것은 매우 흔한 일이지만 JSF 자체로는 이러한 초기화에 사용할 편의성 후크(hook)를 제공하지 않는다. 플로우 정의 언어는 액션(Action)을 통해서 이와 관련된 자연스러운 기능을 제공한다. 스프링 Faces는 액션의 결과를 JSF-관련 데이터 구조로 변경해주는 추가적인 편의성을 제공한다. 예제를 보자.

<on-render>
    <evaluate expression="bookingService.findBookings(currentUser.name)"
              result="viewScope.bookings" result-type="dataModel" />
</on-render>
         
이렇게 하면 bookingService.findBookings 매서드 결과를 취하고 그것을 표준 JSF DataTable 컴포넌트에서 해당 목록을 사용할 수 있도록 커스텀 JSF DataModel로 감싼다.

<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking"
             rendered="#{bookings.rowCount > 0}">
    <h:column>
        <f:facet name="header">Name</f:facet>
        #{booking.hotel.name}
    </h:column>                  
    <h:column>
    <f:facet name="header">Confirmation number</f:facet>
        #{booking.id}
        </h:column>
    <h:column>
        <f:facet name="header">Action</f:facet>
        <h:commandLink id="cancel" value="Cancel" action="cancelBooking" />
    </h:column>
</h:dataTable>
           
커스텀 DataModel은 request 스코프 외의 저장을 위한 직렬화와 EL에서 현재 선택한 줄에 대한 접근 등 몇몇 추가적인 편의성을 제공한다. 예를 들어, DataTable 내의 컴포넌트에 의해 액션 이벤트가 발생한 뷰에서 포스트백 할 때, 여러분은 선택한 줄의 모델 인스턴스를 가질 수 있다.

<transition on="cancelBooking">
    <evaluate expression="bookingService.cancelBooking(bookings.selectedRow)" />           
</transition>
           
12.7. 스프링 웹 플로우로 JSF 이벤트 처리하기

스프링 웹 플로우는 낮은 결합도를 유지하면서 JSF 액션 이벤트를 처리할 수 있게 해준다. 자바 코드에서 JSF API에 의존하지 않아도 된다. 이벤트를 커스텀 자바 액션 코드를 전혀 사용하지 않고 플로우 정의 언어를 사용하여 완전하게 처리할 수 있다. 이렇게 하면 (JSF 뷰 템플릿과 SWF 플로우 정의) 이벤트를 연결할 때 만들어지는 구성물들을 전체 애플리케이션을 빌드하고 다시 배포할 필요 없이 즉시 리프래시 되기 때문에 보다 기민한 개발 프로세스가 가능해진다.

12.7.1. JSF In-page 액션 이벤트 처리하기

간단하지만 JSF에서 가장 흔한 경우가 모델을 조작하는 이벤트를 발생시키고 동일한 뷰로 모델의 변경된 상태를 보여주는 것이다. 플로우 정의 언어는 transition 엘리먼트에서 이것을 지원한다.

이 것에 대한 좋은 예제는 페이징 처리를 하는 목록 표다. 거대한 결과 목록 중의 일부만 읽어오고 보여주고 싶다고 가정해보자. 그리고 사용자는 그 결과를 페이징할 수 있다. 목록을 읽어오고 보여주는 초기 view-state 정의는 다음과 같다.
 
<view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
                  result="viewScope.hotels" result-type="dataModel" />
    </on-render>
</view-state>
           

JSF DataTable로 현재 호텔 목록을 보여주도록 할 수 있다. 그런 다음 표 하단에 "More Results" 링크를 제공한다.
 
<h:commandLink id="nextPageLink" value="More Results" action="next"/>
           
이 커맨드링크는 action 속성에서 "next" 이벤트를 보낸다. 그럼 여러분은 이벤트를 view-state 정의에 추가하려 처리할 수 있다.
 
<view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
            result="viewScope.hotels" result-type="dataModel" />
    </on-render>
    <transition on="next">
        <evaluate expression="searchCriteria.nextPage()" />
    </transition>
</view-state>
           
여기서 searchCriteria 인스턴스에서 page 카운트를 증가하여 "next" 이벤트를 처리한다. 그럼 다음 on-render 액션을 변경된 criteria로 호출한다. 그러면 다음 페이지 결과를 DataModel로 로딩해준다. transition  엘리먼트에 to 속성이 없기 때문에 동일한 뷰를 다시 보여준다. 그리고 모델에 변경된 사항을 뷰에 반영해준다.

12.7.2. JSF 액션 이벤트 처리하기

in-page 이벤트 다음 단계는 조작한 모델을 가지고 다른 뷰로 이동하는 이벤트다. 순수 JSF로 이것을 하려면 faces-config.xml에 네비게이션 로직을 추가하고 자바 코드를 JSF가 관리하는 빈에 추가해야 한다.(두 작업 모두 다시 배포해야 한다.) 플로우 정의 언어를 사용하면, in-page 이벤트를 다루던 방식과 매우 비슷하게 한 곳에서 그런 것을 다룰 수 있다.

계속해서 페이징 처리하는 목록을 살펴보자. 보여지는 DataTable의 각각의 row에 row 인스턴스에 대한 자세한 내용 페이지 링크를 가지고 있도록 하고자 한다. 여러분은 테이블에 다음의 commandLink 컴포넌트를 가지고 있는 컬럼을 추가할 수 있다.

<h:commandLink id="viewHotelLink" value="View Hotel" action="select"/>
           
이것은 "select" 이벤트를 발생시킨다. 그다음 기존의 view-state에 또 다른 transition 엘리먼트를 추가하여 이것을 처리할 수 있다.
 
<view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
            result="viewScope.hotels" result-type="dataModel" />
    </on-render>
    <transition on="next">
        <evaluate expression="searchCriteria.nextPage()" />
    </transition>
    <transition on="select" to="reviewHotel">
            <set name="flowScope.hotel" value="hotels.selectedRow" />
    </transition>
</view-state>
           
여기서 "select" 이벤트는 DataTable에서 현재 선택한 hotel 인스턴스를 플로우 스코프에 넣어서 처리하고 있다. 그렇게 하면 "reviewHotel" view-state에서 참조할 것이다.

12.7.3. 모델 검증 수행하기

JSF는 변경 사항을 모델에 반영하기 전에 필드-수준 입력 검증 관련 유용한 기능을 제공한다. 하지만 변경 사항을 적용한 뒤에 모델-수준의 좀 더 복잡한 검증을 수행할 필요가 있다면 여러분은 관리하는 빈의 JSF 액션 매서드에 커스텀 코드를 추가해야 한다. 이런 종류의 검증은 모메인 모델 자체 책임이지만 도메인 모델 계층에 원하지 않던 JSF API 의존성을 추사하지 않고서는 에러 메시지를 뷰에 전달하기가 어렵다.

스프링 Faces를 사용하면 일반적이고 낮은-수준의 MessageContext를 여러분의 비즈니스 코드에서 유용하게 사용할 수 있고 그곳에 추가한 모든 메시지는 랜더링 시에 FacesContext에서 사용할 수 있다.

예를 들어, 사용자가 호텔 예약을 완료하기 위해 필요한 상세 정보를 입력하는 뷰가 있다고 가정하자. 여러분은 거기서 입력받은 체크인 체크아웃 날짜가 비즈니스 규칙에 맞는지 확인해야 한다. transition 엘리먼트에서 그러한 모델-수준 검증을 호출할 수 있다.
 
<view-state id="enterBookingDetails">
    <transition on="proceed" to="reviewBooking">
        <evaluate expression="booking.validateEnterBookingDetails(messageContext)" />
    </transition>
</view-state>
          
여기서 "proceed" 이벤트는 booking 인스턴스의 모델-수준 검증 매서드를 호출하여 처리한다. 매서드를 호출할 때 MessageContext 인스턴스를 넘겨줘서 메시지를 기록할 수 있게 한다. 그런다음 h:messages 컴포넌트를 사용하여 JSF 메시지를 보여줄 수 있다.

12.7.4. Ajax 이벤트 처리하기

스프링 Faces는 표준 JSF 컴포넌트에 Ajax-기반 일부 뷰 수정 기능을 추가한 몇몇 특별한 UICommand 컴포넌트를 제공한다. 이들 컴포넌트는 사용자가 사용하는 브라우져의 기능이 떨어진다면 전체 페이지를 리프래시 하여 모두 잘 동작할 것이다.

[노트] 노드
스프링 Faces의 코어 JSF 지원이 JSF 1.1 호환가능 하지만, 스프링 Faces Ajax 컴포넌트는 JSF 1.2를 필요로 한다.

Revisiting the earlier example with the paged table, you can change the "More Results" link to use an Ajax request by replacing the standard commandButton with the Spring Faces version (note that the Spring Faces command components use Ajax by default, but they can alternately be forced to use a normal form submit by setting ajaxEnabled="false" on the component):

           
<sf:commandLink id="nextPageLink" value="More Results" action="next" />
           

This event is handled just as in the non-Ajax case with the transition element, but now you will add a special render action that specifies which portions of the component tree need to be re-rendered:

<view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria)"
                  result="viewScope.hotels" result-type="dataModel" />
    </on-render>
    <transition on="next">
        <evaluate expression="searchCriteria.nextPage()" />
        <render fragments="hotels:searchResultsFragment" />
    </transition>
</view-state>
           

The fragments="hotels:searchResultsFragment" is an instruction that will be interpreted at render time, such that only the component with the JSF clientId "hotels:searchResultsFragment" will be rendered and returned to the client. This fragment will then be automatically replaced in the page. The fragments attribute can be a comma-delimited list of ids, with each id representing the root node of a subtree (meaning the root node and all of its children) to be rendered. If the "next" event is fired in a non-Ajax request (i.e., if JavaScript is disabled on the client), the render action will be ignored and the full page will be rendered as normal.

In addition to the Spring Faces commandLink component, there is a corresponding commandButton component with the same functionality. There is also a special ajaxEvent component that will raise a JSF action even in response to any client-side DOM event. See the Spring Faces tag library docs for full details.

An additional built-in feature when using the Spring Faces Ajax components is the ability to have the response rendered inside a rich modal popup widget by setting popup="true" on a view-state .

<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">
    <on-entry>
        <render fragments="hotelSearchFragment" />
    </on-entry>
    <transition on="search" to="reviewHotels">
        <evaluate expression="searchCriteria.resetPage()"/>
    </transition>
</view-state>
           

If the "changeSearchCriteria" view-state is reached as the result of an Ajax-request, the result will be rendered into a rich popup. If JavaScript is unavailable, the request will be processed with a full browser refresh, and the "changeSearchCriteria" view will be rendered as normal.

'Spring Web Flow > Chapter 12' 카테고리의 다른 글

SWF 12장 JSF 통합  (0) 2009.03.10
top

Write a comment.


Validator에도 여러 가지가 있네

모하니?/Coding : 2008.11.15 23:15


JSF 스캐(스크린캐스팅)를 찍다가 알게 된건데, 기본 검증기, Application-level 검증, 커스텀 검증기, 표준 검증기가 있었습니다.

기본 검증기는 프레임워크에서 제공하는 것으로 JSF에는 길이 검사라던가, 숫자가 최소치와 최대치 사이의 값인지 범위를 검사할 수 있는 기본 Validator들을 제공하고 있었습니다. 스프링 MVC는 어떨까요? 글쎄요. 없는 것 같네요. ValidationUtils는 있지만 JSF 처럼 간단하게 뷰에서 바로 써먹을 수 있는 건 없는 것 같습니다.

다음은 폼에서 이미 검증을 마쳐서 모델에 사용자가 입력한 데이터를 담은 상태로 비즈니스 로직을 검사하는 검증입니다. 이 검증은 프레임워크에 독립적이며 도메인 클래스가 해당 로직을 가지고 있기도 합니다. 예를 들어.. member.validateBy주민번호() 같은 메소드(주민등록 번호로 성별과 생년 월일이 일치하는지 검사하는 로직)를 만들고 이를 컨트롤러에서 호출한 다음에 예외를 잡아서 화면에 어떤 에러 메시지를 출력하는 방법이 있겠습니다. 비즈니스 로직에 적합한지 검사하려면 역시 화면에 붙어있는 검증기와는 별개로 이런게 필요한 것 같습니다. 스프링MVC에서도 검증 로직이 순전히 도메인 레벨에서 가능하다면 이런 식으로 검증할 수도 있겠습니다.

다음은 검증기는 검증기인데, 특정 인터페이스를 따르지도 않고 완전한 POJO 검증기 입니다. 위에서 애플리케이션 검증 로직을 별도의 클래스로 빼내고 그 로직을 뷰에서 값을 입력 받을 때 호출하게 하는 건데, JSF의 EL은 메소드 호출도 정말 간단하게 할 수 있더군요. 그냥 이런 검증기를 managed-bean으로 등록하고 그 로직을 호출하면 됐습니다. 검증 로직을 별도의 클래스로 분리하고 한 곳에서 관리할 때 좋겠습니다.

마지막은 스프링이 제공하는 Validator인터페이스 처럼 프레임워크의 틀에 맞는 검증기를 구현하고 그것을 설정하여 사용하는 겁니다. JSF에도 그런 구조가 갖춰져 있죠. 이 걸 사용하는 장점은 어떤 틀이 있기 때문에 위처럼 중구 난방으로 작성할 수 있는 코드에 규약을 정하고 그걸 따르는 검증기를 공유할 수 있다는 겁니다. JSF는 스프링 @MVC와 달리 이 검증 로직 실행을 프레임워크의 Phase 중에서 Validation Phase에 하기 때문에 이 검증 로직을 만족하지 못하면 모델에 값이 들어갈 수가 없습니다. 스프링은 아니죠. 일단 모델에 값을 받은 상태에서 검증을 하는거죠.

흠~~ 그래서 결론적으로 생각해볼 때, 여러 검증 단계와 방법을 제공하는 건 JSF가 더 좋아보이지만, 모델에 값을 설정한 상태에서 Validator라는 규격을 가지고 그 안에서 비즈니스 로직 검사도 수행(application-level 검증)도 할 수 있는.. 스프링 MVC의 단순한 구조가 오히려 개발을 더 깔끔하게 할 수 있게 해주지 않나 생각합니다. 모든 개발자가 검증 로직을 사방한대서 한다고 생각하면.. 어휴.. 끔찍하죠.ㅋㅋ
top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2008.11.16 06:55 PERM. MOD/DEL REPLY

    spring-modules에 보면 view단에서 쓰는 배리데터도 있어.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.16 12:38 신고 PERM MOD/DEL

    오호.. 그렇군요.

Write a comment.


JSF의 universal EL

JSF/exercise : 2008.09.20 11:21


참조 : http://www.ibm.com/developerworks/edu/j-dw-java-jsf1-i.html

JSP의 EL은 JavaBean 스펙에 따른 게터, 세터만 사용하는데 비해, JSF의 universal EL은 다른 메소드 호출도 됩니다.

<table>
<tr>
<td><h:outputLabel value="First Number" for="firstNumber" /></td>
<td><h:inputText id="firstNumber"
value="#{calculator.firstNumber}" required="true" /></td>
<td><h:message for="firstNumber" /></td>
</tr>
<tr>
<td><h:outputLabel value="Second Number" for="secondNumber" />
</td>
<td><h:inputText id="secondNumber"
value="#{calculator.secondNumber}" required="true" /></td>
<td><h:message for="secondNumber" /></td>
</tr>
</table>

굵게 표시한 부분이 universal EL인데, 뒷단 빈의 속성 값과 연결해 줍니다.

<div>
<h:commandButton action="#{calculator.add}" value="Add" />
<h:commandButton action="#{calculator.multiply}" value="Multiply" />
<h:commandButton action="#{calculator.clear}" value="Clear" immediate="true"/>
</div>

그리고 위 코드에 있는 EL은 add(), multyply() 등의 메소드를 호출해줍니다. 모든 액션 메소드를 호출하기 전에 폼 검증 단계를 거치는데, immediate="true"를 사용하면 그 과정을 생략하고 바로 메소드를 호출합니다.

꺄오.. JSF 괜찮은거 같은데~

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top

Write a comment.


Spring Faces 소개하기, 파트 1

JSF/article : 2008.09.18 10:15


참조, 요약, 번역: http://www.jsfcentral.com/articles/intro_spring_faces_1.html

JavaServer Faces와 스프링의 연동을 돕는 Spring Faces라는 모듈이 있는데, 이 모듈을 Spring Web Flow 2에 도입했다. 본 기사는 Spring Faces에 대한 첫 번째 기사로, JSF 기준과 Spring 기준으로 각각 두 프레임워크를 통합하는 방법을 살펴볼것이다.

스프링은 예전부터 기본적인 JSF 연동을 자체 웹 모듈에서 지원해왔다. 기존 JSF 웹 계층과 스프링이 관리하는 비즈니스 계층 사이를 연결해주는 형태였다. 이 방법을 'JSF-기준 연동'이라고 한다. 이 방법으로도 잘 사용해왔지만, 스프링 웹 팀은 그 둘 사이에 뭔가 잘 안 맞는 것.. 너무 많은 구성물과 너무 많은 개념적인 오버헤드가 생겨서 관리하기 쉽지 않다는 것을 느꼈다.

스프링 Faces는 시야를 바꿔서 통합에 대한 접근 방법을 전환했다. 즉 스프링 기반 웹 애플리케이션에 JSF의 장점을 끌어오는 것을 목표로 했다. 이것은 '스프링-기준 연동'이라는 접근 방법으로 JSF UI 컴포넌트 모델을 사용하여 웹 애플리케이션 개발을 하는 것이다. 본 기사에서는 이 접근 방법의 장점과 왜 이것을 JSF과 스프링 개발자에게 권하는지 살펴보자.

JSF와 스프링 - 완벽한 조화인가?

JSF는 그 자체로 rich 웹 애플리케이션을 개발할 때 매우 많은 장점을 제공한다. 특히 복잡한 UI를 가지고 상태를 유지하는(stateful) 프로그래밍 모델을 필요한 곳에서 말이다. 이 UI 컴포넌트 모델들은 견고하며 강력하다. 제대로 적용하면, 웹 브라우져서에서 복잡한 컨트롤을 만들어야 하는 복잡도를 낮출 수 있다. 풍족한 UI를 선언적으로 만들 수 있고, 통합 EL을 사용하여 개별 컨트롤을 직접 도메인 모델에 유연하게 바인딩할 수 있기 때문에, 보다 빠르게 복잡한 웹 UI를 개발할 수 있다. 이 모든 것을 간단한 POJO 프로그래밍 모델로 달성할 수 있다.

스프링을 JSF를 앞단에 둔 애플리케이션의 도메인 계층에 적용하는 것이 자연스럽고 이상적이다. POJO 프로그래밍 모델을 이용할 수 있기 때문이다. JSF의 풍부하고 잘 정의된 확장 포인트를 사용하면, 스프링이 관리하는 비즈니스 계층을 JSF 앞단에 간단하게 연결할 수 있다.

EL을 사용한 JSF-기준 연동

JSF-기준 연동은, JSF 컨트롤러 모델이 애플리케이션을 주고하고 JSF가 관리하는 빈을 스프링 비즈니스 계층과 연결한다. 스프링은 몇몇 연동 클래스를 제공하여 faces-config.xml에서 스프링 빈을 참조할 수 있게 하는 것이다. 가장 흔한 방법으로는 DelegatingVariableResolver 를 사용하면, EL을 사용하여 스프링 빈을 참조할 수 있다. EL을 사용해서 스프링 빈을 JSF가 관리하는 빈에 주입하는 것이다. 예를 들어, WebApplicationContext에 다음과 같은 빈이 있다고 치자.

<bean id="mySpringService" class="com.foo.MySpringServiceImpl">

EL을 사용해서 faces-config.xml에 정의한 <managed-bean>에서 이 빈을 JSF가 관리하는 빈에 주입할 수 있다.

<managed-bean>
  <managed-bean-name>myJsfManagedBean</managed-bean-name>
  <managed-bean-class>com.foo.MyJsfManagedBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>mySpringService</property-name>
    <value>#{mySpringService}</value>
  </managed-property>
</managed-bean>

즉 이렇게 하면, 스프링이 관리하는 싱글톤 서비스를 JSF가 매번 생성하는 객체에 주입할 수 있다. 스프링 2.0부터, request와 session 스콥을 사용할 수 있기 때문에, JSF 관리하는 빈을 모두 없애고, EL로 스프링 컨트롤러를 사용할 수도 있다.

JSF-기준 접근방법으로 충분한가?


스프링의 간단한 JSF 연동 클래스로, 부드럽게 스프링이 관리하는 서비스를 JSF 기반 앞 단과 통합할 수 있었다. 하지만, 이것으로 충분한가? 나는 그렇지 않다고 확신한다. 이 방법은 JSF 컨트롤러 모델을 사용하고 있는데, 여기에 몇 가지 단점들이 존재한다.
  • 순수-MVC 접근방법에 따라, 모든 것이 뷰를 렌더링하는것으로 주도된다. 랜더링 전에 모델을 초기화 하는 편리한 포인트가 없다.
  • 성가신 네비게이션 모델은 여러분이 실수를 해도 거의 피드백이 없다.(오타가 있어도 말이다.) 그리고 규칙이 추가되거나 변경될 때마다 애플리케이션을 다시 시작해야 한다.
  • 검증 모델이 충분하지 않다. 서버쪽에서의 필드 수준 검증을 중심으로 하고 있다. 컴포넌트 트리를 순회하지 않고도 클라이언트쪽 필드 검증과 서버쪽 모델 검증을 수행할 수 있는 편리한 방법이 필요하다.
  • URL 맵핑이 좀 유연하지 않고, 리다이렉트 지원이 충분치 않다.
  • request와 session 사이의 보다 세밀한 스콥프가 필요하다. 특히 페이지 내에서 여러번 이벤트를 발생시키는 Ajax 기반 뷰의 경우에 그렇다.
  • 예외 처리 기능이 매우 제한적이다. 특히 뷰 랜더링할 때 그렇다.
  • 컨트롤러 로직이 JSF 빈으로 분산되어 있다. 단위 테스트하기가 힘들고 변경할 때마다 애플리케이션을 다시 시작해야 한다.
JSF의 UI 컴포넌트 모델은 견고하다. 그 행위 들은 잘 정의되어 있는 JSF 컴포넌트 라이프사이클 경계 내에서 실행되고 캡슐화되어 있다. 하지만 컨트롤러 모델은 다소 제한적이다. 특히 스프링, 스프링 MVC, 스프링 Web Flow의 유연함과 막강함을 사용하고자 하는 사람들에게 더 제한적으로 느껴진다. 또한 이 접근 방법은 개념적인 오버헤드를 발생시킨다. faces-config.xml, JSF가 관리하는 빈, JSF 뷰 템플릿 그리고 스프링 기반 비즈니스 계층의 모든 컴포넌트를 계속해서 관리해야 한다.

처음에는, 스프링 Web Flow 1.x도 JSF-기준 방법으로 연동을 시도했었다. 하지만, 이 방법이 너무 제한적었다. 여전히 많은 JSF 구성요소를 사용했고 제대로 동작하려면 faces-config.xml에 뭔가를 추가해야 했다. agile이라고 할 수 없었다.

만약에 JSF의 UI 컴포넌트 모델을 스프링 환경에 연동할 수 있으면 어떨까 고민을 했다. 스프링 프로그래밍 모델을 사용하고 보다 스프링을 기준으로 한 접근 방법으로 말이다. 만약 스프링이 전체 요청을 관리하면, 여러분은 보다 편리하게 전체 애프리케이션 설정을 관리할 수 있고 편하게 프로그래밍을 할 수 있을 것이다. 또한 스프링 MVC의 유연한 라우팅 기반 시설과 스프링 Web Flow 2.x의 agile statefule 컨트롤러 모델을 사용할 수 있겠다. 이는 stateful JSF 뷰와 잘 어울린다. 바로 이러한 동기로 인해 스프링 Faces가 생겼고 스프링 포트폴리오에 추가됐다.

스프링 Faces의 스프링-기준 JSF


스프링 Faces는 JSF와 스프링 연동에 있어서 훨씬 규범적인(prescriptive)-미리 무언가를 예상하고 마련해 두는- 접근방법을 채택했다. JSF의 막강함은 그가 제공하는 여러 확장 포인트인데, 스프링 Faces는 이 모든 장점을 수용하여 JSF를 보다 자연스럽게 스프링에 녹아들게 했다. 환경에 대해 몇가지 가정을 세웠다. 일단 스프링 MVC DispatcherServlet을 사용하여 요청 처리를 라우팅하고, 스프링 Web Flow 2.x의 기초 컨트롤러 모델을 사용한다. 또, 스프링 JavaScript 모듈을 사용하여 경량 JSF Ajax 컴포넌트를 제공한다고 가정했다. (스프링 Faces는 어떠한 JSF 컴포넌트 라이브러리도 사용할 수 있도록 설계했기 대문에, 이들 컴포넌트는 전부 옵션이기 필수가 아니다.)

사용자 삽입 이미지
그림 1. 스프링 Faces 아키텍처에 대한 하이 레벨 뷰

본 기사 남은 부분에서, 스프링 Web Flow 2 배포에 포함되어 있는 Spring Travel에 스프링 Faces를 적용해볼 것이다.

전체 스프링 Faces 예제 소스는 /project/spring-webflow-samples/booking-faces/에 있다.

이미 동작하고 있는 예제가 필요하다면, 여기를 클릭하라.

스프링 Faces 예제의 구조

먼저 살펴볼 것은  /src/main/webapp/WEB-INF/faces-config.xml 다. 이 안에 설정한 것은 오직 FaceletViewHandler 뿐이고, 스프링 Faces가 보다 미리 마련해두는 방식을 채택했기 때문에, 모든 JSF 연동에 필요한 구성물들은 자동으로 클래스패스에 있는 spring-faces.jar에 포함되어 있다.

또한 다음 파일들을 살펴보고 라우팅에 대한 기본 설정에 익숙해져야 할 것이다.

  • /src/main/webapp/WEB-INF/web.xml
  • /src/main/webapp/WEB-INF/config/webmvc-config.xml
  • /src/main/webapp/WEB-INF/config/webflow-config.xml
이 설정에 대해선느 스프링 Web Flow 2 레퍼런스 가이드에 나와있으니 자세히 설명하진 않겠다. 다만 이 설정의 결과만 설명하겠다.

/spring 이하의 모든 요청은 스프링 DispatcherServlet이 처리하도록 되어 있다. DispatcherServlet은 나머지 URL을 보고 stateless JSF 뷰를 보여줘야 하는지, SWF를 사용해서 stateful JSF 뷰를 보여줘야 하는지 판단하다.

예를 들어,

/spring/intro -> renders the stateless Facelets template at /WEB-INF/intro.xhtml

/spring/main -> hands control over to the flow defined at /WEB-INF/flows/main/main.xml

/spring/booking?hotelId=5 -> hands control over to the flow defined at /WEB-INF/flows/booking/booking.xml, passing the hotelId parameter as input to the flow

그림 2에 있는 /flows 디렉토리 구조를 보면, 스프링 Faces 컨틀롤러와 뷰 구성물을 논리적으로 재사용 가능한 모듈로 조직화 하도록 한 것을 볼 수 있다.

사용자 삽입 이미지
그림 2. 모듈들의 논리적인 조직화

스프링 Web Flow와 Agile JSF 컨트롤러

스프링 Faces의 핵심은 스프링 Web Flow 연동에서 온다. 그리고 고수준의 flow DSL을 사용할 수 있으며, 이것으로 정확하고 엘레강트한 구조로 이벤트 처리, 모델 조화, 뷰 네비게이션을 제공할 수 있다. 플로우 정의는 동적이며 애플리케이션 재실행 없이 핫-릴로딩이 가능하다. 웹 컨테이너에 배포할 필요가 없기 때문에 완전한 단위 테스트도 가능하다. 보다 기민한 JSF 개발이 가능하다. 세밀한 스콥(flash, view, flow 스콥)을 사용하여 여러 요청을 넘나들며 도메인 모델을 직접 사용할 수 있다. 따라서 여러분은 도메인 모델에 보다 많은 가치를 부여하는데 힘을 쓸 수 있고, 모델을 매 요청에 저장해두고 가져오는 등의 기반 시설에 대해 걱정하는 시간을 줄일 수 있다. 이런 stateful 특징은 풍부한 JSF 뷰와 잘 어울리며 여러 이벤트로 뷰가 자주 변경되는 상황에 적당하다.

스프링 Faces를 사용하면, JSF postback 라이프사이클은 SWF 제어 하에 실행된다.
PhaseListener를 통해 JSF 라이프사이클에 플로우를 실행하는 SWF 1.x의 제한적인 연동에 비하면, 스프링 Faces JSF 확장 포인트는 SWF 구조를 기반으로 만들었다. 이로인한 아키텍처 적인 장점은 다음과 같다.

  • JSF 뷰는 SWF의 자동 POST + Redirect + GET 행위와 자연스럽게 동작하며, step-behind-URL을 없앴고, 일반적인 JSF 애플리케이션에 있던 브라우저 리프래시 경고 문제를 제거했다.
  • FacesMessage는 스프링의 MessageContext로 바인딩되어 스프링의 강력한 i18n 기능을 사용할 수 있다. 메시지들은 flash 스콥으로 저장되며 따라서 리다이렉트를 해도 보존된다.
  • 컴포넌트 트리 상태는 자동적으로 플로우 실행 상태와 동기화한다. pluggable storage 매키니즘을 적용하여 다양한 클러스터링 시나리오를 다룰 수 있다.
끝. 다음 기사에는 예제를 좀 더 자세히 살펴보겠다.

저자에 대하여

Jeremy Grelle는 SpringSource의 수석 소프트웨어 엔지니어이며 스프링 Faces 프로젝트 기술 리더다.


'JSF > article' 카테고리의 다른 글

Spring Faces 소개하기, 파트 1  (2) 2008.09.18
JavaServer Faces 시작하기 Part 1 Building basic applications  (0) 2008.09.15
top

  1. 2008.09.19 14:07 PERM. MOD/DEL REPLY

    비밀댓글입니다

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.19 16:00 신고 PERM MOD/DEL

    넵ㅋㅋ :)

Write a comment.


초간단 JSF 예제 돌리기 성공

JSF/exercise : 2008.09.16 22:46


꺄오~~ 처음으로 돌려보는 JSF 예제 기념샷.

사용자 삽입 이미지
사용자 삽입 이미지

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top

TAG JSF

Write a comment.


JavaServer Faces 시작하기 Part 1 Building basic applications

JSF/article : 2008.09.15 17:38


참조 : http://www.ibm.com/developerworks/edu/j-dw-java-jsf1-i.html

JSF가 제공하는 장점
• Clean separation of behavior and presentation
• Component-level control over statefulness
• Events easily tied to server-side code
• Leverages familiar UI-component and Web-tier concepts
• Offers multiple, standardized vendor implementations
• Excellent IDE support

JSF 애플리케이션 구성 요소
• JavaBeans for managing application state and behavior
• Stateful GUI components
• Event-driven development (via listeners as in traditional GUI
development)
• Pages that represent Model-View-Controller (MVC)-style views; pages
reference view roots via the JSF component tree

JSF 구성요소
• An event-publishing model
• A lightweight inversion-of-control (IoC) container
• Components for just about every other common GUI feature, including
(but not limited to):
  • Pluggable rendering
  • Server-side validation
  • Data conversion
  • Page-navigation management
- 이 중에서 IoC 컨테이너를 스프링으로 대체할 수 있음.(Part 2에서 살펴볼 예정)

JSF와 JSP 기술
• JSF 애플리케이션 UI는 JSP로 구성되어 있고, JSP에 JSF 커스텀 캐그를 사용해서 UI 컴포넌트를 랜더링한다. 여기에 이벤트 핸들러 등록하고, 검증기(Validator) 사용하고, 데이타 컨버터(Converter) 사용하는 거임.
• 사실 JSF는 JSP에 전혀 기술적으로 묶여있지 않다. JSP 페이지와는 전혀 다른 라이프사이클 가지고 있다.
• JSF 컴포넌트 상태는 단순히 JSP 페이지를 바꾼다고 바뀌는게 아니라, 컨트롤러에 바꾸며, 이미 기존 컴폰넌트가 존재할 때는 그 녀석의 상태를 화면에 뿌린다.
• 자바코드보다 EL을 많이 쓸 것이다.

JSF와 MVC
• HTML -> 모델 1 -> 모델 2
• 모델2 아키텍처는 MVC를 웹 애플리케이션에 맞게 정화한(watered-down) 것.
• 모델2
  • 컨트롤러 servlet(or 액션)
 • 뷰 JSP
• OO라기 보단 절차적에 가까웠기에 스트럿츠는 심지어 자신조차 스트럿츠 이길 원치 않았다. 자기 코드 기반 버리고 웹워크 위에 스프럿츠2를 만들었어.
• 그 보다는 덜 절차적인 스프링 MVC랑 웹어크도 있지만, 스트럿츠가 대세인데다가, 이 둘도 JSF가 제공하는 Statefull 컴포넌트는 제공하지 않는다.
• 모델 2 프레임워크의 진짜 이슈는 이벤트 모델이 너무 단순하고 stateful GUI 컴포넌트가 없다는 것이다. 그래서 너무 많은 작업을 개발자가 도맡아야해.

풍족한(richer) MVC 환경
• JSF는 모델 2 보다 훨씬 풍족한 MVC 환경을 제공한다.
• 모델 2 보다 더 진짜 MVC 프로그래밍에 가깝다.
• 모델 2 프레임워크 보다 훨씬 상세한(fine-grained), 이벤트 기반의 GUI를 제공한다.
  • request 받았다 VS 버튼 눌렀다, 아이템 선택했다, 트리 노드 열었다.
  • 이로 인해 HTTP에 너무 묶이지 않고, 개발자의 수고를 덜 수 있다.
• 표현 로직과 비즈니스 로직을 컨트롤러에서 빼내고, JSP 페이지에서 비즈니스 로직을 빼낸다.(이건 JSF를 쓰더라도 개발자가 어떻게 구현하느냐에 따라 달린거 아닐라나...)
• 간단한 컨트롤러는 JSF에 전혀 묶이지도 않아서 테스트 하기도 쉽다.(스프링 2.5 컨트롤러도 테스트는 괜찮아 졌는데.. 그 보다 좋을까 어떨까?)

JSF의 MVC 구현체 자세히 살펴보기
• 맵핑하는 빈들을 통해 뷰와 모델을 연결한다.
• 저자는 JSF에 묶이는 빈(컨트롤러)과 그렇지 않은 빈(모델)을 따로 맵핑한다.
• JSP와 달리 JSF 뷰는 Stateful 컴포넌트 모델이다.
• JSF 뷰는 두 가지로 구성되어 있다.
  • View root: UI 상태를 가지고 있는 UI 컴포넌트 집합
  • JSP 페이지: UI 컴포넌트를 JSP 페이지에 바인딩하고 뒷단의 빈 속성(혹은 속성의 속성)을 컴포넌트 필드로 바인딩한다.

이후부턴 예제... 예제는 스크린캐스팅으로 10월 첫주에 올라갑니다.

'JSF > article' 카테고리의 다른 글

Spring Faces 소개하기, 파트 1  (2) 2008.09.18
JavaServer Faces 시작하기 Part 1 Building basic applications  (0) 2008.09.15
top

TAG JSF

Write a comment.


JSF 기초 2

JSF/exercise : 2008.07.26 22:02


참조 : JSF for nonbelievers: The JSF application lifecycle

JSF 라이프사이클

사용자 삽입 이미지
1. Restore view

요청이 FacesSevlet으로 전달되면, 컨트롤러는 요청을 분석해서 뷰 ID를 뽑아낸다. (JSP 페이지 이름을 바탕으로)

JSF 프레임워크 컨트롤러는 뷰 ID를 사용해서 현재 뷰에서 사용할 컴포넌트들을 가져온다. 뷰가 없으면, 새로 만들어서 사용한다. 만약에 뷰가 이미 있으면, 그것을 사용한다. 뷰에는 모든 GUI 컴포넌트들이 있다.

이 단계에서는 세 가지 경우가 있는데 각각 new view, initial view, postback 이다.

new view: 이 경우에 JSF는 Faces 페이지 뷰를 만들고 이벤트 핸들러와 벨리데이터를 컴포넌트에 연결시킨다. 그렇게 만들어진 뷰는 FacesServlet 객체에 저장된다.

initial view: 이 경우에는 비어있는 뷰를 만든다. 비어있는 뷰는 사용자가 이벤트를 발생시켰을 때 만들어지고, 이 다음 단계는 render response로 넘어간다.

postback: 이미 만들어둔 페이지를 다시 보여줄 때가 postback이다. 이 경우에 JSF는 기존에 존재하던 뷰의 상태 정보를 유지한채 보여준다. 이 다음 단계는 apply request values가 된다.(원래 그 단계인데, 뭘 새삼 언급해주는거지;;)

2. Apply request values

이 단계의 목적은 각각이 컴포넌트들이 현재 상태를 가져오는 것이다. 컴포넌트들은 반드시 그 값들을 사용해서 FacesContext 객체에서 가져오거나 새로 만들어진다. 컴포넌트 값들은 보통 요청 파라메터에서 가져오는데, 쿠키나 헤더에서 가져올 수도 있다.

컴포넌트의 immediate event handling 속성이 true 가 아닐 경우: 값의 타입을 객체의 속성 타입으로 변환하는 작업을 한다. 이 때 만약 캐스팅 시에 에러가 나면, response render 단계에서 validation error랑 같이 보여준다.

컴포넌트의 immediate event handling 속성이 true 일 경우: 타입 변환 + 검증작업까지 한다. 그리고 변환된 값을 컴포넌트에 저장한다. 만약 값 변환이나 값 검증이 실패하면, 에러 메시지를 생성해서 FacesContext에 있는 큐에 넣는다. 그럼 다른 검증 에러들과 함께 response render 단계에서 보여준다.

3. Process Validation

사용자가 입력한 값이 검증 룰에 비교해봤을 때 적당한지를 살펴본다. 적절치 않을 때는 FacesContext에 에러 메시지를 추가하고 컴포넌트를 invalid 상태로 표시한다.

만약 컴포넌트가 invalid로 표시되어 있다면: JSF는 바로 render response 단계로 넘어간다.

만약 invalid 컴포넌트가 아니면: update model values 단계로 간다.

4. Update model values

서버쪽에 있는 모델이 가진 속성 값들을 수정한다. 이 단계는 항상 validation 단계 다음에 오기 때문에 빈 속성값의 유효함을 보장받는다.(물론 폼 필드 수준일 뿐, 비즈니스 룰 수준에서는 유효하지 않을 수도 있다.)

5. Invoke application

JSF 컨트롤러는 폼 처리를 할 애플리케이션을 호출한다. 컴포넌트 값이 그에 따라 바뀔 것이고, 검증될 것이고(여기선 비즈니스 룰 수준의 검증을 말하는 거겠죠), 모델 객체에 반영이 될 것이다. 즉 비즈니스 로직을 수행한다.

이 단계에서, 다음에 보여줄 논리적인 뷰를 명시할 수 있다. 간단하게 폼 처리의 성공 여부를 반환하면 된다. 네비게이션 룰은 faces-config.xml에 정의한다. 네비게이션이 이루어지면, 최종 단계로 이동한다.

6.  Render response

모든 컴포넌트의 현재 상태를 화면에 보여준다. 그림2는 객체 상태 다이어그램으로 JSF 라이프사이클 6 단계를 보여주고 있다.

사용자 삽입 이미지

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top

Write a comment.


JSF 기초 1

JSF/exercise : 2008.07.24 23:26


참조 : JSF for nonbelievers: Clearing the FUD about JSF

기본 아키텍처

사용자 삽입 이미지

JSF 예제

1. web.xml 과 faces-config.xml 설정하기

1-1. web.xml

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

<!-- Faces Servlet Mapping -->
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/calc/*</url-pattern>
</servlet-mapping>

이건 뭐 별 설명이 필요 없을 것 같네요. 스프링의 DispatcherServlet하고 비슷한 일을 할 듯 합니다. 중요 클래스니까 언제 한 번 열어봐야겠네요.

1-2. faces-config.xml

<faces-config>
    ...
  <managed-bean>
    <description>
      The "backing file" bean that backs up the calculator webapp
    </description>
    <managed-bean-name>CalcBean</managed-bean-name>
    <managed-bean-class>com.arcmind.jsfquickstart.controller.CalculatorController</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
  </managed-bean>

<navigation-rule>
  <from-view-id>/calculator.jsp</from-view-id>
  <navigation-case>
    <from-outcome>success</from-outcome>
    <to-view-id>/results.jsp</to-view-id>
  </navigation-case>
</navigation-rule>

</faces-config>

흠.. JSF에서 사용할 컨트롤러 빈의 이름과 스코프를 등록하고, 네비게이션을 등록해두네요. 네비게이션을 등록해둔 걸 보면, 서브밋 할 때 action="result.jsp" 같은 코드를 사용하지 않아도 알아서 가주겠죠?

2. 모델 객체 만들기

package com.arcmind.jsfquickstart.model;

/**
 * Calculator
 *
 * @author Rick Hightower
 * @version 0.1
 */
public class Calculator {
    //~ Methods ----------------------------------------------------------------

    /**
     * add numbers.
     *
     * @param a first number
     * @param b second number
     *
     * @return result
     */
    public int add(int a, int b) {
        return a + b;
    }

    /**
     * multiply numbers.
     *
     * @param a first number
     * @param b second number
     *
     * @return result
     */
    public int multiply(int a, int b) {
        return a * b;
    }
   
}

3. 컨트롤러 만들기(완전 POJO)

package com.arcmind.jsfquickstart.controller;

import com.arcmind.jsfquickstart.model.Calculator;


/**
 * Calculator Controller
 *
 * @author $author$
 * @version $Revision$
 */
public class CalculatorController {
    //~ Instance fields --------------------------------------------------------

    /**
     * Represent the model object.
     */
    private Calculator calculator = new Calculator();

    /** First number used in operation. */
    private int firstNumber = 0;

    /** Result of operation on first number and second number. */
    private int result = 0;

    /** Second number used in operation. */
    private int secondNumber = 0;

    //~ Constructors -----------------------------------------------------------

    /**
     * Creates a new CalculatorController object.
     */
    public CalculatorController() {
        super();
    }

    //~ Methods ----------------------------------------------------------------

    /**
     * Calculator, this class represent the model.
     *
     * @param aCalculator The calculator to set.
     */
    public void setCalculator(Calculator aCalculator) {
        this.calculator = aCalculator;
    }

    /**
     * First Number property
     *
     * @param aFirstNumber first number
     */
    public void setFirstNumber(int aFirstNumber) {
        this.firstNumber = aFirstNumber;
    }

    /**
     * First number property
     *
     * @return First number.
     */
    public int getFirstNumber() {
        return firstNumber;
    }

    /**
     * Result of the operation on the first two numbers.
     *
     * @return Second Number.
     */
    public int getResult() {
        return result;
    }

    /**
     * Second number property
     *
     * @param aSecondNumber Second number.
     */
    public void setSecondNumber(int aSecondNumber) {
        this.secondNumber = aSecondNumber;
    }

    /**
     * Get second number.
     *
     * @return Second number.
     */
    public int getSecondNumber() {
        return secondNumber;
    }

    /**
     * Adds the first number and second number together.
     *
     * @return next logical outcome.
     */
    public String add() {
       
        result = calculator.add(firstNumber, secondNumber);

        return "success";
    }

    /**
     * Multiplies the first number and second number together.
     *
     * @return next logical outcome.
     */
    public String multiply() {

        result = calculator.multiply(firstNumber, secondNumber);
       
        return "success";
    }
}


흠.. 이 코드를 보고서 좀 놀랐습니다. 스프링 2.5로 컨틀롤러를 만들어도, 가능하긴 한데, 수많은 애노테이션들이 붙고, 그 애노테이션들을 정말 잘 알고 있어야 했는데.. 결국 그 애노테이션들 없이는 스프링의 컨트롤러는 의미도 없고 재사용할 수도 없기 떄문에 엄밀히 따지면 POJO라고 하긴 좀 뭐했습니다. 그런데 JSF의 저 컨트롤러는 뭐.. 틈잡을것이 하나도 없습니다.

4. 뷰 만들기

4-1. index.jsp

<jsp:forward page="/calc/calculator.jsp" />

흠.. 얘는 네비게이션에 등록하지도 않았고, JSF Servlet이 담당할 URL로 들어오지 않을테고.. 저기서 JSF  Servlet이 담당할 URL로 포워딩시키는 군요.

4-2. calculator.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<f:view>
  <h:form id="calcForm">
     <h:panelGrid columns="3">
    <h:outputLabel value="First Number" for="firstNumber" />
    <h:inputText id="firstNumber" value="#{CalcBean.firstNumber}" required="true" />
        <h:message for="firstNumber" />   

    <h:outputLabel value="Second Number" for="secondNumber" />
    <h:inputText id="secondNumber" value="#{CalcBean.secondNumber}" required="true" />
        <h:message for="secondNumber" />
    </h:panelGrid>
   
    <h:panelGroup>
    <h:commandButton id="submitAdd" action="#{CalcBean.add}"  value="Add" />
    <h:commandButton id="submitMultiply" action="#{CalcBean.multiply}" value="Multiply" />
</h:panelGroup>
  </h:form>
</f:view>

흠~ 이제 좀 재밌는 코드가 나왔습니다.

맨위에 첫 줄은, 폼을 비록한 HTML 관련 태그들이 담겨있고, 두 번째 줄은 JSF가 사용할 로직, 벨리데이션, 컨트롤러등을 위한 태그들이 담겨있다고 합니다.

<f:view> 안에 들어가야 JSF 컴포넌트 트리를 만든다고 합니다. JSF 를 사용할 땐 저 안에 모든 JSF 컴포넌트를 넣어야 겠군요.

<h:form> 은, html 폼을 나타내는 JSF 컴포넌트인가 봅니다. 속성중에  column=3은 한 줄에 세칸이라는 뜻이고, 따라서 저 안에 있는 컴포넌트들은 세줄씩 마침 코드에서도 한 줄 띄어쓰기로 구분해주고 있네요.

<h:message>는 에러 메시지 보여줄 때 사용할 것 같은데, 뭘 참조하라는게 없군요. 자동으로 메시지 생성해서 넣어줄 것 같은데... 내가 원하는 메시지를 보여주고 싶을 땐 어떻게 해야되지??

의문 1. 내가 원하는 메시지를 보여주고 싶을 땐 <h:message>를 어떻게 설정해야 하나?

JSP의 EL 처럼 JSF에도 EL 이 있는데, 그건 바로 #{}. CalcBean은 아까 faces-config.xml이였나.. 거기에 등록했던 컨트롤러이고, value 속성은 해당 컨트롤러의 필드값을 참조하고, action은 메소드를 호출하고 그 결과를 가져오나 보군요.

의문 2. 인자가 있는 메소드도 지원할까? 지원한다면, 어떻게 써야 하나?

예상했던 것처럼 역시나 저 폼을 서브밋하면 어디로 갈지를 폼에다가 적지 않았습니다. 아까 저 페이지? URL?에 대한 네비게이션을 정의해두었죠.

4-3. result.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
...
<f:view>
  First Number: <h:outputText id="firstNumber" value="#{CalcBean.firstNumber}"/>
  <br />
  Second Number: <h:outputText id="secondNumber" value="#{CalcBean.secondNumber}"/>
  <br />
  Result: <h:outputText id="result" value="#{CalcBean.result}"/>
  <br />
</f:view>


흠.. 이번에도 역시 <f:view>를 써서 JSF 컴포넌트 트리로 감싸고, <h:outputText> 라는 컴포넌트를 쓰고 있군요. value를 사용해서 필드값들만 참조합니다. 간단하군요.

돌리는 건 내일해야 겠습니다. 11시 반도 안 됐는데 졸리네요;

'JSF > exercise' 카테고리의 다른 글

JSF의 universal EL  (0) 2008.09.20
초간단 JSF 예제 돌리기 성공  (0) 2008.09.16
JSF 기초 2  (0) 2008.07.26
JSF 기초 1  (0) 2008.07.24
top

TAG JSF

Write a comment.


불신자를 위한 JSF 시리즈

모하니?/Reading : 2008.07.22 18:25


JSF for nonbelievers: Clearing the FUD about JSF
JSF for nonbelievers: The JSF application lifecycle
JSF for nonbelievers: JSF conversion and validation
JSF for nonbelievers: JSF component development

외국에선 상당히 많은 개발자들이 사용하고 있다는 JSF.. 저도 한 번 써보고 싶어서 공부를 시작합니다. 위에 두 개의 아티클은 한국 IBM DeveloperWorks에 번역된 기사를 찾긴 했는데, 번역이.. 좀;; 그래서 걍 원문을 읽기로 했습니다.

나머지 두 개는 제가 번역해야겠습니다. ㅋㅋ
top

TAG JSF

Write a comment.


15.3. JavaServer Faces

Spring/Chapter 15 : 2007.12.27 22:55


15.3.1. DelegatingVariableResolver

JSF 웹 계층과 스프링의 미들티어와 연동하는 가장 쉬운 방법은 DelegatingVariableResolver 클래스를 사용하는 것입니다.

faces-context.xml 파일을 다음과 같이 수정합니다.

<faces-config>
  <application>
    <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
      <locale-config>
        <default-locale>en</default-locale>
        <supported-locale>en</supported-locale>
        <supported-locale>es</supported-locale>
      </locale-config>
      <message-bundle>messages</message-bundle>
    </application>
</faces-config>

DelegatingVariableResolver는 먼저 값을 가져오는 것을 JSF 구현체의 기본 리졸버에게 위임할 것이고, 그 다음에 스프링의 비즈니스 문맥이 담긴 WebApplicationContext에 위임합니다. 이 방법을 사용해서 간단하게 JSF에 의해 관리되는 bean들에 의존성을 주입할 수 있습니다.

JSF가 관리하는 bean들은 faces-config.xml에 정의 되어 있으며 아래의 예제에서 #{userManager}는 스프링의 비즈니스 문맥으로부터 가져오는 bean을 나타냅니다.

<managed-bean>
  <managed-bean-name>userList</managed-bean-name>
    <managed-bean-class>com.whatever.jsf.UserList</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>userManager</property-name>
    <value>#{userManager}</value>
  </managed-property>
</managed-bean>

15.3.2. FacesContextUtils

faces-config.xml에 있는 bean들(JSF 빈)의 한 프로퍼티를 주입할 때는 위와 같은 방법이 용이합니다. 그러나 명시적으로 스프링 bean이 왕창 필요할 때는  FacesContextUtils를 사요할 수 있습니다.

ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());

WebApplicationContextUtils 와 사용법은 유사하며 차이점은 인자로 facesContext를 넘겨준다는 것입니다.

'Spring > Chapter 15' 카테고리의 다른 글

15.3. JavaServer Faces  (2) 2007.12.27
15.2. Common configuration  (0) 2007.12.27
Integrating with other web frameworks  (0) 2007.12.27
top

  1. remnant 2010.06.02 00:40 PERM. MOD/DEL REPLY

    안녕하세요.
    저도 이번 해에 들어 처음으로 Spring과 Spring Security 를 배우게 되었는데요. JSF로 custom tag library를 만들었어요. 근데, renderer 클래스를 implement한 클래스를 unit test 하려고 하는데요. 자꾸만 "FacesContextUtils.getWebApplicationContext(facesContext)" 가 들어있는 곳을 testing하려하면 NullPointerException 에러가 나네요.

    FacesContextUtils 에서 51번째 줄에서 에러가 난다해서 찾아보니..

    Object attr = facesContext.getExternalContext().getApplicationMap().get(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

    아마도 getApplicationMap부분에서 부터 에러가 나는듯 싶습니다. 현재 mockito도 써봤고 easyMock 과 jmock도 사용해봤는데. 전부다 같은 에러에서 끝나는군요.

    혹시나 어떻게 이 문제를 풀어야할지 아시거나 추천해주실만한 소스 있으시면 좋겠네요.

    whiteship님의 블로그만큼 스프링을 제대로 카버하는 곳이 한국 블로그 중에는 없는듯 하네요.ㅋㅋ

    그럼 답장 기다리겠습니다. (pam0708@gmail.com)

    mark

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.02 17:23 PERM MOD/DEL

    에러 스택을 보지 않고선 감을 못잡겠네요;
    이런건 KSUG 포럼에 올려주시면 저 말고도 여러 뛰어난 개발자 분들이 도움을 주실 것 같습니다.

Write a comment.