RichFaces 简介

http://www.ibm.com/developerworks/cn/java/j-richfaces/

最近,一家客户委托我们实现一个项目,我认为这个项目非常棒。他们没有专职的开发人员,要求我们设计和开发他们的第一个生产应用程序,该应用程序包括一个服务器和一个浏览器客户机。该应用程序将在他们的局域网和 Internet 上运行,并且使用一个虚拟专用网(VPN)。对于我来说,经历一个项目从设想到实现再到培训的整个过程并不鲜见,但还是很少有机会自主地确定项目的几乎每个方面。这个项目的一个主要方面是,每个人都习惯于桌面应用程序。如果在浏览器用户界面中包括类似的特性,他们也许不会特别注意到,但是如果没有这些特性,他们肯定会有很多抱怨。例如,项目初始阶段的主页面将为动态查询收集选择标准。有些输入区需要客户端操作,至少有一个输入区需要 Ajax 功能。最后,我选择了 RichFaces 组件套,该组件套构建在 Ajax4jsf(参见 参考资料)之上,并与之合并。

选择组件

本文的目的不是倡导某一个产品或组件套件,而是让您有足够的信息开始使用 RichFaces,并且有足够的背景知识,以便在开发自己的 RIA 或富 Web 客户机时能作出比较。我鼓励您尝试各种可能性,参考本文和其他文章,得出自己的结论。

一个很好的起点是 JSF AJAX Component Library Feature Matrix(参见 参考资料)。请务必仔细阅读该页面底部的每条注解,因为这个模型很少更新,而这个专区经常发生变化。我自己的简短列表很快就减少到只有 RichFaces、Woodstock 和 IceFaces(见 参考资料)。

除了 Rich Internet Application(RIA)功能和 Ajax 外,我还需要:

  • 开源的 LGPL 或 Apache 形式的许可,如果可能的话
  • 使用 JSF 和 Facelets
  • 和 JSF Reference Implementation(RI)组件一起使用
  • 灵活但是一致的感观或主题
  • 足够大的组件集,以覆盖大多数应用程序需求
  • 易于使用,不会出现阻塞
  • 动态创建能力,有可用的 API
  • 活跃的开发和社区

到目前为止,RichFaces 已经能满足这些标准,这些组件在创建高效的、功能完备的应用程序方面已经显现出价值。您的标准依旧可能变化。

本文探索一些有用的 RichFaces 特性,并提供一个用于演示的应用程序代码(参见 下载小节)。不过,在讨论 RichFaces 之前,需要介绍一些必要的基础设施元素。

从头开始

虽然在初始阶段客户的应用程序可以只使用一个 servlet 容器,但是将来会需要更多的支持,并且很可能要包括用于其他子公司的项目。为了尽量靠近标准,我选择开源的 Glassfish Application Server V2,它支持 JEE 5,并且使用 Java SE 6 作为底层运行时。至于 Web 框架,我选择 JSF 和 Facelets。一个额外的好处是,Java EE 5 中包括了 JSF 支持;对于 Glassfish V2、WebSphere Application Server Community Edition V2 等等,受支持的 JSF 版本是 1.2。JSF 2.0 的目标是获得 Facelets(或类似的)支持,最主要的 Facelets 开发人员都属于 JSF 专家组。

本文假设读者有这些方面的基础知识。示例代码下载小节包括了您需要的用于 Tomcat 6.0.16 和 Glassfish 的所有文件,并且这些文件都在这两者上经过测试。在线版本(参见 参考资料)在 Glassfish V2 上运行。如果您需要关于这些技术的更多背景知识,请参阅 参考资料,并访问适当的链接。

并不是更小的 JSF 版本

