使用 ZK 框架的富 Internet 应用程序

一个开源 Ajax 框架

ZK 是一个用 Java™ 代码编写的开源 Asynchronous JavaScript + XML (Ajax) 框架,使用该框架,您无需编写 JavaScript 代码就可以编写一个支持 Web 2.0 的富 Internet 应用程序。Dojo 等典型的 Ajax 框架拥有一些 JavaScript 库,用于公开某些 API 以进行 “Ajax 化” 调用。另一方面,ZK 使用一个基于 XML 的元定义(meta-definition)来定义用户界面。当客户机请求这个页面时,XML 将转化为 HTML 代码。本文将向您介绍 ZK,通过一个真实的示例来展示其使用方法,这个示例运行在 Apache Tomcat 上并连接到 MySQL 数据库。

Sachin K Mahajan, 软件开发人员, IBM  

Sachin 毕业于美国盐湖城犹他大学,获得硕士学位。他曾为美国和印度的多个规模不等的公司工作,担任各种技术和管理职务。Sachin 目前在 IBM Software Group 的 Lotus 分公司工作。


developerWorks 投稿作者

2010 年 4 月 06 日

简介

您可以将 ZK 看做是没有 JavaScript 的 Ajax。它包含一个基于 Ajax 的、事件驱动的引擎,一组丰富的 XHTML 和 XUL 元素,一种名为 ZUML 的标记语言,这种语言用于创建特性丰富的用户界面。业务逻辑可以通过 Java 代码直接编写并集成到您的应用程序中,并基于事件或组件触发。ZK 最强大的特性是其丰富的、用于用户界面开发的控件库。有意思吧?

首先,我将更详细地描述前面的术语:

  • XHTML:可扩展超文本标记语言(Extensible Hypertext Markup Language),是 HTML 和 XML 的结合体,结合了 HTML 的威力和灵活性与 XML 的可扩展性。清单 1 提供了一个 XHTML 代码示例。
    清单 1. XHTML 代码示例
    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 
    Transitional//EN" "DTD/xhtml1-transitional.dtd">
    <html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
     <head>
     <title>Hello ZK</title>
     </head>
     <body>
     <h1>Introducing XHTML</h1>
     </body>
     </html>
  • XUL:XML 用户界面语言(XML User Interface Language),简称 XUL(发音同 “Zool”),是一种由 Mozilla 研发的标记语言,一个用于描述图形用户界面的 XML 应用程序。XUL 能够创建多种元素,比如输入控件、工具栏、菜单、树状图、键盘快捷键等。清单 2 展示了一个 XUL 代码示例。
    清单 2. XUL 代码示例
    <?xml version="1.0"?>
    <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
    <window id="main" title="My App" width="300" height="300"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
       <caption label="Hello World"/>
       </window>
  • ZUML:ZK 用户界面标记语言(ZK User Interface Markup Language),用于定义富用户界面。由于它基于 XML,因此每个元素都描述组件,而属性描述组件值。清单 3 展示了一个 ZUML 代码示例。
    清单 3. ZUML 代码示例
    <window title="Hello ZUML" border="normal">
       Hello World!
     </window>

获取 ZK

获取和安装 ZK 非常简单。ZK 文档网站上包含大量关于库和如何建立文件夹结构的文档(参见 参考资料 获取链接)。因此,获取 ZK(包括运行 hello world 应用程序)应该非常简单。

为何要使用 ZK?

ZK 是一个直接 Ajax 实现 — 或者换句话说,一个以服务器为中心的模型。ZK 与其他框架不同,其他框架包含大量令人眼花缭乱的 Ajax 调用细节。另外,Ajax 调用需要大量使用 JavaScript 和相关知识,以便在浏览器(客户机)上操作 Document Object Model (DOM) 并在客户机/服务器通信过程中同步数据。ZK 消除了这些复杂性,使您能够专注于业务逻辑。ZK 的其他好处包括:

  • 丰富的用户界面。
  • Web 服务访问。
  • 组件数据绑定。
  • 简单但强大的标记语言 ZUML。
  • 由于没有客户机代码,因此具有高度的可维护和可扩展性。
  • 高度易用性。
  • 提高开发人员生产力。

ZK 应用

为理解 ZK 的工作方式,我们来看一个真实示例。这个示例是一个客户管理应用程序,用户可以通过它进行各种操作,比如添加新客户,编辑客户数据,以及数据库中的客户条目的软删除(soft deletion)。但是,在深入代码之前,我将描述几个通过 ZK 生成的用户界面屏幕。检查过这些屏幕之后,我将描述 ZK 的架构,它是生成这个出色 UI 的底层引擎。最后,我将介绍这个应用程序使用的详细代码和配置参数。

