Richlets

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)。

实现org.zkoss.zk.ui.Richlet接口

所有的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,你可以实现initdestroy方法以在加载时初始化和销毁richlet。就像servlet,richlet被加载一次,且为关联URL的所有请求服务(serves all requests for the URL it is associated with)。

每个URL一个Richlet

就像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
   }
}

配置web.xml zk.xml

在实现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)。