Facelets 并不像其名称那样表示一个小号的 JSF;相反,在其核心,Facelets 提供了 JSP 的替代品 JSF ViewHandler,而这正是我在本文要使用的内容。当我第一次研究 JSF 时,我曾阅读过 Hans Bergsten 的文章 “Improving JSF by Dumping JSP”(参见 参考资料)。之后不久,我就发现了 Facelets,此后就一味沉浸于此。Facelets 支持所有的 JSF UI 组件,并且构建了它自己的组件树,以反映 JSF 应用程序的视图。虽然 JSP 和 JSF 技术已得到改进,如今可以更好地协作,但是 Facelets 完全消除了 Bergsten 的文章中提到的问题。

我喜欢让事情尽量简单而直接。在示例项目中您将看到,实际上所有代码(而不是标记)都是由用于 getter、setter 和方法绑定的 Expression Language(EL)表达式组成的。虽然更复杂的项目可能需要更复杂的表达式,但是通常情况下 Facelets 便于将 Java 代码与 Web 页面标记分隔开。

在这里您将注意到,这种开发与使用 JSP 的 “常规” JSF 开发的主要不同之处在于:

  • 您将需要 jsf-facelets.jar。
  • web.xml 和 faces-config.xml 中的一些标注。
  • Web 页面是 XHTML 文档。
  • 使用 XML 名称空间,而不是 JSP 标记库。

随着格式化的进行,不仅仅是初始部分(参见 清单 1),Web 页面中的所有部分看上去都应该很熟悉。我将这个特性视为 Facelets 的一个朴素特性。对于本文的项目,以及将 Facelets 主要用于视图的其他项目,您实际上只需要知道这一点。Facelets 还包括很多其他有用的特性,例如为方便 Web 页面设计者而提供的简单的模板和元素。如果读者有兴趣了解更多关于 Facelets 的信息,建议从 “Inside Facelets Part 1: An Introduction”(参见 参考资料)入手。

清单 1. Facelets XHTML 文档的初始部分
 <?xml version='1.0' encoding='UTF-8' ?> 
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html" >

演示组件

RichFaces 看上去非常强大;平均每个组件有超过 20 个特定的属性,并且还有非常多的通用属性。但是,大多数属性都有合理的默认值,在一般使用过程中,这些组件的设置并不困难。有些花哨的组件可以处理各种不同的效果,例如 Google Maps 和 Virtual Earth。您可能想使用它们来让用户感到兴奋,但是在这里我还是着重关注那些在很多应用程序中都有用的组件。这足以让我兴奋。

本文主要演示的组件有:

  • Calendar—一个弹出式组件,允许选择日期。 图 1显示了一个示例。<和 >滚动月份;<<和 >>滚动年份。单击底部的 Today可以选择今天的日期。单击 Clean可以清除日期选择。左边的数字列显示一年中的星期。
    图 1. RichFaces Calendar 组件
    RichFaces Calendar 组件图
  • List Shuttle—一个选择和排序组件,可以在可用区与选定区之间移动项目,还可以在选定区中上下移动项目。 图 2显示了一个示例:
    图 2. RichFaces List Shuttle 组件
    RichFaces List Shuttle 组件图
  • Suggestion Box—一个输入组件,提供可点击的建议,以完成输入。图 3显示了一个示例:
    图 3. RichFaces Suggestion Box 组件
    RichFaces Suggestion Box 组件图
  • Tab Panel—一个输出组件,创建带标记的页面。 图 4显示了一个示例:
    图 4. RichFaces Tab Panel 组件
    RichFaces Tab Panel 组件图

我们还将使用一个 Panel Bar 进行说明。图 5显示了一个示例:

图 5. RichFaces Panel Bar 组件
RichFaces Panel Bar 组件图

我们将使用 Simple Toggle Panels 显示结果。图 6 显示了一个示例:

图 6. RichFaces Simple Toggle Panel 组件
RichFaces Simple Toggle Panel 组件图

如前所述,RichFaces 构建在 Ajax4jsf 之上。以此为基础,任何组件都可以以几种不同的方式支持 Ajax。本文中的示例应用程序为 Suggestion Box 和 Simple Toggle Panel 组件使用 Ajax 功能。

