我最近开始将 JSF 2.0 与 Facelets 一起使用,但对已知现有的新复合组件感到困惑 <ui:include>
以及 Facelets 1.x 提供的其他模板技术。
这些方法有什么区别?从功能上讲,它们似乎提供了相同的功能:<ui:param>
对比 <cc:attribute>
, <ui:insert>
+ <ui:define>
vs 标记文件,重用现有模板。在复合组件的情况下,除了语法和清晰的接口(interface)规范之外还有什么吗?性能会有所不同吗?
最佳答案
What is the difference between those approaches?
Facelet 模板
如果要将主页布局片段拆分为可重复使用的模板,请使用 Facelet 模板(如
<ui:composition>
、 <ui:include>
和 <ui:decorate>
)。例如页眉、菜单、内容、页脚等。例子:
Facelet 标记文件
如果您希望拥有一组可重用的组件以防止/最小化代码重复,请使用 Facelet 标记文件。例如一组标签+输入+消息组件。与复合组件的主要区别在于 Facelet 标记文件的输出不代表单个
UIComponent
在某些情况下,当复合组件不够用时,它可能是唯一的解决方案。一般来说,有一个 <ui:include>
与一个或多个 <ui:param>
传递托管 bean 属性(因此不是硬编码值)是一个信号,表明包含文件可以更好地作为标记文件。例子:
复合组件
如果您想创建单个且可重复使用的自定义组件,请使用复合组件
UIComponent
使用纯 XML 承担单一职责。这样的复合组件通常由一堆现有组件和/或 HTML 组成,并在物理上呈现为单个组件,并且应该绑定(bind)到单个 bean 属性。例如代表单个 java.time.LocalDate
的组件属性(property)由 3 个受抚养人 <h:selectOneMenu>
表示日、月和年的组件,或组合 <p:fileUpload>
的组件和 <p:imageCropper>
成单<my:uploadAndCropImage>
指单定制com.example.Image
实体作为属性(property)。例子:
自定义组件
当由于缺乏标准/可用组件集的支持而无法使用 Facelet 标记文件或复合组件实现功能时,请使用自定义组件。通常,当您想要对解码和/或编码进行高度控制和/或定制,并且还为最终用户提供相对容易地扩展/覆盖解码和/或编码的可能性时。示例在开源组件库的源代码中随处可见,例如PrimeFaces和 OmniFaces .
标签处理程序
当您想要控制 JSF 组件树的构建而不是 HTML 输出的呈现时,您应该使用标记处理程序而不是组件。
例子:
示例项目
以下是一些利用上述所有技术的示例项目。
Could performance differ?
从技术上讲,性能问题可以忽略不计。应根据具体的功能需求和实现的最终抽象程度、可重用性和可维护性来进行选择。每种方法都有其明确的目的和局限性。
然而,在构建/恢复 View 期间(特别是:在保存/恢复 View 状态期间),复合组件确实有很大的开销。而且,在旧版本的 Mojarra 中,复合组件在分配默认值时存在性能问题,自 2.1.13 以来已经修复。此外,Mojarra 有一个 memory leak当
<cc:attribute method-signature>
用于方法表达式,基本上整个组件树都会在 HTTP session 中重新引用,这是自 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
,那么表现就会很痛苦。如果您只想使用简单的包含文件或标记文件已经可以实现的基本功能,请不要滥用复合组件。不要使用易于配置(阅读:不需要 *.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>
不要将此设置用于开发,否则您必须重新启动整个服务器才能反射(reflect) Facelets 文件中的更改! Mojarra 2.2.11 和更新版本,MyFaces 已经默认为 -1
当javax.faces.PROJECT_STAGE
未设置为 Development
.
关于jsf-2 - 何时使用 <ui :include>, 标记文件、复合组件和/或自定义组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6822000/