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

한국 developerWorks  >  자바 | 웹 개발  >

JSF 2 fu, Part 1: 웹 애플리케이션 개발 합리화하기

JSF 2를 사용하여 탐색을 간소화하고 XML 구성을 없애고 리소스에 쉽게 액세스하기

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

PDF - Fits A4 and Letter
394KB (19 pages)

Get Adobe® Reader®

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

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

David Geary, President, Clarity Training, Inc.

원문 게재일 : 2009 년 5 월 12 일
번역 게재일 : 2009 년 7 월 14 일

JSF(Java™ Server Faces) 버전 2.0에서는 강력한 Ajaxified 웹 애플리케이션을 쉽게 구현할 수 있습니다. 이 기사는 JSF 2.0 Expert Group 회원인 David Geary가 집필한 3편의 기사로 구성된 시리즈의 첫 번째 기사이며 JSF 2의 새 기능을 활용하는 방법에 대해 설명합니다. 또한 JSF 2 개발 작업을 합리화할 수 있도록 XML 구성을 어노테이션 및 규칙으로 대체하는 방법, 탐색을 간소화하는 방법 및 리소스에 쉽게 액세스하는 방법에 대해 설명합니다. 또한 애플리케이션에서 Groovy를 사용하는 방법에 대해서도 살펴봅니다.

지식인들이 모여서 기술을 개발하는 상아탑과 수 없이 쏟아지는 요구를 해결하는 과정에서 프레임워크가 탄생되는 실제 환경 중에서 어느 쪽이 웹 애플리케이션 프레임워크를 탄생시키는 데 가장 적합한 환경인지에 대한 논쟁이 진행되고 있다. 상아탑보다는 수 없이 많은 요구가 쏟아지는 실제 환경이 우세한 듯 보이며 필자 또한 이러한 의견이 현실에 더 가깝다고 생각한다.

JSF 1은 상아탑에서 개발되었으며 아주 좋은 결실을 맺지는 못했다. (물론 JSF 1의 결과에 대해서는 다른 견해를 가진 사람들도 있다.) 하지만 JSF는 한 가지 중요한 성과를 거두었다. 그것은 바로 시장이 실제 환경의 수많은 혁신을 따라잡을 수 있게 되었다는 점이다. 초기에 Facelets가 JSP(JavaServer Pages)의 강력한 대안으로 등장한 후 다양한 기능을 제공하는 JSF Ajax 라이브러리인 Rich Faces, JSF를 통해 독창적인 방식으로 Ajax를 지원하는 ICEFaces, Seam, Spring Faces, Woodstock 구성 요소, JSF Templating 등이 그 뒤를 이었다. 이러한 오픈 소스 JSF 프로젝트는 모두 필요에 의해 기능을 구현한 개발자에 의해 개발되었다.

JSF 2.0 Expert Group에서는 기본적으로 이러한 오픈 소스 프로젝트의 우수한 기능 중 일부를 표준화했다. JSF 2를 개발하는 과정에서 여러 지식인의 도움을 받은 것도 사실이지만 실제 환경에서 요구하는 혁신 또한 JSF 2의 원동력이었다. 돌이켜 보면 Gavin King(Seam), Alexandr Smirnov(Rich Faces), Ted Goddard(ICEFaces) 및 Ken Paulson(JSF Templating)과 같은 선구자가 미리 닦아 놓은 길이 있었기 때문에 Expert Group에서 이처럼 큰 작업을 비교적 쉽게 완수할 수 있었다는 생각이 든다. 실제로 이들 선구자 모두 JSF 2 Expert Group의 일원이었다. 여러 가지 관점에서 보았을 때 JSF 2에는 상아탑과 실제 환경의 장점이 결합되어 있으며 그에 걸맞은 결과를 보여 주기도 한다. JSF 2는 이전 버전에 비해 매우 많은 부분이 향상되었다.

3편으로 구성된 시리즈 중 첫 번째인 이 기사의 두 가지 목적은 흥미로운 JSF 2 기능을 소개하는 것과 JSF 2에서 제공하는 기능을 활용할 수 있도록 이러한 기능을 효과적으로 사용하는 방법을 보여 주는 것이다. 이 기사에서는 두 가지 목적을 동시에 추구하기 위해 JSF 2를 사용하는 방법과 JSF를 효과적으로 사용하는 데 도움이 되는 몇 가지 팁을 함께 설명한다. 이 기사에서 제시할 팁은 다음과 같다.

  • 팁 1: XML 구성 제거하기
  • 팁 2: 탐색 간소화하기
  • 팁 3: Groovy 사용하기
  • 팁 4: 리소스 처리 활용하기