华丽的界面

dWRFDemo1示例应用程序很小。它的真正目的是演示所选择组件的设置和使用。因此,它只是收集和显示输入数据。至于如何在生产应用程序中使用数据和组件,我留给您自己去想象。除了必要的 JAR、图像、用作资源包的属性文件以及级联样式表(Cascading Style Sheets,CSS)文件外,该应用程序包括两个 XHTML 页面和两个 Java 类。这种简洁性允许代码具有 IDE 不可知性。实际上,我故意使用一个 Java 编辑器、文件的 Wordpad、javac和 jar命令进行创建。

图 7显示了输入页面的 URL,这里假设 Tomcat 或 Glassfish 采用默认设置,这个 URL 为 http://localhost:8080/dWRichFacesDemo1。 这个输入页面允许使用 Calendar组件选择一个日期。Order ByList Shuttle 组件让您可以移动和重新排列可用项目。 CitySuggestion Box 让您可以输入一个城市名称。City启用了 Ajax 支持; 如果按下空格键,将显示所有可用的城市。如果键入首字母为 A 或 J 的城市名称,那么将列出相应的城市。随着输入的字符数逐渐增多,列表中可用的城市范围逐渐缩小。可以单击左侧的 Panel Bar 条目,查看基本的组件说明。

图 7. dWRFDemo1输入页面
dWRFDemo1 input page image

输入完毕后,单击 Submit按钮。 这个应用程序很小,不会执行任何编辑。由于 Calendar 组件禁止手动输入,所以不可能输入无效的日期。 通过 Submit 按钮可以显示结果页面,如 图 8所示:

图 8. dWRFDemo1结果页面
dWRFDemo1 结果页面图

在结果页面上,单击 Result选项卡,然后单击适当的 Simple Toggle Panel 条目,以查看输入值。单击 Edit按钮返回到输入页面。

设置

对于一个应用程序,最重要的东西是 JSF、Facelets 和 RichFaces 的实现者 —即实现这些功能的 JAR。这些 JAR 被包括在可下载的 WAR 的 lib 目录中(参见 下载小节),下面的列表标出了它们的版本。该列表假设您的 Web 容器支持当前的 EL 和 servlet API 版本。如果在运行该演示应用程序时遇到问题,请检查 JSF、Facelets 和 RichFaces 的需求(参见 参考资料)。您还应该查看 下载说明

  • JSF 1.2 (包括在 Glassfish V2 中)
    • jsf-api.jar
    • jsf-impl.jar
  • Facelets 1.1.14
    • jsf-facelets.jar
  • RichFaces
    • richfaces-api-3.1.4.GA.jar
    • richfaces-impl-3.1.4.GA.jar
    • richfaces-ui-3.1.4.GA.jar
  • 虽然没有明确要求,但是 RichFaces 假定下面这些 JAR 也是可用的:
    • commons-beanutils-1.7.0.jar
    • commons-collections-3.2.jar
    • commons-digester-1.8.jar
    • commons-logging-1.0.4.jar
    • jhighlight-1.0.jar

下面 清单 2中显示了用于启用 JSF 的 web.xml 条目:

清单 2. web.xml 中需要的最少的 JSF 条目
 <servlet> 
   <servlet-name>Faces Servlet</servlet-name> 
   <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> 
   <load-on-startup>1</load-on-startup> 
 </servlet> 
 <servlet-mapping> 
   <servlet-name>Faces Servlet</servlet-name> 
   <url-pattern>*.jsf</url-pattern> 
 </servlet-mapping>

清单 3显示了 Facelets 需要的另一个条目。该条目覆盖了默认后缀 .jsp。通常,对于 faces-config.xml 中的视图处理程序,Facelets 需要另一个覆盖条目,但是正如您将从下面看到的那样,RichFaces 将覆盖包括在 web.xml 中。

