JavaServer Faces(以下简称JSF)技术是基于java技术Web应用的服务器端用户界面组件框架。
JSF技术的主要组件有以下:
- 代表用户界面(以下简称UI)组件并且能管理其状态的API,处理事件,服务器端数据验证,数据转换,定义页面导航,支持国际化和易访问,并且对这些功能提供可扩展的能力。
- 两种JSP定制标签库,即表达JSP页面中UI组件的标签库和把组件联系组织(wiring )到服务器端对象的标签库。
- 通过添加组件标签把组件拖到页面上
- 将组件产生的事件和服务器端代码联系起来
- 将页面上的UI组件和服务器端数据绑定
- 应用可重用和可扩展的组件构造UI
- 跨requests保存或恢复UI状态
![](jsfIntro-server.gif)
As shown in Figure 9-1, the user interface you create with JavaServer Faces technology (represented by myUI
in the graphic) runs on the server and renders back to the client.
这个JSP页面myform.jsp
,就是一个JSF页面,即一个包含了JSF标签的JSP页面。它通过应用JSF技术定义的标签库表现UI组件。这个Web应用的UI组件(由图中的myUI代表)管理被JSP引用的对象。这些对象包括:
- 映射到JSP页面上的标签的UI组件对象
- 任何事件监听器,数据验证器,转换器都在组件上注册
- 包装了数据和组件的应用特有功能的JavaBeans组件
JSF技术的优点
JSF技术一个最好的优点是它在行为和表现之间提供了一个清晰的划分。用JSP技术构建的Web应用部分完成了这种划分。但是,一个JSP的应用不能映射HTTP请求到特定组件事件,也不能将服务器上的UI元素作为有状态对象来管理,但一个JSF应用能做到。JSF技术允许你构建能将行为和表现出色的分开的的Web应用,而传统上这只有客户端UI架构才能提供。
这种针对逻辑和表现的划分可以使Web应用开发团队的成员集中精力关注他/她自己的开发进程,并且提供了一个简单的变成模型来将这些不同开发成员的进程链接起来。举个例子,页面设计者不需要任何编程就可以应用JSF技术里的UI组件在web页面里连接到服务器端对象,也不需要写任何脚本。
最重要的使,JSF技术提供了一个胖的架构来管理组件的状态,处理组件数据,验证用户的输入,处理事件。
什么是JSF应用?
在绝大多数情况下,一个JSF应用和其他Java应用没什么不同。一个典型的JSF应用包括以下部分:
- 一组JSP页面(当然你也可以不用JSP,而用你自己的表现技术)
- 一组后台beans,这些beans组件定义了页面上的UI组件的属性和功能
- 一个配置应用的资源文件,这个文件定义了文件导航规则,并配置beans和其他定制对象,比如定制组件
- 一个部署描述文件(
web.xml
)
- 也许一组由应用开发者创建的定制对象,这些对象可能包括定制组件,数据验证器,转换器或监听器
- 一组用来在页面上显示定制对象的定制标签
- 一组JSP页面(当然你也可以不用JSP,而用你自己的表现技术)
一个包含了JSP页面的JSF应用也采用被JSF技术定义的JSTL 来显示页面上的UI组件和其他对象。
一个简单JSF应用
这一节描述了不同的开发角色开发一个简单JSF应用的步骤。这些角色包括:- 页面设计者,应用JSF标签库创建页面
- 应用开发者,针对以下内容编写代码,定制转换器,数据验证器,监听器和后台beans
- 组件开发者,创建定制UI组件
- 应用架构师,配置应用,包括定义导航规则,配置定制对象,创建部署描述文件
这个应用很简单,并且不包含任何定制组件。请看12章学习组件编写者的职责。
开发步骤
开发一个简单JSF应用通常需要完成下列任务:
- 映射
FacesServlet
实例
- 应用UI组件和core tags创建页面
- 在应用配置资源文件中定义页面导航
- 开发后台beans.
- 添加管理的bean声明到应用配置资源文件中
- 映射
guessNumber的应用。它请你猜一个0到10之间的数字。第二个页面告诉你是否猜对了。这个例子会检查你输入的有效性。系统日志打印了
Duke's number。
The example used in this section is the guessNumber
application, located in the <INSTALL>
/javaeetutorial5/examples/web/
directory. It asks you to guess a number between 0 and 10, inclusive. The second page tells you whether you guessed correctly. The example also checks the validity of your input. The system log prints Duke's number. Figure 9-2 shows what the first page looks like.
Figure 9-2 The greeting.jsp
Page of the guessNumber
Application
The source for the guessNumber
application is located in the <
INSTALL
>/javaeetutorial5/examples/web/guessNumber/
directory created when you unzip the tutorial bundle (see About the Examples, page xxx).
To build, package, and deploy this example, follow these steps:
To learn how to configure the example, refer to the deployment descriptor (the web.xml
file), which includes the following configurations:
To run the example, open the URL http://localhost:8080/guessNumber
in a browser.
映射FacesServlet实例
所有的JSF应用必须在部署描述中包含一个指向FacesServlet实例的映射
。
FacesServlet实例接收请求并将其转入处理周期,并初始化资源。以下部分部署描述文件完成了对
FacesServlet实例的的映射:
<servlet>
<display-name>FacesServlet</display-name>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>/guess/*</url-pattern>
</servlet-mapping>
FacesServlet的映射用一个前缀辨明一个包含JSF组件的JSP页面。正因为这个,这个应用的第一个JSP页面的URL
必须包含这个映射。为了达到这个目标,这个应用包括一个包含如下链接的HTML页面:
<a href="guess/greeting.jsp">
创建页面
创建页面是页面设计者的职责。这个任务涉及页面上的UI组件,映射这些组件到beans,并添加注册了转换器,验证器或监听器的标签到组件上。
在这一节我们会构建这个greeting.jsp页面,及这个应用的第一个页面。就像其他的JSP页面一样,你需要添加通用HTML和HEAD标签:<HTML xmlns="http://www.w3.org/1999/xhtml"xml:lang="en">
<HEAD> <title>Hello</title> </HEAD>
...
</HTML>
你还需要页面说明来指定包含内容类型:
<%@ page contentType="application/xhtml+xml" %>
声明标签库
为了在JSP页面中应用JSF组件,你需要在你的页面中访问两个标准标签库,即HTML组件标签库和core标签库声明:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http:.//java.sun.com/jsf/core" prefix="f" %>
第一个标签声明用前缀h声明了HTML组件标签库。所有这个页面中的组件标签都用这个前缀。core标签库声明为f前缀。这个页面中所有的core标签都用这个前缀。
User Interface Component Model includes a table that lists all the component tags included with JavaServer Faces technology. Adding UI Components to a Page Using the HTML Component Tags (page 316) discusses the tags in more detail.
添加视图和表单标签
所有的JSF页面都由组件树代表(represented ),称为视图(view)。view标签代表view的根,所有的JSF组件标签必须在view标签里面,view标签是在core标签里定义的。
form标签代表一个输入表单组件,允许用户输入数据并提交到服务器,通常通过点一个按钮(submit)即可提交。所有的代表可编辑的组件的UI组件标签(比如text field和菜单)必须被嵌入form标签。比如页面greeting.jsp,有些包含在表单中的标签如:
outputText
, inputText
, commandButton
和 message
。你可以为form标签指定一个ID。这个ID映射到服务器上相关的form的UI组件。
view标签和form标签添加后,我们的页面看上去就成了这样(最小化了HTML和HEAD标签):
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
</h:form>
</f:view>
添加一个Label组件
outputText
标签代表一个label。greeting.jsp页有两个
outputText标签。一个显示数字0,另一个显示数字10:
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/>
<h:outputText value="#{UserNumberBean.maximum}"/>
标签的value属性用表达式从UserNumberBean
取得mininum和maxinum属性。
添加了outputText标签和一些静态文本之后,greeting页成了现在这个样子::
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
</h:form>
</f:view>
添加一个图片
为了在页面上显示一个图片,你需要采用graphicImage
标签。其url属性指定了图片文件的路径。让我们用
graphicImage
标签来添加Duke:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
</h:form>
</f:view>
添加Text Field
inputText
标签表示文本框组件。在guessNumber
例子中,这个文本框取得整型输入值。在greeting.jsp中的这个标签有三个属性:id,label,value。
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}">
...
</h:inputText>
id属性与由标签表示的组件对象的ID一致。这里,id属性是必须的,因为message标签(用来显示验证错误信息)需要它指向userNo组件。
label属性指定了被错误信息应用的名字来指向这个组件。在这个例子里,label被设置为“User Number”。作为一个例子,如果用户输入23,错误信息就会显示成:
User Number: Validation Error: Value is greater than allowable maximum of 10.value属性把userNo组件的值和UserNumberBean.userNumber绑定了,UserNumberBean.userNumber保存了用户输入文本框的数据。
添加了inputText
标签后,页面greeting 成了如下样子:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}">
...
</h:inputText>
</h:form>
</f:view>
See Backing Beans for more information on creating beans, binding to bean properties, referencing bean methods, and configuring beans.
See Using Text Components (page 321) for more information on the inputText
tag.
给文本框注册一个验证器
通过在一个文本框组件标签里面嵌入一个validateLongRange
标签,页面设计者就给这个文本框注册了一个LongRangeValidator。这个验证器检查是否这个文本框组件里的数据在一个范围里面,这个范围是由
validateLongRange
标签的minimum
和maximum
属性定义的。
在greeting页,我们要验证用户输入到文本框的数值。我们在inputText
标签里面添加了一个validateLongRange
标签。其maximum和
minimum
属性用表达式的方式,分别从UserNumberBean
获取maximum
和maximum
的属性值,如#{UserNumberBean.minimum}
and #{UserNumberBean.maximum}
。See Backing Beans for details on value expressions.
validateLongRange
标签后,页面如下:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}">
<f:validateLongRange
minimum="#{UserNumberBean.minimum}"
maximum="#{UserNumberBean.maximum}" />
</h:inputText>
</h:form>
</f:view>
添加定制信息
当转换或验证失败时,JSF技术提供了标准错误信息来在页面上显示。在部分场景中,你可能需要重载这些标准信息。举个例子,如果一个用户在greeting.jsp的文本框
输入了一个字母,他/她就会看到下面的错误信息:
User Number: 'm' must be a number between -2147483648 and 2147483647 Example: 9346
这显然是个错误,因为这个输入框只接受0到10。
为了重载这个信息,你可以在文本框标签中添加一个converterMessage
属性。这个属性引用了你的定制错误信息:
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}"
converterMessage="#{ErrMsg.userNoConvert}"
>
...
</h:inputText>
这表明,converterMessage引用了资源ErrMsg中的
userNoConvert
键值。这个应用架构需要在资源包中定义信息并且配置资源包。See Configuring Error Messages for more information on this.
See Referencing Error Messages (page 348) for more information on referencing error messages.
添加一个按钮
commandButton
标签代表常被用于提交输入数据的按钮。这个action属性指明导航机制对下一步往哪个页面导航。 Defining Page Navigation discusses this further.
添加了commandButton
标签后,页面如下:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}">
<f:validateLongRange
minimum="#{UserNumberBean.minimum}"
maximum="#{UserNumberBean.maximum}" />
</h:inputText>
<h:commandButton id="submit"
action="success" value="Submit" />
</h:form>
</f:view>
See Using Command Components for Performing Actions and Navigation (page 327) for more information on the commandButton
tag.
显示错误信息
用户提交表单后,当数据转换或验证失败,message
标签常常被用来在页面上显示错误信息。
如果输入亚的数据没有符合
注册在文本框组件的LongRangeValidator
的实现定义的规则,
greeting.jsp中的
message
标签就会显示错误信息。
在页面上,将message
放到哪里,错误信息就会显示在哪里。message
标签的style
属性允许你指定信息文本的显示风格。它的for属性指向了哪个组件的值验证失败。在这个场景中,userNo
组件代表页面中的inputText
标签。
message
放到页面最下面:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="helloForm1">
<h2>Hi. My name is Duke. I'm thinking of a number from
<h:outputText lang="en_US"
value="#{UserNumberBean.minimum}"/> to
<h:outputText value="#{UserNumberBean.maximum}"/>.
Can you guess it?</h2>
<h:graphicImage id="waveImg" url="/wave.med.gif" />
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}"
converterMessage="#{ErrMsg.userNoConvert}">
<f:validateLongRange
minimum="#{UserNumberBean.minimum}"
maximum="#{UserNumberBean.maximum}" />
</h:inputText>
<h:commandButton id="submit"
action="success" value="Submit" />
<h:message showSummary="true" showDetail="false"
style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1"
for="userNo"/>
</h:form>
</f:view>
response.jsp
页,我们就可以定义页面导航规则了。
定义页面导航规则
通过定义页面导航,意味着当用户点了一个按钮或者一个超链接,当前页面将往哪个页面流转。在应用配置源文件中配置的这个应用的导航采用了一个强大的基于规则的系统。下面就是一条为guessNumber
定义的导航 规则:
<navigation-rule>
<from-view-id>/greeting.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/response.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/response.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/greeting.jsp</to-view-id>
</navigation-case>
</navigation-rule>
这条导航规则表述了,当greeting.jsp上的一个按钮被按下并且导航系统被给予一个"success
"的逻辑结果时,
应用就会导航到response.jsp。
在这个例子中,逻辑结果在UICommand
组件的action
属性定义:
<h:commandButton id="submit" action="success"
value="Submit" />
To learn more about how navigation works, see Navigation Model.
配置错误信息
如果标准错误信息不能切合你的需要,你可以在资源包中创建一个新的错误信息,并在你的应用配置源文件中配置好它。The guessNumber
example has one custom converter message, as described in Adding a Custom Message.
下面这条信息存储在资源包中, ApplicationMessages.properties
:
userNoConvert=The value you entered is not a number.
资源包会在应用配置文件里配置:
<application>
<resource-bundle>
<base-name>guessNumber.ApplicationMessages</base-name>
<var>ErrMsg</var>
</resource-bundle>
</application>
base-name元素指明资源包的全名。var元素指明页面作者通过表达式语言指向的的名字。下面是
inputText
标签:
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}"
converterMessage="#{ErrMsg.userNoConvert}">
...
</h:inputText>
converterMessage
属性上的表达式引用了
converterMessage在
ErrMsg
资源上的键值。
See Registering Custom Error Messages (page 461) for more information on configuring custom error messages.
开发Beans
开发beans是应用开发者的职责。一个典型的JSF应用都用一个后台bean和每个页面挂钩。后台bean定义了和页面上应用的UI组件的属性和方法。页面作者用组件标签值属性把组件值和bean属性绑定起来。回忆一下
greeting.jsp
上的userNo组件,它就是引用了
UserNumberBean
的
userNumber
属性:
<h:inputText id="userNo" label="User Number"
value="#{UserNumberBean.userNumber}">
...
</h:inputText>
这里的userNumber
后台bean映射到userNo组件的数据:
Integer userNumber = null;
...
public void setUserNumber(Integer user_number) {
userNumber = user_number;
}
public Integer getUserNumber() {
return userNumber;
}
public String getResponse() {
if(userNumber != null &&
userNumber.compareTo(randomInt) == 0) {
return "Yay! You got it!";
} else {
return "Sorry, "+userNumber+" is incorrect.";
}
}
添加受管理的Bean声明
在开发完后台beans后,你需要在应用配置文件里配置它们,这样JSF就可以在需要的时候自动创建这些beans的新的实例。
在应用配置文件里添加受管bean的声明是应用架构师的职责。以下就是
UserNumberBean的受管bean声明:
<managed-bean>
<managed-bean-name>UserNumberBean</managed-bean-name>
<managed-bean-class>
guessNumber.UserNumberBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>minimum</property-name>
<property-class>long</property-class>
<value>0</value>
</managed-property>
<managed-property>
<property-name>maximum</property-name>
<property-class>long</property-class>
<value>10</value>
</managed-property>
</managed-bean>
UserNumberBean
,它的
minimum
属性和
maximum
分别被初始化为0和10,并且,当这个bean被创建后,就会被添加到session范围。
页面作者可以用统一表达式语言访问bean的属性,像下面这样:
<h:outputText value="#{UserNumberBean.minimum}"/>
For more information on configuring beans, see Configuring a Bean.
用户界面组件模型
JSF的UI组件是可配置,可重用的元素,它们构成了JSF应用的用户界面。一个组件可以是简单的,如按钮;或者符合的,如表格,表格由多个组件构成。
JSF技术提供了一个胖的,可伸缩的组件架构,包含如下:- 一组
UIComponent
类,用来指定UI组件的状态和行为
- 一个持有模型定义了如何用不同方式持有组件
- 一个时间和监听模型定义如何处理组件事件
- 一个转换模型定义如何在组件上注册数据转换器
- 一个验证模型定义如何在组件上注册数据验证器
- 一组
这一节简短描述了这些组件模型。
用户界面组件类
JSF技术提供了一组UI组件类,与指定了UI组件功能的行为接口关联,这些组件功能包括组件状态,持有对象引用,驱动事件处理和表示一组标准组件。
组件类是完全可扩展,允许组件编写者创建它们自己的定制组件。请看 Chapter 12 ,一个定制图片映射组件的例子。
所有JSF UI组件类都扩展了UIComponentBase
类,这个类定义了UI组件的缺省状态和行为。JSF技术包含以下一组UI组件类:
UIColumn
: 代表UIData
组件中数据的一列
UICommand
: 代表一个产生actions的控制
UIData
: 代表绑定到由DataModel
组件表示的一组数据
UIForm
: 包装了一组可以提交数据到服务器的控件。这个组件类似HTML中的form标签
UIGraphic
: 显示一个图片
UIInput
: 从用户取得输入数据,这个类是UIOutput
的子类
UIMessage
: 显示本地化的信息
UIMessages
:显示一组本地化信息
UIOutput
: 在页面上显示输出数据
UIPanel
: 管理子组件的布局
UIParameter
: 代表交互参数
UISelectBoolean
: 允许用户通过选与反选设置一个布尔值的控件,这个类是UIInput的子类
UISelectItem
: 代表一组条目中的一个条目
UISelectItems
: 代表整组条目
UISelectMany
:允许用户从一组条目中选择多个条目,这个类是UIInput的子类
UISelectOne
: 允许用户从一组条目中选择一个条目,这个类是UIInput的子类
UIViewRoot
: 代表组件树的根
UIComponentBase
,组件类可以实现一个或更多的行为接口,每个行为接口都为一组组件定义了确定的行为。
这些行为接口如下:
ActionSource
: 表明此组件可以产生一个action事件。这个接口意在给基于JSF技术1.1_01或更早版本的组件使用。
ActionSource2
: 扩展了ActionSource
,因此它提供了同样的功能。可是它还允许组件引用处理事件的方法时候用EL。
EditableValueHolder
: 扩展了ValueHolder
,并为可编辑组件详细指定了附加功能,比如验证器和值变化的事件。
NamingContainer
: 使以此组件为根的所有组件拥有唯一的ID。
StateHolder
: 指定有状态组件必须在请求间被保存。
ValueHolder
: 标明维持本地值和在模型层访问数据的选择。
UICommand
实现了
ActionSource2
和
StateHolder
。
UIOutput
和继承了实现了
StateHolder
和
ValueHolder
的组件类都实现了
StateHolder
and
ValueHolder。
UIInput
和继承了
UIInput
的组件类都实现了
EditableValueHolder
和
StateHolder
,
ValueHolder
。
UIComponentBase
实现了
StateHolder
。
See the tJavaServer Faces Technology 1.2 API Specification (http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/javax/faces/component/package-summary.html) for more information on these interfaces.
只有组件编写者才需要直接使用组件类和行为接口。页面作者和应用开发者只需要通过在页面上包含标签来使用标准UI组件。举个例子,UICommand
能由一个按钮或超链接持有。
下一节解释了持有模型如何工作,页面作者如何通过选择合适的标签来持有组件。
组件持有模型
JSF组件架构设计成组件功能由组件列定制,组件持有能被分开的持有者定义。这样设计有几个好处,包括:- 组件编写者可以在只定义一次组件行为的情况下创建多个持有者,每个持有者定义了不同的方式来针对同一或不同的客户端持有组件
- 页面作者和应用开发者能通过选择组件和持有者的合适组合来改变页面上的组件显示。
render kit 定义了如何将组件类映射到适宜特殊客户端的组件标签。JSF实现包含了标准HTMLrender kit来render一个HTML客户端。
The render kit defines a set of Renderer
classes for each component that it supports.
Each Renderer
class defines a different way to render the particular component to the output defined by the render kit. For example, a UISelectOne
component has three different renderers. One of them renders the component as a set of radio buttons. Another renders the component as a combo box. The third one renders the component as a list box.
Each JSP custom tag defined in the standard HTML render kit is composed of the component functionality (defined in the UIComponent
class) and the rendering attributes (defined by the Renderer
class). For example, the two tags in Table 9-1 represent a UICommand
component rendered in two different ways.
The command part of the tags shown in Table 9-1 corresponds to the UICommand
class, specifying the functionality, which is to fire an action. The button and hyperlink parts of the tags each correspond to a separate Renderer
class, which defines how the component appears on the page.
The JavaServer Faces implementation provides a custom tag library for rendering components in HTML. It supports all the component tags listed in Table 9-2. To learn how to use the tags in an example, see Adding UI Components to a Page Using the HTML Component Tags (page 316).
转换器模型
一个JSF模型能有选择地把组件和服务器端数据关联起来。这个对象就是一个JavaBeans组件,比如后台bean。一个应用可以gets和sets这个对象的数据。当一个组件绑定倒一个对象,这个应用就拥有了这个组件数据的两个视图:
- 模型视图,其中的数据代表数据类型,比如int 或者long
- 一般视图,其中的数据代表通用数据,可以被用户读写。举个例子,一个
java.util.Date可能代表一个格式为
mm/dd/yy 的文本字符串或者一组3个文本字符串。
当bean属性和组件被组件数据支持的数据类型关联时,JSF在这两种视图间自动转换组件数据。举个例子,如果一个UISelectBoolean
组件和java.lang.Boolean类型的bean属性关联,JSF实现会自动转换组件数据,即从String转换为Boolean。另外,一些组件数据必须绑定倒特殊类型。例如,一个
UISelectBoolean
数据必须绑定到boolean
或java.lang.Boolean。
UIOutput
组件或这个组件的子组件上注册转换器实现。如果你在一个组件上这测了转换器实现,这个转换器实现就会在两个视图直接转换组件数据。
你也可以用JSF实现支持的标准转换器或者创建你自己的定制转换器。
在应用中创建自定义转换器,有三件事必须做:
- 应用开发者必须实现
Converter
类。 See Creating a Custom Converter (page 396).
- 应用架构必须在应用中注册转换器。See Registering a Custom Converter (page 464).
- 页面作者必须在需要转换数据的组件中指明这个转换器。 See Using a Custom Converter (page 374).
- 应用开发者必须实现
事件和监听器模型
JSF事件和监听器模型类似JavaBeans事件模型,它有应用可以用来处理UI组件产生的事件的强类型的事件类和接口。
An Event
object identifies the component that generated the event and stores information about the event. To be notified of an event, an application must provide an implementation of the Listener
class and must register it on the component that generates the event. When the user activates a component, such as by clicking a button, an event is fired. This causes the JavaServer Faces implementation to invoke the listener method that processes the event.
JavaServer Faces technology supports three kinds of events: value-change events, action events, and data-model events.
An action event occurs when the user activates a component that implements ActionSource
. These components include buttons and hyperlinks.
A value-change event occurs when the user changes the value of a component represented by UIInput
or one of its subclasses. An example is selecting a checkbox, an action that results in the component's value changing to true
. The component types that can generate these types of events are the UIInput
, UISelectOne
, UISelectMany
, and UISelectBoolean
components. Value-change events are fired only if no validation errors were detected.
Depending on the value of the immediate
property (see The immediate Attribute, page 318) of the component emitting the event, action events can be processed during the invoke application phase or the apply request values phase, and value-change events can be processed during the process validations phase or the apply request values phase.
A data-model event occurs when a new row of a UIData
component is selected. The discussion of data-model events is an advanced topic. It is not covered in this tutorial but may be discussed in future versions of this tutorial.
There are two ways to cause your application to react to action events or value-change events emitted by a standard component:
-
- Implement an event listener class to handle the event and register the listener on the component by nesting either a
valueChangeListener
tag or anactionListener
tag inside the component tag.
- Implement a method of a backing bean to handle the event and refer to the method with a method expression from the appropriate attribute of the component's tag.
- Implement an event listener class to handle the event and register the listener on the component by nesting either a
See Implementing an Event Listener (page 398) for information on how to implement an event listener. See Registering Listeners on Components (page 356) for information on how to register the listener on a component.
See Writing a Method to Handle an Action Event (page 411) and Writing a Method to Handle a Value-Change Event (page 413) for information on how to implement backing bean methods that handle these events.
See Referencing a Backing Bean Method (page 369) for information on how to refer to the backing bean method from the component tag.
When emitting events from custom components, you must implement the appropriate Event
class and manually queue the event on the component in addition to implementing an event listener class or a backing bean method that handles the event. Handling Events for Custom Components (page 439) explains how to do this.
Validation Model 数据验证模型
JSF技术支持验证如文本框的本地数据的机制。这种验证发生在反应模型数据和本地值更新之前。
JavaServer Faces technology supports a mechanism for validating the local data of editable components (such as text fields). This validation occurs before the corresponding model data is updated to match the local value.
就像数据转换模型,数据验证模型定义了一组标准类来完成通用的数据检验。JSF核心标签库定义了一组标签为标准验证器实现负责。
Like the conversion model, the validation model defines a set of standard classes for performing common data validation checks. The JavaServer Faces core tag library also defines a set of tags that correspond to the standard Validator
implementations. See Table 10-7 for a list of all the standard validation classes and corresponding tags.
Most of the tags have a set of attributes for configuring the validator's properties, such as the minimum and maximum allowable values for the component's data. The page author registers the validator on a component by nesting the validator's tag within the component's tag.
The validation model also allows you to create your own custom validator and corresponding tag to perform custom validation. The validation model provides two ways to implement custom validation:
-
- Implement a
Validator
interface that performs the validation. See Implementing the Validator Interface (page 403) for more information.
- Implement a backing bean method that performs the validation. See Writing a Method to Perform Validation (page 412) for more information.
- Implement a
If you are implementing a Validator
interface, you must also:
-
- Register the
Validator
implementation with the application. See Registering a Custom Validator (page 463) for more information.
- Create a custom tag or use a
validator
tag to register the validator on the component. See Creating a Custom Tag (page 406) for more information.
- Register the
If you are implementing a backing bean method to perform validation, you also must reference the validator from the component tag's validator
attribute. See Referencing a Method That Performs Validation (page 372) for more information.