我正在开发一个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
答案 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;实现可以在扩展项目中编写。