清单 3. 用于 Facelets 后缀的 web.xml 条目
 <context-param> 
 <param-name>javax.faces.DEFAULT_SUFFIX</param-name> 
 <param-value>.xhtml</param-value> 
 </context-param>

清单 4显示了 web.xml 中实现 RichFaces 所需的元素:

清单 4. 用于实现 RichFaces 的 web.xml 条目
 <context-param> 
  <param-name>org.richfaces.SKIN</param-name> 
  <param-value>classic</param-value> 
 </context-param> 
 <context-param> 
  <param-name>org.ajax4jsf.VIEW_HANDLERS</param-name> 
  <param-value>com.sun.facelets.FaceletViewHandler</param-value> 
 </context-param> 
 <filter> 
  <display-name>RichFaces Filter</display-name> 
  <filter-name>richfaces</filter-name> 
  <filter-class>org.ajax4jsf.Filter</filter-class> 
 </filter> 
 <filter-mapping> 
  <filter-name>richfaces</filter-name> 
  <servlet-name>Faces Servlet</servlet-name> 
  <dispatcher>REQUEST</dispatcher> 
  <dispatcher>FORWARD</dispatcher> 
  <dispatcher>INCLUDE</dispatcher> 
 </filter-mapping>

我将按照操作顺序解释清单 4 中的元素,而不是按照它们在 web.xml 中的出现顺序。

  • <filter>和 <filter-mapping>

    RichFaces 使用一个过滤器来处理 Ajax 请求中接收到的代码。这些元素定义过滤器类(org.ajax4jsf.Filter),并将它映射到 清单 2中定义的 JSF Faces Servlet。

  • <context-param>和 <param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>

    RichFaces 需要知道应用程序中将使用 Facelet。这些元素执行这个任务,并有效地替换 faces-config.xml 中常规的 Facelets 条目。注意,Facelets 视图处理程序类是 com.sun.facelets.FaceletViewHandler

  • <context-param>和 <param-name>org.richfaces.SKIN</param-name>

    RichFaces 有一些内置的配色方案或皮肤。这些元素定义要在应用程序中使用的皮肤。 classic皮肤是中等程度的蓝色。

关于清单 2、3 和 4 中的条目,好的方面是,在所有应用程序中它们几乎都是一样的,实际上这就是样板代码。此外,还有一段代码也是在每个应用程序中可以看到的:清单 5是 清单 1的修改版,用于将 RichFaces 名称空间包括在应用程序的 XHTML 页面中:

清单 5. Facelets/RichFaces XHTML 文档的初始部分
 <?xml version='1.0' encoding='UTF-8' ?> 
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:a4j="http://richfaces.org/a4j"
     xmlns:rich="http://richfaces.org/rich">

准备好了

现在,我们可以开始使用 RichFaces 组件。从 Panel Bar 和 Panel Bar Items(参见 图 5)开始。您可能不经常使用这些组件,但是它们都很容易使用,并且为 RichFaces 语法提供了第一个良好的用例。

这里的思想是,Panel Bar 是 Panel Bar Items 的一个容器。每个 Panel Bar Item 有一个标签,并且可以包含任何其他组件。Panel Bar Items 位于另一个 Panel Bar Items 之上;当单击条目栏时,将显示实际的内容。每次只显示一个条目的内容。在这个应用程序中,如 清单 6所示,我们将使用文本。注意,所有组件都有一个 rich:前缀,以引用 清单 5中包括的名称空间项。

清单 6. RichFaces Panel Bar 组件
 <rich:panelBar height="192" width="256"> 
  <rich:panelBarItem label="#{dWRFD1.calComp} #{dWRFD1.info}"> 
     <h:outputText value="#{dWRFD1.calCompText}" style="font: menu;" /> 
  </rich:panelBarItem> 
  <rich:panelBarItem label="#{dWRFD1.lsComp} #{dWRFD1.info}"> 
     <h:outputText value="#{dWRFD1.lsCompText}" style="font: menu;" /> 
  </rich:panelBarItem> 
  <rich:panelBarItem label="#{dWRFD1.sbComp} #{dWRFD1.info}"> 
     <h:outputText value="#{dWRFD1.sbCompText}" style="font: menu;" /> 
  </rich:panelBarItem> 
 </rich:panelBar>

