IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  자바 | 웹 개발  >

JSF 2 fu, Part 3: 이벤트 처리, JavaScript 및 Ajax

두 가지 새로운 JSF 2 기능을 사용하여 복합 구성 요소 개선하기

developerWorks
문서 옵션
PDF format - Fits A4 and Letter

PDF - Fits A4 and Letter
328KB (22 pages)

Get Adobe® Reader®

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

David Geary, President, Clarity Training, Inc.

원문 게재일 : 2009 년 7 월 14 일
번역 게재일 : 2009 년 8 월 25 일

JSF(Java™ Server Faces) 2 Expert Group의 회원인 David Geary가 JSF 2의 새 기능을 소개하기 위해 집필한 세 편의 기사로 구성된 시리즈 중 마지막 기사입니다. 프레임워크의 새로운 이벤트 모델 및 Ajax에 대한 내장 지원 기능을 사용하여 강력하고 재사용 가능한 구성 요소를 만드는 방법에 대해 설명합니다.

JSF의 가장 큰 장점 중 하나는 구성 요소 기반 프레임워크라는 점이다. 이는 재사용할 수 있는 구성 요소를 구현할 수 있다는 것을 의미한다. 하지만 JSF 1에서는 대부분의 경우 구성 요소를 구현하기가 너무 어려워서 강력한 재사용 메커니즘임에도 불구하고 거의 사용되지 않았다.

하지만 Part 2에서 살펴본 것처럼 JSF 2에서는 Java 코드와 구성 작업 없이 복합 구성 요소라는 새 기능을 사용하여 구성 요소를 쉽게 구현할 수 있다. 이 기능은 JSF 구성 요소의 가능성을 실현시켜 주는 기능이기에 JSF 2의 가장 중요한 부분이라고도 할 수 있다.

JSF 2에 대한 이 마지막 세 번째 기사에서는 JSF 2를 효과적으로 활용하는 데 도움이 되는 다음과 같은 팁과 함께 JSF 2에 새롭게 도입된 Ajax 및 이벤트 처리 기능과 복합 구성 요소 기능을 활용하여 구성 요소를 개발하는 방법에 대해 설명한다.

  • 팁 1: 구성 요소화하기
  • 팁 2: Ajax 스타일 따르기
  • 팁 3: 진행률 표시하기

Part 2에서 자세히 설명한 두 구성 요소를 첫 번째 팁에서 간단히 살펴본 후 후속 팁에서 Ajax 및 이벤트 처리를 사용하여 이들 구성 요소를 변환하는 방법에 대해 설명한다.

팁 1: 구성 요소화하기

Part 1에서 설명한 places 애플리케이션에는 여러 가지 복합 구성 요소가 있다. 그중에서 map 구성 요소는 그림 1과 같이 확대/축소 수준을 지정하는 풀다운 메뉴와 함께 주소에 해당하는 지도를 표시한다.


그림 1. places 애플리케이션의 map 구성 요소
map 구성 요소

Listing 1에서는 map 구성 요소의 코드 중 일부를 보여 준다.


Listing 1. map 구성 요소
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
    ...
    xmlns:composite="http://java.sun.com/jsf/composite"
    xmlns:places="http://java.sun.com/jsf/composite/components/places">
    
   <!-- INTERFACE -->
   <composite:interface>
     <composite:attribute name="title"/>
   </composite:interface>
        
   <!-- IMPLEMENTATION --> 
   <composite:implementation">
     <div class="map">
       ...
       <h:panelGrid...>
         <h:panelGrid...>
            <h:selectOneMenu onchange="submit()"
                 value="#{cc.parent.attrs.location.zoomIndex}"
                 valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
                 style="font-size:13px;font-family:Palatino">
            
              <f:selectItems value="#{places.zoomLevelItems}"/>
                           
            </h:selectOneMenu>               
          </h:panelGrid>
        </h:panelGrid>   
        
        <h:graphicImage url="#{cc.parent.attrs.location.mapUrl}" 
          style="border: thin solid gray"/>  
       ...
      
     </div>
   ...
       
  </composite:implementation>    
</html>

