Facelets复合组件接口的多个实现

时间:2013-10-30 13:26:00

标签: jsf-2 facelets composite-component

我正在开发一个JSF 2应用程序,该应用程序由一个核心组件组成,该组件可以通过(通常是客户端特定的)代码扩展。一般来说:应用程序的扩展部分先于核心部分。

对于Java代码,这是通过使用传统机制完成的。对于表示层,我们使用javax.faces.view.facelets.ResourceResolver实现,在使用核心资源之前,首先尝试在扩展 jar中查找资源。

我们使用大量复合组件来实现可重用的标记。想一想用于显示地址,工资等的组件。

Facelets在应用程序的可扩展性质方面引起了严重的麻烦,我开始怀疑是否存在解决我们遇到的问题的解决方案。

我们想要实现的目标是为复合组件提供标准接口,但通过解析多个实现以某种方式覆盖实现,其中扩展实现应该在核心实现之前。

当然,理念是,核心定义应用程序的标准布局/模板,扩展定义客户端特定的格式选项,或隐藏/显示部分应用程序所做的托管模型。

例如:

<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:cc="http://java.sun.com/jsf/composite"
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:pui="http://java.sun.com/jsf/composite/pui">

    <cc:interface>
        <cc:attribute name="saveButtonLabel" />
        <cc:attribute name="saveButtonIcon" />
        <cc:attribute name="saveButtonIconPosition" />
    </cc:interface>

    <cc:implementation>
        <pui:pension_plan_custom_state pensionPlanBean="#{pensionPlanBean}" />
        <pui:pension_plan_general pensionPlanBean="#{pensionPlanBean}" />
        <pui:pension_plan_pension_plan pensionPlanBean="#{pensionPlanBean}" />
        <pui:pension_plan_salary pensionPlanBean="#{pensionPlanBean}" />
        <pui:pension_plan_investments pensionPlanBean="#{pensionPlanBean}" />
        <pui:pension_plan_benefit_types benefitTypes="#{pensionPlanBean.benefitTypesViewData}" />

        <div class="buttons">
            <!-- Irrelevant -->
        </div>
    </cc:implementation>
</ui:composition>

pension_plan_benefit_types复合组件为例。它的接口规定客户端给出名称benefitTypes的属性。如果客户希望屏幕的这一部分被不同的内容覆盖而不是标准实现,那么我们需要一个地方来覆盖它。

另请注意,核心不知道(可选)扩展提供的命名空间。 核心并非真正关心,只要复合材料的界面稳定且不需要更改。

作为最后的手段,已尝试以下方法(伪代码):

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:cc="http://java.sun.com/jsf/composite"
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:pui="http://java.sun.com/jsf/composite/pui">

    <cc:interface>
        <cc:attribute name="benefitTypes" required="true" type="com.foo.bar.PensionPlanBenefitTypesViewData" />
    </cc:interface>

    <cc:implementation>
        <ui:include src="/resources/pui/markup/pension_plan_benefit_types_markup.xhtml" />
    </cc:implementation>
</ui:composition>

这个想法在哪里,javax.faces.view.facelets.ResourceResolver将来我们的救援。

它的工作类型,但是根据我们必须为复合组件编写的实现,我们在臭名昭着的构建中遇到了各种各样的问题 - 与JSF生命周期的rendertime部门。它基本上不会像我们期望的那样工作。

现在最大的问题是:

我们是否有一种方法可以同时拥有稳定的合同/命名空间,并且有多个动态解决的实现?

希望有人能够对此有所了解,感谢您的意见。

亲切的问候,

的Rens

2 个答案:

答案 0 :(得分:1)

JSF 2.2中已经使用资源库契约功能解决了这种情况。使用该功能,可以根据其本地化和活动合同具有相同复合组件的多个实现。请注意,每个视图的本地化/合同都是活动的。

但是可能更适合您的选项是:

<ui:include src="#{...}">

<ui:decorate template="#{...}">

从托管bean或复合组件类本身(cc:interface componentType = ...)提供模板名称。在这种情况下,我建议使用最新版本的MyFaces Core,因为它的算法已针对这些情况进行了优化(小视图状态大小和快速性能)。我认为你不需要在这里处理ResourceResolver逻辑。

答案 1 :(得分:1)

我们扩展了ResourceHandlerWrapper,以便在请求加载来自WEB-INF/resources的xhtml资源时(首先)扫描类路径。

通过在MANIFEST.MF文件中定义显式类路径,我们可以让扩展jar文件优先于标准实现。通过这样做,我们也可以以编程方式生成其他内容,可以在UI中显示给开发人员(在开发模式下运行时),让他/她知道“覆盖”&#39;实现可以在扩展项目中编写。