|
Facelets 및 JSF 2
오픈 소스 Facelets 구현을 표준화하는 동안 JSF 2 Expert Group에서는 태그 라이브러리와의 역호환성을 유지하면서 기본 Facelets API에 몇 가지 변경 사항을 적용했다. 즉, 오픈 소스 버전의 Facelets로 구현한 기존 보기가 JSF 2에서도 작동된다.
소프트웨어 개발자로서 필자의 첫 작업은 UNIX 기반 CAD/CAM(computer-aided design and computer-aided manufacturing) 시스템의 GUI를 구현하는 것이었다.
처음에는 모든 작업이 순조롭게 진행되었지만 시간이 지나면서 필자의 코드에서는 점점 더 많은 문제가 발暉杉? 제품을 릴리스할 때까지 버그를 수정하기에 여념이 없을 정도로 시스템이 불안했으며 버그 보고서가 수없이 쏟아져 나왔다.
이 프로젝트를 수행할 때 DRY(Don't Repeat Yourself) 원칙을 따랐다면 그렇게 노심초사하지 않아도 되었을 것이다. Dave Thomas와 Andy Hunt가 제안한 DRY 원칙은 다음과 같다.
모든 지식은 시스템 내에서 명백하고 신뢰할 수 있는 단일 형태로 표현되어야 한다.
필자의 CAD/CAM 애플리케이션은 DRY하지 않았다. 즉, 서로 연결되어 있는 항목이 너무 많아서 한 영역에서 변경하게 되면 다른 영역에서 예기치 않은 변경이 발생했다.
JSF 1은 여러 면에서 DRY 원칙을 위반했다. 예를 들어, XML 및 Java 코드 형식으로 관리 Bean에 두 가지 표현을 제공해야 한다. 여러 표현이 필요하기 때문에 관리 Bean을 작성 및 변경하기가 어렵다. Part 1에서 살펴본 것처럼 JSF 2에서는 XML 대신 어노테이션을 통해 관리 Bean에 신뢰할 수 있는 단일 표현을 지정하는 방식으로 관리 Bean을 구성할 수 있다.
관리 Bean뿐만 아니라 양호해 보이는 사례(예: 모든 보기에 동일한 스타일시트가 포함되어 있는 경우)에서도 DRY 원칙이 위반되는 경우를 자주 볼 수 있다. 이 경우 스타일시트의 이름을 변경하면 여러 보기도 변경해야 한다. 가능하다면 스타일시트 포함을 캡슐화하는 것이 효과적이다.
DRY 원칙은 코드 설계에도 적용된다. 예를 들어, 트리를 탐색하는 코드가 포함된 여러 메소드가 있다면 서브클래스에서 트리 탐색 알고리즘을 캡슐화하는 방법을 사용할 수 있다.
특히 개발 과정에서 대부분의 변경이 발생하는 UI를 구현할 때는 DRY 원칙을 따르는 것이 매우 중요하다.
JSF 2에서 DRY 원칙을 지원하는 여러 가지 방법 중 하나는 templating이다. 템플리트를 통해 애플리케이션의 보기에서 공통으로 사용되는 기능을 캡슐화할 수 있기 때문에 해당 기능을 한 번만 지정하면 된다. 여러 컴퍼지션에서 하나의 템플리트를 사용하여 JSF 2 애플리케이션의 보기를 작성할 수 있다.
Part 1에서 소개한 places 애플리케이션에는 세 개의 보기가 있다(그림 1 참조).
그림 1. places 애플리케이션의 보기: login, source viewer 및 places
많은 웹 애플리케이션과 마찬가지로 places 애플리케이션에서는 같은 레이아웃을 공유하는 여러 보기가 있다. JSF templating을 사용하면 이러한 레이아웃을 비롯한 여러 가지 공유 아티팩트(예: CSS(Cascading Style Sheets) 및 xxJavaScript)를 템플리트로 캡슐화할 수 있다. Listing 1은 그림 1에서 보았던 세 보기에 대한 템플리트이다.
Listing 1의 템플리트에서는 애플리케이션의 모든 보기에 대해 다음과 같은 인프라를 제공한다.
Listing 1에서 보듯이 템플리트는 <ui:insert> 태그를 사용하여 레이아웃에 컨텐츠를 삽입한다.
Listing 1에서 창 제목, 머리글 및 오른쪽 메뉴에 했던 것처럼 <ui:insert> 태그에 대한 본문을 지정한 경우 JSF는 태그의 본문을 기본 컨텐츠로 사용한다. login 보기에 대한 마크업을 보여 주는 Listing 2를 보면 알 수 있듯이 템플리트를 사용하는 컴퍼지션은 <ui:define> 태그를 통해 컨텐츠를 정의하거나 기본 컨텐츠를 재정의할 수 있다.
login 보기에서는 창 제목, 머리글 및 오른쪽 메뉴의 경우 템플리트의 기본 컨텐츠를 사용하고 login 보기와 관련된 기능인 컨텐츠 섹션과 왼쪽 메뉴만을 정의한다.
창 제목, 머리글 또는 오른쪽 메뉴에 대한 <ui:define> 태그를 제공하여 템플리트에 정의된 기본 컨텐츠를 재정의할 수 있다. 예를 들어, Listing 3에서는 source-viewer 보기(그림 1의 가운데 사진)를 보여 준다.
source-viewer 보기는 컨텐츠 섹션 및 오른쪽 메뉴의 컨텐츠를 정의한다. 또한 왼쪽 메뉴의 경우 Listing 1의 템플리트에서 정의한 기본 컨텐츠를 재정의한다.
Listing 4에서는 places 보기(그림 1의 맨 아래 사진)를 보여 준다.
Listing 2, 3 및 4에는 유사점이 있다. 즉, 세 보기 모두 해당 템플리트를 지정하고 컨텐츠를 정의한다. 또한 보기 인프라의 대부분이 템플리트와 포함 파일로 캡슐화되기 때문에 새 보기를 쉽게 작성할 수 있다.
JSF templating 사용과 관련하여 또 하나 흥미로운 점은 Listing 2, 3 및 4에서 살펴본 것과 같은 보기가 시간이 지나도 변경되지 않기 때문에 기본적으로 보기 코드에 대한 유지보수가 필요하지 않다는 점이다.
템플리트를 사용하는 보기와 마찬가지로 템플리트도 거의 변경되지 않는다. 또한 여러 가지 공통 기능을 유지보수가 거의 필요하지 않는 코드로 캡슐화했기 때문에 보기의 실제 컨텐츠(예: login 페이지 왼쪽 메뉴의 컨텐츠)에 집중할 수 있다. 보기의 실제 컨텐츠에 집중한다는 것은 다음 팁에서 다루는 핵심 주제이다.
JSF 2 templating
templating의 기본 개념은 단순하다. 여러 보기에서 공통으로 사용되는 기능을 캡슐화하는 단일 템플리트를 정의한다. 각 보기는 컴퍼지션과 템플리트로 구성된다.
JSF는 보기를 작성할 때 컴퍼지션의 템플리트를 로드한 다음 컴퍼지션에 정의된 컨텐츠를 템플리트에 삽입한다.
CAD/CAM GUI가 릴리스된 후 필자는 Bob이라는 개발자와 함께 수 개월 동안 관련이 없는 프로젝트에 참여했다. 그의 코드 베이스에 대한 작업을 진행하면서 놀랍게도 매우 쉽게 코드를 변경하고 버그를 수정할 수 있었다.
이내 필자는 Bob의 코드와 필자의 코드 사이에 아주 큰 한 가지 차이점이 있다는 것을 알 수 있었다. 그는 대개 5 - 15행의 코드로 구성된 작은 메소드를 작성했으며 이러한 메소드들이 서로 결합되어 전체 시스템이 이루어져 있었다. 필자는 이전 프로젝트에서 많은 내용이 들어 있는 긴 메소드를 수정하기 위해 많은 고생을 해야 했지만 Bob은 원자성 기능을 가진 작은 메소드를 빠르게 결합했다. Bob의 코드와 필자의 코드 사이에서 볼 수 있는 유지보수성 및 확장성의 차이는 빛과 어둠으로 비교할 수 있을 정도였으며 필자는 그 이후로 작은 메소드에 매료되었다.
Bob과 필자 모두 당시에는 의식하지 못하고 있었지만 Smalltalk의 Composed Method라는 설계 패턴을 사용했었다.
소프트웨어를 식별 가능한 한 가지 작업을 단일 추상 수준에서 수행하는 메소드로 나눈다.
Composed Method 패턴을 사용하면 깔끔하게 문서화된 결과를 얻을 수 있다는 장점이 있다. (Neal Ford의 "Evolutionary architecture and emergent design: Composed method and SLAP"에서 이 패턴에 대한 자세한 설명을 볼 수 있다.) 여기에서는 Composed Method 패턴을 JSF 보기와 함께 사용하는 방법을 중점적으로 살펴본다.
JSF 2에서는 보기를 나눠서 더 작은 보기로 작성하는 것이 좋다. templating을 통해 공통 기능을 캡슐화하므로 보기를 더 작은 단위로 나눌 수 있다. 또한 앞에서 설명한 Listing에서 본 것처럼 JSF 2의 <ui:include> 태그를 사용하면 보기를 더 작은 기능 단위로 나눌 수 있다. 예를 들어, 그림 2에서는 places 애플리케이션 login 페이지의 왼쪽 메뉴를 보여 준다.
그리고 Listing 5에서는 메뉴의 컨텐츠를 정의하는 파일을 보여 준다.
Listing 5의 마크업은 단순하기 때문에 파일을 쉽게 읽고, 이해하고, 유지하고, 확장할 수 있다. 만일 똑같은 코드가 login 보기를 구현하는 데 필요한 모든 내용이 포함된 하나의 긴 XHTML 페이지에 있다면 코드를 변경하기가 쉽지 않을 것이다.
그림 3에서는 places 보기의 왼쪽 메뉴를 보여 준다.
Listing 6에서는 places 보기 왼쪽 메뉴의 구현을 보여 준다.
Listing 6에서는 양식을 구현하고 아이콘 구성 요소를 사용한다. (아이콘 구성 요소에 대해서는 아이콘 구성 요소에서 간단히 설명할 것이며 지금은 페이지 작성자가 이미지와 메소드에 아이콘을 연결하는 방법만 살펴본다.) 로그아웃 아이콘의 이미지는 그림 3의 맨 아래에 있으며, 로그아웃 아이콘의 메소드(places.logout())는 Listing 7에서 볼 수 있다.
필자가 보기에 places 보기의 왼쪽 메뉴를 구현한 Listing 6은 약 30행의 마크업으로 구성되어 있기 때문에 거의 최대 임계값에 도달한 것으로 보인다. 이 Listing은 읽기가 조금 어렵다. 이 코드에서 두 가지 항목 즉, 양식과 아이콘을 고유한 파일로 리팩토링할 수 있다. Listing 8에서는 양식과 아이콘을 고유한 XHTML 파일로 캡슐화한 Listing 6의 리팩토링된 버전을 보여 준다.
Listing 9에서는 addressForm.xhtml을 보여 준다.
Listing 10에서는 logoutIcon.xhtml을 보여 준다.
여러 개의 작은 파일을 사용하여 보기를 작성하면 Smalltalk의 Composed Method 패턴의 장점을 활용하게 된다. 또한 변화에 쉽게 대응할 수 있도록 파일을 구성할 수도 있다. 예를 들어, 그림 4에서는 places 애플리케이션의 세 가지 보기를 구성하고 있는 파일을 보여 준다.
그림을 보면 views, sections 및 templates라는 세 개의 디렉토리에 places 애플리케이션을 구현하는 데 사용되는 대부분의 XHTML 파일이 있는 것을 볼 수 있다. views 및 templates 디렉토리에 있는 파일은 거의 변경되지 않기 때문에 sections 디렉토리에 집중할 수 있다. login 페이지의 왼쪽 메뉴에 있는 아이콘을 변경하려는 경우 이동할 위치(sections/login/menuLeft.xhtml)를 정확히 알고 있다.
원하는 디렉토리 구조를 사용하여 XHTML 파일을 구성할 수 있다. 논리적인 구조를 사용하면 수정해야 하는 코드를 쉽게 찾을 수 있다.
DRY 원칙을 따르고 Composed Method 패턴을 사용하는 것과 더불어 사용자 정의 구성 요소를 사용하여 기능을 캡슐화하는 것도 좋은 방법이다. 구성 요소는 강력한 재사용 메커니즘이므로 이 장점을 활용할 줄 알아야 한다. JSF 1과는 달리 JSF 2에서는 사용자 정의 구성 요소를 쉽게 구현할 수 있다.
어린 시절에 필자가 좋아했던 두 가지 장난감은 화학 실험 세트와 LEGO였다. 두 가지 장난감 모두 기본적인 빌딩 블록을 결합하여 새로운 것을 만들어 내는 놀이였으며 이러한 특징은 필자가 오랫동안 소프트웨어 개발을 통해 느껴왔던 매력이기도 하다.
JSF의 가장 큰 장점은 구성 요소 모델이지만 JSF 1에서는 사용자 정의 구성 요소를 구현하기가 어려웠기 때문에 지금까지는 이 장점이 충분히 실현되지 않았다. JSF 1에서는 Java 코드를 작성하고, XML 구성을 지정하고, JSF의 수명 주기를 잘 파악하고 있어야 했다. 하지만 JSF 2에서는 다음과 같은 특징을 가지고 있는 사용자 정의 구성 요소를 구현할 수 있다.
이 기사의 나머지 부분에서는 places 애플리케이션의 세 가지 사용자 정의 구성 요소인 아이콘, 로그인 패널 및 주소에 해당하는 지도와 날찌 정보를 보여 주는 패널을 구현한다. 그 전에 먼저 JSF 2 복합 구성 요소에 대해 설명한다.
JSF 2는 Facelets templating, 리소스 처리(Part 1 참조) 및 단순한 이름 지정 규칙을 결합하여 복합 구성 요소를 구현한다. 이름으로 알 수 있듯이 복합 구성 요소는 기존 구성 요소를 사용하여 구성 요소를 작성하는 데 사용된다.
resources 디렉토리 아래에 있는 XHTML 파일에서 복합 구성 요소를 구현한 후 네임스페이스와 태그에 연결한다. 그림 5에서는 places 애플리케이션에 대한 복합 구성 요소가 구성되어 있는 모습을 보여 준다.
복합 구성 요소를 사용하려면 네임스페이스를 선언하고 태그를 사용해야 한다. http://java.sun.com/jsf/composite 뒤에 구성 요소가 있는 resources 디렉토리의 서브디렉토리 이름이 추가된 형식의 네임스페이스가 항상 사용된다. 구성 요소 자체의 이름은 .xhtml 확장자를 제외한 XHTML 파일의 이름이다. 이 규칙을 따르면 구성 작업을 추가로 수행하지 않아도 된다. 예를 들어, 다음과 같은 방법으로 places 애플리케이션에서 login 구성 요소를 사용할 수 있다.
또한 다음과 같은 방법으로 icon 구성 요소를 사용할 수 있다.
마지막으로 다음과 같은 방법으로 place 구성 요소를 사용한다.
places 애플리케이션에서는 두 가지 아이콘을 사용한다(그림 6 참조).
각 아이콘은 링크이다. 사용자가 그림 6의 왼쪽 아이콘을 클릭하면 현재 보기에 대한 마크업이 표시되는 반면 오른쪽 아이콘을 활성화하면 사용자가 애플리케이션에서 로그아웃된다.
링크에 대한 CSS 클래스 이름과 이미지를 지정할 수 있으며 링크에 메소드를 연결할 수도 있다. 이러한 메소드는 사용자가 연결된 링크를 클릭할 때 호출된다.
Listing 11에서는 places 애플리케이션에서 icon 구성 요소를 사용하여 마크업을 표시하는 방법을 보여 준다.
Listing 12에서는 icon 구성 요소를 사용하여 로그아웃하는 방법을 보여 준다.
Listing 13에서는 icon 구성 요소에 대한 코드를 보여 준다.
모든 복합 구성 요소와 마찬가지로 Listing 13의 icon 구성 요소에는 <composite:interface>와 <composite:implementation>이라는 두 섹션이 있다. <composite:interface> 섹션은 구성 요소를 구성하는 데 사용할 수 있는 인터페이스를 정의한다. icon 구성 요소에는 구성 요소의 모습을 정의하는 image와 구성 요소의 동작을 정의하는 actionMethod라는 두 가지 속성이 있다.
<composite:implementation> 섹션에는 구성 요소의 구현이 들어 있으며 이 구현에서는 #{cc.attrs.ATTRIBUTE_NAME} 표현식을 사용하여 구성 요소의 인터페이스에 정의된 속성에 액세스한다. (cc는 JSF 2 표현식 언어의 예약 키워드로 복합 구성 요소를 의미한다.)
Listing 13의 icon 구성 요소는 <h:graphicImage>의 styleClass 속성을 사용하여 이미지에 대한 CSS 클래스를 지정한다. 해당 CSS 클래스의 이름은 icon으로 하드코딩되므로 이 이름을 사용하여 CSS 클래스를 지정할 수 있다. 그리고 JSF는 애플리케이션의 모든 아이콘에 이 클래스를 사용한다. 하지만 CSS 클래스 이름을 재정의해야 하는 경우에는 어떻게 해야 할까? 이러한 경우 필자는 CSS 클래스 이름에 대해 다른 속성을 추가한 후 이 속성이 지정되지 않았을 때 사용될 기본값을 제공할 수 있다. Listing 14에서는 이 속성을 구현한 코드를 보여 준다.
Listing 14에서는 icon 구성 요소의 인터페이스에 styleClass라는 속성을 추가하고 구성 요소의 구현에서 이 속성을 참조했다. 이처럼 변경했으므로 이제부터는 다음과 같이 아이콘 이미지에 대해 선택적 CSS 클래스를 지정할 수 있다.
styleClass 속성을 지정하지 않으면 JSF는 기본값인 icon을 사용한다.
login 구성 요소: 전체적으로 구성 가능한 구성 요소
JSF 2에서는 전체적으로 구성 가능한 복합 구성 요소를 구현할 수 있다. 예를 들어, places 애플리케이션에는 login 구성 요소가 있다(그림 7 참조).
그림 7. places 애플리케이션의 login 구성 요소
Listing 15에서는 places 애플리케이션에서 login 구성 요소를 사용하는 방법을 보여 준다.
Listing 15에서는 이름 및 매개변수 프롬프트와 같은 login 구성 요소의 속성을 매개변수화할 뿐 아니라 구성 요소의 Log In 단추에 작업 리스너도 연결한다. 이 단추는 login 구성 요소의 인터페이스에서 노출된다(Listing 16 참조).
login 구성 요소의 인터페이스에서 Log In 단추는 loginButton이라는 이름으로 노출된다. 이 이름의 대상은 form이라는 이름의 양식에 있는 Log In 단추이므로 targets 속성은 form:loginButton이 된다.
Listing 17에서는 Listing 16의 Log In 단추에 연결된 작업 리스너를 보여 준다.
Listing 17의 작업 리스너는 대략적인 코드를 보여 주기 위한 것으로 사용자가 로그인할 때 서블릿 컨테이너 로그 파일에 메시지를 기록한다. 하지만 이 코드를 보면 JSF 2를 사용해서 전체적으로 구성 가능한 구성 요소를 구현할 수 있고, 이러한 구성 요소에 기능을 연결할 수 있으며 더 나아가 이 모든 작업을 Java 코드나 XML 구성 없이 수행할 수 있다는 것을 알 수 있다. 여기서 다시 한번 fu의 힘을 느낄 수 있다.
JSF 2에서는 Java 코드 또는 구성 없이 전체적으로 구성 가능한 구성 요소를 구현할 수 있다. 복합 구성 요소를 중첩할 수도 있으므로 복잡한 구성 요소를 관리하기 쉬운 작은 단위로 쪼갤 수 있다. 예를 들어, 그림 8에서는 지정된 주소에 대한 지도와 날씨 정보를 표시하는 place 구성 요소를 보여 준다.
그림 8. places 애플리케이션의 place 구성 요소
Listing 18에서는 places 애플리케이션에서 place 구성 요소를 사용하는 방법을 보여 준다.
Listing 19에서는 place 구성 요소에 대한 코드를 보여 준다.
Listing 19에서 place 구성 요소는 <places:map>과 <places:weather>라는 두 개의 중첩 구성 요소를 사용한다. Listing 20에서는 map 구성 요소를 보여 준다.
Listing 20에서는 #{cc.parent.attrs.location.ATTRIBUTE_NAME} 표현식을 사용하고 있다. 이 표현식을 보면 복합 구성 요소의 parent 속성을 사용하여 상위 구성 요소의 속성에 쉽게 액세스할 수 있다는 것을 알 수 있다. 따라서 구성 요소를 부담 없이 중첩할 수 있다.
그렇다고 해서 중첩된 구성 요소의 상위 속성에만 얽매일 필요는 없다. Listing 19의 place 구성 요소에서 했던 것처럼 중첩 여부와 상관 없이 다른 구성 요소에 속성을 전달하듯이 지도 제목과 같은 속성을 상위 구성 요소에서 중첩된 구성 요소로 전달할 수도 있다.
Listing 21에서는 weather 구성 요소를 보여 준다.
복합 구성 요소 리팩토링
map 구성 요소에 대한 마크업인 Listing 20은 필자가 보기에 조금 길다. 한눈에 이해하기가 약간 어려울 뿐만 아니라 복잡하기 때문에 나중에 문제가 발생할 수도 있다. Listing 8, 9 및 10에서 places 보기의 왼쪽 메뉴를 리팩토링했던 것처럼 Listing 20도 관리하기 쉬운 여러 파일로 쉽게 리팩토링할 수 있다. 이 경우에는 리팩토링을 연습해 볼 수 있는 기회를 주기 위해 리팩토링된 코드를 제공하지 않는다.
weather 구성 요소에서도 map 구성 요소와 마찬가지로 상위 구성 요소 속성(weather 웹 서비스의 weather HTML)과 구성 요소 관련 속성(title)을 사용한다. (Part 1에서 애플리케이션에서 특정 위치에 대한 지도 및 날씨 정보를 가져오는 방법을 볼 수 있다.)
따라서 중첩 구성 요소를 구현할 경우에는 한 가지 선택을 할 수 있다. 중첩 구성 요소가 상위 구성 요소의 속성에 의존하게 하거나 속성을 중첩 구성 요소에게 명시적으로 전달하도록 상위 구성 요소에게 요청할 수도 있다. 예를 들어, Listing 19의 place 구성 요소는 title 속성을 중첩 구성 요소에게 명시적으로 전달하지만 중첩 구성 요소는 mapURL 및 weather HTML과 같은 상위 구성 요소의 속성에 의존한다.
구성 요소에게 명시적으로 전달되는 속성을 구현할 것인지 또는 상위 속성에 의존할 것인지 여부는 커플링과 편의성 중 하나를 선택해야 하는 선택의 문제이다. 이 경우에는 map 및 weather 구성 요소가 상위 구성 요소(place 구성 요소)의 속성에 의존하고 있기 때문에 상위 구성 요소와 밀접하게 연결되어 있다. 여기에서 모든 map 및 weather 구성 요소를 명시적으로 전달되는 속성으로 지정하여 map 및 weather 구성 요소를 place 구성 요소와 분리할 수도 있었다. 하지만 그렇게 하면 place 구성 요소에서 모든 속성을 map 및 weather 구성 요소에게 명시적으로 전달해야 하기 때문에 불편함을 감수해야 한다.
설명 |
이름 |
크기 |
다운로드 방식 |
---|---|---|---|
Source code for the examples |
jsf2fu2.zip |
7.4MB |
저자, 강사 및 컨설턴트인 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로 두 차례 선정되었다.
JavaServer Faces 2로 확장 가능한 UI 구현하기
JSF(Java Server Faces) 2를 사용하면 templating 및 복합 구성 요소라는 두 가지 강력한 기능을 통해 쉽게 수정하고 확장할 수 있는 사용자 인터페이스를 구현할 수 있습니다. JSF 2의 새 기능을 다루는 3편의 기사로 구성된 시리즈의 두 번째 기사인 이 기사에서는 JSF 2 Expert Group의 회원인 David Geary가 웹 애플리케이션에서 templating 및 복합 구성 요소를 효과적으로 활용하는 방법을 보여 줍니다.
JSP(Java Server Pages) 메일링 목록에 빠져 있던 2000년에 필자는 초기 단계의 웹 프레임워크인 Struts를 개발 중이던 Craig McClanahan을 우연히 만났다. 당시 Swing에서 서버측 Java 프로그래밍으로 옮겨 오면서 필자는 Swing의 레이아웃 관리자와 비슷한 개념을 적용하여 JSP 보기의 레이아웃과 해당 컨텐츠를 분리한 작은 프레임워크를 구현했다. 필자의 templating 라이브러리를 Struts에 포함시키자는 Craig의 제안에 필자는 흔쾌히 동의했다. 이렇게 하여 Struts 1.0에 번들로 포함된 Struts Template Library는 Struts의 유명한 Tiles 라이브러리의 기반이 되었으며 결국에는 최상위 Apache 프레임워크로 발전하게 되었다.
오늘날 JSF 2의 기본 표시 기술인 Facelets는 상당 부분이 Tiles를 기반으로 하고 있는 templating 프레임워크이다. 또한 Facelets의 templating 기능을 기반으로 하는 복합 구성 요소라는 강력한 메커니즘이 제공되기 때문에 Java 코드와 XML 구성을 사용하지 않고도 사용자 정의 구성 요소를 구현할 수 있다. 이 기사에서는 JSF 2를 효과적으로 활용하는 데 도움이 되는 3가지 팁과 함께 templating 및 복합 구성 요소에 대해 설명한다.
Facelets 및 JSF 2
오픈 소스 Facelets 구현을 표준화하는 동안 JSF 2 Expert Group에서는 태그 라이브러리와의 역호환성을 유지하면서 기본 Facelets API에 몇 가지 변경 사항을 적용했다. 즉, 오픈 소스 버전의 Facelets로 구현한 기존 보기가 JSF 2에서도 작동된다.
소프트웨어 개발자로서 필자의 첫 작업은 UNIX 기반 CAD/CAM(computer-aided design and computer-aided manufacturing) 시스템의 GUI를 구현하는 것이었다.
처음에는 모든 작업이 순조롭게 진행되었지만 시간이 지나면서 필자의 코드에서는 점점 더 많은 문제가 발暉杉? 제품을 릴리스할 때까지 버그를 수정하기에 여념이 없을 정도로 시스템이 불안했으며 버그 보고서가 수없이 쏟아져 나왔다.
이 프로젝트를 수행할 때 DRY(Don't Repeat Yourself) 원칙을 따랐다면 그렇게 노심초사하지 않아도 되었을 것이다. Dave Thomas와 Andy Hunt가 제안한 DRY 원칙은 다음과 같다.
모든 지식은 시스템 내에서 명백하고 신뢰할 수 있는 단일 형태로 표현되어야 한다.
필자의 CAD/CAM 애플리케이션은 DRY하지 않았다. 즉, 서로 연결되어 있는 항목이 너무 많아서 한 영역에서 변경하게 되면 다른 영역에서 예기치 않은 변경이 발생했다.
JSF 1은 여러 면에서 DRY 원칙을 위반했다. 예를 들어, XML 및 Java 코드 형식으로 관리 Bean에 두 가지 표현을 제공해야 한다. 여러 표현이 필요하기 때문에 관리 Bean을 작성 및 변경하기가 어렵다. Part 1에서 살펴본 것처럼 JSF 2에서는 XML 대신 어노테이션을 통해 관리 Bean에 신뢰할 수 있는 단일 표현을 지정하는 방식으로 관리 Bean을 구성할 수 있다.
관리 Bean뿐만 아니라 양호해 보이는 사례(예: 모든 보기에 동일한 스타일시트가 포함되어 있는 경우)에서도 DRY 원칙이 위반되는 경우를 자주 볼 수 있다. 이 경우 스타일시트의 이름을 변경하면 여러 보기도 변경해야 한다. 가능하다면 스타일시트 포함을 캡슐화하는 것이 효과적이다.
DRY 원칙은 코드 설계에도 적용된다. 예를 들어, 트리를 탐색하는 코드가 포함된 여러 메소드가 있다면 서브클래스에서 트리 탐색 알고리즘을 캡슐화하는 방법을 사용할 수 있다.
특히 개발 과정에서 대부분의 변경이 발생하는 UI를 구현할 때는 DRY 원칙을 따르는 것이 매우 중요하다.
JSF 2에서 DRY 원칙을 지원하는 여러 가지 방법 중 하나는 templating이다. 템플리트를 통해 애플리케이션의 보기에서 공통으로 사용되는 기능을 캡슐화할 수 있기 때문에 해당 기능을 한 번만 지정하면 된다. 여러 컴퍼지션에서 하나의 템플리트를 사용하여 JSF 2 애플리케이션의 보기를 작성할 수 있다.
Part 1에서 소개한 places 애플리케이션에는 세 개의 보기가 있다(그림 1 참조).
그림 1. places 애플리케이션의 보기: login, source viewer 및 places
많은 웹 애플리케이션과 마찬가지로 places 애플리케이션에서는 같은 레이아웃을 공유하는 여러 보기가 있다. JSF templating을 사용하면 이러한 레이아웃을 비롯한 여러 가지 공유 아티팩트(예: CSS(Cascading Style Sheets) 및 xxJavaScript)를 템플리트로 캡슐화할 수 있다. Listing 1은 그림 1에서 보았던 세 보기에 대한 템플리트이다.
Listing 1의 템플리트에서는 애플리케이션의 모든 보기에 대해 다음과 같은 인프라를 제공한다.
Listing 1에서 보듯이 템플리트는 <ui:insert> 태그를 사용하여 레이아웃에 컨텐츠를 삽입한다.
Listing 1에서 창 제목, 머리글 및 오른쪽 메뉴에 했던 것처럼 <ui:insert> 태그에 대한 본문을 지정한 경우 JSF는 태그의 본문을 기본 컨텐츠로 사용한다. login 보기에 대한 마크업을 보여 주는 Listing 2를 보면 알 수 있듯이 템플리트를 사용하는 컴퍼지션은 <ui:define> 태그를 통해 컨텐츠를 정의하거나 기본 컨텐츠를 재정의할 수 있다.
login 보기에서는 창 제목, 머리글 및 오른쪽 메뉴의 경우 템플리트의 기본 컨텐츠를 사용하고 login 보기와 관련된 기능인 컨텐츠 섹션과 왼쪽 메뉴만을 정의한다.
창 제목, 머리글 또는 오른쪽 메뉴에 대한 <ui:define> 태그를 제공하여 템플리트에 정의된 기본 컨텐츠를 재정의할 수 있다. 예를 들어, Listing 3에서는 source-viewer 보기(그림 1의 가운데 사진)를 보여 준다.
source-viewer 보기는 컨텐츠 섹션 및 오른쪽 메뉴의 컨텐츠를 정의한다. 또한 왼쪽 메뉴의 경우 Listing 1의 템플리트에서 정의한 기본 컨텐츠를 재정의한다.
Listing 4에서는 places 보기(그림 1의 맨 아래 사진)를 보여 준다.
Listing 2, 3 및 4에는 유사점이 있다. 즉, 세 보기 모두 해당 템플리트를 지정하고 컨텐츠를 정의한다. 또한 보기 인프라의 대부분이 템플리트와 포함 파일로 캡슐화되기 때문에 새 보기를 쉽게 작성할 수 있다.
JSF templating 사용과 관련하여 또 하나 흥미로운 점은 Listing 2, 3 및 4에서 살펴본 것과 같은 보기가 시간이 지나도 변경되지 않기 때문에 기본적으로 보기 코드에 대한 유지보수가 필요하지 않다는 점이다.
템플리트를 사용하는 보기와 마찬가지로 템플리트도 거의 변경되지 않는다. 또한 여러 가지 공통 기능을 유지보수가 거의 필요하지 않는 코드로 캡슐화했기 때문에 보기의 실제 컨텐츠(예: login 페이지 왼쪽 메뉴의 컨텐츠)에 집중할 수 있다. 보기의 실제 컨텐츠에 집중한다는 것은 다음 팁에서 다루는 핵심 주제이다.
JSF 2 templating
templating의 기본 개념은 단순하다. 여러 보기에서 공통으로 사용되는 기능을 캡슐화하는 단일 템플리트를 정의한다. 각 보기는 컴퍼지션과 템플리트로 구성된다.
JSF는 보기를 작성할 때 컴퍼지션의 템플리트를 로드한 다음 컴퍼지션에 정의된 컨텐츠를 템플리트에 삽입한다.
CAD/CAM GUI가 릴리스된 후 필자는 Bob이라는 개발자와 함께 수 개월 동안 관련이 없는 프로젝트에 참여했다. 그의 코드 베이스에 대한 작업을 진행하면서 놀랍게도 매우 쉽게 코드를 변경하고 버그를 수정할 수 있었다.
이내 필자는 Bob의 코드와 필자의 코드 사이에 아주 큰 한 가지 차이점이 있다는 것을 알 수 있었다. 그는 대개 5 - 15행의 코드로 구성된 작은 메소드를 작성했으며 이러한 메소드들이 서로 결합되어 전체 시스템이 이루어져 있었다. 필자는 이전 프로젝트에서 많은 내용이 들어 있는 긴 메소드를 수정하기 위해 많은 고생을 해야 했지만 Bob은 원자성 기능을 가진 작은 메소드를 빠르게 결합했다. Bob의 코드와 필자의 코드 사이에서 볼 수 있는 유지보수성 및 확장성의 차이는 빛과 어둠으로 비교할 수 있을 정도였으며 필자는 그 이후로 작은 메소드에 매료되었다.
Bob과 필자 모두 당시에는 의식하지 못하고 있었지만 Smalltalk의 Composed Method라는 설계 패턴을 사용했었다.
소프트웨어를 식별 가능한 한 가지 작업을 단일 추상 수준에서 수행하는 메소드로 나눈다.
Composed Method 패턴을 사용하면 깔끔하게 문서화된 결과를 얻을 수 있다는 장점이 있다. (Neal Ford의 "Evolutionary architecture and emergent design: Composed method and SLAP"에서 이 패턴에 대한 자세한 설명을 볼 수 있다.) 여기에서는 Composed Method 패턴을 JSF 보기와 함께 사용하는 방법을 중점적으로 살펴본다.
JSF 2에서는 보기를 나눠서 더 작은 보기로 작성하는 것이 좋다. templating을 통해 공통 기능을 캡슐화하므로 보기를 더 작은 단위로 나눌 수 있다. 또한 앞에서 설명한 Listing에서 본 것처럼 JSF 2의 <ui:include> 태그를 사용하면 보기를 더 작은 기능 단위로 나눌 수 있다. 예를 들어, 그림 2에서는 places 애플리케이션 login 페이지의 왼쪽 메뉴를 보여 준다.
그리고 Listing 5에서는 메뉴의 컨텐츠를 정의하는 파일을 보여 준다.
Listing 5의 마크업은 단순하기 때문에 파일을 쉽게 읽고, 이해하고, 유지하고, 확장할 수 있다. 만일 똑같은 코드가 login 보기를 구현하는 데 필요한 모든 내용이 포함된 하나의 긴 XHTML 페이지에 있다면 코드를 변경하기가 쉽지 않을 것이다.
그림 3에서는 places 보기의 왼쪽 메뉴를 보여 준다.
Listing 6에서는 places 보기 왼쪽 메뉴의 구현을 보여 준다.
Listing 6에서는 양식을 구현하고 아이콘 구성 요소를 사용한다. (아이콘 구성 요소에 대해서는 아이콘 구성 요소에서 간단히 설명할 것이며 지금은 페이지 작성자가 이미지와 메소드에 아이콘을 연결하는 방법만 살펴본다.) 로그아웃 아이콘의 이미지는 그림 3의 맨 아래에 있으며, 로그아웃 아이콘의 메소드(places.logout())는 Listing 7에서 볼 수 있다.
필자가 보기에 places 보기의 왼쪽 메뉴를 구현한 Listing 6은 약 30행의 마크업으로 구성되어 있기 때문에 거의 최대 임계값에 도달한 것으로 보인다. 이 Listing은 읽기가 조금 어렵다. 이 코드에서 두 가지 항목 즉, 양식과 아이콘을 고유한 파일로 리팩토링할 수 있다. Listing 8에서는 양식과 아이콘을 고유한 XHTML 파일로 캡슐화한 Listing 6의 리팩토링된 버전을 보여 준다.
Listing 9에서는 addressForm.xhtml을 보여 준다.
Listing 10에서는 logoutIcon.xhtml을 보여 준다.
여러 개의 작은 파일을 사용하여 보기를 작성하면 Smalltalk의 Composed Method 패턴의 장점을 활용하게 된다. 또한 변화에 쉽게 대응할 수 있도록 파일을 구성할 수도 있다. 예를 들어, 그림 4에서는 places 애플리케이션의 세 가지 보기를 구성하고 있는 파일을 보여 준다.
그림을 보면 views, sections 및 templates라는 세 개의 디렉토리에 places 애플리케이션을 구현하는 데 사용되는 대부분의 XHTML 파일이 있는 것을 볼 수 있다. views 및 templates 디렉토리에 있는 파일은 거의 변경되지 않기 때문에 sections 디렉토리에 집중할 수 있다. login 페이지의 왼쪽 메뉴에 있는 아이콘을 변경하려는 경우 이동할 위치(sections/login/menuLeft.xhtml)를 정확히 알고 있다.
원하는 디렉토리 구조를 사용하여 XHTML 파일을 구성할 수 있다. 논리적인 구조를 사용하면 수정해야 하는 코드를 쉽게 찾을 수 있다.
DRY 원칙을 따르고 Composed Method 패턴을 사용하는 것과 더불어 사용자 정의 구성 요소를 사용하여 기능을 캡슐화하는 것도 좋은 방법이다. 구성 요소는 강력한 재사용 메커니즘이므로 이 장점을 활용할 줄 알아야 한다. JSF 1과는 달리 JSF 2에서는 사용자 정의 구성 요소를 쉽게 구현할 수 있다.
어린 시절에 필자가 좋아했던 두 가지 장난감은 화학 실험 세트와 LEGO였다. 두 가지 장난감 모두 기본적인 빌딩 블록을 결합하여 새로운 것을 만들어 내는 놀이였으며 이러한 특징은 필자가 오랫동안 소프트웨어 개발을 통해 느껴왔던 매력이기도 하다.
JSF의 가장 큰 장점은 구성 요소 모델이지만 JSF 1에서는 사용자 정의 구성 요소를 구현하기가 어려웠기 때문에 지금까지는 이 장점이 충분히 실현되지 않았다. JSF 1에서는 Java 코드를 작성하고, XML 구성을 지정하고, JSF의 수명 주기를 잘 파악하고 있어야 했다. 하지만 JSF 2에서는 다음과 같은 특징을 가지고 있는 사용자 정의 구성 요소를 구현할 수 있다.
이 기사의 나머지 부분에서는 places 애플리케이션의 세 가지 사용자 정의 구성 요소인 아이콘, 로그인 패널 및 주소에 해당하는 지도와 날찌 정보를 보여 주는 패널을 구현한다. 그 전에 먼저 JSF 2 복합 구성 요소에 대해 설명한다.
JSF 2는 Facelets templating, 리소스 처리(Part 1 참조) 및 단순한 이름 지정 규칙을 결합하여 복합 구성 요소를 구현한다. 이름으로 알 수 있듯이 복합 구성 요소는 기존 구성 요소를 사용하여 구성 요소를 작성하는 데 사용된다.
resources 디렉토리 아래에 있는 XHTML 파일에서 복합 구성 요소를 구현한 후 네임스페이스와 태그에 연결한다. 그림 5에서는 places 애플리케이션에 대한 복합 구성 요소가 구성되어 있는 모습을 보여 준다.
복합 구성 요소를 사용하려면 네임스페이스를 선언하고 태그를 사용해야 한다. http://java.sun.com/jsf/composite 뒤에 구성 요소가 있는 resources 디렉토리의 서브디렉토리 이름이 추가된 형식의 네임스페이스가 항상 사용된다. 구성 요소 자체의 이름은 .xhtml 확장자를 제외한 XHTML 파일의 이름이다. 이 규칙을 따르면 구성 작업을 추가로 수행하지 않아도 된다. 예를 들어, 다음과 같은 방법으로 places 애플리케이션에서 login 구성 요소를 사용할 수 있다.
또한 다음과 같은 방법으로 icon 구성 요소를 사용할 수 있다.
마지막으로 다음과 같은 방법으로 place 구성 요소를 사용한다.
places 애플리케이션에서는 두 가지 아이콘을 사용한다(그림 6 참조).
각 아이콘은 링크이다. 사용자가 그림 6의 왼쪽 아이콘을 클릭하면 현재 보기에 대한 마크업이 표시되는 반면 오른쪽 아이콘을 활성화하면 사용자가 애플리케이션에서 로그아웃된다.
링크에 대한 CSS 클래스 이름과 이미지를 지정할 수 있으며 링크에 메소드를 연결할 수도 있다. 이러한 메소드는 사용자가 연결된 링크를 클릭할 때 호출된다.
Listing 11에서는 places 애플리케이션에서 icon 구성 요소를 사용하여 마크업을 표시하는 방법을 보여 준다.
Listing 12에서는 icon 구성 요소를 사용하여 로그아웃하는 방법을 보여 준다.
Listing 13에서는 icon 구성 요소에 대한 코드를 보여 준다.
모든 복합 구성 요소와 마찬가지로 Listing 13의 icon 구성 요소에는 <composite:interface>와 <composite:implementation>이라는 두 섹션이 있다. <composite:interface> 섹션은 구성 요소를 구성하는 데 사용할 수 있는 인터페이스를 정의한다. icon 구성 요소에는 구성 요소의 모습을 정의하는 image와 구성 요소의 동작을 정의하는 actionMethod라는 두 가지 속성이 있다.
<composite:implementation> 섹션에는 구성 요소의 구현이 들어 있으며 이 구현에서는 #{cc.attrs.ATTRIBUTE_NAME} 표현식을 사용하여 구성 요소의 인터페이스에 정의된 속성에 액세스한다. (cc는 JSF 2 표현식 언어의 예약 키워드로 복합 구성 요소를 의미한다.)
Listing 13의 icon 구성 요소는 <h:graphicImage>의 styleClass 속성을 사용하여 이미지에 대한 CSS 클래스를 지정한다. 해당 CSS 클래스의 이름은 icon으로 하드코딩되므로 이 이름을 사용하여 CSS 클래스를 지정할 수 있다. 그리고 JSF는 애플리케이션의 모든 아이콘에 이 클래스를 사용한다. 하지만 CSS 클래스 이름을 재정의해야 하는 경우에는 어떻게 해야 할까? 이러한 경우 필자는 CSS 클래스 이름에 대해 다른 속성을 추가한 후 이 속성이 지정되지 않았을 때 사용될 기본값을 제공할 수 있다. Listing 14에서는 이 속성을 구현한 코드를 보여 준다.
Listing 14에서는 icon 구성 요소의 인터페이스에 styleClass라는 속성을 추가하고 구성 요소의 구현에서 이 속성을 참조했다. 이처럼 변경했으므로 이제부터는 다음과 같이 아이콘 이미지에 대해 선택적 CSS 클래스를 지정할 수 있다.
styleClass 속성을 지정하지 않으면 JSF는 기본값인 icon을 사용한다.
login 구성 요소: 전체적으로 구성 가능한 구성 요소
JSF 2에서는 전체적으로 구성 가능한 복합 구성 요소를 구현할 수 있다. 예를 들어, places 애플리케이션에는 login 구성 요소가 있다(그림 7 참조).
그림 7. places 애플리케이션의 login 구성 요소
Listing 15에서는 places 애플리케이션에서 login 구성 요소를 사용하는 방법을 보여 준다.
Listing 15에서는 이름 및 매개변수 프롬프트와 같은 login 구성 요소의 속성을 매개변수화할 뿐 아니라 구성 요소의 Log In 단추에 작업 리스너도 연결한다. 이 단추는 login 구성 요소의 인터페이스에서 노출된다(Listing 16 참조).
login 구성 요소의 인터페이스에서 Log In 단추는 loginButton이라는 이름으로 노출된다. 이 이름의 대상은 form이라는 이름의 양식에 있는 Log In 단추이므로 targets 속성은 form:loginButton이 된다.
Listing 17에서는 Listing 16의 Log In 단추에 연결된 작업 리스너를 보여 준다.
Listing 17의 작업 리스너는 대략적인 코드를 보여 주기 위한 것으로 사용자가 로그인할 때 서블릿 컨테이너 로그 파일에 메시지를 기록한다. 하지만 이 코드를 보면 JSF 2를 사용해서 전체적으로 구성 가능한 구성 요소를 구현할 수 있고, 이러한 구성 요소에 기능을 연결할 수 있으며 더 나아가 이 모든 작업을 Java 코드나 XML 구성 없이 수행할 수 있다는 것을 알 수 있다. 여기서 다시 한번 fu의 힘을 느낄 수 있다.
JSF 2에서는 Java 코드 또는 구성 없이 전체적으로 구성 가능한 구성 요소를 구현할 수 있다. 복합 구성 요소를 중첩할 수도 있으므로 복잡한 구성 요소를 관리하기 쉬운 작은 단위로 쪼갤 수 있다. 예를 들어, 그림 8에서는 지정된 주소에 대한 지도와 날씨 정보를 표시하는 place 구성 요소를 보여 준다.
그림 8. places 애플리케이션의 place 구성 요소
Listing 18에서는 places 애플리케이션에서 place 구성 요소를 사용하는 방법을 보여 준다.
Listing 19에서는 place 구성 요소에 대한 코드를 보여 준다.
Listing 19에서 place 구성 요소는 <places:map>과 <places:weather>라는 두 개의 중첩 구성 요소를 사용한다. Listing 20에서는 map 구성 요소를 보여 준다.
Listing 20에서는 #{cc.parent.attrs.location.ATTRIBUTE_NAME} 표현식을 사용하고 있다. 이 표현식을 보면 복합 구성 요소의 parent 속성을 사용하여 상위 구성 요소의 속성에 쉽게 액세스할 수 있다는 것을 알 수 있다. 따라서 구성 요소를 부담 없이 중첩할 수 있다.
그렇다고 해서 중첩된 구성 요소의 상위 속성에만 얽매일 필요는 없다. Listing 19의 place 구성 요소에서 했던 것처럼 중첩 여부와 상관 없이 다른 구성 요소에 속성을 전달하듯이 지도 제목과 같은 속성을 상위 구성 요소에서 중첩된 구성 요소로 전달할 수도 있다.
Listing 21에서는 weather 구성 요소를 보여 준다.
복합 구성 요소 리팩토링
map 구성 요소에 대한 마크업인 Listing 20은 필자가 보기에 조금 길다. 한눈에 이해하기가 약간 어려울 뿐만 아니라 복잡하기 때문에 나중에 문제가 발생할 수도 있다. Listing 8, 9 및 10에서 places 보기의 왼쪽 메뉴를 리팩토링했던 것처럼 Listing 20도 관리하기 쉬운 여러 파일로 쉽게 리팩토링할 수 있다. 이 경우에는 리팩토링을 연습해 볼 수 있는 기회를 주기 위해 리팩토링된 코드를 제공하지 않는다.
weather 구성 요소에서도 map 구성 요소와 마찬가지로 상위 구성 요소 속성(weather 웹 서비스의 weather HTML)과 구성 요소 관련 속성(title)을 사용한다. (Part 1에서 애플리케이션에서 특정 위치에 대한 지도 및 날씨 정보를 가져오는 방법을 볼 수 있다.)
따라서 중첩 구성 요소를 구현할 경우에는 한 가지 선택을 할 수 있다. 중첩 구성 요소가 상위 구성 요소의 속성에 의존하게 하거나 속성을 중첩 구성 요소에게 명시적으로 전달하도록 상위 구성 요소에게 요청할 수도 있다. 예를 들어, Listing 19의 place 구성 요소는 title 속성을 중첩 구성 요소에게 명시적으로 전달하지만 중첩 구성 요소는 mapURL 및 weather HTML과 같은 상위 구성 요소의 속성에 의존한다.
구성 요소에게 명시적으로 전달되는 속성을 구현할 것인지 또는 상위 속성에 의존할 것인지 여부는 커플링과 편의성 중 하나를 선택해야 하는 선택의 문제이다. 이 경우에는 map 및 weather 구성 요소가 상위 구성 요소(place 구성 요소)의 속성에 의존하고 있기 때문에 상위 구성 요소와 밀접하게 연결되어 있다. 여기에서 모든 map 및 weather 구성 요소를 명시적으로 전달되는 속성으로 지정하여 map 및 weather 구성 요소를 place 구성 요소와 분리할 수도 있었다. 하지만 그렇게 하면 place 구성 요소에서 모든 속성을 map 및 weather 구성 요소에게 명시적으로 전달해야 하기 때문에 불편함을 감수해야 한다.
설명 |
이름 |
크기 |
다운로드 방식 |
---|---|---|---|
Source code for the examples |
jsf2fu2.zip |
7.4MB |
저자, 강사 및 컨설턴트인 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로 두 차례 선정되었다.