구성 요소의 장점 중 하나는 주위 기능에 영향을 주지 않고도 더 좋은 구성 요소로 대체할 수 있다는 것이다. 예를 들어, 그림 2에서는 Listing 1image 구성 요소가 GMaps4JSF의 Google Maps 구성 요소(참고자료 참조)로 바뀌었다.


그림 2. GMaps4JSF의 지도 이미지
GMaps4JSF map 구성 요소

Listing 2에서는 map 구성 요소의 업데이트된 일부 코드를 보여 준다.


Listing 2. 지도 이미지를 GMaps4JSF 구성 요소로 바꾸기

<h:selectOneMenu onchange="submit()"
              value="#{cc.parent.attrs.location.zoomIndex}"
              valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
              style="font-size:13px;font-family:Palatino">
     
  <f:selectItems value="#{places.zoomLevelItems}"/>
                    
</h:selectOneMenu>   

...         

<m:map id="map" width="420px" height="400px" 
     address="#{cc.parent.attrs.location.streetAddress}, ..." 
     zoom="#{cc.parent.attrs.location.zoomIndex}"
     renderOnWindowLoad="false">
     
  <m:mapControl id="smallMapCtrl" 
              name="GLargeMapControl" 
          position="G_ANCHOR_TOP_RIGHT"/>
          
  <m:mapControl  id="smallMapTypeCtrl" name="GMapTypeControl"/>                  
  <m:marker id="placeMapMarker"/>     
    
</m:map>

이 listing에서는 GMaps4JSF 구성 요소를 사용하기 위해 <h:graphicImage> 태그를 GMaps4JSF 구성 요소 세트의 <m:map> 태그로 변경했다. <m:map> 태그의 zoom 속성에 대해 올바른 backing-bean 특성을 지정하여 GMaps4JSF 구성 요소를 확대/축소 풀다운에 손쉽게 연결했다.

확대/축소 수준의 경우 사용자가 확대/축소 수준을 변경하면 Listing 1에서 부분적으로 굵게 표시된 행 중 첫 번째 행에서 볼 수 있듯이 <h:selectOneMenu>onchange 속성과 함께 양식이 제출된다. 이렇게 양식이 제출되면 JSF 수명 주기가 시작되며, 결과적으로 확대/축소 수준에 대한 새 값이 상위 복합 구성 요소에 저장되어 있는 location Bean의 zoomIndex 특성에 삽입된다. 이 Bean 특성은 Listing 2의 첫 번째 행에서 입력 구성 요소에 바인딩된다.

확대/축소 수준 변경과 관련된 양식 제출에 대한 탐색을 지정하지 않았기 때문에 요청이 처리된 후 동일한 페이지가 새로 고쳐지면서 새로운 확대/축소 수준이 반영된 지도 이미지가 다시 그려진다. 하지만 이처럼 페이지를 새로 고치면 지도 이미지에서 단일 구성 요소만 변경된 경우에도 전체 페이지가 다시 그려진다. 팁 2: Ajax 스타일 따르기에서는 Ajax를 사용하여 확대/축소 수준 변경에 대한 응답으로 이미지만을 다시 그리는 방법을 보여 준다.

login 구성 요소

places 애플리케이션에서는 login 구성 요소도 사용된다. 그림 3에서는 작동 중인 login 구성 요소를 보여 준다.


그림 3. login 구성 요소
login 구성 요소

Listing 3에서는 그림 3에서 본 login 구성 요소를 생성하는 데 사용된 마크업을 보여 준다.


Listing 3. 필수 속성만을 가지고 있는 최소화된 login 구성 요소

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:util="http://java.sun.com/jsf/composite/components/util">

  <util:login loginAction="#{user.login}"
              managedBean="#{user}"/>
                
</ui:composition>

login 구성 요소에는 다음 두 가지 필수 속성만 있다.

  • loginAction: 로그인 동작 메소드
  • managedBean: 이름 및 암호 특성을 가지고 있는 관리 Bean

Listing 4에서는 Listing 3에서 지정한 관리 Bean을 보여 준다.


Listing 4. User.groovy

package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
 
@ManagedBean() 
@SessionScoped  
               
public class User {    
  private final String VALID_NAME     = "Hiro"
  private final String VALID_PASSWORD = "jsf"
  
  private String name, password;
 
  public String getName() { name }
  public void setName(String newValue) { name = newValue }
  
