探索 ZK 中的 CDI 编程模式

实现简单的应用程序

Java™ Specification Request (JSR) 299: Contexts and Dependency Injection (CDI) for the Java EE platform 定义了一组功能强大的服务。服务包括类型安全的 Java EE 依赖注入和可允许组件交互的事件通知模型,它简化了 Java EE Web 层对 Java EE 服务的访问。从本质上讲,任何在 Java EE Web 层中使用的第三方框架都可通过便携式扩展机制利用 CDI 服务。本文将扩展 “使用 ZK 框架的富 Internet 应用程序” 一文中的示例应用程序并解释如何使用 ZK 框架及集成其功能强大的 CDI 服务来修改真实案例。

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

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


developerWorks 投稿作者

2011 年 2 月 28 日

简介

ZK,一个用 Java 代码编写的开源 Asynchronous JavaScript and XML (Ajax) 框架,能让您开发具有 Web 2.0 功能的富 Internet 应用程序,而无需编写一行 JavaScript 代码。

ZK 就像没有 JavaScript 的 Ajax。它是功能强大的框架,由一个基于 Ajax 的事件驱动的引擎、一套内容丰富的 XHTML 和 XUL 组件以及用来创建功能丰富的用户界面的 ZUML 标记语言组成。

本文中,将会学习与 ZK 框架有关的 Contexts and Dependency Injection for the Java EE platform (CDI) 编程模式。本文基于 “使用 ZK 框架的富 Internet 应用程序:一个开源 Ajax 框架” 一文中的应用程序示例,描述了 ZK 的强大功能。使用 ZK 和 CDI,您将扩展这个详细的实际客户管理应用程序。

可以 下载 本文中的应用程序源代码。

JSR-299 和 CDI

Java Specification Request (JSR) 299,或者说 Java CDI,是依赖注入和上下文生命周期管理的 Java 标准。通过该标准,可以定义一组服务来让应用程序开发更轻松更简洁。这些服务提供:

  • 通过事件通知机制的对象互动
  • 类型安全的依赖注入
  • 绑定到上下文的有状态对象的生命周期方法
  • 一个 “decorator” 拦截器来绑定拦截器到对象
  • 一个服务提供者接口 (SPI) 来开发便携式扩展

由于 CDI 强调松耦合和强类型,因此有些方面 bean 不需要知道,如实现、线程模型或生命周期。这些方面根据不同部署而不同,因此根本不会影响客户端。松耦合让代码易于维护和扩展。

ZK 和 CDI

ZK 框架内的 ZK CDI,提供了与 CDI 的无缝集成,在 ZK 框架内部暴露 CDI 服务。它让企业开发人员可用一个 ZK 提供的压缩的功能强大的 Ajax 前端与 CDI 驱动的应用程序集成。联合使用 CDI 和 ZK 可以毫不费力地缩小 Java 的 EE Web 层和 Java EE 之间的差距。

ZK CDI 扩展允许在 ZK 编程模型内无缝使用 CDI 特性。除了内置 CDI 特性,ZK CDI 扩展提供以下一些特性让开发更轻松。

自定义变量解析器/EL 解析
通过 EL 名解析 <zscript />、EL 表达式(${...})、ZK 注释的数据绑定表达式(@{…}) 中的 CDI 托管 bean。
ZK 自定义范围
除了内置 CDI 范围(Session、Request、Application 和 Conversation),该扩展还提供五个 ZK 范围:Desktop、Page、 Execution、IdSpace 和 Component。
ZK 组件作为托管 bean
能将 ZK 组件注入托管 bean,例如 ZK composer。
使用 ZK 自定义注释 CDI 提供的事件通知模型的 UI 事件处理函数
能用 ZK 自定义注释来注释任何方法并将它转换为事件处理方法。

ZK CDI 扩展基于 Weld,它是用来定义 CDI 的参考实现(查看 参考资料 中更多信息)。


使用 ZK 和 CDI

下面的这个简单例子演示了如何从 ZUL 文件访问托管 CDI bean。( .zul 文件扩展用于 ZK 用户界面文件。) 在 CDI 上下文中,托管 bean,或简单 bean,是 Java EE 组件,它可以根据上下文,或通过 EL 表达式注入其他组件中。

清单 1 中简单的 HelloWorld 例子显示了如何通过 ZUL 文件中的 EL 表达式来访问托管 bean。首先定义一个 HelloWorld 类,只有一个 String 字段,名为 text ,还有 getter 方法,名为 getText()。根据 CDI 规范,有一个 no-arg 默认构造函数使得这个类能成为托管 bean。要通过统一 EL 表达式引用 HelloWorld 托管 bean,需要用 @javax.inject.Named 限定符来注释。可以通过提供 @Named 限定符值成员将任何 EL 名称赋给托管 bean。 如果未指定,EL 名称默认为将第一个字符转换为小写的 bean 类的未限定的类名。本例中,HelloWorld 默认为 helloWorld EL。