먼저 이 시리즈의 모든 기사에서 사용되는 예제 애플리케이션을 살펴보자. 이 기사에서 설명하는 애플리케이션 소스 코드는 다운로드 섹션에서 다운로드할 수 있다.

필수 맵핑 기반 웹 서비스 매시업 예제

그림 1에서는 주소를 확대/축소 레벨과 기상 예보 기능이 제공되는 지도로 변환하는 JSF 매시업(이하 places 애플리케이션)이라고 부른다.


그림 1. Yahoo! 웹 서비스의 지도 및 날씨 정보 보기
Yahoo! 웹 서비스의 지도 및 날씨 정보 보기

장소를 작성하려면 주소 양식을 입력하고 Go 단추를 누른다. 그러면 애플리케이션이 해당 주소를 Yahoo! Maps 및 Yahoo! Weather라는 두 웹 서비스에 전달한다.

Map 서비스에서는 Yahoo! 서버에서 해당 주소와 일치하는 11개의 지도 URL을 확대/축소 레벨에 따라 리턴한다. Weather 서비스는 미리 조합되어 있는 HTML을 전달한다. 이미지 URL 및 HTML은 각기 <h:graphicImage><h:outputText>를 통해 JSF에 쉽게 표시된다.

places 애플리케이션에서는 주소를 원하는 만큼 입력할 수 있다. 그림 2와 같이 동일 주소를 여러 번 사용할 수도 있다. 그림 2의 실제 용도는 확대/축소 레벨을 보여 주기 위한 것이다.


그림 2. 확대/축소 레벨
확대/축소 레벨

애플리케이션의 핵심

places 애플리케이션에는 표 1에 나열된 것과 같은 4개의 관리 Bean이 있다.


표 1. places 애플리케이션의 관리 Bean
관리 Bean 이름클래스범위
mapServicecom.clarity.MapService 애플리케이션
weatherServicecom.clarity.WeatherService애플리케이션
placescom.clarity.Places 세션
placecom.clarity.Place 요청
places 애플리케이션 실행하기

places 애플리케이션을 실행하려면 Yahoo! 웹 서비스를 사용하는 데 필요한 애플리케이션 ID를 Yahoo!(developer.yahoo.com/maps/ajax)로부터 받아야 한다. Yahoo! Maps 웹 서비스에서 Get an App ID 단추를 클릭한다. ID를 받은 후에는 MapService.javaWeatherService.java에서 YOUR_ID_HERE를 이 ID로 바꾼다.

이 애플리케이션의 경우 그림 1에서 보여 주는 것과 같은 Place의 목록은 세션 범위에 저장되고 하나의 Place는 요청 범위에서 관리된다. 또한 이 애플리케이션은 애플리케이션 범위의 mapServiceweatherService 관리 Bean을 사용하여 Yahoo!의 Map 및 Weather 웹 서비스와의 상호 작용을 지원하는 간단한 API를 제공한다.

장소는 쉽게 작성할 수 있다. Listing 1에서는 그림 1의 보기에 포함된 주소 양식에 대한 코드를 보여 준다.


Listing 1. 주소 양식
<h:form>
  <h:panelGrid columns="2">
    #{msgs.streetAddress} <h:inputText value="#{place.streetAddress}" size="15"/>
    #{msgs.city}          <h:inputText value="#{place.city}"          size="10"/>
    #{msgs.state}         <h:inputText value="#{place.state}"         size="2"/>
    #{msgs.zip}           <h:inputText value="#{place.zip}"           size="5"/>

    <h:commandButton value="#{msgs.goButtonText}"
        style="font-family:Palatino;font-style:italic"
        action="#{place.fetch}"/>

  </h:panelGrid>
</h:form>

사용자가 Go 단추를 눌러서 양식을 제출하면 JSF에서 단추의 동작 메소드인 place.fetch()가 호출된다. 이 메소드는 웹 서비스의 정보를 Place.addPlace()에게 보낸다. Place.addPlace()는 새 Place 인스턴스를 생성한 후 전달 받은 데이터를 사용하여 인스턴스를 초기화한 다음 요청 범위에 저장한다.

Listing 2에서는 Place.fetch()를 보여 준다.


