【问题标题】:Multiple implementations of Facelets composite component interfaceFacelets复合组件接口的多种实现
【发布时间】:2013-10-30 13:26:00
【问题描述】:

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

对于 Java 代码,这是通过使用常规机制完成的。对于表示层,我们使用javax.faces.view.facelets.ResourceResolver 实现,它首先尝试在 extension jar 中查找资源,然后再使用 core 资源。

我们使用大量复合组件来实现可重用标记。想想显示地址、薪水等的组件。

当涉及到应用程序的可扩展特性时,Facelets 引起了很大的麻烦,我开始怀疑是否有解决我们遇到的问题的方法。

我们想要实现的是为复合组件提供一个标准接口,但通过解决多个实现以某种方式覆盖实现,其中扩展了 实施应先于核心实施。

这个想法当然是,core 定义应用程序的标准布局/模板,extensions 定义客户端特定的格式选项,或隐藏/显示部分应用程序执行的托管模型。

例如:

<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 的属性将由客户端提供。如果客户只希望屏幕的这一部分被不同的内容覆盖,而不是标准实现,我们需要一个地方来覆盖它。

还要注意,core 不知道(可选)extension 提供的命名空间。 core 并不关心,只要复合的接口是稳定的并且不需要更改即可。

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

<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 生命周期的渲染时间部门相比。它基本上不像我们期望的那样工作。

现在最大的问题是:

有没有一种方法可以让我们既拥有稳定的合约/命名空间,又拥有多个动态解析的实现?

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

亲切的问候,

伦斯

【问题讨论】:

    标签: jsf-2 facelets composite-component


    【解决方案1】:

    这种情况已经在 J​​SF 2.2 中通过资源库契约特性得到解决。使用该功能,可以根据其本地化和活动合同对同一复合组件进行多个实现。请注意,本地化/合同在每个视图中都是有效的。

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

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

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

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

    【讨论】:

    • 已经有一段时间了,与此同时,事情已经以另一种方式解决了。我们通过写一个ResourceResolver 来解决我们的特定需求,从而解决了部分问题。我不确定我们是否尝试过您提出的建议,但我所知道的是,混合构建,- (&lt;ui:include /&gt;) 和渲染时间花费了我们很多时间。最后它只是不能可靠地工作。我无法确认您提出的建议不再是解决方案,因此接受您的回答会很奇怪。我会自己关闭这个话题。也许未来的读者可以尝试您的解决方案:) 无论如何谢谢!
    【解决方案2】:

    我们已经扩展了ResourceHandlerWrapper,这样当请求加载来自WEB-INF/resources 的xhtml 资源时,将(首先)扫描类路径。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      相关资源
      最近更新 更多