清单 1. 访问托管 bean
@Named
@SessionScoped
public class HelloWorld implements Serializable {

	private String text = "HelloWorld";
	
	public String getText() {
		return text;
	}
}

清单 2 中的 ZUL 代码使用其默认名 helloWorld 访问 HelloWorld bean。

清单 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 ?> 。可以使用这个指定解析器类,供 ZK EL 计算程序(${...})、ZK 注释的数据绑定程序(@{...}) 以及 <zscript> 解释程序来解析未知变量。

ZK CDI 扩展的一个特性是自定义 EL 解析器,称为 DelegatingVariableResolver,它可通过统一 EL 表达式中的 EL 名解析 HelloWorld 托管 bean。

在清单 2 的 index.zul 文件中,定义一个简单的窗口组件,并用 ${helloWorld.text} EL 表达式显示一个 HelloWorld 类的文本字段。在 ZUL 提交阶段,当 ZUL 解析器遇到 EL 表达式,它将使用 <?variable-resolver ?> 中指定的 DelegatingVariableResolver 来解析 helloWorld bean 实例。由于 HelloWorld 现在是容器托管 bean,容器用来提供 HelloWorld bean 实例。将会使用容器返回的 bean 实例来计算 ${helloWorld.text}getText() 方法的结果将返回 “Hello World” 字符串,如图 1 所示。

图 1. HelloWorld
屏幕显示 My CDI-注入 bean 显示 HelloWorld。

使用 ZK 和 CDI 实现实际应用程序

这一章通过实现实际应用程序来探索更多 CDI 特性。将根据 “使用 ZK 框架的富 Internet 应用程序” 一文中的 Manage Customer 应用程序来构造。Manage Customer 应用程序允许用户执行各种操作,例如添加新用户、编辑用户数据以及在数据库中将客户项软删除。图 2 显示的是 Manage Customers 应用程序主要用户界面屏幕。

图 2. Manage Customers Dashboard
屏幕显示用户名、编号、日期以及是否被删除。

已列出应用程序中注册的用户。列表是一个网格,其中列为 ID、用户名称、活动日期及删除标志。网格中的数据可以通过单击列名旁的按钮排序(升序或降序)。ID (int)、名称(String)和活动日期(Date)列已启用排序。该应用程序中也可使用分页,如屏幕底部所示。允许一次显示 5 条记录。用户可以翻到下一页或直接翻到指定页。

图 3 显示了 Manage Customer 应用程序的顶部栏。

图 3. 顶部菜单栏
下拉菜单显示可以在哪注册新用户。

菜单栏是使用 ZK 的 menubar 小部件实现的。它包含注册新用户和退出应用程序的选项。


安装开发环境

在深入实现细节之前,让我们回顾一下创建管理用户的示例应用程序的细节。这里是用 Eclipse IDE 来创建应用程序,但实际任何一个 IDE 都可以。

基本的构想是创建一个动态 Web 应用程序项目,将它指向应用程序服务器运行时,本例中是 Apache Tomcat 运行时。安装好项目和运行时后,复制文件夹结构,如图 4。

图 4. 目录结构
ZK 管理用户目录结构

Manage Customer 应用程序的目录结构遵循图 4 中相同的模式。

应用程序的核心文件包含在 WebContent 文件夹中,子目录如下:

  • META-INF 包含连接到 MySQL 数据库的数据库凭证信息。
  • WEB-INF 包含含有运行应用程序所需的 ZK JAR 文件的库文件夹。它还包含三个配置文件。
    • beans.xml,它指明应用程序中的 bean 类,这些类可用于注入。
    • web.xml,它描述数据源、ZK servlet,以及 Weld 配置。
    • zk.xml,它可能包含 ZK 相关配置。

所有其他相关 ZUL 和 HTML 文件包含在 WebContent 文件夹中。这些文件作为应用程序视图部分,提供 Web 应用程序的动态和静态内容。

示例文件 zkManageCustomer.zip(查看 下载)包含应用程序的压缩版本。它还包含 Eclipse 所需的元数据文件,因此可以无缝地直接导入 IDE 中。

Eclipse 中的 Java 2 Platform, Enterprise Edition (J2EE) 视图有个服务器选项卡,右键单击会显示创建新服务器的选项卡。服务器可用来从 Eclipse IDE 中管理应用程序服务器。

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

