何时使用<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