Listing 2. Place.fetch() 메소드
public class Place {
  ...
  private String[] mapUrls
  private String weather
  ...
  public String fetch() {
    FacesContext fc = FacesContext.getCurrentInstance()
    ELResolver elResolver = fc.getApplication().getELResolver()

    // Get maps

    MapService ms = elResolver.getValue(
      fc.getELContext(), null, "mapService")

    mapUrls = ms.getMap(streetAddress, city, state)

    // Get weather

    WeatherService ws = elResolver.getValue(
      fc.getELContext(), null, "weatherService")

    weather = ws.getWeatherForZip(zip, true)

    // Get places

    Places places = elResolver.getValue(
      fc.getELContext(), null, "places")

    // Add new place to places

    places.addPlace(streetAddress, city, state, mapUrls, weather)

    return null
  }
}

Place.fetch()는 JSF의 변수 확인자를 사용하여 mapServiceweatherService 관리 Bean을 찾은 다음 이러한 관리 Bean을 사용하여 Yahoo! 웹 서비스로부터 지도 및 날씨 정보를 가져온다. 그런 다음 fetch()places.addPlace()를 호출하면 호출된 메소드가 지도 및 날씨 정보와 주소를 함께 사용하여 요청 범위의 새 Place를 작성한다.

fetch()null을 리턴한다는 점에 주의해야 한다. fetch()는 단추와 연관된 동작 메소드이기 때문에 null 값이 리턴되면 JSF가 동일한 보기를 다시 로드하게 되며 결과적으로 Listing 3과 같이 사용자의 세션에 있는 모든 장소가 표시된다.


Listing 3. 하나의 보기에서 여러 장소 표시하기
<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">

  <h:form>
    <!-- Iterate over the list of places -->
    <ui:repeat value="#{places.placesList}" var="place">

      <div class="placeHeading">
        <h:panelGrid columns="1">

          <!-- Address at the top -->
          <h:panelGroup>
            <div style="padding-left: 5px;">
              <i><h:outputText value="#{place.streetAddress}"/></i>, 
              <h:outputText value="#{place.city}"/>
              <h:outputText value="#{place.state}"/>
              <hr/>
            </div>
          </h:panelGroup>

          <!-- zoom level prompt and drop down -->
          <h:panelGrid columns="2">
            <!-- prompt -->
            <div style="padding-right: 10px;margin-bottom: 10px;font-size:14px">
              #{msgs.zoomPrompt}
            </div>

            <!-- dropdown -->
            <h:selectOneMenu onchange="submit()"
                 value="#{place.zoomIndex}"
                 valueChangeListener="#{place.zoomChanged}"
                 style="font-size:13px;font-family:Palatino">

              <f:selectItems value="#{places.zoomLevelItems}"/>

            </h:selectOneMenu>
          </h:panelGrid>

          <!-- The map -->
          <h:graphicImage url="#{place.mapUrl}" style="border: thin solid gray"/>

        </h:panelGrid>

        <!-- The weather -->
        <div class="placeMap">
          <div style="margin-top: 10px;width:250px;">
            <h:outputText style="font-size: 12px;"
              value="#{place.weather}"
              escape="false"/>
          </div>
        </div>
      </div>

    </ui:repeat>
  </h:form>

</ui:composition>

Listing 3의 코드에서는 Facelets <ui:repeat> 태그를 사용하여 사용자의 세션에 저장된 장소 목록을 반복한다. 각 장소에 대한 출력은 그림 3과 비슷하다.


그림 3. 보기에 표시된 장소
보기에 표시된 장소

확대/축소 레벨 변경하기

zoom 메뉴(그림 3Listing 3 참조)에는 onchange="submit()" 속성이 있기 때문에 사용자가 확대/축소 레벨을 선택하면 JavaScript submit() 함수가 zoom 메뉴와 관련된 양식을 제출한다. 양식이 제출되면 JSF가 메뉴와 관련된 값 변경 수신기인 Place.zoomChanged() 메소드(Listing 4 참조)를 호출한다.


Listing 4. Place.zoomChanged()
public void zoomChanged(ValueChangeEvent e) {
  String value = e.getComponent().getValue()
  zoomIndex = (new Integer(value)).intValue()
}