配置 MySQL

示例应用程序将会配置为与 Tomcat 和 MySQL 一起协同工作。尽管如此,将其运用到其他启用 CDI 的应用程序服务器应该也没有问题。由于本例使用 JDBC,应该在任何支持的 SQL 数据库下都能正常运行,如 DB2 Express-C,只需要对连接代码做最小程度的修改。

要将 Tomcat 连接到 MySQL 数据库,需要定义资源引用。该元素会指定资源管理器连接工厂引用,如清单 3 所示。本例中,是由 jdbc/mysql 指定的数据库连接,是 javax.sql.DataSource 类型。

清单 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。

清单 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"/>

用户数据有一个表,它可以通过运行清单 5 的脚本来创建。

清单 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 扩展支持

要利用 ZK CDI 扩展,就要复制 zkcdi.jar 文件(位于 ZK CDI 扩展的二进制发行版中)到 Web 应用程序项目下的 WEB-INF/lib 文件夹。zkcdi.jar 应当用作一个 Web 应用程序库。

启用 Weld 对 Tomcat 的支持

要启用 Weld 对 Tomcat 的支持:

  1. 指定网站根目录下 WEB-INF/web.xml 文件中的 Weld servlet listener(用于启动 Weld 并控制与请求的交互):
    <listener>
       <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>
    <listener>
       <listener-class>org.jboss.weld.el.WeldELContextListener</listener-class>
    </listener>
  2. 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>
  3. 添加空的 beans.xml 文件到 WEB-INF 文件夹下,以启用 CDI 的依赖注入。

其他应用程序或环境下安装 Weld 的类似指令请查看 参考资料


扩展应用程序

Manage Customers 应用程序提供以下功能:

  • 用户操作的仪表板,包括所有用户的视图
  • 添加新用户
  • 编辑已有用户
  • 删除用户(软删除)

图 2 显示的是仪表板,其中有已注册用户列表。用户可以根据 ID 或名称对数据排序。index.zul 文件有各种属性来定义应用程序外观,如 borderlayoutmenubarmenumenupopup

清单 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 文件仅包含应用程序视图部分,而控制器代码单独写进 composer 类 ManageCustomer 中。这样可以利用 ZK CDI 特性。

在 ZK MVC 方法中,控制器可以通过使用 apply 属性应用到特定组件中。本例使用这种方法将 ManageCustomer 应用到仪表板主窗口组件中。还演示了将变量解析器指令用于 DelegatingVariableResolver 和 EL 表达式,以使用容器提供的 ManageCustomer 托管 bean。

在仪表板页中有两个主要组件。

  • 顶部的菜单有两个子菜单项:Register New Customer 和 Exit。

    Menubar 是 ZK menubar 组件,有两个子 ZK menuitem 组件,ID 是 addexit

  • 表格现在列出在数据库中的用户。本例中的表格是 ZK listbox 组件,其 ID 是 customerList。表格列标题由 customerList 列表框的子部件 listheader 来定义。

到目前为止,已经探索了定义仪表板 UI 的组件,那么数据呢?customerList 列表框什么时候展开? 看看清单 7 中的 ManageCustomer 控制器类。

清单 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());
	}
...

首先,用 @Named 限定符标记 ManageCustomer bean 类,使它能通过统一 EL 表达式访问。这在 index.zul 文件中的窗口组件有展示,其 apply 属性值为 "${manageCustomer}"

下一步是使用 CDI 类型安全依赖注入特性将 CustomerService bean 注入 ManageCustomer 控制器。CustomerService bean 是个工具类,它实现了访问数据库以增加、更新、删除和查询用户信息的方法。可以通过指定 ManageCustomer 类中的 CustomerService字段并用 @javax.inject.Inject 注释来完成。通过 CDI 规范,无论 ManageCustomer bean 实例何时由容器实例化,CustomerService bean 实例将会自动注入。

此时,需要访问 customerList 列表框来展开所有用户数据。本例使用 GenericComposer 工具类,它是由 ZK CDI 扩展提供。用 org.zkoss.cdi.util.GenericComposer 扩展 ManageCustomer 类,从而启用自动注入窗口组件的子组件到 ManageCustomer 控制器类。ZK 组件自动注入要求使用 index.zul 文件中与 @org.zkoss.cdi.inject.ComponentId 相同组件 ID 的修饰符。还有,对于 ZK CDI 扩展规范,ComponentId 限定符成员值必须匹配字段名。例如,将 customerList 列表框注入到 ManageCustomer,要使用:

@Inject @ComponentId("customerList") private transient Listbox customerList;

