何时使用 、标签文件、复合组件和/或自定义组件?

发布于 2024-11-25 22:10:39 字数 367 浏览 4 评论 0 原文

我最近开始将 JSF 2.0 与 Facelets 一起使用,并对了解现有 以及 Facelets 1.x 提供的其他模板技术的新复合组件感到困惑。

这些方法有什么区别?从功能上讲,它们似乎提供了大致相同的功能: + vs 标签文件,重用现有模板。对于复合组件,除了语法和清晰的接口规范之外还有什么吗?性能会有所不同吗?

I started using JSF 2.0 with Facelets recently and got puzzled by new composite components knowing existing <ui:include> and other templating techniques offered by Facelets 1.x.

What is the difference between those approaches? Functionally they seem to offer about the same: <ui:param> vs <cc:attribute>, <ui:insert>+<ui:define> vs tag files, reuse of the existing templates. Is there anything besides syntax and clear interface specification in case of composite components? Could performance differ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海的爱人是光 2024-12-02 22:10:39

这些方法有什么区别?

Facelet 模板

使用 Facelet 模板(如 ) 如果您想将主页面布局片段拆分为可重用模板。例如页眉、菜单、内容、页脚等。

示例:

Facelet 标记文件

如果您希望拥有一组可重用的组件以防止/最大限度地减少代码重复,请使用 Facelet 标记文件。例如一组标签+输入+消息组件。与复合组件的主要区别在于,Facelet 标记文件的输出不代表单个 UIComponent,并且在某些情况下,当复合组件无法满足需求时,它可能是唯一的解决方案。一般来说,拥有一个 和一个或多个传递托管 bean 属性(因此不是硬编码值)的 是一种表明包含文件最好是标记文件。

示例:

复合组件

如果您想使用纯 XML 创建具有单一职责的单一且可重用的自定义 UIComponent,请使用复合组件。这样的复合组件通常由一堆现有组件和/或 HTML 组成,并在物理上呈现为单个组件,并且应该绑定到单个 bean 属性。例如,由 3 个表示日、月和年的依赖 组件表示单个 java.time.LocalDate 属性的组件,或者组合 < code> 引用为单个 单个自定义 com.example.Image 实体作为属性。

示例:

自定义组件

当由于缺乏标准/可用组件集的支持而无法通过 Facelet 标记文件或复合组件实现功能时,请使用自定义组件。通常,当您想要对解码和/或编码进行高度控制和/或定制,并且还为最终用户提供相对容易地扩展/覆盖解码和/或编码的可能性时。示例可以在开源组件库的源代码中找到,例如 PrimeFacesOmniFaces

标签处理程序

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

示例:

示例项目

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


性能会有所不同吗?

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

然而,复合组件在构建/恢复视图期间(特别是:在保存/恢复视图状态期间)确实会产生很大的开销。而且,在旧版本的 Mojarra 中,复合组件在分配默认值时存在性能问题,该问题自 2.1.13 以来已得到修复。此外,当 用于方法表达式,基本上整个组件树在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 及更高版本,当 javax.faces.PROJECT_STAGE 未设置为 Development 时,MyFaces 已默认为 -1

What is the difference between those approaches?

Facelet templates

Use Facelet templates (as in <ui:composition>, <ui:include> and <ui:decorate>) if you want to split main page layout fragments into reuseable templates. E.g. header, menu, content, footer, etc.

Examples:

Facelet tag files

Use Facelet tag files if you want to have a reuseable group of components in order to prevent/minimize code duplication. E.g. a group of label+input+message components. The major difference with composite components is that the output of a Facelet tag file does not represent a single UIComponent and may in some circumstances be the only solution when a composite component doesn't suffice. Generally, having an <ui:include> with one or more <ui:param> which passes a managed bean property (and thus not a hardcoded value) is a signal that the include file can better be a tag file.

Examples:

Composite components

Use composite components if you want to create a single and reuseable custom UIComponent with a single responsibility using pure XML. Such a composite component usually consists of a bunch of existing components and/or HTML and get physically rendered as single component and is supposed to be bound to a single bean property. E.g. a component which represents a single java.time.LocalDate property by 3 dependent <h:selectOneMenu> components representing day, month and year, or a component which combines <p:fileUpload> and <p:imageCropper> into a single <my:uploadAndCropImage> referring a single custom com.example.Image entity as property.

Examples:

Custom components