Place.zoomChanged()는 확대/축소 레벨을 Place 클래스인 zoomIndex의 멤버 변수에 저장한다. 이 서버와의 통신은 탐색에 영향을 주지 않기 때문에 JSF가 동일한 페이지를 다시 로드하게 되면서 지도가 새 확대/축소 레벨로 갱신된다. 이 작업은 예제 코드의 <h:graphicImage url="#{place.mapUrl}..."/>에서 수행된다. 이미지가 그려질 때 JSF는 현재 확대/축소 레벨에 해당하는 지도 URL을 리턴하는 Place.getMapUrl()을 호출한다(Listing 5 참조).


Listing 5. Place.getMapUrl()
public String getMapUrl() {
  return mapUrls == null ? "" : mapUrls[zoomIndex]
}

Facelets의 등장

JSF 1을 사용해 보았다면 이 기사에서 설명하는 JSF 2 코드와의 미세한 차이점을 느꼈을 것이다. 먼저 이 기사에서는 JSP 대신 JSF 2의 새로운 표시 기술인 Facelets를 사용한다. Facelets는 강력하고 유연하며 확장성 높은 사용자 인터페이스를 구현하는 데 도움이 되는 여러 가지 강력한 기능을 제공한다. 이에 대해서는 이 시리즈의 후속 기사에서 자세히 설명할 것이며 지금까지의 코드 Listing에서는 Facelets의 기능을 자세히 다루지 않았다. 하지만 JSF에서 Facelets의 도입으로 인해 향상된 여러 사항 중 하나는 JSF 값 표현식을 XHTML 페이지에 직접 배치할 수 있게 되었다는 것이다. 예를 들어, Listing 1의 경우 #{msgs.city}와 같은 표현식을 페이지에 직접 배치한다. JSF 1에서는 <h:outputText value="#{msgs.city}"/>와 같이 표현식을 <h:outputText>로 랩핑해야 한다. 하지만 보안 상의 이유로 사용자로부터 입력을 받은 텍스트는 항상 이스케이프해야 한다. 예를 들어, 이 기사의 Listing 3에서는 장소 정보를 표시하기 위해 해당 텍스트를 기본적으로 이스케이프하는 <h:outputText>를 사용한다.

Facelets 관점에서 Listing 3<ui:composition> 태그도 살펴볼 필요가 있는 부분이다. 이 태그는 Listing 3의 XHTML 페이지가 다른 XHTML 페이지에 포함된다는 것을 나타낸다. Facelets composition은 유명한 Apache Tiles 프레임워크와 비슷한 Facelets templating의 핵심 구성 요소이다. 이 시리즈의 후속 기사에서 Facelets templating에 대해 자세히 살펴본 후 Composed Method Smalltalk 패턴에 따라 보기를 구조화는 방법에 대해 설명한다.

Facelets를 사용하고 있다는 점을 제외하면 지금까지 설명한 코드는 JSF 1과 크게 다르지 않았다. 이제부터는 몇 가지 중요한 차이점을 살펴볼 것이다. 첫 번째 중요한 차이점은 JSF 2 애플리케이션의 경우 XML 구성을 많이 작성하지 않아도 된다는 것이다.




위로


팁 1: XML 구성 제거하기

웹 애플리케이션에 대한 XML 구성에는 항상 의심의 여지가 있었다. 즉, 지루하고 오류가 발생하기 쉬운 작업이기 때문에 어노테이션, 규칙 또는 도메인 관련 언어를 통해 프레임워크에서 대신 처리하는 것이 최선의 대안이다. 개발자라면 XML의 세세한 부분을 처리하는 데 기력을 쏟기 보다는 중요한 부분을 처리하는 데 집중할 수 있어야 한다.

예를 들어, Listing 6에서는 JSF 1을 사용하여 places 애플리케이션의 관리 Bean을 선언하는 데 필요한 20행의 XML을 보여 준다.


Listing 6. JSF 1의 managed-bean 선언
<managed-bean>
  <managed-bean-class>com.clarity.MapService</managed-bean-class>
  <managed-bean-name>mapService</managed-bean-name>
  <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

<managed-bean>
  <managed-bean-class>com.clarity.WeatherService</managed-bean-class>
  <managed-bean-name>weatherService</managed-bean-name>
  <managed-bean-scope>application</managed-bean-scope>
</managed-bean>

<managed-bean>
  <managed-bean-class>com.clarity.Places</managed-bean-class>
  <managed-bean-name>places</managed-bean-name>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<managed-bean>
  <managed-bean-class>com.clarity.Place</managed-bean-class>
  <managed-bean-name>place</managed-bean-name>
  <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