现在可以在列表框中放入一些数据。数据展开需要在客户端提交页面前完成。GenericComposer 是 Composer 类型,它需要 doAfterCompose() 方法。它是回调方法,在所有组件组装后调用。它允许客户列表数据展开在提交之前,但在所有 ZUL 组件组装之后发生。在已覆盖的 doAfterCompose() 方法里首先要调用 GenericComposerdoAfterCompose()

注册新用户

当用户单击 “Register New Customer”( Manage Customer 仪表板菜单栏的 Add 菜单)后会发生什么?单击之后,应该会显示 Enter Customer Data 窗口,并将输入数据在数据库中保存为一条新的 Customer 记录。要完成这些,首先要在 ManageCustomer 控制器中有 “add” 菜单项的 onClick 事件的事件处理方法。可以使用 ZK CDI 扩展定义的 @org.zkoss.cdi.event.Events 限定符和 CDI 定义的事件通知模型轻松完成。定义一个如清单 8 所示的简单的 registerNewCustomer() 方法。

清单 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);
}

本例使用 @javax.enterprise.event.Observes 为类型为 MouseEvent 的方法参数注释,这是一个 ZK 事件类型。它使 registerNewCustomer() 方法成为 Observer 方法(观察 MouseEvent 类型的方法)。无论 CDI 何时发布 MouseEvent ,都会通知该方法。会有 MouseEvent 类型的多种事件,如何区分?这时 @Events 限定符就发挥作用。@Events 限定符有成员值提示哪种事件需要通知。@Events 成员值可以事件名后跟组件 ID 的形式指定。例如,对 Add menuitem onClonclick 事件,@Events 限定符值可以是 "add.OnClick" ,如 清单 7 所示。

当单击 “Register New Customer” 菜单项后,事件顺序如何?首先,MouseEvent 类型的 ZK 事件发送到服务器。ZK 框架将会接收该事件。然后 ZK CDI 扩展将会发布/发出有适当 @Events 限定符的 CDI 事件,还有 MouseEvent 类型的成员值。CDI 将会通知所有观察 MouseEvent 类型,并有着确定的 @Events 限定符和成员值的方法。

清单 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. Register New Customer
屏幕显示输入客户日期的字段和日期,以及保存和取消按钮。

与 index.zul 页面类似,这个示例使用 <?variable-resolver ?> 指令和 DelegatingVariableResolverAddCustomer 托管的 bean 作为一个控制器应用到 addCustomerWin 窗口组件。Register Customer 对话框实现为一个网格,其中必须包含 Customer name 和 Date 值。AddCustomer 实现类似于 ManageCustomer 类。CustomerService bean 使用 @Inject 限定符注入;addCustomerWin 的子组件也使用 @Inject@ComponentId 限定符自动注入,如清单 10 所示。

清单 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() 方法一样,本例实现了 saveNewCustomerDetails() observer 方法,如清单 11 所述。

清单 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 的一个新实例在该方法每次被发现时都将自动注入到该参数中。

Edit/(soft) Delete 客户

用户可以通过选择 Manage Customer 仪表板中的任意客户行访问 Edit Customer 屏幕,如图 6 所示。

图 6. Edit Customer
屏幕显示用户名、日期和选中的删除框。

registerNewCustomer() 方法一样,本例定义了 observer 方法 editCustomer(),它 @Observes ZK SelectEvent,该事件在列表框中的 listitem 被选中时发送。

清单 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 文件。


结束语

加入 My developerWorks 上的 Web 开发小组

My developerWorks Web 开发小组 中与其他开发人员讨论 Web 开发话题,分享资源。

还不是 My developerWorks 成员?现在加入!

本文探索了 ZK,它是一个用 Java 代码、JSR-299 Contexts 和 Dependency Injection 编写的开源 Ajax 框架。ZK CDI 扩展具有特性,可让您使用 ZK 编程模型中的 CDI 。本文使用了一个运行在 Apache Tomcat 上并连接到 MySQL 数据库的真实的简单例子。

ZK 框架具有一组功能丰富的组件、标记语言、功能强大的开发工具以及大量文档。它是开源的事件驱动的 Ajax 框架。CDI 由 JSR-299 of Java EE platform 6 定义,提供一组强大的特性,如强类型依赖注入、时间通知模型,以及开发便携扩展的 SPI。 ZK CDI 集成了 ZK 编程模型和 CDI,允许 Java EE 6 企业应用程序的无缝开发。


下载

描述名字大小
本文样例代码zkManageCustomers.zip71 KB

参考资料

学习

获得产品和技术

讨论

条评论

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
ArticleID=629697
ArticleTitle=探索 ZK 中的 CDI 编程模式
publish-date=02282011