图 1 展示了这个客户管理应用程序的初始屏幕。

图 1. Manage customer index 页面
Manage Customers 应用程序展示了一个数据电子表格视图,其中包括 ID、Name、Active Date 和 whether the account is deleted。

图 1 展示了在这个应用程序中注册的客户列表。这个列表显示为一个网格,包含 4 列:ID,客户姓名、激活日期和删除标记。可以通过单击列名旁边的按钮对网格中的数据排序(升序或降序)。ID(整数型)、Name(字符串)和 Active Date(日期型)列都支持排序。在本文后面部分,我将解释如何通过使用一个 Comparator 对象来定制排序。这个应用程序还支持分页,如屏幕底部所示。这个页面支持一次显示 5 条记录,并具有移动到下一页或直接移动到特定页面的能力。

图 2. 顶部菜单栏
显示 Register New Customer 和 Exit 菜单的屏幕截图

图 2 展示了这个客户管理应用程序的顶端菜单栏,它使用 ZK 的菜单栏小部件实现,包含 Register New Customer 和 Exit 两个选项。

现在您已经检查了这个示例应用程序的几个用户流,我们现在讨论 ZK 的架构细节。

ZK 内部结构

ZK 应用程序的行为与桌面应用程序类似,因为用户活动通过 Client Engine 自动触发服务器上的事件。反过来,服务器上的组件更新视图以匹配客户机上的视图。客户机(浏览器)只充当一个视图,而应用程序在服务器上运行,并且能够完全访问数据库、Web 服务等资源。因此,安全不是问题。

ZK 框架中有 3 个主要组件:ZK Client Engine、ZK Loader 和 ZK Update Engine。

  • ZK Client Engine:这是 ZK 的客户端,发送请求到服务器以获取相应的 ZK 响应,这个引擎使用这些响应来更新浏览器中的 DOM。
  • ZK Loader:这个组件基于客户机请求的 URL 生成一个 HTML 页面。
  • ZK Update Engine:也称为 Asynchronous Update (AU) Engine,这个组件负责接收 Ajax 请求并更新 ZK 组件中的对应属性,以便 Client Engine 能够更新浏览器中的视图。
图 3. ZK 架构
显示浏览器和服务器的 ZK 架构图。客户机和服务器通过请求/响应互相对话。

图 3 中描述的流的机制如下:

  • ZK Loader 根据客户机请求的 URL 提供 HTML,包括 CSS、 JavaScript 等。这包括 ZK Client Engine,它负责监控客户端事件,将 ZK Requests 发送到服务器并从服务器接收 ZK Responses。
  • Client Engine 根据 onChangeonClick 等用户动作触发事件。
  • 这些事件调用 ZK Update Engine,该引擎更新 ZK 组件的属性并响应 Client Engine。
  • 接收到这个响应之后,Client Engine 更新浏览器中的 DOM 树,以便用户能够看到这个更新后的视图。

使用 ZK 管理客户

接下来,我将继续介绍创建一个示例应用程序来管理客户的细节。我使用 Eclipse IDE 来展示应用程序的创建,但您可以选择使用任何 IDE。

基本的思路是创建一个动态 Web 应用程序项目并将其指向应用服务器运行时,这在本例中为 Apache Tomcat 运行时。

建立新项目和运行时后,复制图 4 中显示的目录结构。

图 4. 目录结构
zkManageCustomers、src Customer.java 和 CustomerService.java 的包视图,WebContent 下面是 addCustomer.zul、editCustomer.zul、index.zul 和 timeout.zul。

这个客户管理应用程序的目录结构遵循图 4 中描述的目录结构的模式。

注意,这个应用程序的核心文件包含在 WebContent 文件夹中,该文件夹包含以下子文件夹:

  • META-INF —— 包含用于连接到 MySQL 数据库的数据库凭证信息。
  • WEB-INF —— 包含一个库文件夹,其中包含运行应用程序所需的 ZK JAR 文件;它还包含描述数据源的 web.xml 文件。
  • 另外,所有关联 zul 文件和 HTML 文件都包含在 WebContent 文件夹中。这些文件充当应用程序的视图部分,向这个 Web 应用程序提供动态和静态内容。