  public String getPassword() { return password }
  public void setPassword(String newValue) { password = newValue }  
  
  public String login() {
    "/views/places"
  }

  public String logout() {
    name = password = nameError = null
    "/views/login"
  }
}

Listing 4의 관리 Bean은 Groovy Bean이다. 여기에서는 Java 언어 대신 Groovy를 사용함으로써 얻을 수 있는 장점이 많지 않다. 세미콜론과 return 명령문을 많이 사용하지 않아도 된다는 정도가 전부일 것이다. 하지만 팁 2의 유효성 검증 섹션에서는 User 관리 Bean으로 사용되는 Groovy를 보면서 Groovy의 진정한 가치를 알 수 있다.

대부분의 경우에는 그림 4와 같이 프롬프트와 단추 텍스트를 사용하여 login 구성 요소를 완전히 구성하려고 한다.


그림 4. 완전히 구성된 login 구성 요소
완전히 구성된 login 구성 요소

Listing 5에서는 그림 4login 구성 요소를 생성하는 데 사용된 마크업을 보여 준다.


Listing 5. login 구성 요소 구성하기

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:util="http://java.sun.com/jsf/composite/components/util">
  
  <util:login loginPrompt="#{msgs.loginPrompt}"
               namePrompt="#{msgs.namePrompt}"
           passwordPrompt="#{msgs.passwordPrompt}"
          loginButtonText="#{msgs.loginButtonText}"
              loginAction="#{user.login}"          
              managedBean="#{user}"/>
                
</ui:composition>

Listing 5에서는 프롬프트 및 로그인 단추 텍스트를 리소스 번들에서 가져온다.

Listing 6에서는 login 구성 요소를 정의한다.


Listing 6. login 구성 요소 정의하기

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!-- Usage:

  <util:login loginPrompt="#{msgs.loginPrompt}"
               namePrompt="#{msgs.namePrompt}"
           passwordPrompt="#{msgs.passwordPrompt}"
          loginButtonText="#{msgs.loginButtonText}"
              loginAction="#{user.login}"
              managedBean="#{user}">
                 
    <f:actionListener for="loginButton" 
                     type="com.clarity.LoginActionListener"/>
                            
  </util:login>

  managedBean must have two properties: name and password. 
  
  The loginAction attribute must be an action method that takes no
  arguments and returns a string. That string is used to navigate
  to the page the user sees after logging in.
  
  This component's loginButton is accessible so that you can
  add action listeners to it, as depicted above. The class specified
  in f:actionListener's type attribute must implement the
  javax.faces.event.ActionListener interface.
  
 -->
 
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:composite="http://java.sun.com/jsf/composite">
    
  <!-- INTERFACE -->
  <composite:interface>
  
    <!-- PROMPTS -->
    <composite:attribute name="loginPrompt"/>
    <composite:attribute name="namePrompt"/>
    <composite:attribute name="passwordPrompt"/>
    
    <!--  LOGIN BUTTON -->      
    <composite:attribute name="loginButtonText"/>
    
    <!-- loginAction is called when the form is submitted -->
    <composite:attribute name="loginAction" 
             method-signature="java.lang.String login()"
                     required="true"/>
                     
    <!-- You can add listeners to this actionSource:  -->
    <composite:actionSource name="loginButton" targets="form:loginButton"/>
      
    <!-- BACKING BEAN -->
    <composite:attribute name="managedBean" required="true"/>
  </composite:interface>
    
  <!-- IMPLEMENTATION -->
  <composite:implementation>
    <div class="prompt">
      #{cc.attrs.loginPrompt}
    </div>
    
    <!-- FORM -->       
    <h:form id="form">
      <h:panelGrid columns="2">
      
        <!-- NAME AND PASSWORD FIELDS -->
        #{cc.attrs.namePrompt}
        <h:inputText id="name" 
                  value="#{cc.attrs.managedBean.name}"/>
    
        #{cc.attrs.passwordPrompt} 
        <h:inputSecret id="password" size="8" 
          value="#{cc.attrs.managedBean.password}"/>
          
      </h:panelGrid>
    
      <p>
        <!-- LOGIN BUTTON -->    
        <h:commandButton id="loginButton"
          value="#{cc.attrs.loginButtonText}"
          action="#{cc.attrs.loginAction}"/>
      </p>
    </h:form>    
  </composite:implementation>