<f:loadBundle>在哪里?

在 JSF 1.2 中,可以在 faces-config.xml 中定义基于属性的资源包,所以不再需要在每个页面上使用<f:loadBundle>。该定义类似于用于 managed bean 的条目,但是特定于资源包。例如:

<resource-bundle> 
<base-name>dWRFDemo1</base-name> 
<var>dWRFD1</var> 
</resource-bundle> 

基本的 <rich:panelBarItem />元素只需要一个标签,它是通过一个 EL 表达式从资源包中提取到这里的。

演示 Panel Bar Items 的实际内容只是一个 <h:outputText />元素,它同样也具有来自资源包的文本。为提高可读性,我使用一个 font样式元素,同时这也表明了 RichFaces 支持 CSS 的灵活性。

注意,对于生成的 JavaScript,不需要程序员的任何参与。只需简单几步,就可以创建一个好看的、多面板的、可单击的组件。这正是 RichFaces 的一个强大之处。即使是像这样简单的组件,也可以有 active/inactive 样式、事件等。

确定日期

Calendar 组件(如 图 1所示)您应该比较熟悉;日期选择也许是 JavaScript 对 Web 页面最早的增强之一。RichFaces Calendar 有超过 80 个可用属性,但是,正如 清单 7所示,您通常只用到其中很少一部分:

清单 7. RichFaces Calendar 组件
 <label for="CalendarID" >#{dWRFD1.calendar}:</label> 
 <rich:calendar name="Calendar" id="CalendarID"
               value="#{dWRFD1Handler.selectedDate}"
               timeZone="#{dWRFD1Handler.timeZone}"
               datePattern="#{dWRFD1.datePattern}" > 
 </rich:calendar>

datePattern属性需要 java.text.SimpleDateFormat定义的一个标准的日期模式。这个示例同样使用资源包来提供值,它将 datePattern定义为 yyyy-MM-ddvalue 和 timeZone属性是使用来自一个 managed bean 的方法装载的,这个 bean 的定义如 清单 8所示:

清单 8. 用于 dWRFD1Handler 的 managed bean 定义
  <managed-bean> 
    <managed-bean-name>dWRFD1Handler</managed-bean-name> 
    <managed-bean-class>com.dW.dWRFD1Handler</managed-bean-class> 
    <managed-bean-scope>session</managed-bean-scope> 
  </managed-bean>

com.dW.dWRFD1Handler类很简单,主要由一个初始化程序、getter 和 setter 组成,对它应该没必要再作讨论。getSelectedDate()setSelectedDate()方法需要一个 java.util.Date。 getTimeZone()方法只是返回 java.util.TimeZone.getDefault();在生产中,这样做是否合适取决于应用程序的需求。

如果您还想允许用户输入日期值,那么可以将 enableManualInput属性设为 true。如果您只想显示 Calendar,那么将 popup属性设置为false。 显然,还有很多其他属性可以设置,但是对于基本的 Calendar 功能只需做这么多。

多种方法

List Shuttle 组件(参见 图 2)是从一个初始组中选择项目并对选定的项目排序的理想组件。 清单 9表明,它比您想象的更容易使用:

清单 9. RichFaces List Shuttle 组件
 <label for="OrderByID">#{dWRFD1.orderBy}:</label> 
 <rich:listShuttle sourceValue="#{dWRFD1Handler.orderBySource}"
  name="OrderBy" id="OrderByID"
  targetValue="#{dWRFD1Handler.orderByTarget}" var="items"
  <h:column> 
  <h:outputText value="#{items}"></h:outputText> 
  </h:column> 
 </rich:listShuttle>

