一 执行JSF配置是应用架构师的责任,包括:
l 向应用注册后端对象以使应用的任何部分都能访问它们.
l 配置支持bean和模型bean,以使在页面开始引用它们时能够用适当的值实例化.
l 定义应用中每个页面的导航规则,使应用有一个连续的页面流.
l 打包所有页面对象以及其它文件,使应用能发布到任何兼容的容器.
二 应用配置资源文件
JSF技术为配置资源提供一个轻便的配置格式:XML文档.应用架构师创建一个或多个称为应用配置资源的文件,使用这个格式注册并配置对象以及定义导航规则.一个应用配置资源文件通常称为faces-config.xml,这些xml文档不仅要良构,而且还必须合法.
应用可以有多个应用配置资源文件,JSF实现用这样的顺序查找这些文件:
l 在父类装载器中以及在web应用的/WEB-INF/lib/里的任何JAR文件中的命名为/META-INF/faces-config.xml的资源,如果带有这个名字的资源存在就作为配置资源装入.这种方式实际上是为已经打包的包含一些组件和渲染器的库准备的.
l 一个初试化参数javax.faces.application.CONFIG_FILES,它指定一个或多个用逗号分隔的web应用多个配置文件的路径.这种方式乐见于可伸缩的企业级应用.
l 一个在应用的/WEB-INF/目录下的命名为faces-config.xml的资源,这是使应用的配置文件可用的最简单方式.
要访问已经向应用注册的资源,应用开发者要使用Application类的实例,它被每个应用自动创建.Application类实例扮演了在XML文件中定义的资源的中心工厂的角色.应用启动时,JSF实现就创建Application类的单个实例并且用应用配置资源文件中的配置信息配置它.
三 配置支持Bean.
要实例化在JSF应用中使用的支持bean 并在作用域里存储他们,你使用可管理bean创建设施.这个设施配置在应用配置资源文件中,它使用可管理XML元素来定义每个bean.这个文件在应用启动时配置.当页面引用一个bean时,JSF实现根据应用配置资源文件中的配置来实例化它.
使用这个设施,你能:
l 在一个整个应用的中心文件中创建bean,而不是有条件的在整个应用中创建bean.
l 不用任何附加代码自定义组件的属性.
l 当创建可管理bean时直接用配置文件中的值来自定义bean属性值.
l 使用value元素,设置一个可管理bean的属性到另一个值绑定表达式的计算结果.
下面将具体介绍如何使用可管理bean创建设施实例化支持bean.
使用managed-bean元素.
使用这个元素创建bean,它代表一个必须在应用中的bean类的实例.运行时,JSF实现处理这个managed-bean元素,如果一个页面引用这个bean,而这个bean还没有实例存在,则JSF则根据这个元素的定义创建它.
<managed-bean>
<managed-bean-name>NA</managed-bean-name>
<managed-bean-class>model.ImageArea</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>shape</property-name>
<value>poly</value>
</managed-property>
...
</managed-bean-name>
</managed-bean>
managed-bean-scope 元素定义bean要存储到的作用域,有4个值:none, request, session, or application.
如果是none,那么bean在每次引用时都要重新创建,不保存到任何作用域对象中,使用这个值的情况是,一个可管理bean引用了另一个bean,这另一个bean就使用none.如果使用了UI组件标记的binding属性来绑定一个支持bean,则这个bean要用request,如果要用session或application来替换request,则要注意线程安全.
managed-bean元素包含0个或多个managed-property元素,每个对应bean类中定义的属性。这些元素用来初始化bean属性的值.如果你不想初始化一个属性值,只需要在应用配置资源文件中不包含这个属性managed-property定义即可.
如果一个可管理bean不包含其它可管理bean元素,它能包含一个map-entries或list-entries元素,map-entries元素配置一套Map实例,list-entries元素配置一套List实例.要影射定义在managed-property元素中的属性,必须确保在组件标记的value表达式中的点后的部分匹配managed-bean元素中的property-name元素.
四 注册消息资源
<application>
<message-bundle>
resources.ApplicationMessages
</message-bundle>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>es</supported-locale>
<supported-locale>de</supported-locale>
<supported-locale>fr</supported-locale>
</locale-config>
</application>
五 注册自定义查核器
<validator>
...
<validator-id>FormatValidator</validator-id>
<validator-class>
validators.FormatValidator
</validator-class>
<attribute>
...
<attribute-name>formatPatterns</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
</validator>
六 注册自定义转换器
<converter>
<description>
Converter for credit card
numbers that normalizes
the input to a standard format
</description>
<converter-id>CreditCardConverter</converter-id>
<converter-class>
converters.CreditCardConverter
</converter-class>
</converter>
七 配置导航规则
导航:是在一个button和超链接组件点击后要显示的下个页面的一套选择规则.
导航规则定义在应用配置资源文件中,每个导航规则指定怎样从一个页面导航到一套其他页面,JSF实现根据当前显示的页面来选择适当的导航.在适当的导航选定后,从当前页面选择访问到的下一个页面的机会依赖于在当前页面中组件被点击的时候调用的action方法,那个逻辑输出或由组件标记引用或由action方法所返回.
逻辑输出可以是开发者选择的任何东西,但也有一些常用的输出:
success 每个项都成功完成,继续下一个页面.
failure 某个项出了问题,继续到一个错误页面.
logon 用户被要求先登录,继续到等录页面.
no results 搜索没有找到任何项,回到搜索页.
通常,动作方法在本页的表单数据上执行一些处理,例如,那个方法检查表单中的用户名称和口令是否和文件中的一致,如果一致那个方法返回输出success,否则返回failure,例如:
<navigation-rule>
<from-view-id>/logon.jsp</from-view-id>
<navigation-case>
<from-action>#{LogonForm.logon}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/storefront.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{LogonForm.logon}</from-action>
<from-outcome>failure</from-outcome>
<to-view-id>/logon.jsp</to-view-id>
</navigation-case>
</navigation-rule>
正象这个例子所示,对于决定要访问的那个适当页面来说,用于处理那个动作的方法和返回的输出都是必须的.
这个导航规则定义从logon.jsp页面导航的可能路径,每个navigation-case元素定义一个从logon.jsp导航的可能路径,第一个navigation-case是说如果LogonForm.logon返回success输出,那么storefront.jsp页面将被处理;第一个navigation-case是说如果LogonForm.logon返回
failure的话logon.jsp会被渲染.
一个应用的导航配置由一套导航规则构成,每个规则都由faces-config.xml文件中的navigation-rule元素定义.
每个导航规则元素都对应到一个由可选的from-view-id元素定义的组件树标识符,这意味着在应用中每个规则定义了一个特定页面所有可能的导航路径,如果没有from-view-id元素,那么定义在navigation-rule元素中的导航规则应用到应用程序中的所有页面.from-view-id也允许通配符匹配模式.例如<from-view-id>/books/*</from-view-id>,就是说这个导航规则应用books目录中的所有页面.
navigation-rule元素可以包含0个或多个navigation-case元素,navigation-case元素定义一套匹配条件,当条件满足时,应用将导航到由包含在同一个navigation-case元素中的to-view-id元素定义的页面.
导航条件由可选的from-outcome 和 from-action元素定义,from-outcome定义逻辑输出,如success,from-action元素使用方法绑定表达式引用一个返回串的动作方法,那就是逻辑输出,这个方法执行一些逻辑来决定那个逻辑输出并返回它.
navigation-case检查元素输出和方法绑定表达式值的顺序是:
如果from-outcome value和from-action value都存在,如果动作方法返回不同的值那么这些元素都被使用,依赖于它执行的过程的结果.
如果只指定了from-outcome元素,则它必须匹配二者之一:要么是UI组件的action属性,要么是UI组件引用的方法的返回值.
如果只指定了from-action元素,则必须匹配组件标记指定的动作表达式的返回值.
有任何情况匹配,定义在to-view-id元素中的组件树将被选择来渲染。
八 用Render Kit注册自定义渲染器.
为了每个渲染工具支持的UI组件,渲染工具定义了一套能以不同方式渲染UI组件到客户端的渲染对象.如标准UISelectOne组件类定义了允许用户从一组条目中选择一个条目的组件,这个组件能使用Listbox渲染器,Menu渲染器,Radio渲染器来渲染,每个渲染器为组件产生一个不同的外观:Listbox渲染器渲染能显示整个集合值.Menu渲染器渲染所有可能值的一个子集,Radio渲染器渲染一套Radio按扭.
应用开发者建立了自己的渲染器后,必须注册它才能在页面中使用,要注册它,使用应用配置资源文件中的render-kit元素,例如:
<render-kit>
<renderer>
<component-family>Area</component-family>
<renderer-type>DemoArea</renderer-type>
<renderer-class>
renderers.AreaRenderer
</renderer-class>
<attribute>
<attribute-name>onmouseout</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
<attribute>
<attribute-name>onmouseover</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
<attribute>
<attribute-name>styleClass</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
</renderer>
</render-kit>
其中:render-kit元素代表一个RenderKit实现,如果没有指定render-kit-id,就假定是缺省的HTML渲染工具;renderer元素代表渲染器实现,通过在render-kit元素中嵌套renderer元素,就把渲染器注册到了和元素render-kit相关的RenderKit,renderer-class是全限定名.
元素component-family和renderer-type由组件使用,用于查找渲染它的渲染器.component-family元素的值必须和组件类的getFamily方法返回的值相匹配.renderer-type元素的值必须和标记处理器类的getRendererType方法返回的值相匹配.而且组件的配置也需要指定component family 和 renderer type的值.
每个属性标记指定渲染器依赖的属性和它的类型.这些元素不影响应用运行时的执行,相反,它是向工具提供关于渲染器支持的属性的信息.
九 注册自定义组件
除了注册自定义渲染器外,你还必须注册和那个自定义渲染器关联的自定义组件.
下面是一个例子注册组件AreaComponent:
<component>
<component-type>DemoArea</component-type>
<component-class>
components.AreaComponent
</component-class>
<property>
<property-name>alt</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<property-name>coords</property-name>
<property-class>java.lang.String</property-class>
</property>
<property>
<property-name>shape</property-name>
<property-class>java.lang.String</property-class>
</property>
<component-extension>
<component-family>Area</component-family>
<renderer-type>DemoArea</renderer-type>
</component-extension>
</component>
component-type元素指出组件注册在其下的名字,其它对象用这个名字引用这个组件.例如,在配置中component-type元素为组件AreaComponent定义了一个值DemoArea,这个值要匹配AreaTag类的getComponentType方法返回的值.
component-class元素是这个组件的全限定类名,property元素指定了属性的和它的值.若自定义组件能包含刻面(即facet元素),你配置那个刻面在组件配置中使用facet元素,它可以在component-class元素后面.
component-extension元素标识component family和renderer type,component family代表一个或一套能被渲染器渲染的组件,renderer type则指定了渲染器能渲染的包含在component family中的组件.
由component-family指定的component family必须匹配组件的getFamily方法返回的值,而renderer-type必须匹配标记处理器方法getRendererType返回的值.
JSF实现通过使用component family 和 renderer type为组件寻找渲染器,允许一个组件可由多个渲染器渲染,也允许一个渲染器渲染多个组件.
十 JSF应用的基本需求
1 JSF应用目录结构
实际上这是个典型的web应用规范的标准目录结构.
index.html
JSP pages
WEB-INF/
web.xml
faces-config.xml
tag library descriptors (optional)
classes/
class files
Properties files
lib/
JAR files
2 JSF Servlet生命周期过程
JSF应用的一个需求就是所有到这个应用的请求都必须通过FacesServlet类实例,它管理web应用的请求处理生命周期,并初始化由JSF应用需要的资源.在JSF应用装入第一个JSP页面前,WEB容器为了开始应用生命周期过程必须调用FacesServlet类实例.要确保调用FacesServlet类实例,必须建立影射,有两种方式:prefix mapping和extension mapping.
prefix mapping,例如:/guess/*,那么在到一个页面的URL中必须包含这个影射,如http://localhost:8080/webapp/guess/greeting.jsp.
extension mapping,例如:*.faces,如果一个带有.faces后缀URL请求服务器上一个一个JSP页面,那么容器将发送这个请求到FacesServlet类实例,它期待一个对应的同名JSP页面,如请求URL是http://localhost/webapp/index.faces,FacesServlet将影射它到index.jsp页面.
3 指定应用配置资源文件的路径
<context-param>
<param-name>javax.faces.application.CONFIG_FILES</param-name>
<param-value>WEB-INF/faces-config.xml</param-value>
</context-param>
4 指定状态在哪儿保存,在web应用的部署描述符文件中添加:
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
5 打开xml格式应用配置资源文件的有效性查核
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
6 查核自定义的对象
<context-param>
<param-name>com.sun.faces.verifyObjects</param-name>
<param-value>true</param-value>
</context-param>
7 限制对JSF组件的访问,这通过web应用容器的安全机制实现:
<security-constraint>
<web-resource-collection>
<web-resource-name>Restrict access to JSP pages</web-resource-name>
<url-pattern>/greeting.jsp</url-pattern>
<url-pattern>/response.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
With no roles defined, no access granted
</auth-constraint>
</security-constraint>
8 JSF需要包含的JAR文件
jsf-api.jar
jsf-impl.jar
jstl.jar
standard.jar
commons-beanutils.jar
commons-digester.jar
commons-collections.jar
commons-logging.jar
9 应用中包含的类和页面以及其他资源.
十一 JSF1.2的变化
根据JSF1.2预览草案,发生了许多变化,尤其是JSF EL已经被放在弃用之列,更引入了两个概念:deferred evaluation和immediate evaluation的概念,这些概念的出现有了更大的背景:要和JSP的EL整合成为一套,这正是目前处于草案时期的JSP2.1的一个重大调整,在这个规范之下,JSP EL已打算独立门户:这个版本的参考实现在java标准扩展包加入了新包:javax.el,供给JSF和JSP使用.在这个背景下变化是错综纷乱的,不过尘埃落定时,JSF和JSP的融合可能会带来服务器端活动页面技术在java语言中的终极版本.