示例文件 zkManageCustomer.zip(参见 下载 部分)包含这个应用程序的 zip 版本。它还包含 Eclipse 需要的元数据文件,以便其可以直接无缝地导入该 IDE。

Eclipse 中的 Java 2 Platform, Enterprise Edition (J2EE) 透视图拥有一个 server 选项卡,右键单击该选项卡将显示一个创建新服务器选项。这个服务器可用于从 Eclipse IDE 管理应用服务器。

新服务器配置好后,新创建的资源需要在服务器上配置。这个服务器配置将部署开发过程中创建的资源。


配置 Tomcat 和 MySQL

示例程序被配置为使用 Tomcat 和 MySQL。但是,您可以轻易将其配置为在另一个 Java 应用服务器(比如 WebSphere)中运行。由于示例程序使用 JDBC,因此它应该能够使用任何受支持的 SQL 数据库,比如 DB2 Express-C,这只需简单地修改连接代码。

要将 Tomcat 连接到 MySQL 数据库,您需要定义一个资源引用。这个元素指定一个资源管理器连接工厂引用的名称。在本例中,它将是由 jdbc/mysql 指定的数据库连接,其类型为 javax.sql.DataSource

清单 4. web.xml 中的资源管理器连接工厂
	. . .
	<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 等属性。

清单 5. context.xml 中的上下文定义
	. . .
	<Context>
	<Resource driverClassName="com.mysql.jdbc.Driver" 
	maxActive="4" maxIdle="2" maxWait="5000" auth="Container" 
	name="jdbc/mysql" password="" type="javax.sql.DataSource" 
	url="jdbc:mysql://localhost:3306/customer" username="root"/>
	</Context>
. . .

客户数据库只有一个表,可以通过运行清单 6 中的脚本创建。