</html>

map 구성 요소와 마찬가지로 login 구성 요소에서도 Ajax 업그레이드를 사용할 수 있다. 두 번째 팁의 유효성 검증 섹션에서 Ajax 유효성 검증을 login 구성 요소에 추가하는 방법을 설명한다.




위로


팁 2: Ajax 스타일 따르기

일반적으로 Ajax를 사용하려면 Ajax 이외의 HTTP 요청의 경우 수행되지 않는 두 가지 단계 즉, 서버에서 양식을 부분적으로 처리하는 단계와 클라이언트에서 DOM(Document Object Model)을 부분적으로 렌더링하는 단계를 순차적으로 수행해야 한다.

부분 처리 및 렌더링

JSF 2에서는 JSF 수명 주기를 실행과 렌더링이라는 독립된 두 가지 논리적 부분으로 분할하여 부분 처리 및 부분 렌더링을 지원한다. 그림 5에서 강조 표시된 부분이 실행 부분이다.


그림 5. JSF 수명 주기의 실행 부분
수명 주기의 실행 부분

그림 6에서 강조 표시된 부분이 JSF 수명 주기의 렌더링 부분이다.


그림 6. JSF 수명 주기의 렌더링 부분
수명 주기의 렌더링 부분

수명 주기를 실행 부분과 렌더링 부분으로 나누는 이유는 단순하다. 서버에서 JSF가 실행(처리)하는 구성 요소와 Ajax 호출이 리턴될 때 JSF가 렌더링하는 구성 요소를 지정하기 위한 것이다. 이러한 작업은 JSF 2의 새로운 기능인 <f:ajax>를 사용하여 수행할 수 있다(Listing 7 참조).


Listing 7. Ajax 확대/축소 메뉴
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax event="change" execute="@this" render="map"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>
             
</h:selectOneMenu>             
     
<m:map id="map"...>

Listing 7Listing 2의 1행에 있는 메뉴를 수정한 것이다. Listing 2에 있던 onchange 속성을 제거하고 <f:ajax> 태그를 추가했다. <f:ajax> 태그가 지정하는 내용은 다음과 같다.

  • Ajax 호출을 트리거하는 이벤트
  • 서버에서 실행할 구성 요소
  • 클라이언트에서 렌더링할 구성 요소

사용자가 확대/축소 메뉴에서 항목을 선택하면 JSF가 Ajax 호출을 서버로 보낸다. 그런 다음 JSF가 수명 주기의 실행 부분을 통해 메뉴를 전달하고(@this<f:ajax>의 주위 구성 요소를 뜻함) 수명 주기의 Update Model Values 단계 동안 메뉴의 zoomIndex를 업데이트한다. Ajax 호출이 리턴되면 JSF가 map 구성 요소를 렌더링한다. 이제 새로 설정된 확대/축소 인덱스를 사용하여 지도가 다시 그려지면서 한 행의 XHTML이 추가된 Ajax 스타일의 확대/축소 메뉴가 생성된다.

하지만 JSF에서는 eventexecute 속성에 대한 기본값이 제공되기 때문에 이 작업을 더 간단하게 수행할 수 있다.

각 JSF 구성 요소에는 구성 요소 태그 안에 <f:ajax> 태그를 포함시킨 경우 Ajax 호출을 트리거하는 기본 이벤트가 있다. 메뉴의 경우에는 change 이벤트가 기본 이벤트이다. 따라서 Listing 7에서 <f:ajax>event 속성을 제거해도 된다. <f:ajax>execute 속성의 기본값은 <f:ajax>의 주위 구성 요소를 의미하는 @this이다. 이 예제의 경우에는 메뉴가 주위 구성 요소이므로 execute 속성도 제거할 수 있다.

<f:ajax>의 기본 속성 값을 사용하면 Listing 7을 Listing 8로 줄일 수 있다.


Listing 8. 단순해진 Ajax 확대/축소 메뉴
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax render="map"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>
             
</h:selectOneMenu>             

<m:map id="map"...>

