何时使用<ui:include>,标记文件,复合组件和/或自定义组件?
最近,我开始在Facelets中使用JSF 2.0,并对新的复合组件感到困惑,这些组件知道现有的<ui:include>
和Facelets 1.x提供的其他模板技术。
这些方法有什么区别? 在function上他们似乎提供了相同的: <ui:param>
vs <cc:attribute>
, <ui:insert>
+ <ui:define>
vs标记文件,重复使用现有的模板。 在复合组件的情况下,除了语法和界面清晰之外,还有什么? 性能可能不同吗?
这些方法有什么区别?
Facelet模板
如果要将主页面布局片段拆分为可重复使用的模板,请使用Facelet模板(如<ui:composition>
, <ui:include>
和<ui:decorate>
)。 例如标题,菜单,内容,页脚等
例子:
- 如何使用JSF 2.0 Facelets在XHTML中包含另一个XHTML?
- ui之间真正的概念区别是什么:decorate和ui:include?
- 如何在使用ui:composition模板时自定义h:head?
- 使用ui时如何更改页面的头元素:组合
- 如何通过导航菜单ajax刷新dynamic包含内容? (JSF SPA)
Facelet标记文件
如果您想拥有一个可重复使用的组件组件,以防止/最小化代码重复,请使用Facelet标记文件。 例如一组标签+input+消息组件。 与复合组件的主要区别在于,Facelet标记文件的输出不代表单个UIComponent
,在某些情况下可能是复合组件不能满足的唯一解决scheme。 一般来说,使用<ui:include>
包含一个或多个<ui:param>
是包含文件最好是标记文件的信号。
例子:
- 如何创build一个自定义的Facelets标签?
- 如何使JSF复合组件的网格?
- 如何为数据表列创build一个复合组件?
- 用于复合组件的Primefaces outputLabel
复合组件
如果要使用纯XML创build一个具有单一责任的自定义UIComponent
,请使用复合组件。 这样的复合组件通常由一堆现有的组件和/或HTML组成,并且物理地呈现为单个组件,并且应该被绑定到单个bean属性。 例如,一个由3个依赖的<h:selectOneMenu>
组件或一个将<p:fileUpload>
和<p:imageCropper>
成一个<my:uploadAndCropImage>
组件的单一java.util.Date
属性的组件自定义com.example.Image
实体作为属性。
例子:
- 我们的复合组件维基页面
- BalusC代码:具有多个input字段的复合组件
- 将两个h:inputText字段分割为小时和分钟,并使用f:convertDateTime分割java.util.Date
- 使用dynamicIDselectMultiple SelectManyCheckBox中的所有项目
- 扩展JSF commandLink组件
- 在同一个命名容器中重复使用facelets组合时避免重复的id
自定义组件
只要Facelet标签文件或复合组件无法实现function,就会使用自定义组件,因为缺less对标准/可用组件的支持。 可以在诸如PrimeFaces和OmniFaces等开源组件库的源代码中find所有的例子 。
标签处理程序
当您想要控制构buildJSF组件树而不是呈现HTML输出时,则应该使用标记处理程序而不是组件。
例子:
- JSF中的自定义Facelet组件
- 如何以编程方式访问使用<ui:define>创build的内容?
- 根据是否指定属性,在标记文件中进行条件呈现
- 执行redirect时,与查询参数关联的转换/validation失败
示例项目
以下是一些利用上述所有技术的示例项目。
- Java EE Kickoff应用程序 ( templates – includes – tagfiles – composite )
- OmniFaces展示 ( 模板 – 包含 – 标签文件 – 合成 )
性能可能不同吗?
从技术上讲,性能问题可以忽略不计。 应根据实现的具体function要求和最终的抽象度,可重用性和可维护性进行select。 每种方法都有其明确的目的和局限性。
然而,在构build/恢复视图期间,复合组件确实具有相当大的开销(具体而言:在保存/恢复视图状态期间)。 而且,在旧版本的Mojarra中,复合组件在分配默认值方面存在性能问题,这从2.1.13开始已经被修复了。 此外,当方法expression式使用<cc:attribute method-signature>
时,Mojarra 内存泄漏 ,基本上整个组件树在HTTP会话中被重新引用,这从2.1.29 / 2.2.8开始是固定的。 内存泄漏可以绕过旧的2.1版本如下:
<context-param> <param-name>com.sun.faces.serializeServerState</param-name> <param-value>true</param-value> </context-param>
或者更老的2.2版本如下:
<context-param> <param-name>javax.faces.SERIALIZE_SERVER_STATE</param-name> <param-value>true</param-value> </context-param>
不过,当你有相对“很多”复合组件,并且你有javax.faces.STATE_SAVING_METHOD
设置为client
,那么性能将是一个痛苦。 如果您只想使用简单的包含文件或标记文件就可以实现的基本function,则不要滥用复合组件。 不要使用configuration的简单性(阅读:不需要*.taglib.xml
文件)作为select复合组件超过标记文件的借口。
使用Mojarra 2.2.10或更高版本时,不要忘记禁用生产模式相对较短的Facelets刷新周期:
<context-param> <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name> <param-value>-1</param-value> </context-param>
不要使用此设置进行开发,否则您必须重新启动整个服务器才能反映Facelets文件中的更改! Mojarra 2.2.11和更新,而当javax.faces.PROJECT_STAGE
没有设置为Development
时,MyFaces已经默认为-1
。