清单 6. 数据库创建脚本
	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`)
	);

调整应用程序以使用 DB2

要将 Tomcat 连接到一个 DB2-Express C 或另一个 DB2 变体数据库,其配置与使用 MySQL 时的配置非常相似。以下的示例展示 web.xml 中的资源管理器连接工厂的配置:

清单 7. web.xml 中的资源管理器连接工厂
DB Connection 
jdbc/db2db 
javax.sql.DataSource 
Container 
. . .

以下是一个典型的上下文定义示例:

清单 8. 上下文定义
. . .
maxActive="4" maxIdle="2" maxWait="5000" auth="Container" 
name="jdbc/db2db" password="" type="javax.sql.DataSource" 
url="jdbc:db2://localhost:(port)/customer" username="db2admin"/>
. . .

应用程序小结

本文前面简要介绍了这个客户管理应用程序,它提供以下功能:

  • 支持用户操作的仪表板页面,包含一个所有客户的视图。
  • 添加新客户。
  • 编辑现有客户。
  • 支持客户删除(软删除)。

图 5 展示了应用程序的仪表板页面,默认视图显示数据库中的客户列表。

图 5. 仪表板屏幕
仪表板屏幕的屏幕截图:显示一个电子表格样式的数据布局

仪表板屏幕显示了一个所有已注册客户的列表。在这个客户列表上,用户能够根据 ID 或 Name 进行排序。

index.zul 拥有各种属性,比如 borderlayoutmenubarmenumenupopup,这些属性定义应用程序的观感。

清单 9. index.zul 文件
<menubar id="menubar" width="800px">
 <menu label="Manage Customers">
   <menupopup>
     <menuitem label="Register New Customer">
      <attribute name="onClick"><![CDATA[
        Window win = (Window) Executions.createComponents("addCustomer.zul", null, null);
        win.doModal();
        win.setTitle("Enter Customer Data");
        win.setClosable(true);
        win.setMaximizable(true);
        ]]></attribute>
     </menuitem>
    <menuseparator />
   <menuitem label="Exit" onClick="win.detach()" />
 </menupopup>
</menu>
</menubar>

如清单 9 所示,我定义了一个 menubar,菜单标签用于注册新客户。单击这个菜单(onclick)时,通过另一个名为 addCustomer 的 zul,我使用 Executions 对象实例化一个 Window 对象。我还设置这个属性来创建对话框 modalclosable 等。另外,我还包含了一个关闭应用程序的退出菜单。这个 menubar,以及这些已定义的属性,给这个应用程序提供了一种富客户端观感。

清单 10 展示了如何使用一个 listbox 元素来填充这个表格,在 listbox 中,我定义了一个模型,将根据这个模型填充表格元素。

清单 10. 定义表格的样例 listbox 元素
	<listbox id="customerList" model="@{myList}" mold="paging" pageSize="5"
		multiple="true" width="800px" rows="${custCount}">
	  <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>
	    <listitem self="@{each=myList}" onClick="showEdit(self.getLabel())">
	      <listcell label="@{myList.id}" />
	      <listcell label="@{myList.name}" />
	      <listcell label="@{myList.date}" />
	      <listcell label="@{myList.deleted}"/>
	    </listitem>
	</listbox>

分页功能可以使用 listboxmold 属性激活。另外,基于列标题的排序功能可以通过在 listheader 的 sort 属性上启用 auto 来定义。myList 对象是一个 Customer 对象列表,包括以下一些属性:id namedate 以及 Customer 的 deleted flag。服务返回这个列表,然后 ZK 通过 "each =myList" 迭代这个列表。然后,listcell 标签在 listbox 中显示这个 Customer 对象的每个属性。

此外,为了启用编辑功能,我将一个 showEdit 方法附加到 onClick 事件。

Register customer 对话框实现为一个网格,该网格有两个必填值:Customer name 和 Date。

清单 11. Customer 对话框网格代码
	<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 label="Save" onClick="submit()" />
	    <button label="Cancel" onClick="addCustomerWin.detach()" />
	    </row>
	   </rows>
	</grid>

对这个对话框的必填约束通过使用 "no empty" 指定为约束属性。ZK 还支持定义自定义约束。

当 Save 按钮被单击时,我将一个 Java 方法 submit() 附加到这个事件。这个 submit() 方法接收用户提供的姓名和日期值,并在一个新创建的 Customer 对象中设置这些值。然后,这个对象被传递到服务以添加到数据库。清单 12 显示了这段代码。

清单 12. Save 按钮的 Java 代码
void submit() throws Exception {
     Customer cust = new Customer();
     cust.setName(customerName.getValue());
     java.util.Date utilDate = date.getValue();
     java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
     cust.setDate(sqlDate);
     com.test.services.CustomerService custSvc = new com.test.services.CustomerService();
     custSvc.addCustomer(cust);
     Executions.getCurrent().sendRedirect("index.zul");
     addCustomerWin.detach();
}
图 6. Register customer
显示客户数据输入弹出窗口的屏幕截图,弹出窗口中带有一条数据验证消息:Customer Name must have a value.

图 7 显示了一个用于编辑客户姓名或日期的屏幕,以及一个 soft delete 选项。

图 7. Edit/Delete 屏幕
带有一个数据输入弹出窗口的应用程序屏幕截图,其中包含一些数据和一个复选框。

编辑机制与设置 Register customer 代码的方式非常相似。您将名称、日期和删除标记的新值传递到更新服务以更新数据库中的记录。如果您想提供其他帮助,您可以使用清单 13 中的代码来创建一个弹出元素。

清单 13. 弹出元素的代码
	<row>
	  <label value="Delete?"/>
	    <hbox>
	      <checkbox id="deleted" name="deleted" checked="${cust.deleted}"/>
	      <label value="whats this?" style="font:9;cursor:help;valign:center"
	       popup="help"/>
	    </hbox>
	    <popup id="help" width="400px">
	    <html>Checking this box will enable soft delete of the record.</html>
	    </popup>
	</row>

ZK 的开发工具

ZK 的最大优势在于它的工具。一个典型的例子就是 ZK-Studio(一个 Eclipse 插件),它用作一个集成开发环境。它包含的特性包括 ZUL Editor、ZUL Visual Editor、ZK Style Designer 和 DB Form Builder。图 8 显示了 ZUL Visual Editor,它用于创建这个样例项目。

图 8. ZUL Visual Editor
ZUL Visual Editor 的屏幕截图,显示了一个典型的文本编辑器

结束语

本文介绍了 ZK 的特性,这是一个用 Java 代码编写的开源 Ajax 框架,展示了一个在 Apache Tomcat 上运行并连接到一个 MySQL 数据库的简单的真实示例。ZK 框架拥有丰富的组件、一种标记语言、强大的开发工具和详细的文档,而且它是一个以事件驱动的开源 Ajax 框架。因此,ZK 正逐渐成为开发低成本的富 Internet 应用程序的流行选择。


下载

描述名字大小
样例应用程序zkManageCustomers.zip67KB

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, Open source
ArticleID=479570
ArticleTitle=使用 ZK 框架的富 Internet 应用程序
publish-date=04062010