이처럼 JSF 2에서는 Ajax를 구성 요소에 정말 쉽게 추가할 수 있다. 물론 앞의 예제는 매우 단순하다. 사용자가 확대/축소 수준을 선택할 때 전체 페이지 대신 지도만 다시 그리게 된다. 양식에 있는 개별 필드의 유효성을 검증하는 것과 같은 일부 작업은 좀 더 복잡하므로 다음 섹션에서 자세히 설명한다.

유효성 검증

사용자가 필드를 벗어날 때 필드의 유효성을 검증하여 피드백을 바로 제공할 수 있다면 매우 편리할 것이다. 예를 들어, 그림 7에서는 Ajax를 사용하여 name 필드의 유효성을 검증한다.


그림 7. Ajax 유효성 검증
Ajax 유효성 검증

Listing 9에서는 name 필드에 대한 마크업을 보여 준다.


Listing 9. name 필드
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:panelGrid columns="2">
  #{cc.attrs.namePrompt}
  <h:panelGroup>
    <h:inputText id="name" value="#{cc.attrs.managedBean.name}"
       valueChangeListener="#{cc.attrs.managedBean.validateName}">
       
       <f:ajax event="blur" render="nameError"/>
       
     </h:inputText>
     
     <h:outputText id="nameError" 
       value="#{cc.attrs.managedBean.nameError}"
       style="color: red;font-style: italic;"/>
  </h:panelGroup>     
  ... 
</h:panelGrid>

다시 한번 <f:ajax>를 사용한다. 이 경우에만 입력에 대한 기본 이벤트인 change가 작동하지 않으므로 blur를 Ajax 호출을 트리거하는 이벤트로 지정한다. 사용자가 name 필드를 벗어나면 JSF가 Ajax 호출을 서버로 보내고 수명 주기의 실행 부분을 통해 name 입력 구성 요소를 실행한다. 이는 JSF가 수명 주기의 Process Validations 단계 동안 Listing 9에서 지정한 name 입력의 값 변경 리스너를 호출한다는 의미이다. Listing 10에서는 값 변경 리스너를 보여 준다.


Listing 10. validateName() 메소드

package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent 
import javax.faces.component.UIInput 
 
@ManagedBean()  
@SessionScoped    
       
public class User {    
  private String name, password, nameError;
 
  ...
  
  public void validateName(ValueChangeEvent e) {
    UIInput nameInput = e.getComponent()
    String name = nameInput.getValue()
    
    if (name.contains("_"))   nameError = "Name cannot contain underscores"
    else if (name.equals("")) nameError = "Name cannot be blank"
    else                      nameError = "" 
  }
  
  ...
}

값 변경 리스너인 user 관리 Bean의 validateName() 메소드는 name 필드의 유효성을 검사한 후 user 관리 Bean의 nameError 특성을 업데이트한다.

Ajax 호출이 리턴되면 Listing 9에 있는 <f:ajax> 태그의 render 속성에 따라 JSF가 nameError 출력을 렌더링한다. 이 출력은 user 관리 Bean의 nameError 특성을 보여 준다.

여러 필드에 대한 유효성 검증

이전 서브섹션에서는 단일 필드에 대해 Ajax 유효성 검증을 수행하는 방법을 살펴보았다. 하지만 동시에 여러 필드의 유효성을 검증해야 하는 경우도 있다. 예를 들어, 그림 8에서는 name 및 password 필드의 유효성을 함께 검증하는 places 애플리케이션을 보여 준다.


그림 8. 여러 필드에 대한 유효성 검증하기
여러 필드에 대한 유효성 검증하기

이 예제에서는 사용자가 양식을 제출할 때 name 및 password 필드의 유효성을 함께 검증하므로 Ajax가 필요하지 않다. 대신 JSF 2의 새로운 이벤트 시스템을 사용한다(Listing 11 참조).


Listing 11. <f:event> 사용하기

<h:form id="form" prependId="false">
  
  <f:event type="postValidate" 
       listener="#{cc.attrs.managedBean.validate}"/>
  ...
</h:form>

<div class="error" style="padding-top:10px;">
  <h:messages layout="table"/>
</div>

Listing 11에서는 <f:ajax>처럼 JSF 2의 새 기능인 <f:event>를 사용한다. <f:event> 태그는 <f:ajax>와 마찬가지로 사용하기가 쉽다.