JSF 2에서는 XML을 사용하지 않고 Listing 7과 같이 클래스를 어노테이션으로 처리한다.


Listing 7. JSF 2의 관리 Bean 어노테이션
@ManagedBean(eager=true)
public class MapService {
  ...
}

@ManagedBean(eager=true)
public class WeatherService {
  ...
}

@ManagedBean()
@SessionScoped
public class Places {
  ...
}

@ManagedBean()
@RequestScoped
public class Place {
  ...
}

규칙에 따라 관리 Bean의 이름은 클래스 이름과 동일하며 클래스 이름의 첫 번째 문자가 소문자로 변환된다. 예를 들어, Listing 7에서 작성된 관리 Bean을 위에서부터 차례대로 나열하면 mapService, weatherService, placesplace이다. ManagedBean 어노테이션의 name 속성을 사용하여 @ManagedBean(name = "place")과 같은 형식으로 관리 Bean 이름을 명시적으로 지정할 수도 있다.

Listing 7에서는 mapServicewebService 관리 Bean의 eager 속성을 사용한다. eager 속성이 true이면 시작 시에 관리 Bean이 작성되어 애플리케이션 범위에 배치된다.

@ManagedProperty 어노테이션을 사용하여 관리 Bean 특성을 설정할 수도 있다. 표 2에서는 JSF 2 관리 Bean 어노테이션의 전체 목록을 보여 준다.


표 2. JSF 2 관리 Bean 어노테이션(@...Scoped 어노테이션은 @ManagedBean과 함께 사용해야 함)
관리 Bean 어노테이션설명속성
@ManagedBean

해당 클래스의 인스턴스를 관리 Bean으로 등록한 후 @...Scoped 어노테이션 중 하나를 사용하여 지정된 범위에 배치한다. 범위를 지정하지 않은 경우에는 bean이 요청 범위에 배치되며, 이름을 지정하지 않은 경우에는 첫 번째 문자가 소문자로 변환된 클래스 이름이 관리 Bean 이름으로 사용된다. 예를 들어, 클래스 이름이 UserBean일 경우 userBean이라는 이름의 관리 Bean이 작성된다. eager name 속성은 둘 다 선택적이다.

이 어노테이션은 인수가 없는 생성자를 구현한 Java 클래스와 함께 사용해야 한다.

eager, name
@ManagedProperty

