richlet 为一个小型的Java程序,可以创建所有必须的组件以响应用户的请求。
当用户请求一个URL内容时,ZK加载器(loader)会检查指定的URL资源是一个ZUML页面,还是一个richlet。若为ZUML页面, ZK加载器会基于ZUML页面的内容自动创建组件,就像在前面章节描述的那样。
若资源为一个richlet, ZK加载器会将处理交给richlet。创建什么组件与如何创建组件都由richlet 处理。换言之,编程创建所有需要的组件以响应用户请求是开发人员的工作。
选择ZUML页面还是richlet取决于你的偏好。对于大多数开发人员,ZUML页面更具有可读性和简洁性。
实现一个richlet是很直接的。首先,实现org.zkoss.zk.ui.Richlet
接口,然后声明richlet 的注释及一个URL(association of the richlet with an URL)。
所有的richlet都必须实现org.zkoss.zk.ui.Richlet
接口。为将实现所有方法的影响降至最低,可以继承org.zkoss.zk.ui.GenericRichlet
类代替。然后,当请求指定的URL时,service
方法会被调用,然后你可创建用户界面。
package org.zkoss.zkdemo;import org.zkoss.zk.ui.Page;import org.zkoss.zk.ui.GenericRichlet; import org.zkoss.zk.ui.event.*; import org.zkoss.zul.*; public class TestRichlet extends GenericRichlet {//Richlet// public void service(Page page) { page.setTitle("Richlet Test"); final Window w = new Window("Richlet Test", "normal", false); new Label("Hello World!").setParent(w); final Label l = new Label(); l.setParent(w); final Button b = new Button("Change"); b.addEventListener(Events.ON_CLICK, new EventListener() { int count; public void onEvent(Event evt) { l.setValue("" + ++count); } }); b.setParent(w); w.setPage(page); } }
就像servlet,你可以实现init
和destroy
方法以在加载时初始化和销毁richlet。就像servlet,richlet被加载一次,且为关联URL的所有请求服务(serves all requests for the URL it is associated with)。
就像servlet,一个richlet被创建且为相同的URL所共享。换言之,richlet(至少为service
方法)必须为线程安全的。另外,组件是不共享的。每个桌面都一套独立的组件。因此,将组件作为一个richlet 的数据成员来存储通常并不是一个好主意。
有许多方式来来解决这个问题。一个典型的方法是使用另一个类来处理每个桌面的组件,如下所述。
class MyApp { //one per desktop Window _main; MyApp(Page page) { _main = new Window(); _main.setPage(page); } } class MyRichlet extends GenericRichlet { public void service(Page page) { new MyApp(page); //create and forget } }
在实现richlet 之后,你可以在zk.xml
中使用下列语句定义richlet。
<richlet> <richlet-name>Test</richlet-name> <richlet-class>org.zkoss.zkdemo.TestRichlet</richlet-class> </richlet>
一旦声明了一个richlet,你可以使用richlet-mapping
将其映射到任意数量的URL,如下所示。
<richlet-mapping> <richlet-name>Test</richlet-name> <url-pattern>/test</url-pattern> </richlet-mapping> <richlet-mapping> <richlet-name>Test</richlet-name> <url-pattern>/some/more/*</url-pattern> </richlet-mapping>
默认情况下,richlet是不可用的。为启用richlet,你必须在web.xml
中添加下列声明。一旦启用了richlet,你可以添加任意多的richlet而无需再修改web.xml
。
<servlet-mapping> <servlet-name>zkLoader</servlet-name> <url-pattern>/zk/*</url-pattern> </servlet-mapping>
然后,你可以访问http://localhost/zk/test 来请求richlet。
在url-pattern
元素内指定的URL必须以/
开始。若URL以/*
开始,那么它会匹配所有相同前缀的请求。为获取真实的请求,你可以检查由当前页面的getRequestPath
方法返回的值。
public void service(Page page) { if ("/some/more/hi".equals(page.getRequestPath()) { ... } }
[提示]: 通过为url-pattern
指定/*
,你可以将所有不匹配的URL映射到被映射的 richlet (you can map all unmatched URL to the mapped richlet)。