虽然只是小版本的升级,但对于希望在 JSF 应用中使用 HTML5 技术的开发人员而言,JSF 2.2 带来的更新很重要,尤其是 pass through 能力,它允许在 JSF 组件不知情的情况下传递 HTML 属性。
HTML5 中增加了很多新特性,其中有些是在已有的元素上增加了对新属性的支持。例如,input 元素的 type 属性支持 text、search、email、url、tel、range、number 和 date 等属性值。另外,它还有一系列的自定义数据属性,用来在 HTML 元素上关联少量数据。这些数据不会显示,但可以用 JavaScript 读取。
对于像 JSF 这样基于组件的库,上述情况带来一个问题:为了识别新属性,所有已有的组件必须更新。对于需要显式支持这些属性的组件而言,的确如此。但在很多情况下,组件只需要在最终生成的标记中包含这些属性即可。JSF 2.2 的 pass-through 属性就是这样实现的。
在 Facelet 页中,pass-through 属性可以通过以下三种方法设置:
1. 通过组件标签的命名空间属性
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://java.sun.com/jsf/passthrough"> <h:form> <h:inputText value="#{bean.value}" p:placeholder="Enter text"/> </h:form> </html>
2. 通过 TagHandler f:passThroughAttribute 设置单个属性
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:form> <h:inputText value="#{bean.value}" > <f:passThroughAttribute name="placeholder" value="Enter text" /> </h:outputText> </h:form> </html>
3. 通过 TagHandler f:passThroughAttributes 设置多个属性
<h:outputText value="Something" > <f:passThroughAttributes value="#{bean.multipleAttributes}" /> </h:outputText>
#{bean.multipleAttributes}代表一个 Map<String,Object> 对象。它的值可以是常量,也可以是表达式。
通过使用 Express Language 3(Java EE 7 的一部分),多个属性也可以通过 EL 表达式直接定义。
<h:outputText value="Something" > <f:passThroughAttributes value="{"one":1, "two":2, "three":3}" /> </h:outputText>
上述改变结果是,开发人员现在可以使用纯 HTML 来编写 JSF 视图,这是 Wicket 等竞争对手框架经常被提及的优势。
在服务器端,可以使用类 UIComponent 的新方法 g_etPassThroughAttributes()_ 和 _getPassThroughAttributes(boolean create)_ 来设置属性。
UIComponent component = new SomeComponent(); Map passThrough = component.getPassThroughAttributes(); passThrough.put("placeholder", "Enter text");
与 pass through 能力一起,JSF 2.2 还进行了两项意义重大的增强:Faces Flow 和“无状态视图(Stateless Views)”。
Faces Flow
Faces Flow 的灵感来自 ADF “任务流(Task Flows)”和 Spring“页面流(Web Flow)”。它提供了对流的直接支持。流被定义为节点间的流转,可以引导用户浏览一组页面和一些相关用例。节点可以是:
- “一个视图(A View)”:应用程序中的任何 JSF 页面
- “一次方法调用(A Method Call)”:通过 EL 表达式从流图调用应用逻辑
- “一个开关(A Switch)”:在流图中基于布尔型 EL 表达式进行导航决策
- “一次流调用(A Flow Call)”:带参数调用另一个流并接收返回值
- “一次流返回(A Flow Return)”:返回至调用流
节点定义了流的入口和出口。
JSF 2.2 引入了如下两个新注释:
- @FlowScoped 是一个 CDI 作用域,定义了 bean 在特定流中的作用范围。Bean 在进入该作用域时自动激活,而退出时自动失效。
- @FlowDefinition 是一个类级别的注释,它允许通过 FlowBuilder API 定义流。
最后,引入了新的 EL 对象 _#{flowScope_},用于流的本地存储。该对象对应 facesContext.getApplication().getFlowHandler().getCurrentFlowScope()。
“无状态视图(Stateless Views)”
许多框架是有状态的,尤其是组件框架。但是如果状态信息不需要维护会有若干优点,最重要的是可以避免集群中节点间的状态复制,或者避免使用粘性会话保证请求返回至发起节点。与上述优点相比,提升框架性能和降低内存消耗等经常被提及的优点就不是那么确定无疑了。虽然状态可能导致 Web 框架的性能以及内存消耗问题,但在企业应用中这种影响实际上是微不足道的。JSF 2.x 的“部分状态保存(Partial State Saving)”仅更新有变化的状态,使得应用和保存状态的过程相当高效,对性能的影响较小。同样地,状态信息占用的内存也非常小。
JSF 的无状态实现方式很直观,处理 <f:view> 的 TagHandler 将其布尔值属性 _transient_ 传递给 UIViewRoot#setTransient 即可。如果页面设置为临时的,JSF StateManager 就不存储它的任何数据,页面还原时,它也会被创建为无状态的。
JSF 2.2 还有许多其它小的变化。Arjan Tijms 在 J-Development 上的文章进行了更为详尽的说明。
参考英文原文:**** JSF 2.2 和 HTML5
感谢杨赛对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
评论