ZK는 JavaScript가 없는 Ajax와 비슷하다. ZK는 Ajax 기반 이벤트 구동형 엔진과 XHTML 및 XUL 구성 요소의 풍부한 설정에 기능이 풍부한 사용자 인터페이스를 작성하기 위한 ZUML 마크업 언어로 구성된 강력한 프레임워크이다.
이 글에서 ZK 프레임워크와 관련된 Java EE 플랫폼용 CDI(Contexts and Dependency Injection) 프로그래밍 모델을 배워보자. 이 글에서는 ZK의 성능을 탐색하는 글인 "Rich Internet applications using ZK: An open source Ajax framework"의 예제 애플리케이션을 빌드한다. ZK와 CDI를 사용하여 고객 관리를 위한 현존하는 자세한 예제 애플리케이션을 확장하게 된다.
이 글의 애플리케이션의 소스 코드를 다운로드할 수 있다.
JSR(Java Specification Request) 299 또는 Java CDI는 의존성 삽입 및 콘텍스트의 라이프사이클 관리를 위한 Java 표준이다. 이 표준을 통해 서비스 세트가 애플리케이션 개발을 더 쉽고 분명하게 정의한다. 서비스는 다음을 제공한다.
- 이벤트 알림 메커니즘을 통해 오브젝트의 상호작용
- 형안전(type-safe) 의존성 삽입
- 콘텍스트로 바인드된 상태기반(stateful) 오브젝트를 위한 라이프사이클 메소드
- 인터셉터를 오브젝트로 바인드하는 "데코레이터" 인터셉터
- 휴대용 확장을 개발하는 서비스 공급자 인터페이스(SPI)
CDI는 느슨한 결합(loose coupling)과 강력한 타이핑(strong typing)을 강조하기 때문에, bean은 구현, 스레드 모델 또는 라이프사이클과 같은 특정한 측면을 인식할 필요가 없다. 이러한 측면은 배치에 따라 달라질 수 있으며 클라이언트에 전혀 영향을 미치지 않는다. 느슨한 결합으로 인해 코드를 유지보수하기가 쉽고 확장할 수 있다.
ZK 프레임워크로 제공되는 ZK CDI는 ZK 프레임워크 내에서 CDI 서비스를 노출하여 CDI와의 원활한 통합을 제공한다. 이를 통해 엔터프라이즈 개발자는 CDI 구동형 애플리케이션을 ZK에서 공급하는 압축적이고 강력한 Ajax 프런트 엔드와 통합할 수 있다. CDI와 ZK를 함께 사용하면 Java의 EE 웹 티어와 Java EE 사이의 간격을 손쉽게 연결할 수 있다.
ZK CDI 확장을 통해 ZK 프로그래밍 모델 내에서 CDI 기능을 원활하게 사용할 수 있다. 내장 CDI 기능 이외에도 ZK CDI 확장은 다음과 같은 기능을 제공하여 개발을 쉽게 만들어 준다.
- 사용자 정의 변수 분석기/EL 분석기(variable resolver/EL resolver)
<zscript />, EL 표현식(${...}) 및 해당 EL 이름으로 ZK 어노테이트된 데이터 바인딩 표현식(@{…}) 내에서 CDI 관리되는 bean을 분석(resolve)한다.- ZK 사용자 정의 범위
- 이러한 확장은 내장 CDI 범위인 세션(Session), 리퀘스트(Request), 애플리케이션(Application), 컨버세이션(Conversation) 이외에도 다섯 가지의 ZK 범위를 더하여 데스크탑(Desktop), 페이지(Page), 이그제큐션(Execution), IdSpace, 구성 요소(Component)를 제공한다.
- 관리되는 bean으로서 ZK 구성 요소
- ZK 작성기와 같이 ZK 구성 요소를 관리되는 bean으로 삽입할 수 있다.
- ZK 사용자 정의 어노테이션 및 CDI 제공 이벤트 알림 모델을 사용한 UI 이벤트 핸들러
- ZK 사용자 정의 어노테이션을 통해 메소드를 어노테이트할 수 있고 이벤트 핸들러 메소드로 변환할 수 있다.
ZK CDI 확장은 CDI를 정의하는 JSR-299 스펙의 참조 구현인 Weld(자세한 내용은 참고자료 참조)를 기반으로 한다.
다음의 간단한 예제에서는 ZUL 파일에서 CDI 관리되는 bean으로 액세스하는 방법을 보여 준다. (.zul 파일 확장자는 ZK 사용자 인터페이스 파일용이다.) CDI 컨텍스트에서 관리되는 bean 또는 간단한 bean은 컨텍스트와 연관되거나 EL 표현식을 통해 접근된 다른 구성 요소로 삽입할 수 있는 Java EE 구성 요소이다.
Listing 1의 간단한 HelloWorld 예제는 ZUL 파일 내에서 관리되는 bean이 EL 표현식을 통해
액세스되는 방법을 보여 준다. 먼저 text라는 이름의 단일 String 필드와 getter 메소드인
getText()으로 HelloWorld 클래스를 정의한다. CDI 스펙에 따르면
no-arg 기본 생성자가 있으면 이 클래스는 관리되는 bean이 될 수 있는
자격을 갖추게 된다. 통합된 EL 표현식을 통해 HelloWorld 관리되는 bean을 참조하려면
@javax.inject.Named 규정자로 어노테이트되어야 한다. EL 이름이
@Named 규정자의 값 멤버를 제공하여 관리되는 bean에 부여될 수 있다. 지정되지 않은 경우에 EL 이름은
첫 번째 문자를 소문자로 변환한 후에 해당 bean 클래스의 비적격 클래스 이름이 기본값이 된다. 예를 들어, HelloWorld는 helloWorld EL이
기본값이 된다.
Listing 1. 관리되는 bean 액세스하기
@Named
@SessionScoped
public class HelloWorld implements Serializable {
private String text = "HelloWorld";
public String getText() {
return text;
}
}
|
Listing 2의 ZUL 코드는 기본값이 된 EL 이름인 helloWorld를 사용하여 HelloWorld bean에 액세스한다.
Listing 2. 기본값 EL 이름
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
<window title="ZK + CDI: Hello World" width="300px" border="normal">
My CDI-injected bean says: ${helloWorld.text}
</window>
|
ZK는 variable-resolver 지시문 <?variable-resolver ?> 를 제공한다.
이를 사용하여 ZK EL 이밸류에이터(${...}), ZK 어노테이트된 데이터 바인더(@{...}) 및
알 수 없는 변수를 분석하는 <zscript> 인터프리터로 사용되는 리졸버 클래스를 지정할 수 있다.
ZK CDI 확장의 기능 중 하나인 사용자 정의 EL 리졸버 DelegatingVariableResolver는
통합된 EL 표현식 내에서 해당 EL 이름으로 HelloWorld 관리되는 bean을 분석하기 위해 사용할 수 있다.
Listing 2의 index.zul 파일에서 간단한 창 구성 요소를 정의하고 ${helloWorld.text} EL 표현식을 사용하여
HelloWorld 클래스의 텍스트 필드를 표시했다. ZUL 렌더링 단계 도중에 ZUL 구문 분석기가 이 EL 표현식을 접하면 helloWorld bean 인스턴스를
해석하기 위해 <?variable-resolver ?>에서 지정한 DelegatingVariableResolver를 사용하게 된다. 왜냐하면 HelloWorld가 이제
컨테이너 관리되는 bean이기 때문에 컨테이너가 HelloWorld bean 인스턴스를 제공하기로 되어 있다. 컨테이너가 리턴한 bean 인스턴스를 사용하여
${helloWorld.text}가 평가된다. getText() 메소드의 평가 결과는 그림 1에서 보여 주는 것처럼 "Hello World" 스트링을 리턴한다.
그림 1. HelloWorld
CDI로 ZK를 사용하여 현존하는 애플리케이션 구현하기
이 섹션에서는 현존하는 애플리케이션을 구현하여 더 많은 CDI 기능을 탐색한다. "Rich Internet applications using ZK" 글에서 시연한 Manage Customer 애플리케이션을 빌드할 것이다. Manage Customer 애플리케이션을 통해 사용자는 새 고객 추가하기, 고객 데이터 편집하기 및 데이터베이스에서 고객 항목 임시 삭제하기 등 다양한 작업을 수행할 수 있다. 그림 2에서는 Manage Customer 애플리케이션의 기본 사용자 인터페이스 화면을 보여 준다.
그림 2. Manage Customers 대시보드
애플리케이션 내에 등록된 고객이 나열된다. 목록은 ID, 고객의 이름, 활성 날짜 및 삭제된 플래그에 대한 열이 있는 격자이다. 격자의 데이터는 열 이름 근처의 단추를 클릭하여 정렬할(오름차순 또는 내림차순 방식) 수 있다. ID(int), Name(String) 및 active date(Date) 열에 대한 정렬이 사용되었다. 또한 화면 아래에서 보여 주는 것과 같이 이 애플리케이션에서 페이지 나누기도 사용되었다. 페이지는 5개의 기록을 동시에 보여 주도록 사용되었다. 사용자는 다음 페이지로 이동하거나 특정 페이지로 직접 이동할 수 있다.
그림 3에서는 Manage Customer 애플리케이션의 맨 위 표시줄을 보여 준다.
그림 3. 맨 위 메뉴 표시줄
메뉴 표시줄은 ZK의 메뉴 표시줄 위젯을 사용하여 구현되었다. 여기에는 새 고객을 등록하고 애플리케이션을 종료하는 옵션이 포함된다.
구현의 세부 사항을 알아 보기 전에, 고객을 관리하는 샘플 애플리케이션의 작성에 대한 일부 세부 사항을 검토해 보자. 애플리케이션을 작성하기 위해 Eclipse IDE를 사용했지만 어떤 IDE를 선택해도 작동해야 한다.
기본적인 개념은 동적 웹 애플리케이션 프로젝트를 작성하는 것이며, 그 프로젝트를 애플리케이션 서버 런타임에 향하도록 하는 것인데, 이 경우에는 Apache Tomcat 런타임이 해당된다. 새 프로젝트와 런타임을 설정한 후에 그림 4에서 보여 주는 것과 같이 폴더 구조를 복제한다.
그림 4. 디렉토리 구조
Manage Customer 애플리케이션의 디렉토리 구조는 그림 4에 보여 주는 것과 동일한 패턴을 따른다.
이 애플리케이션의 핵심 파일은 다음과 같은 서브디렉토리가 있는 WebContent 폴더에 있다.
- META-INF에는 MySQL 데이터베이스에 연결하기 위해 데이터베이스 신임 정보가 있다.
- WEB-INF에는 애플리케이션을 실행하기 위해 필요한 ZK JAR 파일이 들어 있는 라이브러리 폴더가 포함된다. 또한 다음 세 가지 구성 파일도 포함된다.
- beans.xml은 이 애플리케이션 내에서 삽입에 사용 가능한 bean 클래스를 표시한다.
- web.xml은 데이터소스, ZK 서블릿 및 Weld 구성을 설명한다.
- zk.xml은 ZK 특별 구성이 들어 있을 수 있다.
다른 모든 ZUL과 HTML 관련 파일은 WebContent 폴더 내에 들어 있다. 이러한 파일은 웹 애플리케이션에 동적 및 정적 내용을 제공하여 애플리케이션의 보기 파트로서 역할을 한다.
샘플 파일 zkManageCustomer.zip(다운로드 참조)에는 애플리케이션의 압축된 버전이 있다. 또한 Eclipse에 필요한 메타데이터 파일이 포함되어 무리없이 해당 IDE로 직접 가져올 수 있다.
Eclipse에서 J2EE(Java 2 Platform, Enterprise Edition) 퍼스펙티브는 오른쪽 마우스를 클릭하면 새 서버를 작성하는 옵션을 표시하는 서버 탭이 있다. 이 서버를 사용하여 Eclipse IDE로부터 애플리케이션 서버를 관리할 수 있다.
새 서버를 구성한 후에 새로 작성된 자원이 서버에 구성되어야 한다. 이 서버 구성은 개발 코스 도중에 작성된 자원을 배치한다.
예제 프로그램은 Tomcat과 MySQL로 작업하도록 구성된다. 그러나 다른 CDI 사용 가능한 애플리케이션 서버에서도 이를 실행하는 데 아무 문제가 없어야 한다. 예제가 JDBC를 사용하기 때문에, 연결 코드를 약간만 변경하여 DB2 Express-C와 같이 지원되는 모든 SQL 데이터베이스로 작업이 되어야 한다.
Tomcat을 MySQL 데이터베이스에 연결하려면 자원 참조를 정의해야 한다. 이 요소는 Listing 3에 보여 주는 것과 같이
자원 관리자 연결 출하 시 기본 참조의 이름을 지정한다. 이 경우에는 javax.sql.DataSource의 유형인 jdbc/mysql로 지정된 데이터베이스 연결이 될 것이다.
Listing 3. 자원 참조 정의
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
|
또한 WebContent/META-INF 폴더 아래의 context.xml 파일에서 연결 자원을 정의해야 한다. 이 파일에는 드라이버 이름, jndi 이름, 사용자 이름, 비밀번호, 데이터 유형 및 URL과 같은 특성이 들어 있다.
Listing 4. 연결 자원 정의하기
<Resource driverClassName="com.mysql.jdbc.Driver"
maxActive="4" maxIdle="2" maxWait="5000" auth="Container"
name="jdbc/mysql" password="as1008" type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/customer" username="root"/>
|
고객 데이터베이스에 Listing 5에서 스크립트를 실행하여 작성할 수 있는 단일 표가 있다.
Listing 5. 표 작성하기
use customer;
CREATE TABLE 'customer' (
'ID' int(11) NOT NULL AUTO_INCREMENT,
'name' varchar(255) DEFAULT NULL,
'date' date DEFAULT NULL,
'deleted' tinyint(1) DEFAULT '0',
PRIMARY KEY ('ID')
);
|
ZK CDI 확장을 활용하려면 zkcdi.jar 파일(ZK CDI 확장의 바이너리 분배 내)을 웹 애플리케이션 프로젝트의 WEB-INF/lib 폴더로 복사하자. zkcdi.jar는 웹 애플리케이션 라이브러리로 사용되어야 한다.
Tomcat을 위한 Weld 지원을 사용하려면 다음과 같이 하자.
- Weld 서블릿 리스너(Weld를 부트하고 요청과의 상호작용을 제어하기 위해 사용됨)를 웹 루트의 WEB-INF/web.xml 파일에서 다음과 같이 지정한다.
<listener> <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class> </listener> <listener> <listener-class>org.jboss.weld.el.WeldELContextListener</listener-class> </listener>
- Tomcat은 읽기 전용 JNDI가 있기 때문에 Weld가 BeanManager 확장 SPI를 자동으로 바인드할 수 없다. BeanManager를 JNDI로 바인드하려면
배치에 사용할 수 있게 웹 루트의 META-INF/context.xml을 다음과 같은 내용으로 채워야 한다.
<Resource name="BeanManager" auth="Container" type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" />
<resource-env-ref> <description>Object factory for the CDI Bean Manager</description> <resource-env-ref-name>BeanManager</resource-env-ref-name> <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager </resource-env-ref-type> </resource-env-ref> - CDI로 의존성 삽입이 사용 가능하도록 WEB-INF 폴더 아래 빈 beans.xml 파일을 추가한다.
다른 애플리케이션 서버와 환경으로 Weld를 설정하는 유사한 지시사항을 보려면 참고자료를 확인하자.
Manage Customers 애플리케이션은 다음 기능을 제공한다.
- 모든 고객 보기를 포함한 사용자 조작을 위한 대시보드
- 새 고객 추가하기
- 기존 고객 편집하기
- 고객 삭제하기(임시 삭제)
그림 2에서는 등록된 모든 고객의 목록이 나와 있는 대시보드를 보여 준다. 사용자는 ID나 이름을 기준으로 데이터를 정렬할 수 있다.
index.zul 파일은 borderlayout,
menubar, menu 및
menupopup과 같이 애플리케이션의 룩앤필을 정의하는 다양한 속성이 있다.
Listing 6. 룩 정의
<?page id="manageCust" title="Manage Customers" cacheable="false"
language="xul/html" zscriptLanguage="Java" contentType="text/html;charset=UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
<zk>
<window id="win" border="normal" width="810px" minheight="300"
apply="${manageCustomer}">
<caption label="Manage Customers"/>
<borderlayout height="30px">
<north border="none">
<menubar id="menubar" width="800px">
<menu label="Manage Customers">
<menupopup>
<menuitem id="add" label="Register New Customer">
</menuitem>
<menuseparator />
<menuitem id="exit" label="Exit" onClick="win.detach()" />
</menupopup>
</menu>
</menubar>
</north>
</borderlayout>
<listbox id="customerList" mold="paging" pageSize="5" multiple="true" width="800px">
<listhead sizable="true">
<listheader label="Id" sort="auto(id)"/>
<listheader label="Name" sort="auto(name)"/>
<listheader label="Active Date" sort="auto(date)"/>
<listheader label="Deleted?" />
</listhead>
</listbox>
</window>
</zk>
|
Manage Customer의 이전에 했던 구현과는 달리 이 예제는 제어기에서부터
보기를 분리하는 ZK의 MVC 접근 방식을 사용했다. index.zul 파일은
애플리케이션의 보기 파트만 들어 있는 반면에, 제어기 코드는 작성기 클래스
ManageCustomer에서 별도로 쓰여졌다. 이러한 점에서 ZK CDI 기능을 활용할 수 있다.
ZK MVC 접근 방식에서 제어기는 apply 속성을 사용하여 특정 구성 요소에 적용될 수 있다. 예제는
이 기술을 사용하여 ManageCustomer를 대시보드 기본 창 구성 요소에
적용한다. 또한 DelegatingVariableResolver과 EL 표현식에 대해 variable-resolver 지시문을 사용하여
컨테이너로 제공된 ManageCustomer 관리되는 bean 인스턴스를 적용하는 것을
시연한다.
대시보드 페이지에 두 가지 주요 구성 요소가 있다.
- 맨 위의 메뉴에 Register New Customer와 Exit의 두 가지 서브메뉴 항목이 있다.
Menubar는 ID가add및exit로 두 개의 하위 ZKmenuitem구성 요소가 있는 ZK 메뉴 표시줄 구성 요소이다. - 표에는 데이터베이스의 현재 고객이 나열된다. 예제의
표는 ID가
customerList인 ZKlistbox구성 요소이다. 표 열의 머리글은customerList목록 상자의listheader하위 구성 요소로 정의된다.
지금까지 대시보드 UI를 정의하는 구성 요소에 대해 알아 보았는데, 데이터는
어떨까? 언제 customerList 목록 상자가
채워질까? Listing 7에서 보여 주는
ManageCustomer 제어기 클래스를 살펴 보자.
Listing 7. ManageCustomer
@Named
@SessionScoped
public class ManageCustomer extends GenericComposer implements Serializable {
@Inject @SessionScoped CustomerService custSvc;
@Inject @ComponentId("customerList") private transient Listbox customerList;
/**
* Set up list of all customers on the dashboard
* @param component
*/
public void doAfterCompose(Component component) throws Exception {
super.doAfterCompose(component);
List myList = custSvc.getAllCustomers();
ListModelList lm = new ListModelList(myList);
customerList.setModel(lm);
customerList.setItemRenderer(new CustomersListboxRenderer());
}
...
|
먼저 ManageCustomer bean 클래스를 @Named 규정자로 표시하여 통합된 EL 표현식을 통해
이에 액세스할 수 있게 만든다. 이 과정은 "${manageCustomer}"의
apply 속성 값이 있는 index.zul 파일의 창 구성 요소에서
시연되었다.
다음 단계는 CDI 형안전 의존성 삽입 기능을 사용하여 CustomerService bean을
ManageCustomer 제어기 내에 삽입하는 것이다. CustomerService
bean은 고객 정보의 추가, 업데이트, 제거 및 검색을 위해 데이터베이스에 액세스하는 메소드를 구현하는
유틸리티 클래스이다. 이 과정은
ManageCustomer 클래스 내에서 CustomerService 필드를 지정하고
이를 @javax.inject.Inject로 어노테이트하여 진행할 수 있다. CDI 스펙에 따르면
컨테이너가 ManageCustomer bean 인스턴스를 인스턴스화할 때마다
CustomerService bean 인스턴스가 자동으로 그 안에 삽입될 것이다.
이 시점에는 customerList 목록 상자에 액세스하여 모든 고객 데이터로
그 내용을 채워야 한다. 예제는 ZK CDI 확장으로 제공되는
GenericComposer 유틸리티 클래스를 사용한다. ManageCustomer 클래스를
org.zkoss.cdi.util.GenericComposer로 확장한 다음
창 구성 요소의 하위 구성 요소의 ManageCustomer 제어기 클래스로
자동 삽입을 사용 가능하게 만들자. ZK 구성 요소의 자동 삽입은 index.zul 파일에서 지정된
동일한 구성 요소 ID로 @org.zkoss.cdi.inject.ComponentId
규정자의 사용이 필요하다. 또한 ZK CDI 확장 스펙에 따르면
ComponentId 규정자 멤버 값은
필드 이름과 일치해야 한다. 예를 들어 customerList 목록 상자를
ManageCustomer에 삽입하려면 다음을 사용하자.
@Inject @ComponentId("customerList") private transient Listbox customerList;
|
이제 이 목록 상자 내에서 일부 데이터를 배치해 보자. 페이지가 클라이언트 브라우저에서
렌더링되기 전에 데이터 입력을 끝마쳐야 한다. GenericComposer는 유형 작성기이고
doAfterCompose() 메소드가 필요하다. 이 메소드는 모든 구성 요소가
작성된 후에 호출되는 콜백 메소드이다. 이를 통해 렌더링 이전이고 ZUL 구성 요소가 모두 작성된 후에
고객 목록 상자의 데이터 입력이 발생하도록 사용할 수 있다. 여전히 오버라이드된 doAfterCompose() 메소드에서
우선적으로 GenericComposer의 doAfterCompose()를
호출해야 한다.
누군가가 "Register New Customer(새 고객 등록)"(Manage Customer 대시보드 메뉴 표시줄에서 Add 메뉴 항목)를 클릭하면 어떻게 될까? 클릭하면 그 후에는 Enter Customer Data 창이 표시되고
데이터베이스에서 새 Customer 기록으로 입력 데이터가 저장될 것이다. 이렇게 하려면 먼저
ManageCustomer 제어기에서 "add" 메뉴 항목
onClick 이벤트를 위해 이벤트 핸들링 메소드가 있어야 한다. 이는
ZK CDI 확장 정의된
@org.zkoss.cdi.event.Events 규정자와 CDI 정의된 이벤트 알림 모델을 사용하여 쉽게 할 수 있다. Listing 8에서 보여 주는
것과 같이 간단한 registerNewCustomer() 메소드를 정의하자.
Listing 8. registerNewCustomer() 메소드 정의하기
public void registerNewCustomer(@Observes @Events("add.onClick")
MouseEvent evt) throws Exception {
Window win1 = (Window)Executions.createComponents("addCustomer.zul", null, null);
win1.doModal();
win1.setTitle("Enter Customer Data");
win1.setClosable(true);
win1.setMaximizable(true);
}
|
예제는 ZK 이벤트 유형인 유형 MouseEvent의 메소드
매개변수를 위한 @javax.enterprise.event.Observes
어노테이션을 사용한다. 이렇게 하면
registerNewCustomer() 메소드는 Observer 메소드(유형 MouseEvent를 관찰하는 메소드)가 된다. 유형
MouseEvent의 이벤트가 CDI로 게시될 때마다 이 메소드는 알림을 받는다. 유형
MouseEvent의 다양한 이벤트가 있을 수 있는데, 이 중에서 어떻게 구분할 수 있는가? 여기에서 @Events 규정자가
구출하려고 나타난다. @Events 규정자는
이 메소드가 어떠한 종류의 이벤트로 알려져야 하는지 표시하는 멤버 값으로
제공될 수 있다. @Events 멤버 값은 구성 요소 ID와
이어서 이벤트 이름의 형태로 지정될 수 있다.
예를 들어 Add menuitem onClick
이벤트의 경우 @Events 규정자는 Listing 7에서
보여 주는 것과 같이 "add.OnClick" 값으로 제공될 수 있다.
"Register New Customer" 메뉴 항목을 클릭했을 때 이벤트의 순서는 어떻게
되는가? 우선, 유형 MouseEvent의 ZK 이벤트가
서버에 전송된다. ZK 프레임워크는 이 이벤트를 수신하게 된다. 그 다음에
ZK CDI 확장은 적절한 @Events 규정자로
MouseEvent 유형에서 멤버 값과 함께 CDI 이벤트를 게시/작동시키게 된다. CDI는 정확한
@Events 규정자와 멤버 값으로 MouseEvent 유형에서 관찰되는 모든 메소드를 알리게 된다.
Listing 9. 고객 추가하기
<?page title="Add Customer" contentType="text/html;charset=UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.cdi.DelegatingVariableResolver"?>
<zk>
<window id="addCustomerWin" title="Register New Customer" border="normal"
apply="${addCustomer}">
<grid fixedLayout="true" width="450px">
<rows>
<row>
<label value="Customer Name" />
<textbox id="customerName" constraint="no empty" />
</row>
<row>
<label value="Date" />
<datebox id="date" constraint="no empty"/>
</row>
<row>
<button id="saveBtn" label="Save" />
<button id="cancelBtn" label="Cancel" onClick="addCustomerWin.detach()"/>
</row>
</rows>
</grid>
</window>
</zk>
|
호출된 이후에 registerNewCustomer() 메소드는
addCustomer.zul을 사용하는 새 창 구성 요소를 간단하게 작성하고, 이를 모달 대화 상자 창으로 만든다. 그림 5에는 이에 대한 예제가 있다.
그림 5. 새 고객 등록하기
이 예제는 index.zul 페이지와 유사하게도
<?variable-resolver ?>
지시문과 DelegatingVariableResolver를 사용하여
AddCustomer 관리되는 bean을 제어기로서
addCustomerWin 창 구성 요소에
적용한다. Register Customer 대화 상자는 Customer 이름과 Date의 필수 값이 있는
격자로 구현된다. AddCustomer 구현은
ManageCustomer 클래스와 유사하다. CustomerService bean은
@Inject 규정자를 사용하여 삽입되었고,
addCustomerWin의 하위 구성 요소도 Listing 10에서 보여 주는 것과 같이 @Inject와
@ComponentId 규정자를 사용하여 자동으로 삽입된다.
Listing 10. 고객 추가하기
@Named
@SessionScoped
public class AddCustomer extends GenericComposer implements Serializable {
@Inject @SessionScoped CustomerService custSvc;
@Inject @ComponentId("customerName") private transient Textbox customerName;
@Inject @ComponentId("date") private transient Datebox date;
@Inject @ComponentId("saveBtn") private transient Button saveBtn;
}
|
ManageCustomer 클래스의 registerNewCustomer() 메소드와 같이
예제는 Listing 11에서 설명한 것과 같이 saveNewCustomerDetails() 옵저버 메소드를 구현한다.
Listing 11. 새 고객 세부 사항 저장하기
public void saveNewCustomerDetails(
@Observes @Events("saveBtn.onClick") MouseEvent evt, @New Customer newCustomer)
throws Exception {
newCustomer.setName(customerName.getValue());
java.util.Date utilDate = date.getValue();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
newCustomer.setDate(sqlDate);
custSvc.addCustomer(newCustomer);
Executions.getCurrent().sendRedirect("index.zul");
evt.getTarget().getParent().detach();
}
|
Save 단추(saveBtn)를 클릭할 때마다
saveNewCustomerDetails() 메소드는
해당되는 onClick
MouseEvent의 알림을 받는다. 이 메소드는 또한 유형
Customer의 추가 매개변수를 한 개 더 가진다. @New 규정자로 어노테이트되기 때문에 CDI 스펙에 따르면
Customer bean의 새 인스턴스는 이 메소드가 관찰될 때마다 자동으로 매개변수에
삽입된다.
그림 6에서 보여 주는 것과 같이 사용자는 Manage Customer 대시보드에서 아무 고객 행을 선택하면 Edit Customer 화면에 액세스할 수 있다.
그림 6. 고객 편집하기
이 예제는 registerNewCustomer() 메소드와 유사하게도
옵저버 메소드 editCustomer()를 목록 상자에서 listitem이 선택될 때마다
전송되는 @Observes ZK
SelectEvent로 정의한다.
Listing 12. 고객 편집하기
public void editCustomer(
@Observes @Events("customerList.onSelect") SelectEvent evt) throws Exception {
Listitem selectedCustomer = customerList.getSelectedItem();
String custId = ((Listcell) (selectedCustomer.getChildren().get(0))).getLabel();
Map<String, String> args = new HashMap<String, String>();
args.put("custId", custId);
Window win2 = (Window) Executions.createComponents("editCustomer.zul", null, args);
win2.doModal();
win2.setTitle("Enter Customer Data");
win2.setClosable(true);
win2.setMaximizable(true);
}
|
editCustomer.zul의 editCustomerWin 창 구성 요소를 위한 EditCustomer 제어기 클래스를
구현하는 것은 AddCustomer와 매우 유사하다. 반복하지 않기 위해 이 글에서는 설명하지 않겠다.
이 애플리케이션의 코드, EditCustomer 클래스의 소스 및 editCustomer.zul 파일을 다운로드할 수 있다.
이 글에서 Java 코드로 쓰인 오픈 소스 Ajax 프레임워크인 ZK와 JSR-299 컨텍스트 및 의존성 삽입에 관해 살펴 보았다. ZK CDI 확장의 기능을 통해 ZK 프로그래밍 모델 내에서 CDI를 사용할 수 있다. Apache Tomcat에서 실행하고 MySQL 데이터베이스에 연결하는 현존하는 간단한 예제를 사용했다.
ZK 프레임워크는 풍부한 구성 요소 세트, 마크업 언어, 강력한 개발 도구 및 훌륭한 문서를 갖추었다. 이는 오픈 소스 이벤트 구동형 Ajax 프레임워크이다. 또한 Java EE 플랫폼 6의 JSR-299로 정의되는 CDI는 형안전 의존성 삽입, 이벤트 알림 모델 및 휴대용 확장을 개발하기 위한 SPI를 비롯한 강력한 기능 세트를 제공한다. ZK CDI 확장은 ZK 프로그래밍 모델과 CDI를 통합하여, 이를 통해 Java EE 6 엔터프라이즈 애플리케이션을 원활하게 개발할 수 있다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| Sample code for this article | zkManageCustomers.zip | 71 KB | HTTP |
교육
- "Rich Internet applications using ZK: An open source Ajax framework"(developerWorks 저, 2010년 1월)에서는 ZK를 소개하고,
이를 사용하여 Apache Tomcat에서 실행하고 MySQL 데이터베이스로 연결하는 현존하는 예제를 제시한다.
- ZK open source Ajax를 둘러 보고 시연하며 다운로드해 보자.
- 기초, ZUL 구성 요소 및 ZK에 대한 심도 있는 정보를 보려면 ZK Developer's
Guide를 읽어보자.
- ZK(ZK Explorer, ZK SpreadSheet, ZK Calendar 등)를 사용한 애플리케이션의 라이브 데모를 보자.
- ZK Studio
documentation: Getting Started, Developer's Guides, and Webinars를 모두 알아보자.
- JSR-299: Contexts and
Dependency Injection for the Java™ EE platform에 대해 모두 알아보자.
- 개발 환경을 설정하는 데 도움을 받으려면 Getting
started with ZK CDI를 읽어보자.
- CDI를 정의하는 JSR-299 스펙의 참조 구현인 Weld에 대해 읽어보자.
- "Dependency injection with Guice"(developerWorks 저, 2008년 12월)를 읽고 Java 개발을 위한 Google의 오픈 소스 의존성 삽입 프레임워크인 Guice에 대해 알아보자.
- "Introduction to Spring 2 and JPA"(developerWorks 저, 2006년 8월)는 오래 되었지만 여전히 유용하다. Spring 프레임워크와 DI 개념에 대한 논의.
- "Java EE 5: Power and productivity with less complexity"(developerWorks 저, 2007년 11월)에서는 DI 세부 사항을 포함한 JEE 5에 대해 빠르고 간편하게 둘러 볼 수 있다.
- 다른 애플리케이션 서버와 환경으로 Weld 설정에 대해 자세히 배우려면 "Community Documentation"
Chapter 18: Application servers and environments supported by
Weld를 확인하자.
제품 및 기술 얻기
- IBM 제품 평가판을
다운로드하거나 IBM SOA Sandbox의
온라인 시험판을 살펴보고 DB2®, Lotus®, Rational®, Tivoli® 및 WebSphere®의 애플리케이션 개발 도구 및 미들웨어 제품을 사용해 볼 수 있다.
토론
- developerWorks 포럼 & 블로그를 통해 developerWorks 커뮤니티에 참여하자.