관리 Bean의 특성을 설정한다. 어노테이션은 클래스 멤버 변수의 선언 앞에 있어야 한다. name 속성은 특성의 이름을 지정하며, 기본적으로 멤버 변수의 이름이 사용된다. value 속성은 특성의 값이며 문자열 또는 JSF 표현식(예: #{...})일 수 있다.

value, name
@ApplicationScoped관리 Bean을 애플리케이션 범위에 저장한다.
@SessionScoped관리 Bean을 세션 범위에 저장한다.
@RequestScoped관리 Bean을 요청 범위에 저장한다.
@ViewScoped관리 Bean을 보기 범위에 저장한다.
@NoneScoped관리 Bean에 범위가 지정되어 있지 않음을 지정한다. 범위가 지정되지 않은 관리 Bean은 해당 bean을 다른 bean에서 참조할 때 유용하다.
@CustomScoped

관리 Bean을 사용자 정의 범위에 저장한다.

사용자 정의 범위는 페이지 작성자가 액세스할 수 있는 지도이다. 사용자 정의 범위에 있는 bean의 가시성 및 수명은 프로그래밍 방식으로 제어할 수 있다. value 속성은 지도를 가리킨다.

value

faces-config.xml에서 관리 Bean 선언을 제거하면 XML이 상당히 줄어들지만 필자가 관리 Bean에 대해 수행한 것처럼 어노테이션을 사용하거나 JSF 2의 간소화된 탐색 처리처럼 규칙을 사용하는 방법을 통해 JSF 2를 사용하면 실제로 거의 모든 XML을 제거할 수 있다.




위로


팁 2: 탐색 간소화하기

JSF 1에서는 탐색이 XML에 지정되었다. 예를 들어, login.xhtml에서 places.xhtml로 이동하기 위해 Listing 8의 탐색 규칙을 사용할 수 있다.


Listing 8. JSF 1의 탐색 구성 규칙 및 케이스
<navigation-rule>
  <navigation-case>
    <from-view-id>/pages/login.xhtml</from-view-id>
    <outcome>places</outcome>
    <to-view-id>/pages/places.xhtml</to-view-id>
  </navigation-case>
</navigation-rule>

Listing 8에서 XML을 제거하기 위해 JSF 2의 탐색 규칙을 활용할 수 있다. JSF는 단추의 동작 끝에 .xhtml을 추가한 후 해당 파일을 로드한다. 이는 곧 어노테이션 등이 없어도 규칙만 있으면 navigation-rule-writing 비즈니스를 완전히 제거할 수 있음을 의미한다. Listing 9에서는 단추의 동작이 places이므로 places.xhtml이 로드된다.


Listing 9. 규칙을 통한 탐색
<h:commandButton id="loginButton"
  value="#{msgs.loginButtonText}"
  action="places"/>

Listing 9의 경우에는 탐색 XML이 필요하지 않다. Listing 9의 단추는 places.xhtml 파일이 단추가 있는 파일과 같은 디렉토리에 있는 경우에만 places.xhtml을 로드한다. 슬래시(/)로 시작되지 않는 동작은 JSF에서 상대 경로로 간주된다. 좀 더 명시적으로 지정하려는 경우 Listing 10과 같이 절대 경로를 지정할 수 있다.


Listing 10. 절대 경로를 이용한 탐색
<h:commandButton id="loginButton"
  value="#{msgs.loginButtonText}"
  action="/pages/places"/>

사용자가 Listing 10의 단추를 활성화하면 /pages/places.xhtml 파일이 로드된다.

기본적으로 JSF는 한 XHTML 페이지에서 다른 XHTML 페이지로 이동하지만 Listing 11과 같이 faces-redirect 매개변수를 사용하여 리디렉션할 수도 있다.


Listing 11. 리디렉션을 이용한 탐색
<h:commandButton id="loginButton"
  value="#{msgs.loginButtonText}"
  action="places?faces-redirect=true"/>




위로


팁 3: Groovy 사용하기

Java 기술의 정수는 Java 언어가 아니라 JVM(Java virtual machine)이다. JVM에서 실행되는 Scala, JRuby 및 Groovy와 같은 강력하고 혁신적인 새로운 언어는 새로운 차원의 코드 작성 환경을 제공한다. 이름과는 달리 Ruby, Smalltalk 및 Java 언어의 장점을 결합해 놓은 Groovy는 이러한 언어 중에서 인기가 많은 언어에 속한다(참고자료 참조).

Groovy를 사용하는 이유로는 사촌 형제라고 할 수 있는 Java 언어에 비해 훨씬 단순하면서도 강력하다는 점부터 시작하여 여러 가지가 있다. 그 중 두 가지 이유는 세미콜론과 캐스팅이 필요하지 않다는 것이다.

모르고 지나쳤을 수도 있겠지만 Place 클래스를 보여 주는 Listing 2는 Groovy로 작성된 코드이다. 세미콜론이 없는 것을 보고 알 수도 있었겠지만 코드에서 MapService ms = elResolver.getValue(...) 행을 보면 확실히 알 수 있다. Java 코드에서는 ElResolver.getValue()Object 유형을 리턴하므로 결과를 캐스팅해야 한다. 하지만 Groovy에서는 캐스팅이 자동으로 수행된다.

일반적으로 Java 코드로 작성하게 되는 구성 요소, 렌더러, 유효성 검증기 및 변환기와 같은 JSF 아티팩트에도 Groovy를 사용할 수 있다. 실제로 이 기능은 JSF 2에서 새로운 기능이 아니다. Groovy 소스 파일은 Java 바이트코드로 컴파일되므로 Groovy에서 생성된 .class 파일을 javac에서 생성된 코드처럼 사용할 수 있다. 지금까지의 작업을 모두 이해했다면 당연히 Groovy 소스 코드를 빠르게 전개할 수 있는 방법을 알고 싶을 것이다. Eclipse 사용자의 경우에는 이 방법이 매우 간단하다. Groovy Eclipse 플러그인(참고자료 참조)을 다운로드한 후 설치하기만 하면 되기 때문이다. Sun의 JSF 구현인 Mojarra의 경우에는 1.2_09 버전부터 Groovy를 명시적으로 지원하고 있다(참고자료 참조).




위로


팁 4: 리소스 처리기 사용하기

JSF 2에는 리소스를 정의 및 액세스하는 작업에 대한 표준 메커니즘이 있다. 즉, resources라는 최상위 레벨 디렉토리에 리소스를 저장하고 몇 가지 JSF 2 태그를 사용하여 보기에서 리소스에 액세스한다. 예를 들어, 그림 4에서는 places 애플리케이션의 리소스를 보여 준다.


그림 4. places 애플리케이션의 리소스
Places 애플리케이션의 리소스

리소스에 적용되는 유일한 요구 사항은 resources 디렉토리 또는 그 서브디렉토리에 있어야 한다는 것이다. resources 디렉토리의 서브디렉토리에는 사용자가 원하는 이름을 지정할 수 있다.

보기 코드에서 <h:outputScript><h:outputStylesheet>라는 한 쌍의 JSF 2 태그를 사용하여 리소스에 액세스할 수 있다. 이들 태그는 JSF 2의 <h:head><h:body> 태그와 함께 작동한다(Listing 12 참조).


Listing 12. XHTML에서 리소스에 액세스하기
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">

  <h:head>
    ...
  </h:head>

  <h:body>
    <h:outputStylesheet library="css" name="styles.css" target="body"/>
    <h:outputScript library="javascript" name="util.js" target="head"/>
    ...
  </h:body>
</html>

<h:outputScript><h:outputStylesheet> 태그에는 각각 스크립트 또는 스타일시트를 식별하는libraryname이라는 두 속성이 있다. library 이름은 리소스가 있는 resources 디렉토리의 서브디렉토리에 해당한다. 예를 들어, resources/css/en 디렉토리에 스타일시트가 있는 경우 library의 이름은 css/en이 된다. name 속성은 리소스 자체의 이름이다.

재할당 가능한 리소스

페이지에서 리소스를 표시할 위치를 지정하는 기능은 개발자에게 중요한 기능이다. 예를 들어, JavaScript를 페이지 본문에 배치한 경우에는 페이지가 브라우저에 로드될 때 JavaScript가 실행된다. 이에 반해 페이지의 머리글에 JavaScript를 배치한 경우에는 호출될 때만 JavaScript가 실행된다. 리소스의 위치에 따라 리소스의 사용 방법이 달라지므로 리소스의 위치를 지정할 수 있어야 한다.

JSF 2 리소스는 재할당 가능하다. 이는 리소스를 배치할 페이지 내의 위치를 개발자가 지정할 수 있다는 뜻이다. 이 위치는 target 속성을 사용하여 지정한다. 예를 들어, Listing 12에서는 본문에 CSS가 있고 머리글에 JavaScript가 있다.

JSF EL(expression language)을 사용하여 리소스에 액세스해야 하는 경우도 있다. 예를 들어, Listing 13에서는 <h:graphicImage>를 사용하여 이미지에 액세스하는 방법을 보여 준다.


Listing 13. JSF 표현식 언어를 사용하여 리소스에 액세스하기
<h:graphicImage value="#{resource['images:cloudy.gif']}"/>

Listing 13에 대한 대안 - EL을 사용하지 않고 수행하는 방법

Listing 13의 구문은 직관적으로 파악하기가 쉽지 않은 편이다. 실제로는 JSF에서 작성된 지도에 액세스하여 리소스를 저장하기 때문에 이 구문을 사용할 필요가 거의 없다. <h:graphicImage library="images" name="cloudy.gif"/>와 같이 EL을 사용하지 않고 <h:graphicImage/>를 사용하여 이미지에 액세스할 수 있다.

EL 표현식 내에서 리소스에 액세스하는 구문은 resource['LIBRARY:NAME']이다. 여기서, LIBRARYNAME<h:outputScript><h:outputStylesheet> 태그의 libraryname 속성에 해당한다.




위로


후속 기사 소개

이 기사에서는 관리 Bean 어노테이션, 간소화된 탐색 및 리소스 지원 등과 같이 JSF 2 기능과 관련된 기본적인 내용만을 다루었다. 이 시리즈의 나머지 두 기사에서는 Facelets, JSF 2의 복합 구성 요소 및 내장 Ajax 지원에 대해 설명한다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
Source code jsf2fu1.zip1.9MBHTTP
다운로드 방식에 대한 정보


참고자료

교육

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

  • Groovy Eclipse Plugin: 이 플러그인을 사용하여 Groovy 개발 과정을 간소화할 수 있다.


토론


필자소개

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 소개 개인정보 보호정책 문의