<f:event> 태그를 구성 요소 태그 안에 넣게 되면 type 속성을 사용하여 지정한 이벤트가 해당 구성 요소에 대해 발생할 때 JSF가 listener 속성에 지정된 메소드를 호출한다. 따라서 Listing 11<f:event> 태그가 의미하는 바는 양식의 유효성을 검증한 후 사용자가 이 복합 구성 요소에 전달한 관리 Bean의 validate() 메소드를 호출한다는 것이다. Listing 12에서 이 메소드를 보여 준다.


Listing 12. validate() 메소드
package com.clarity

import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent 
import javax.faces.component.UIInput 
 
@ManagedBean()  
@SessionScoped    
       
public class User {    
  private final String VALID_NAME     = "Hiro";
  private final String VALID_PASSWORD = "jsf";
  
  ...
  
  public void validate(ComponentSystemEvent e) {
    UIForm form = e.getComponent() 
    UIInput nameInput = form.findComponent("name")
    UIInput pwdInput = form.findComponent("password")
    
    if ( ! (nameInput.getValue().equals(VALID_NAME) &&
        pwdInput.getValue().equals(VALID_PASSWORD))) {
      
      FacesContext fc = FacesContext.getCurrentInstance()
      fc.addMessage(form.getClientId(), 
        new FacesMessage("Name and password are invalid. Please try again."))
      fc.renderResponse()
    }
  }
  
  ...
}

Listing 12validate() 메소드는 구성 요소 시스템 이벤트를 받아서 이벤트가 적용되는 구성 요소인 로그인 양식에 대한 참조를 가져온다. 그런 다음 양식의 findComponent() 메소드를 사용하여 name 및 password 구성 요소를 가져온다. 이들 구성 요소의 값이 각각 Hiro와 jsf가 아닌 경우에는 메시지를 faces 컨텍스트에 저장한 후 JSF에게 수명 주기의 Render Response 단계를 즉시 진행하도록 지시한다. 이렇게 하면 Update Model Values 단계를 건너뛸 수 있기 때문에 잘못된 이름과 암호가 모델에 저장되는 것을 피할 수 있다(그림 5 참조).

Listing 10Listing 12의 유효성 검증 메소드는 Groovy로 작성되었다. Listing 4에서는 Groovy를 사용해서 얻을 수 있는 장점이 세미콜론과 return 명령문을 사용하지 않아도 된다는 것뿐이었지만 Listing 10Listing 12의 Groovy 코드에서는 캐스팅을 수행하지 않아도 되는 장점이 있다. 예를 들어, Listing 10에서는 ComponentSystemEvent.getComponent()UIComponent.findComponent()가 모두 UIComponent 유형을 리턴한다. Java 언어를 사용한다면 이러한 메소드의 리턴 값을 캐스팅해야 한다. 하지만 Groovy에서는 캐스팅이 자동으로 수행된다.




위로


팁 3: 진행률 표시하기

Ajax 스타일 따르기 팁에서는 map 구성 요소의 확대/축소 메뉴를 Ajax 스타일로 만드는 방법을 살펴보았다. 이렇게 하면 사용자가 확대/축소 수준을 변경할 경우 places 애플리케이션이 페이지에서 지도 부분만 다시 그리게 된다. 그림 9처럼 처리 중인 Ajax 이벤트의 상태를 사용자에게 알려 주는 피드백을 제공하는 경우에도 Ajax를 자주 사용한다.


그림 9. 진행 표시줄
진행 표시줄

그림 9에서는 확대/축소 메뉴를 애니메이션 GIF로 변경했다. 이 GIF는 Ajax 호출이 진행되는 동안 표시된다. Ajax 호출이 완료되면 진행 표시기가 확대/축소 메뉴로 바뀐다. Listing 13에서는 이러한 작업을 수행하는 코드를 보여 준다.


Listing 13. Ajax 요청 모니터링하기
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
     value="#{cc.parent.attrs.location.zoomIndex}"
     style="font-size:13px;font-family:Palatino">

  <f:ajax render="map" onevent="zoomChanging"/>
  <f:selectItems value="#{places.zoomLevelItems}"/>

  ...             
</h:selectOneMenu>
...
<h:graphicImage id="progressbar" style="display: none" 
              library="images" name="orange-barber-pole.gif"/>

