3

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

现在最大的问题是:

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

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

亲切的问候,

任斯

4

2 回答 2

1

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

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

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

或者

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

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

于 2013-10-30T15:36:38.790 回答
1

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

By defining an explicit classpath in a MANIFEST.MF file, we can let the extension jar files take precedence over the standard implementation. By doing so, we can programmatically generate additional content too, that can be shown in the UI to the developer (when running in development mode) to let him/her know that an 'overriding' implementation could be written in the extension project.

于 2014-07-16T12:07:38.423 回答