このドキュメントは、初めてZKを使用するユーザーのための入門チュートリアルです。 本資料はデータベースを使う簡単なウェブアプリケーションを作成し、ステップバイステップで説明します。Javaの基本知識さえあれば、ZKでAjaxウェブアプリケーションを開発することが可能です。
なお、ユーザーの皆様はJDK (1.4+)とサーブレットコンテナ(ex.Tomcat)が備わっている環境で作業することを想定しています。
やるべきことを忘れないように、これらのことをリストアップし、アプリケーションに保存することにしましょう。 これが今回開発するデータベースを使う簡単なアプリケーションです。 インストールの手順を省くため、ここではJavaデータベース(HSQL DB)を使います。
hsqldb フォルダ(データベースファイル)をホームディレクトリー(ex. C:\ )にコピーします。
シナリオ
まずは必要なZKライブラリーを適当なディレクトリーに置いたり、設定ファイルを編集したりする環境設定をします。
ワーキングディレクトリーの構造
Tomcatのウェブアプリケーションディレクトリー(ex.
$TOMCAT_HOME/webapps)の下にワーキングディレクトリーを作成しましょう。 ワーキングディレクトリーの構造は以下の通りです:+ProjectName +META-INF +WEB-INF +classes +lib web.xml zk.xml +src web pages
- WEB-INF/web.xml:サーブレットの定義や、ZKアプリを実行するのに必要なリスナーです。
- WEB-INF/zk.xml:ZKのコンフィグディスクリプタです。(オプション)
- WEB-INF/classes:全てのJavaクラスファイルです。
- WEB-INF/lib:ZKライブラリーです。
必要なjarファイルは:
- ZK
- bsh.jar: BeanShell Javaインタープリター
- commons-el.jar: Apache用EL(Expression Language)インタープリター
- zcommon.jar: ZKの共有ライブラリー
- zhtml.jar: XHTML関係コンポーネンツ
- zk.jar: ZKコアコード
- zkplus.jar:統合コード: Acegi Security・Spring・Hibernate・data binding
- zul.jar: XUL関係コンポーネンツ
- zweb.jar: Web関係ユーティリティーコード
- HSQLDB
- hsqldb.jar: Hsqlデータベース
- src/ ソースファイルです。
web.xmlを設定しましょう次に、ZKが必要なサーブレットとリスナーをweb.xmlにて設定しましょう。
<!-- ZK --> <listener> <description>Used to clean up when a session is destroyed</description> <display-name>ZK Session Cleaner</display-name> <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class> </listener> <servlet> <description>ZK loader for ZUML pages</description> <servlet-name>zkLoader</servlet-name> <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class> <init-param> <param-name>update-uri</param-name> <param-value>/zkau</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>zkLoader</servlet-name> <url-pattern>*.zul</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>zkLoader</servlet-name> <url-pattern>*.zhtml</url-pattern> </servlet-mapping> <servlet> <description>The asynchronous update engine for ZK</description> <servlet-name>auEngine</servlet-name> <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>auEngine</servlet-name> <url-pattern>/zkau/*</url-pattern> </servlet-mapping>
データベースの概要
アプリケーションの仕様からみれば、次の属性、イベントid・イベント名・優先順位・日付が必要です。データベースの概要は以下の通りです。
Field Type id varchar(50) name varchar(50) priority int date date ドメインオブジェクト
上記のテーブルに基づき、以下のドメインオブジェクトを作成します。public class Event { private String id; private String name; private int priority; private Date date; public Event(){} public Event(String id,String name,int priority,Date date){ this.id = id; this.name = name; this.priority = priority; this.date = date; } //getter and setter methods are ommited, please refer to the source code. }DAOオブジェクト
このアプリケーションのDAOオブジェクトは以下のメソッドが必要です:findAll(),delete(),insert(),and update().public class EventDAO { private String url = "jdbc:hsqldb:file:/hsqldb/event"; private String user = "sa"; private String pwd = ""; public EventDAO() { try { Class.forName("org.hsqldb.jdbcDriver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //The implementation is ommited, please refer to the source code. public List findAll(){} public boolean delete(Event evt){} public boolean insert(Event evt){} public boolean update(Event evt){} }
初めてのZKコンポーネント
まずは拡張子がzulであるファイル(たとえばtodo.zul)を作成し、ウェブアプリケーションのホームディレクトリー(例:
$TOMCAT_HOME/webapps/ProjectName/)に置きます。 ZKコンポーネントを宣言する方法はHTMLと同様です。では、windowコンポーネントを宣言してみましょう。<window title="To do list" width="640px" border="normal"> </window>それからTomcatを開始し、ブラウザを開き、http://localhost:8080/todo/todo.zulを参照します(ポート番号は設定によって違います)。 結果は以下になります:タイトルが”To do List”になっているウィンドウです。
![]()
ZKの世界では全てのものはコンポーネンツの組み合わせにより作られています。お好きなように
windowのタイトル、幅、枠などを調整することができます。やり方はとても簡単で直観的なので、いくつか変更してみてください。ZKコンポーネンツ間の階層関係
これからは、ZKコンポーネンツでページを豊富にしましょう。 テーブルを作成しますので、
listboxコンポーネントを宣言します。リストボックスはwindowタグの中でデータを表示させるためのコンポーネントです。<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> </listbox> </window>ここでは
listboxはwindowコンポーネントの子コンポーネントになっています。 つまり、ZKコンポーネンツ間では階層関係が存在します。windowをlistboxの子コンポーネントとして宣言するというように階層関係を間違えてしまうと、UIの例外が発生します。入れ子コンポーネント
listboxの宣言の中で、id属性を使って”box”という識別子を指定します。これによって、”box”でlistboxを参照することが可能になります。さらに、listboxは入れ子構造のコンポーネントで、listhead (aka:テーブルの欄)とlistitem (aka:テーブルの列)の二つの子コンポーネントが使用できます。<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> <listhead> </listhead> <listitem> </listitem> </listbox> </window>テーブルには三つの欄が必要ですので、listheadの中に”Item”・”Priority”・”Date”の三つのlistheaderコンポーネンツを宣言しましょう。
<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Date" width="90px" /> </listhead> <listitem> </listitem> </listbox> </window>結果は以下になります。
![]()
欄が三つありますので、それぞれの列にも三つのフィールドが必要になります。listitemコンポーネントの中で三つのlistcellコンポーネンツを宣言します。
<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem> <listcell/> <listcell/> <listcell/> </listitem> </listbox> </window>listboxコンポーネントの入れ子構造は以下の通りです。+listbox +listhead listheader +listitem listcell入力コンポーネンツ
listboxにイベントを表示させるには、イベント名(テキスト)・優先順位(数字)・日付(日付 )等イベントに関する情報を入力しなければなりません。そこでtextbox・intbox・dateboxをwindowコンポーネントの中で宣言します。<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem> <listcell/> <listcell/> <listcell/> </listitem> </listbox> <listcell/> Item:<textbox id="name" cols="50" /> Priority:<intbox id="priority" cols="1" /> Date:<datebox id="date" cols="8"/> <button label="Add" width="36px" height="24px"/> <button label="Update" width="46px" height="24px"/> <button label="Delete" width="46px" height="24px"/> </window>結果は:
![]()
レイアウトコンポーネント
入力するエリアを
listboxと分けて表示するため、groupboxコンポーネントを使って入力コンポーネンツをグループにします。そうすると、入力コンポーネンツは枠に囲まれます。<window title="To do list" width="640px" border="normal"> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem> <listcell/> <listcell/> <listcell/> </listitem> </listbox> <groupbox> <caption label="Event" /> Item: <textbox id="name" cols="50" /> Priority: <intbox id="priority" cols="1" /> Date: <datebox id="date" cols="8"> <button label="Add" width="36px" height="24px"/> <button label="Update" width="46px" height="24px"/> <button label="Delete" width="46px" height="24px"/> </groupbox> </window>上記のコードでは、
groupboxの他、captionコンポーネントを宣言し、グループボックスの枠の上部に”Event”というラベルを表示させます。captionコンポーネントはHTMLのレジェンド要素と類似しています。結果は以下になります。![]()
ここまでで、ユーザーインターフェースページの作成は完了です。次はこのページをデータベースと連結させます。
UIとデータベース間の対話
シナリオではイベントを表示・新規作成・編集・削除することができます。次に、ページとデータベースとの対話を実現します。JavaコードでZKコンポーネンツと対話
ZKのパワフルな特徴の一つは、Javaコードでページに定義されているZKコンポーネンツと対話できることです。ZKは三つの選択肢を提供しています:これらのJavaコードをページの中に埋め込むか、別のファイルに保存するか、または、Javaクラスにします。ここでは一番目の方法について詳しく説明します。Javaコードをページに埋め込む
まずはイベントデータをデータベースから読み込みます。そして<zscript>タグを使ってJavaコードをページに埋め込みます。
zscript要素はスクリプトコードを定義する特別な要素です。zscriptはZULページがレンダリングされる度に処理され、一般では初期化、グローバル変数の宣言、グローバルメソッドの宣言で使います。ここではeventDAOのインスタンスを宣言し、結果を
Listに保存します。zscript要素の中で定義されたグローバル変数はEL表記でアクセスできます。JSPと同様に、ZUMLページではELが使用できます。EL表記のシンタックスは${expr}です。
データベースアクセスを初期化する方法は以下の通りです。
<window title="To do list" width="640px" border="normal"> <zscript> import events.Event; import events.EventDAO; import java.util.ArrayList; //fetch all events from database EventDAO evtdao = new EventDAO(); List allEvents = evtdao.findAll(); </zscript> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem> <listcell/> <listcell/> <listcell/> </listitem> </listbox> <groupbox> <caption label="New" /> Item: <textbox id="name" cols="50" /> Priority: <intbox id="priority" cols="1" /> Date: <datebox id="date" cols="8"> <button label="Add" width="36px" height="24px"/> <button label="Update" width="46px" height="24px"/> <button label="Delete" width="46px" height="24px"/> </groupbox> </window>forEachループを使う
次にlistitemコンポーネントでforEachループを使ってallEventsに保存されているデータを
listboxコンポーネンツに入れます。 forEach属性は生成されるコンポーネンツの数を決定します。集合を指定する場合、ZKローダーは同じ数のコンポーネンツを生成します。each変数は集合の中にあるオブジェクトに対応します。ここでは下のようにEL表記でオブジェクトとその属性を取得します。
<window title="To do list" width="640px" border="normal"> <zscript> import events.Event; import events.EventDAO; import java.util.ArrayList; //fetch all events from database EventDAO evtdao = new EventDAO(); List allEvents = evtdao.findAll(); </zscript> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem forEach="${allEvents}" value="${each}"> <listcell label="${each.name}" /> <listcell label="${each.priority}" /> <listcell label="${each.date}" /> </listitem> </listbox> <groupbox> <caption label="New" /> Item: <textbox id="name" cols="50" /> Priority: <intbox id="priority" cols="1" /> Date: <datebox id="date" cols="8"> <button label="Add" width="36px" height="24px"/> <button label="Update" width="46px" height="24px"/> <button label="Delete" width="46px" height="24px"/> </groupbox> </window>
入力したデータをデータベースに保存
はじめに<zscript>の中でadd( )メソッドを宣言しましょう。上記のadd( )メソッドの中に以下の三つのステップを完成させます。<zscript> .... void add(){} <zscript>
- 入力したデータを取得
- データをデータベースに保存
- Ajaxでビューを更新
入力したデータを取得
ZKではJavaコードにあるUIコンポーネンツにアクセスできます。アクセスの方法は、id属性でコンポーネンツの識別子を指定します。 この例では、入力されたデータはtextbox(id ="name")、 intbox(id ="priority")、 datebox(id="date")、この三つの入力コンポーネンツに保存されていますので、それぞれのvalue属性にアクセスすればデータを取得できます。
name.value; //イベント名 priority.value; //優先順位 date.value; //日付データをデータベースに保存
データを取得したら、データベースに保存する手順はとても簡単です。
Event newEvt = new Event(UUID.randomUUID().toString(),name.value,priority.value.intValue(),date.value); evtdao.insert(newEvt); //synchronized data object with database allEvents = evtdao.findAll();Ajaxでビューを更新
ZKではJavaコードにより簡単にAjaxの形でビューを更新できます。ここではJavaコードで新しいリストアイテムを
listboxに挿入するだけでOKです。ZKが自動的にページを更新してくれます。
//insert a new Event into the listbox Listitem li = new Listitem(); li.setValue(newEvt); li.appendChild(new Listcell(name.value)); li.appendChild(new Listcell(priority.value)); li.appendChild(new Listcell(new SimpleDateFormat("yyyy-MM-dd").format(date.value))); box.appendChild(li);
- appendChild( )で子コンポーネントを挿入します。
完全なコードは以下の通りです。
<window title="To do list" width="640px" border="normal"> <zscript> import events.Event; import events.EventDAO; import java.util.ArrayList; import java.text.SimpleDateFormat; import java.util.UUID; //fetch all events from database EventDAO evtdao = new EventDAO(); List allEvents = evtdao.findAll(); void add(){ //insert into database Event newEvt = new Event(UUID.randomUUID().toString(),name.value,priority.value.intValue(),date.value); evtdao.insert(newEvt); //synchronized data object with database allEvents = evtdao.findAll(); //insert a new Event into the listbox Listitem li = new Listitem(); li.setValue(newEvt); li.appendChild(new Listcell(name.value)); li.appendChild(new Listcell(priority.value)); li.appendChild(new Listcell(new SimpleDateFormat("yyyy-MM-dd").format(date.value))); box.appendChild(li); } </zscript> <listbox id="box" multiple="true" rows="4"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem forEach="${allEvents}" value="${each}"> <listcell label="${each.name}" /> <listcell label="${each.priority}" /> <listcell label="${each.date}" /> </listitem> </listbox> <groupbox> <caption label="New" /> Item: <textbox id="name" cols="50" /> Priority: <intbox id="priority" cols="1" /> Date: <datebox id="date" cols="8"> <button label="Add" width="36px" height="24px"/> <button label="Update" width="46px" height="24px"/> <button label="Delete" width="46px" height="24px"/> </groupbox> </window>ZKコンポーネンツにイベントリスナーを登録
ページが変化したのは、90%以上はユーザーの操作によるものです。 add( )メソッドも同じです。add( )はユーザーが”add”ボタンをクリックした場合のみ作動しなければなりません。ボタンがクリックされたかどうかを判断するには、
buttonコンポーネントの宣言の中ににonClickイベントリスナーを宣言し、add( )メソッドを指定します。ユーザーがボタンをクリックすると、add( )メソッドは実行されます。とても直観的なやり方ではありませんか? ZKはいつも最もシンプルな方法を提供しています!
<button label="Add" width="36px" height="24px" onClick="add()" />add以外のコントロールコード
add以外のコントロールコードは以下になります。
delete(), イベントをデータベースから削除し、データモデルとlistboxを更新します。update(), データベースにあるイベントをアップデートし、データモデルとlistboxを更新します。move(),listboxにある情報をグループボックスにある入力コンポーネンツに移動します。cleargp(),グループボックスにある入力コンポーネンツのデータをクリアします。<zscript> import events.Event; import events.EventDAO; import java.util.ArrayList; import java.text.SimpleDateFormat; import java.util.UUID; //fetch all events from database EventDAO evtdao = new EventDAO(); List allEvents = evtdao.findAll(); void add(){ //insert into database Event newEvt = new Event(UUID.randomUUID().toString(), name.value,priority.value.intValue(),date.value); evtdao.insert(newEvt); //synchronized data with database allEvents = evtdao.findAll(); //insert a listEvent into the listbox Listitem li = new Listitem(); li.setValue(newEvt); li.appendChild(new Listcell(name.value)); li.appendChild(new Listcell(priority.value.toString())); li.appendChild(new Listcell(new SimpleDateFormat("yyyy-MM-dd").format(date.value))); box.appendChild(li); } void update(){ //update database Event editEvt = (Event)box.selectedItem.value; editEvt.setName(name.value); editEvt.setPriority(priority.value); editEvt.setDate(date.value); evtdao.update(editEvt); //update listbox List children = box.selectedItem.children; ((Listcell)children.get(0)).label = name.value; ((Listcell)children.get(1)).label = priority.value.toString(); ((Listcell)children.get(2)).label = new SimpleDateFormat("yyyy-MM-dd").format(date.value); } void delete(){ evtdao.delete((Event)box.selectedItem.value); box.removeItemAt(box.getSelectedIndex()); cleargb(); } void move(){ name.value = ((Event)box.selectedItem.value).getName(); priority.value = ((Event)box.selectedItem.value).getPriority(); date.value = ((Event)box.selectedItem.value).getDate(); } void cleargb(){ name.value = null; priority.value = null; date.value = null; } </zscript>必要なイベントリスナーを追加
最後のステップはZKコンポーネンツに必要なイベントリスナーを追加します。
- 削除ボタンに
onClickイベントリスナーを追加- 編集ボタンに
onClickイベントリスナーを追加listboxにonSelectイベントリスナーを追加<window title="To do list" width="640px" border="normal"> <zscript> //the implementation part is ommited, please refer to the above listing. void add(){} void delete(){} void update(){} void move(){} void cleargb(){} </zscript> <listbox id="box" multiple="true" rows="4" onSelect="move()"> <listhead> <listheader label="Item" /> <listheader label="Priority" width="50px" /> <listheader label="Opened" width="90px" /> </listhead> <listitem forEach="${allEvents}" value="${each}"> <listcell label="${each.name}" /> <listcell label="${each.priority}" /> <listcell label="${each.date}" /> </listitem> </listbox> <groupbox> <caption label="Event" /> Item: <textbox id="name" cols="25" /> Priority: <intbox id="priority" cols="1" /> Date: <datebox id="date" cols="8" /> <button label="Add" width="36px" height="24px" onClick="add()" /> <button label="Update" width="46px" height="24px" onClick="update()" /> <button label="Delete" width="46px" height="24px" onClick="delete()" /> </groupbox> <window>
このドキュメントではZKを用いて簡単なウェブアプリケーションを作成する基本知識を説明しました。
項目別の詳細資料は以下の通りです。.
