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