何时使用<ui:include>,标记文件,复合组件和/或自定义组件?


102

我最近开始将JSF 2.0与Facelets结合使用,并且对新的复合组件感到困惑,因为他们知道<ui:include>Facelets 1.x提供的现有模板技术和其他模板技术。

这些方法之间有什么区别?在功能上,它们似乎提供了几乎相同的功能:<ui:param>vs <cc:attribute><ui:insert>+ <ui:define>vs标签文件,现有模板的重用。如果是复合组件,除了语法和清晰的接口规范外,还有什么?性能会有所不同吗?

Answers:


176

这些方法之间有什么区别?

Facelet模板

使用模板的facelet(如<ui:composition><ui:include><ui:decorate>如果要将主页布局片段拆分为可重复)。例如页眉,菜单,内容,页脚等。

例子:

Facelet标记文件

如果要具有一组可重用的组件,请使用Facelet标记文件,以防止/减少代码重复。例如一组标签+输入+消息组件。复合组件的主要区别在于,Facelet标记文件的输出不代表单个UIComponent,在某些情况下可能是复合组件不足的唯一解决方案。通常,具有<ui:include>一个或多个<ui:param>通过托管Bean属性(因此不是硬编码值)的信号表明,包含文件可以更好地是标记文件。

例子:

复合组件

如果您要UIComponent使用纯XML 来创建具有单一职责的单一可重用定制,请使用复合组件。这种复合组件通常由一堆现有组件和/或HTML组成,并在物理上呈现为单个组件,并且应该绑定到单个bean属性。例如,java.util.Date由3个从属<h:selectOneMenu>组件表示单个属性的组件,或将一个自定义实体作为属性进行组合<p:fileUpload>并组合<p:imageCropper>成单个组件的组件。<my:uploadAndCropImage>com.example.Image

例子:

定制组件

每当Facelet标记文件或复合组件无法实现功能时,都要使用自定义组件,这是因为标准/可用组件集中缺乏支持。在诸如PrimeFacesOmniFaces之类的开源组件库的源代码中,到处都有示例

标签处理程序

当您要控制JSF组件树的构建而不是HTML输出的呈现时,则应使用标记处理程序而不是组件。

例子:

示例项目

这是一些利用所有上述技术的示例项目。


性能会有所不同吗?

从技术上讲,性能问题可以忽略不计。选择应基于具体的功能要求以及实现的最终抽象程度,可重用性和可维护性。每种方法都有其明确定义的目的和局限性。

但是,复合组件在构建/还原视图期间(特别是在保存/还原视图状态期间)确实会产生大量开销。而且,在Mojarra的旧版本中,复合组件在分配默认值方面存在性能问题,此问题自2.1.13开始已得到修复。同样,当使用a 表示方法表达式时,Mojarra也会发生内存泄漏<cc:attribute method-signature>,基本上整个组件树都在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为时,性能将很痛苦。如果仅希望使用简单的包含文件或标记文件已经可以实现的基本功能,则不要滥用复合组件。不要以易于配置(阅读:不需要*.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已经默认设置为-1when javax.faces.PROJECT_STAGE未设置为Development


为什么要渲染1个组件(复合组件)而不是3(facelet标记文件)?我的意思是,在阳光明媚的日子里,您可能会感觉像是1而不是3 ...但是我想它后面还有其他东西。在您的示例中,您正在扩展UINamingContainer ...这是否可能是选择cc的原因之一(以便能够覆盖某些jsf实现特定的功能)?
2012年

2
标记文件应视为包含类。复合组件应被视为真实组件。复合组件需要实现NamingContainer,否则当同一组件多次重复使用时,您将遇到重复的ID问题。
BalusC

@BalusC假设我有一堆HTML和JSF创建了一个“块”,使我可以添加或删除地址(及其所有属性:街道,数字,城市等)。我需要在2或3页中使用相同的块。这是否属于您对复合组件的描述?
RinaldoPJr 2013年

1
@Rinaldo:我想我应该使用带有动态填充的组件ID的标记文件,如stackoverflow.com/questions/5713718/…所示。IMO,如果可以使用标记文件来完成,请使用它。如果无法使用标记文件完成,请使用复合文件。如果您需要多个组件来操纵单个属性(而不是地址,而是应该在单个属性中使用的街道名称+门牌号码),那么复合组件将是唯一的解决方案。
BalusC 2013年

2
@Tarik:与标记文件相比,复合文件有很多开销。换句话说:性能不佳。仅在需要基于一组紧密相关的现有组件创建单个自定义UI组件时才使用它。标记文件无法做到这一点。例如,ZEEF.com只有一种合成:上传/下载/裁剪图像多合一,用于页面图片,个人资料图片,链接块标题,图像块等。它仅绑定到一个Image属性在豆子里。
BalusC 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.