我最近开始将 JSF 2.0 与 Facelets 一起使用,并且对知道<ui:include>
Facelets 1.x 提供的现有模板技术和其他模板技术的新复合组件感到困惑。
这些方法有什么区别?从功能上讲,它们似乎提供了大致相同的功能:<ui:param>
vs <cc:attribute>
、<ui:insert>
+ <ui:define>
vs 标记文件,重用现有模板。在复合组件的情况下,除了语法和清晰的接口规范之外还有什么?性能会有所不同吗?
我最近开始将 JSF 2.0 与 Facelets 一起使用,并且对知道<ui:include>
Facelets 1.x 提供的现有模板技术和其他模板技术的新复合组件感到困惑。
这些方法有什么区别?从功能上讲,它们似乎提供了大致相同的功能:<ui:param>
vs <cc:attribute>
、<ui:insert>
+ <ui:define>
vs 标记文件,重用现有模板。在复合组件的情况下,除了语法和清晰的接口规范之外还有什么?性能会有所不同吗?
这些方法有什么区别?
如果要将主页布局片段拆分为可重复使用的模板,请使用 Facelet 模板(如<ui:composition>
、<ui:include>
和)。<ui:decorate>
例如页眉、菜单、内容、页脚等。
例子:
如果您想拥有一组可重用的组件以防止/最小化代码重复,请使用 Facelet 标记文件。例如一组标签+输入+消息组件。与复合组件的主要区别在于,Facelet 标记文件的输出不代表单个UIComponent
,并且在某些情况下,当复合组件不够用时,它可能是唯一的解决方案。通常,具有<ui:include>
一个或多个<ui:param>
传递托管 bean 属性(因此不是硬编码值)的信号表明包含文件可以更好地成为标记文件。
例子:
如果您想UIComponent
使用纯 XML 创建具有单一职责的单一且可重用的定制,请使用复合组件。这样的复合组件通常由一堆现有组件和/或 HTML 组成,并作为单个组件物理呈现,并且应该绑定到单个 bean 属性。例如,一个组件由代表日、月和年java.time.LocalDate
的 3 个从属组件表示单个属性,或者一个组件将单个自定义实体组合成一个引用单个自定义实体作为属性。<h:selectOneMenu>
<p:fileUpload>
<p:imageCropper>
<my:uploadAndCropImage>
com.example.Image
例子:
每当使用 Facelet 标记文件或复合组件无法实现功能时,请使用自定义组件,因为标准/可用组件集缺乏支持。通常,当您想要对解码和/或编码进行高度控制和/或定制时,并且还为最终用户提供相对容易地扩展/覆盖解码和/或编码的可能性。示例可以在PrimeFaces和OmniFaces等开源组件库的源代码中找到。
当您想要控制 JSF 组件树的构建而不是呈现 HTML 输出时,您应该使用标记处理程序而不是组件。
例子:
以下是一些利用上述所有技术的示例项目。
性能会有所不同吗?
从技术上讲,性能问题可以忽略不计。应根据具体的功能需求和实现的最终抽象程度、可重用性和可维护性来做出选择。每种方法都有其明确定义的目的和局限性。
然而,复合组件在构建/恢复视图期间(特别是:在保存/恢复视图状态期间)确实有很大的开销。而且,在旧版本的 Mojarra 中,复合组件在分配默认值时存在性能问题,这已经从 2.1.13 开始修复。此外,当 a用于方法表达式时,Mojarra 存在内存泄漏,基本上整个组件树在 HTTP 会话中被重新引用,自 2.1.29 / 2.2.8 以来已修复此问题。<cc:attribute method-signature>
在旧的 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
,那么性能将会很痛苦。如果您只想要简单的包含文件或标记文件已经可以实现的基本功能,请不要滥用复合组件。不要以易于配置(阅读:不需要*.taglib.xml
文件)为借口,更喜欢复合组件而不是标记文件。
使用 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 和更新版本,并且 MyFaces 已经默认为-1
whenjavax.faces.PROJECT_STAGE
未设置为Development
.