第1章

绪论

1.1 JSF简介

JSF(Java Server Faces)是JCP标准化组织通过的Web应用开发标准框架,两个开源实现一是Oracle公司Mojarra(意译为“银鲈”)的项目,网址是http://javaserverfaces.java.net;二是Apache软件基金会的Myfaces项目,网址是http://myfaces.apache.org。JSF社区网址是http://www.javaserverfaces.org

1.JSF的主要特点

(1)JSF是基于事件驱动的MVC框架(见4.3节),具有可配的视图导航功能(见4.2节)。

(2)JSF基于组件开发,与其他框架的标签不同的是其页面组件(见2.1节)和框架实现是合而为一的整体。JSF简化了用户图形界面(GUI 读['ɡu:i:])的开发过程。

(3)JSF实现了异步请求(Ajax)功能,它同时基于组件和框架(见4.4节)。

(4)JSF扩展了Servlet的service,形成了其特有的请求处理生命周期(见4.1节),并明确提供了校验数据有效性和转换数据类型的接口。

(5)JSF覆盖了JSP的功能并实现了 Facelet,而且提供了视图定义语言(VDL),实现了页面框架模板功能(见2.2节)。

(6)JSF提供了依赖注入技术的标准实现,命名为“Managed Beans”(MBean),也称为“Backing Bean”或者“Page Bean”;同时JSF提供了统一的表达式,使页面和Java有机地成为一体(见2.3节)。

(7)JSF开创了Faces的概念,提供了Faces的可扩展性,形成了其生态环境。在Faces的世界中,涌现出一大批优秀的Faces扩展实现,丰富并增强了基于JSF的开发,如RichFaces。

(8)JSF提供了组件的扩展能力,开发人员也可以根据业务需要自定义组件(见4.1节)。

2.JSF的许可证

JSF的两个开源实现中Mojarra使用的许可证是和Glassfish(意译为“玻璃鱼”)一样的CDDL+GPL License,Myfaces使用的许可证是Apache License。从JSF的两个实现的许可协议可以看出开发人员和商业应用在不修改其源代码的情况下具有免费使用JSF的权利,并且没有为开源做贡献的义务并承担法律责任,基于JSF开发的商用源代码具有自主的知识产权。

3.JSF的历史

(1)JSF 1.0

JSF 1.0是JSF规范的初始版本,是JCP的第127号规范请求(JSR127)。它发布于2004年3月11日,并不包含任何的Java EE/J2EE发行版本。

(2)JSF 1.1

JSF 1.1是JSF 1.0的修正版,发布于2004年5月27日。

(3)JSF 1.2

JSF 1.2是JSF规范的第1个重要的版本,发布于2006年5月22日。作为JCP的第252号规范请求(JSR252),JSF首次进入Java EE规范成为Java EE5的成员。

(4)JSF 2.0

JSF 2.0是JSF规范的第2个重要的版本,发布于2009年6月28日,作为JCP的第314号规范请求(JSR314)成为Java EE6的成员。JSF 2.0相较之前的版本具有颠覆性的改变,如对异步请求的支持、Facelet和模板功能、自定义组件,以及验证功能集成了JSR303规范等。

(5)JSF 2.1

JSF 2.1是JSF 2.0的修正版,发布于2010年10月22日,本书写作时为当前版本。

(6)JSF 2.2

JSF 2.2是JCP的第344号规范请求(JSR344),目前尚未正式发布,从其早期草案中不难发现该版本是一个之前版本的修正和增强版。

4.JSF的依赖项目

与JSF相关的项目版本如表1-1所示。

表1-1 与JSF相关的项目版本

1.2 RichFaces简介

RichFaces是RedHat公司的JBoss社区开发的一套基于JSF的UI组件库,支持异步请求功能。RichFaces作为JSF的扩展,对JSF起到了推动作用。如从JSF 2.0开始提供的异步组件<f:ajax>的思路和特点非常接近RichFaces 3中的异步支持组件<a4j:support>,RichFaces 4开始将这一组件用<a4j:ajax>替换并相对于<f:ajax>增加了补充功能。

1.RichFaces的主要特点

(1)全面支持JSF的最新版本,项目更新及时。

(2)可以无缝地和其他Faces库一起工作,相比其他Faces产品文档更完善,社区更活跃。

(3)提供了丰富的UI组件(rich)和异步处理组件(a4j),使基于JSF的开发更加快捷和方便。通过使用rich标签和a4j标签的组件,开发人员可以实现更复杂和更强大的业务功能(详见3.1节)。

(4)支持服务器推送功能(详见3.1节)和HTML5(本书不包含这个知识点)。

(5)支持高级的Ajax请求队列(详见3.2节)。

(6)支持动态资源(详见6.1节)。

(7)提供了皮肤功能,开发人员可以为产品定制开发个性化的主题(详见6.2节)。

(8)提供了组件开发套件(CDK),开发人员可以定制开发自己的组件(详见6.3节)。

(9)支持GAE(Google App Engine)和移动开发(本书不包含这部分知识点)。

(10)支持最新版本的Java EE服务器(如Jboss Application Server 7及Oracle GlassFish 3)和Servlet容器(如Apache Tomcat 7及Jetty 8)。

项目的网址为http://www.jboss.org/richfaces

社区网址为https://community.jboss.org/en/richfaces

2.RichFaces的许可证

RichFaces采用的许可证是LGPL 2.1,LGPL许可证协议不具有感染性,开发人员和商业应用对基于RichFaces开发的源代码具有自主知识产权。

3.RichFaces的历史

(1)Ecadel阶段

Ajax4jsf之父Alexander Smirnov在2005年结合Ajax和JSF两项先进的Web开发技术形成Ajax4jsf,并带进Ecadel公司。该公司在2006年3月,将Ajax4jsf作为RichFaces的一部分发布。同年晚些时候,二者拆分,EcadelRichFaces作为商用JSF外部组件发布;EcadelAjax4jsf作为开源软件发布。

(2)RichFaces 3.x

2007年3月,两个产品的名称分别易帜为“JBoss Ajax4jdf”和“JBoss RichFaces”。

RichFaces 3.1.0 GA于2007年9月发布,将Ajax4jsf和RichFaces作为一个开源产品发布。

2008年3月,RichFaces 3.2.0 GA发布。2009年1月,RichFaces 3.3.0.GA发布。

(3)RichFaces 3.3.3.Final

2009年6月,JSF 2.0发布。2010年4月,RichFaces 3.3.3.Final发布。该版本是非常重要的版本,它实现了JSF 2的部分功能,可以在JSF 1.2和JSF 2.0下使用。

在JSF 2.0发布之前,RichFaces的异步功能来自Ajax4jsf。这部分功能后来被JSF 2.0融入,形成了标准的实现。

(4)RichFaces 4.0.0.Final

2011年3月,RichFaces 4.0.0.Final发布,该版本是RichFaces首个全面支持JSF 2.0的版本。相比RichFaces 3.3.3.Final,它全面支持JSF 2,但组件库缺失了很多RichFaces 3.3.3Final版本中的组件。最关键的是,从RichFaces 3.3.3.Final升级到RichFaces 4.0.0.Final不是替换jar包就能解决的。这次升级对很多标签和属性的名称做了改动,这样的重大改动还包括配置参数、使用ECSS代替XCSS及皮肤样式表名称等。

(5)RichFaces 4.x

2011年12月,RichFaces 4.1.0.Final发布。这个版本修正了RichFaces 4.0的很多问题,开始恢复缺失的组件。

2012年2月,RichFaces 4.2.0.Final发布。这个版本继续修复前面版本的问题,优化性能并完善产品,提供了更好的易用性。

2012年4月,RichFaces 4.2.1.Final发布。这个小版本继续修复问题,没有新功能。

4.RichFaces组件包

RichFaces 4.x包含的4个jar包如表1-2所示。

表1-2 RichFaces 4.x包含的4个jar包

5.RichFaces的依赖项目和版本

RichFaces 4.x依赖的项目和版本如表1-3所示。

表1-3 RichFaces依赖的项目和版本

6.RichFaces与浏览器

JSF和RichFaces都是跨平台和跨浏览器的,表1-4所示为RichFaces 4.x版本支持的主流浏览器版本。

表1-4 RichFaecs 4.x版本支持的主流浏览器版本

对于Opera等其他浏览器和上述浏览器的其他版本,RichFaces没有给出明确的支持说明,只是提到部分支持。

1.3 第1个例子

以下我们通过一个简单小书房工程(一个简单的个人图书管理系统)的例子快速进入JSF和RichFaces工程,来感性地认识JSF和RichFaces工程的创建和使用。本书的全部示例项目均使用Maven来管理,有关Maven的基本使用方法请参考附录C。本书的全部示例项目均发布在github上,有关示例项目请参见附录A;有关本书的开发和调试环境的说明请参考附录B。

小书房工程的实现步骤如表1-5所示。

表1-5 小书房工程的实现步骤

1.3.1 创建JSF工程

Maven提供了很多原型(archetype)供开发人员使用,目的是使开发人员不用从头开始初始化一个项目,我们从其提供的Web应用的原型开始第1个示例:

mvn archetype:create -DgroupId=com.mycompany.projectname -DartifactId=projectname -DarchetypeArtifactId=maven-archetype-webapp

在基于Web应用原型创建项目的命令中,参数create指示maven要创建一个项目。如果在创建项目过程中需要交互方式(Interactive mode),则使用generate替代create。groupId是要创建的项目名字空间;artifactId是项目名称;archetypeArtifactId是原型项目名称,指示maven要以哪个原型为基础开发项目。

我们定制第1个示例小图书馆的名称为“tinylibrary”,它是本书基础知识项目jsfrf的一个附属项目,因此使用相同的名字空间前缀并加上tinylibrary作为本示例的基础名字空间。示例如下:

mvn archetype:create -DgroupId=creative.fire.jsfrf.tinylibrary -DartifactId=tinylibrary -DarchetypeArtifactId=maven-archetype-webapp

执行上述命令,我们得到了一个基本的Web应用项目。其源代码位于src/main/java目录(当前没有这类文件),测试代码位于src/main/test目录(当前没有这类文件),页面及配置文件位于src/main/webapp目录,资源文件位于src/main/resources目录,生成文件位于target目录,如图1-1所示。

图1-1 Maven的Web应用原型目录结构

接下来,我们为该Web项目配置JSF功能。

1.JSF依赖包

首先配置tinylibrary的JSF依赖包,根据项目运行的服务器类型,JSF的配置稍有不同。对于Java EE应用服务器,如JBoss AS和GlassFish等已经包含JSF的支持,因此只在开发阶段需要JSF包的依赖;对于Servlet容器,如Tomcat和Jetty等需要将JSF包随项目一起打包部署。编辑项目根目录下的Maven配置文件pom.xml如下:

Java EE服务器配置
<dependency>
    <groupId>javax.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>${jsf.version}</version>
    <scope>provided</scope>
</dependency>
Servlet容器配置
<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-api</artifactId>
    <version>${sun.faces.version}</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.sun.faces</groupId>
    <artifactId>jsf-impl</artifactId>
    <version>${sun.faces.version}</version>
    <scope>runtime</scope>
</dependency>

Servlet容器可选替代方案如下:

使用Mojarra实现
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>${jsf.version}</version>
</dependency>
使用Myfaces实现
<dependency>
    <groupId>org.apache.myfaces.core</groupId>
    <artifactId>myfaces-api</artifactId>
    <version>${myfaces.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.myfaces.core</groupId>
    <artifactId>myfaces-impl</artifactId>
    <version>${myfaces.version}</version>
</dependency>

在以上配置中,版本参数的配置均使用变量,它们定义在pom文件的properties部分。在一个相对独立的部分中配置版本信息可以解决的问题是当依赖的包有版本升级时,修改对应的版本信息变量即可完成对依赖库的升级工作,这是Maven强大且易用的地方;否则开发人员需要下载相关版本的包文件,并替换当前的依赖包。这里我们以JSF的2.1版本作为示例:

<properties>
    <jsf.version>2.1.7</jsf.version>
    <myfaces.version>2.1.6</myfaces.version>
    <sun.faces.version>2.1.2</sun.faces.version>
</properties>

配置JSF依赖包后打包测试项目,在项目根目录下执行mvn package,Maven开始检查本地资源库。当项目依赖的资源在本地不存在时,Maven会向pom文件中<repositories>配置的远程仓库发出请求,查找并下载该资源。当项目的依赖资源均在本地时,即开始编译项目并生成压缩包。本示例使用的是war包。

2.web.xml

如果编译打包没有问题,则为项目增加JSF配置。编辑/src/main/webapp/WEB-INF/ web.xml,添加如下配置:

<context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
</context-param>
<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.配置IDE支持

最后,在IDE中使用Maven项目并运行Web应用。使用Maven生成和配置的tinylibrary项目是IDE中立的,即项目中不包含IDE所需的项目文件。以Eclipse为例,导入一个项目时需要使用项目文件(.project和.classpath),类似的文件需要IDE自身来生成。

在常用的IDE中,NetBeans和IntelliJ IDEA可以直接导入Maven项目。NetBeans对Maven和JSF的支持非常好,JSF项目Mojarra及其自带的GlassFish服务器一脉相承。在开发阶段,NetBeans对JSF组件的Content Assist(自动提示/语法补全)功能也非常好。IntelliJ IDEA是非常强大和智能的IDE,其收费版本对Web项目的支持也非常出色,但其社区版本开发Web应用还有不便之处。

本书开发和测试IDE使用Eclipse,它没有NetBeans大而全。其思想是只保留核心的功能,一切扩展留给插件完成。因此使用Eclipse开发Maven项目,JSF和RichFaces就要多出配置插件的工作(Eclipse的Maven插件m2e和JBoss Tools插件详见附录B)。事情都有两面性,安装额外插件的工作换来的是小而精巧的开发和调试环境。

本书示例使用的Eclipse插件如图1-2所示。

图1-2 本书示例使用的Eclipse插件

安装m2e插件就可以使用Eclipse管理Maven项目,但是如果此时直接导入tinylibrary,则该项目不会被Eclipse识别为一个Web项目,因为没有为其配置WTP(Web Tools Platform)的支持。WTP是Eclipse调试Web项目的插件,是Eclipse的JavaEE版本自带的。可以通过如下两种方法完成对WTP的支持。

(1)使用命令mvn eclipse:eclipse -Dwtpversion=2.0生成Eclipse的项目文件,包括.settings目录、.classpath文件和.project文件。

(2)在pom.xml文件中增加maven-eclipse-plugin插件的配置,然后执行mvn eclipse:eclipse,这是一种为项目增加WTP固定配置的方法。

maven-eclipse-plugin插件配置如图1-3所示。

图1-3 maven-eclipse-plugin插件配置

至此,我们可以将项目导入到Eclipse中,如图1-4所示。

图1-4 导入项目到Eclipse

Eclipse的项目管理列表中出现了Maven项目的管理选项,我们选择已存在的项目并在下一个窗口中定位tinylibrary项目的路径,如图1-5所示。

4.调试运行

最后演示如何在Eclipse中使用服务器调试tinylibrary,本书使用的服务器是Tomcat,在Eclipse中可以使用相同方式运行其他应用服务器。Eclipse不包含任何服务器,每种服务器都是安装后配置的。如图1-6所示,右击项目名称,选择Run As选项。接下来选择服务器,如果选择Run On Server后出现错误,说明WTP的配置不对。为此需要删除.settings/org. eclipse.wst.common.component,然后按照上述配置WTP的方法重新配置即可。

图1-5 定位tinylibrary路径

图1-6 使用Tomcat调试

如果列表中不存在希望运行的服务器,则选择Manually define a new server单选按钮后手动配置,如图1-7所示。

在tinylibrary项目的源代码中,本节所述的源代码标识为step1,读者可以解压stuff目录下的step1.rar研究其中的内容。

1.3.2 创建RichFaces工程

本节我们使用同样方式创建一个RichFaces工程,该工程和1.3.1节中的工程没有关联,对应的源代码在stuff目录下的step2.rar中。

mvn archetype:create -DgroupId=creative.fire.jsfrf.tinylibrary -DartifactId=tinylibrary -DarchetypeGroupId=org.richfaces.archetypes -Darchetype ArtifactId =richfaces-archetype-simpleapp -DarchetypeVersion=4.2.0.Final

图1-7 Manually define a new server单选按钮

执行以下操作步骤。

(1)定义pom文件中org.richfaces.bom.version变量的值,本书使用4.2.0.Final。

(2)输入命令mvn eclipse:eclipse -Dwtpversion=2.0。

(3)在Eclipse中导入RichFaces版的tinylibrary。

(4)输入命令mvn install或者选择Eclipse的m2e插件中对应按钮(参见附录C)。

(5)使用WTP插件测试该项目在tomcat下的运行情况。

如图1-8所示,RichFaces使用了以“xhtml”为扩展名的页面文件,这种类型的文件是JSF的Facelet风格的页面文件。Facelet是JSF的2.0版本推广使用的,用于代替JSP的技术。本书的示例均基于Facelet技术。

1.3.3 tinylibrary 1.0

本节开发tinylibrary项目,可以选择1.3.2一节创建的工程来实践,因为其中已经包含了JSF和RichFaces的全部依赖包。以下选用1.3.1一节中的工程作为本工程的基础,以使读者了解如何在JSF工程中添加RichFaces功能。对应代码在stuff目录下的step3.rar中。

图1-8 Maven的RiceFaces原型目录结构

1.RichFaces依赖包

编辑pom.xml文件,在<properties>中添加RichFaces的版本变量,在<dependencies>中添加RichFaces的依赖包:

<rf.version>4.2.0.Final</rf.version>
<dependency>
    <groupId>org.richfaces.ui</groupId>
    <artifactId>richfaces-components-ui</artifactId><version>${rf.version}</version>
</dependency>
<dependency>
    <groupId>org.richfaces.core</groupId>
    <artifactId>richfaces-core-impl</artifactId>
    <version>${rf.version}</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
2.faces-config.xml

faces-config.xml文件是JSF默认的基本配置文件,从1.3.2节生成的项目中复制即可,其路径是/tinylibrary/src/main/webapp/WEB-INF/faces-config.xml。

3.源代码列表

源代码列表如表1-6所示。

表1-6 tinylibrary源代码列表

4.源代码

以图书列表为例,其功能对应的Java类是一个ViewScoped级别的Mbean。在xhml页面中引用的名称为“listBean”,它包含一个图书实体类的集合。BookListBean类的代码片段如下:

@ManagedBean(name = "listBean")
@ViewScoped
public class BookListBean {
    public List<Book> getBooks() {return books;}}

图书页面可以划分为3个部分,即xml格式的标签声明、页面头部和页面体部,其功能是使用RichFaces的rich:dataGrid组件迭代图书集合。每个图书表格中的左上显示图书描述,是图书详情的链接;右上显示图书作者。下面是图书封面图片的代码:

<?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:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:rich="http://richfaces.org/rich"
    xmlns:a4j="http://richfaces.org/a4j">
<h:head>
    <h:outputStylesheet>
    .vtop {
    vertical-align: top;
    width: 150px;
    }
    </h:outputStylesheet>
    <title>tinylibrary1.0</title>
</h:head>
<h:body>
    <h:form>
        <h:outputText value="欢迎#{reception.name}" />
        <rich:dataGrid value="#{listBean.books}" var="book" columns="3" columnClasses="vtop vtop vtop">
            <rich:panel header="#{book.alias}">
                <h:panelGrid columns="2">
                    <h:commandLink action="#{bookBean.edit}" value="#{book.desc}">
                        <f:param name="bookId" value="#{book.id}" />
                        </h:commandLink>
                    <h:outputText value="#{book.author}" />
                </h:panelGrid>
                    <h:outputLink value="#{book.url}">
                    <h:graphicImage url="/resources/img/#{book. image}" height="90" width="70" />
                </h:outputLink>
            </rich:panel>
        </rich:dataGrid>
    </h:form>
</h:body>
</html>
5.运行

在tinylibrary根目录下使用mvn install编译、打包并安装到仓库,然后在Eclipse中启动Tomcat或者复制war包到Tomcat的webapp目录下并启动Tomcat,显示的图书列表页面如图1-9所示。

图1-9 图书列表页面

图书详情页面如图1-10所示。

图1-10 图书详情页面

1.4 本章小结

本章首先介绍了JSF和RichFaces的基本概况,包括JSF和RichFaces的主要特点,以及历史背景等。然后通过3个工程示例讲解了如何创建一个JSF和RichFaces工程,以及如何使已有JSF项目支持RichFaces。最后通过tinylibrary的第1个版本的概述,说明了JSF和RichFaces的开发模式,以及如何编写代码。读者可以通过附录A提供的资源地址下载示例,笔者相信阅读他人的代码是一种好的学习途径。