示例代码中实际的 XHTML 标记包括更多属性,以覆盖某些默认的标签,但是通常情况下只需 sourceValuetargetValue、 var和 column属性。

sourceValue和 targetValue值是包含任何类型的对象的 java.util.List类。和演示代码一样,大多数情况下您将使用包含 String的列表。清单 10并不是初始化 sourceValue,而是显示与示例 List Shuttle 相关的所有 Java 代码。

清单 10. 相关的 dWRFD1HandlerList Shuttle 代码
  private List<String> lOrderBySource = new ArrayList<String>(), 
                       lOrderByTarget = new ArrayList<String>(); 
  ... 
  public List getOrderBySource() 
  { 
    return lOrderBySource; 
  } 

  public List getOrderByTarget() 
  { 
    return lOrderByTarget; 
  } 
  ... 
  public void setOrderBySource( List<String> orderBySource ) 
  { 
    lOrderBySource = orderBySource; 
  } 

  public void setOrderByTarget( List<String> orderByTarget ) 
  { 
    lOrderByTarget = orderByTarget; 
  }

var属性声明一个变量,该变量将用于对列表进行迭代,JSF 组件经常使用这种模式。如果列表中的对象支持多个字段,那么实际上这里可以使用多个列。在这种情况下, value="#{items}"被改为 value="#{items.getterMethodName}",这应该没什么好奇怪的。在这里,我们使用的是一个 String类列表,因此只有一个列。用户做出选择之后,在提交时处理程序会收到排好序的目标列表,其中包含用户的选择。

Suggestion Box 组件

如果您经常使用论坛和邮件列表,那么您迟早会看到人们如何将数千乃至数百万条目下载到一个下拉列表中。Suggestion Box 组件(参见 图 3)提供一种方式来显示有效的选择,使用户不必面对那样极端的情况。 实际上,这一点正是我开始研究 RichFaces 和类似套件的主要原因,因为应用程序中有些输入项,例如城市,有太多的可选项,这种情况下下拉列表已经不适用了。Suggestion Box 的功能类似于我们熟悉的很多桌面应用程序中提供的自动完成组件。显然,为了让这种功能有机会在 Web 应用程序中有效地工作,必须借助 Ajax 提交。

清单 11显示了该功能所需的三种不同的组件:label 和 input text(注意,这些是标准的 JSF RI 组件)、 <a4j:region>以及<rich:suggestionbox>。 <h:inputText>使用 getCity()和 setCity() 方法和 managed bean 来为它提供值。字段的输入可以通过键盘,也可以通过从 Suggestion Box 中进行选择。

清单 11. RichFaces Suggestion Box 组件
 <label for="CityID">#{dWRFD1.city}:</label> 
 <h:inputText name="City" id="CityID" size="10"
    value="#{dWRFD1Handler.city}" /> 
 <a4j:region renderRegionOnly="true"> 
  <rich:suggestionbox id="citySuggestionBoxId" for="CityID"
    suggestionAction="#{dWRFD1City.suggest}" var="result"
    eventsQueue="foo" ignoreDupResponses="true"
    selectedClass="selCtl" > 
    <h:column> 
      <h:outputText value="#{result}" style="font: menu;" /> 
    </h:column> 
  </rich:suggestionbox> 
 </a4j:region>

<a4j:region>表示在 Ajax 提交时发送的一个区域。您需要清楚,通常情况下,如果没有包括任何区域,RichFaces 会假定一个默认区域,这个区域的范围是从 <f:view>到 </f:view>。这实际上就是整个页面。当我第一次使用 <rich:suggestionbox>时,本来一切都正常,但是在单步调试时却发现,所有其他字段也会随之一起提交,也会被验证、转换并经过 JSF 的整个生命周期。简单地说,这对于需要对每次按键都作出响应的组件来说不是件好事。RichFaces Developer Guide(参见 参考资料)中有一段内容讨论了通常情况下适用的另一种形式的 Ajax 提交,应该给出了正确的方法:

注意,"ajaxSingle"="true" 可以减少将来的传输,但是不会阻止服务器端对其他输入组件的解码。有些 JSF 组件,例如 <h:selectOneMenu>,会重新识别请求映射值中作为 null 值丢失的数据,并尝试通过验证过程并得到失败的结果。因此,必要时可以使用 <a4j:region> 来限制将在服务器端处理的组件树的一部分。

至于 renderRegionOnly属性,RichFaces Developer Guide 这样描述:

禁止在活动区域以外的 AJAX 响应内容中呈现的标志。如果该属性被设为 “true”,那么区域以外的组件不会包括在 AJAX 响应中。如果该属性被设为 “false”,那么将会在整个树中搜索要加入到响应中的组件。该属性的默认值为 “false”。

在本例中,我们希望惟一回到服务器的元素是 suggestionAction方法请求和它的 Object参数(通过键盘当前输入的 String)。返回时,应该只更新和呈现 Suggestion Box 内容。

Suggestion Box 本身需要的最基本的属性是 suggestionActionvar和至少一个用于显示结果的列。 suggestionAction方法是另一个 managed bean 中的 suggest(),这个 bean 基于 demo 代码中的第二个 Java 类 com.dW.City。该方法的签名为:public List suggest(Object anObject)

在 demo 代码中,在初始化时首先创建一个以 A 和 J 开头的城市的列表。如果用户在 City 文本域中按下空格键,则返回完整的列表。如果按下 A 键,则返回一个包含以 A 开头的城市的子列表。对于以 J 开头的城市也是如此。每键入一个字符,结果就会随之缩小。在您自己的代码中,只要与输入相符,你可以做任何事情。在实际应用程序中,结果来自一个有限的数据库集合,这也许是最常见的。如果您熟悉这种数据,那么也许可以修改一下这个方法,看能不能优化结果。例如,我曾经碰到一个示例,有些按键是可以忽略的,所以该方法可以直接返回,而不必访问数据库了。

var属性定义一个迭代变量,以便在输出列内容时使用。它与 List Shuttle 组件的 var属性的用法是一样的。

eventsQueue属性不是必需的,但是我建议您也同样对待。您只需添加该属性,并提供一个名称。它会执行两个重要的服务:

  • 将方法调用(事件)放入队列,以保证顺序。在队列中,在前一个方法请求返回之前,不会发送下一个方法请求。
  • 如果队列中有多个同种类型的事件,那么只发送最新的那个。例如,Suggestion Box 对于每次按键都发送一个请求。如果当之前的请求返回时队列中有多个按键请求,那么只将最新的按键请求发送到服务器。记住,虽然对于每次按键都会发送请求,但是发送的参数是 input text 组件的整个内容。

ignoreDupResponses属性的作用应该是不言而喻的。

selectedClass是应用于该组件的一个 CSS 类。RichFaces 使用皮肤(skin)的概念。这是通过组件上的选择栏实现的。我自己的应用程序有几个 RI 下拉列表在选择栏中使用了系统颜色。Suggestion Box 使用 classic皮肤颜色,这让外观看起来有些不一致。SelCtl类告诉 Suggestion Box 使用系统的高亮显示颜色。

存放标签

Tab Panel 组件(参见 图 4)很容易使用。通常的 RichFaces 属性在该组件中都可以使用,但是您将使用的主要属性是 switchType。该属性的默认值为 server,但是您可能最常用的值反而是 clientajax属性也可以使用。如 清单 12所示,这里使用一个典型的 RichFaces “三明治式”<rich:tabPanel> 元素和堆叠的 “三明治式” <rich:tab>元素来创建一组选项卡式页面:

清单 12. RichFaces Tab Panel 组件
 <rich:tabPanel switchType="client" > 
  <rich:tab label="#{dWRFD1.info}"> 
    #{dWRFD1.resultText} 
  </rich:tab> 
  <rich:tab label="#{dWRFD1.result}"> 
  </rich:tab> 
 </rich:tabPanel>

label属性用于显示选项卡的名称。在 demo 代码中,和通常一样,label的值是从资源包中提取的。和 Panel Bar Items 类似,选项卡可以包含任何类型的组件。对于 demo,我使用资源包文本作为 Info 选项卡的内容,使用 Simple Toggle Panels 作为 Result 选项卡的内容。

完成

我猜您可能在想:“这些都很简单”。这就对了。一旦理解了 RichFaces 的基础,大多数组件使用起来都很简单。因此,对于 Simple Toggle Panel (参见 图 6和 清单 13)我只讲一点点,其他的就留给您作为练习吧。

清单 13. RichFaces Simple Toggle Panel 组件
 <h:panelGrid columns="1" width="50%"> 
  <rich:simpleTogglePanel switchType="ajax"
     label="#{dWRFD1.calComp} #{dWRFD1.value}" opened="false" > 
    #{dWRFD1Handler.selectedDate} 
  </rich:simpleTogglePanel> 
  <rich:simpleTogglePanel switchType="ajax"
     label="#{dWRFD1.lsComp} #{dWRFD1.value}" opened="false" > 
    #{dWRFD1Handler.orderByTarget} 
  </rich:simpleTogglePanel> 
  <rich:simpleTogglePanel switchType="ajax"
     label="#{dWRFD1.sbComp} #{dWRFD1.value}" opened="false" > 
    #{dWRFD1Handler.city} 
  </rich:simpleTogglePanel> 
  <rich:simpleTogglePanel switchType="ajax"
     label="#{dWRFD1.face}" opened="false" > 
    <img src="images/myphoto.jpg"
       height="80" width="64"/> 
  </rich:simpleTogglePanel> 
 </h:panelGrid>

Simple Toggle Panel 由一个条状栏和一个内容显示组成,后者可以是任何组件。通过单击条状栏,可以显示或隐藏内容,这非常像只有一个项目的 Panel Bar。注意, switchType属性再次出现。 opened属性确定是否在第一次显示时显示内容。对于这个 demo,我将多个 Simple Toggle Panels 放在一个 JSF RI <h:panelGrid>中,后者被放在一个 Tab 中,而这个 Tab 则被放在一个 Tab Panel 中。

结束语

RichFaces 为构建 RIA 和支持 Ajax 的 Web 应用程序提供了大量的 JSF 组件。本文只演示了其中一小部分,但是您应该已经大致了解 RichFaces 背后的原理,并且也看到了在很多应用程序中可能有用的组件。该组件套件中的所有组件都有在线的 demo、文档和其他资源,这些资源可以从 RichFaces 主页的 “Most Important Links” 区获得(参见 参考资料)。

如果您选择使用 RichFaces,那么我鼓励您深入探索文档中讨论的 a4j:组件和处理,以理解如何将这些概念应用到其他 RichFaces 组件上。有时候研究可能会延长开发时间,让客户觉得备受挫折,然而,另一方面,投入的研究时间在开发过程和运行时性能方面会得到很多回报。

包含更多组件的 RichFaces 3.2 有望在 2008 年三月底发布。无论您使用哪个 RIA 组件集,这种激烈的竞争应该有助于提高它们的稳定性和生产率。

下载

描述 名字 大小
本文的 WAR 演示文件1 j-RichFacesDemo1.zip 5.5MB

注意:

  1. 由于源文件和 WAR 文件只差两个文件 —Java 文件 —我将 Java 源文件放在 WAR 文件中。因此,这里只有一个下载文件。要获得关于使用 WAR 文件的说明,请参阅下载中包含的 readme.txt 文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值