Listing 13에서는 처음에는 표시되지 않는 진행 표시줄 이미지를 추가하고 <f:ajax>에 대한 onevent 속성을 지정한다. 이 속성은 Listing 13에서 실행된 Ajax 호출이 진행되는 동안 JSF가 호출하게 되는 JavaScript 함수(Listing 14 참조)를 참조한다.


Listing 14. Ajax 요청에 응답하는 JavaScript

function zoomChanging(data) {
  var menuId = data.source.id;
  var progressbarId = menuId.substring(0, menuId.length - "menu".length)
      + "progressbar";

  if (data.name == "begin") {
    Element.hide(menuId);
    Element.show(progressbarId);
  } 
  else if (data.name == "success") {
    Element.show(menuId);
    Element.hide(progressbarId);
  }
}

Listing 14의 함수는 이벤트를 발생시킨 구성 요소(이 경우에는 확대/축소 수준 메뉴)의 클라이언트 ID 및 name 특성으로 표현되는 Ajax 요청의 현재 상태와 같은 정보가 포함된 개체를 받는다.

Listing 14zoomChanging() 함수는 진행 표시줄 이미지의 클라이언트 ID를 계산한 다음 Prototype Element 개체를 사용하여 Ajax 호출 동안 해당 HTML 요소를 숨기거나 표시한다.




위로


결론

JSF 1은 여러 해 동안 사용하기 어려운 프레임워크로 인식되었으며 이러한 인식은 여러 면에서 타당한 이유를 가지고 있었다. JSF 1은 실제 사용 환경을 충분히 고찰하지 않은 채로 상아탑에서 개발되었기 때문에 애플리케이션과 구성 요소를 구현하기가 매우 어려웠다.

이와는 달리 JSF 2는 JSF 1를 기반으로 오픈 소스 프로젝트를 구현한 개발자에 의해 실제 경험을 바탕으로 개발되었기 때문에 Ajax 스타일의 강력한 애플리케이션을 쉽게 구현할 수 있는 다재다능한 프레임워크가 될 수 있었다.

이 시리즈에서는 어노테이션, 구성 대체 규칙, 단순화된 탐색, 리소스 지원, 복합 구성 요소, 내장 Ajax, 확장 이벤트 모델 등의 몇 가지 유명한 JSF 2 기능을 살펴보았다. 하지만 JSF 2에는 보기 및 페이지 범위, 책갈피를 지정할 수 있는 페이지에 대한 지원 및 프로젝트 스테이지와 같이 이 시리즈에서 다루지 않은 기능들도 많이 있다. 이러한 기능도 모두 이전 버전에 비해 크게 향상된 JSF 2를 만드는 데 중요한 역할을 맡고 있다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
Source code for the article examplesj-jsf2-fu-3.zip7.7MBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기
  • JSF: JSF 2.0을 다운로드할 수 있다.

  • GMaps4JSF: GMaps4JSF를 다운로드할 수 있다.

토론


필자소개

David Geary

저자, 강사 및 컨설턴트인 David Geary는 개발자에게 JSF와 GWT(Google Web Toolkit)를 사용하여 웹 애플리케이션을 구현하는 방법을 가르치는 Clarity Training, Inc.의 사장이다. JSTL 1.0 및 JSF 1.0/2.0 Expert Groups의 일원이었으며, Sun에서 시행하는 Web Developer Certification Exam의 공동 출제자였으며, Apache Struts 및 Apache Shale을 포함한 오픈 소스 프로젝트에 기여했다. 그가 집필한 Graphic Java Swing은 꾸준히 베스트셀러로 판매되고 있는 Java 서적 중 하나이며 Core JSF(Cay Horstman과 공동 집필)는 현재 베스트셀러로 판매되고 있는 JSF 서적이다. 컨퍼런스와 사용자 그룹에서 정기적으로 강의를 하고 있으며 2003년부터 NFJS tour에서 정회원으로 활동 중이며 Java University에서 여러 과정을 맡고 있으며 JavaOne rock star로 두 차례 선정되었다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


Java 및 모든 Java 관련 상표는 미국 또는 기타 국가에서 사용되는 Sun Microsystems, Inc.의 상표이다. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의