Use a custom component whenever the functionality cannot be achieved with Facelet tag files or composite components, because of the lack of support in the standard/available set of components. Generally when you want a high degree of control and/or customization of the decoding and/or encoding, and also to offer the endusers the possibility to relatively easily extend/override the decoding and/or encoding. Examples can be found over all place in source code of open source component libraries such as PrimeFaces and OmniFaces.

Tag handlers

When you want to control the building of the JSF component tree instead of rendering of the HTML output, then you should use a tag handler instead of a component.

Examples:

Example projects

Here are some example projects which utilize all of above mentioned techniques.


Could performance differ?

Technically, the performance concern is negligible. The choice should be made based on the concrete functional requirements and the final degree of abstraction, reusability and maintainability of the implementation. Each approach has its own well definied purpose and limitations.

Composite components do however have a significant overhead during building/restoring of the view (specifically: during saving/restoring the view state). And, in older versions of Mojarra, composite components had performance issues with assigning default values, this is already fixed since 2.1.13. Also, Mojarra had a memory leak when a <cc:attribute method-signature> is used for method expressions, basically the entire component tree is re-referenced in HTTP session, this is fixed since 2.1.29 / 2.2.8. The memory leak can be bypassed in older 2.1 versions as below:

<context-param>
    <param-name>com.sun.faces.serializeServerState</param-name>
    <param-value>true</param-value>
</context-param>

Or in older 2.2 versions as below:

<context-param>
    <param-name>javax.faces.SERIALIZE_SERVER_STATE</param-name>
    <param-value>true</param-value>
</context-param>

Still, when you have relatively "a lot of" composite components, and you have javax.faces.STATE_SAVING_METHOD set to client, then the performance will be a pain. Do not abuse composite components if you merely want the basic functionality which is already possible with a simple include file or tag file. Do not use the ease of configuration (read: no *.taglib.xml file needed) as an excuse to prefer composite components over tag files.

When using Mojarra 2.2.10 or older, do not forget to disable the relatively short Facelets refresh period for production mode:

<context-param>
    <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
    <param-value>-1</param-value>
</context-param>

Do not use this setting for development, otherwise you've to restart the whole server to get changes in Facelets files to be reflected! Mojarra 2.2.11 and newer, and MyFaces already defaults to -1 when javax.faces.PROJECT_STAGE is not set to Development.

拔了角的鹿 2024-12-02 22:10:39

如果组件具有仅为特定子组件生成标记的自定义渲染器,并且您想要创建可重用的“组件”,则通常必须使用 tagui:include 而不是一个复合组件

原因是,标签本身不是 @BalusC 回答的 UIComponent 本身,而是一个“简单的外壳”,因此父组件渲染器将能够渲染子组件。

示例

这样的 primefaces 菜单需要 作为子项。

标记将起作用

<p:breadCrumb>
    <myTags:breadCrumbItems value="foo"/>
</p:breadCrumb>

包含将起作用

<p:breadCrumb>
    <ui:include src="/resources/includes/breadCrumbItems.xhtml">

复合组件将不起作用

<p:breadCrumb>
    <myComps:breadCrumbItems value="foo"/>
</p:breadCrumb>

我的想法:

新开发人员发现这些差异令人困惑,即使对于经验丰富的开发人员来说,区分标签和复合组件也很烦人。

他们应该向复合组件添加一个属性,该属性内部使其表现为标签,但无需在 taglib xml 文件中注册它们,并且具有cc属性的优点。

或者让标签通过添加新内容(例如 )来注册自己。

If components have a custom renderer that only generate markup for specific child components and you want to create a reusable 'component' you often must use a tag or ui:include instead of a composite component.

The reason is, that the tag itself is not a UIComponent itself as answered by @BalusC but rather a 'simple shell' and so the parent component renderer will be able to render the children.

Example

A primefaces Menu like <p:breadCrumb> requires <p:menuItem> as children.

Tag will work

<p:breadCrumb>
    <myTags:breadCrumbItems value="foo"/>
</p:breadCrumb>

Include will work

<p:breadCrumb>
    <ui:include src="/resources/includes/breadCrumbItems.xhtml">

<ui:param name="value" value="foo"/>
</ui:include>
</p:breadCrumb>

Composite component will not work

<p:breadCrumb>
    <myComps:breadCrumbItems value="foo"/>
</p:breadCrumb>

My thoughts:

New developers find these differences confusing as they are and even for experienced developers its annoying to differentiate between tags and composite components.

They should add an attribute to composite components <composite:interface behaveAsTag="true"> that internal makes it behave as a tag, but removes the need to register them in the taglib xml file and has advantages of cc attributes.

Or let tags register themselves by adding something new like <tag:interface>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文