我有一组从一组 excel 文件静态生成的 jsf 组件(它们由业务人员更新)。每个生成的文件都表示一个业务对象,该对象的数据略有不同,并且它们都属于同一类。
为了动态渲染,我找到的唯一解决方案是设置一堆ui:fragment
并在运行时调度到正确的组件:
<!-- IMPLEMENTATION -->
<composite:implementation>
<ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
<limites:limites-cartcred limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'cdcp'}">
<limites:limites-cdcp limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'cheqpredatado'}">
<limites:limites-cheqpredatado limite="#{cc.attrs.limite}"/>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.type eq 'confirming'}">
<limites:limites-confirming limite="#{cc.attrs.limite}"/>
</ui:fragment>
<!-- many more lines -->
<!-- many more lines -->
<!-- many more lines -->
<ui:fragment rendered="#{cc.attrs.type eq 'contacorr'}">
<limites:limites-contacorr limite="#{cc.attrs.limite}"/>
</ui:fragment>
但我发现这种表现很糟糕。我认为 JSF 只会渲染一个组件,但它似乎正在渲染所有这些组件并在运行时"隐藏"其他组件。
有没有更有效的方法来实现我的目标?我想根据有关业务类的运行时信息呈现单个组件(很像 if-then-else),但我只能确定要在运行时呈现的组件是什么。
澄清:发生的情况是,limites:limites*
引用的每个组件都是一个巨大的复杂页面,其中包含许多其他组件。在运行时,名为 ui:fragments' 的参数type' will decide what component to render. But my tests show that if I only render one component, but leave the other
(即使知道它们不会被渲染),它的渲染速度会比我删除组件慢得多。
因此,如果我的页面完全像这样:
<composite:interface>
<composite:attribute name="type" required="true" />
<composite:attribute name="limite" required="true" />
</composite:interface>
<composite:implementation>
<ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
<limites:limites-cartcred limite="#{cc.attrs.limite}"/>
</ui:fragment>
</composite:implementation>
即使参数相同,它的渲染速度也会比初始版本快得多(大约 10 倍)。我怀疑 JSF 会创建整个组件树,并且只有在运行时它才会决定(取决于提供的参数)它是否会相互渲染。
编辑
快到了。我只需要动态包含我的复合组件。我尝试评估ELExpression,但这不起作用。我需要的是一种在组件创建中访问当前范围的方法,并使用它来生成正确的文件名:
//obviously, ELExpressions don't work here
Resource resource = application.getResourceHandler().createResource("file-#{varStatus.loop}.xhtml", "components/dynamicfaces");
是的,rendered
属性在渲染时进行评估,而不是在构建时计算。是的,这是相对可怕的。想象一下,一个这样的条件需要 1 毫秒,评估其中的 10 个条件总共需要 10 倍的时间,即 10 毫秒。如果分页表中依次有十个这样的组件,则 Web 应用程序加载时间将延长 0,1 秒。大约眨眼多了一眼。但是,如果您不分页和/或使用MSIE作为参考浏览器,则需要更长的时间。您是否在适当的浏览器中对数据进行分页和测试?
最好的办法是用 JSTL 标记(如 <c:if>
/<c:choose>
)替换<ui:fragment>
,以便它在构建时而不是渲染时进行评估。或者,或者在后备 Bean 构造函数中而不是在视图中构建组件树。
一种可能性可能是使用 binding
属性访问容器从受管 Bean 内部构建组件,并从爪哇端。这样,您可以只包含不需要的组件根本不会评估组件。
.JSP:
<h:panelGroup binding="#{managedBean.panel}"/>
托管豆:
private UIPanel panel;
// getter and setter
// Action method, might also work in a @PostConstruct
public String showComponent() {
if (showComponent1) {
UIOutput component1 = new HtmlOutputText();
component1.setValue("Hello world!");
getPanel().getChildren().add(component1);
}
return "viewId";
}
我还没有将其与复合组件一起使用,这个问题似乎有更多细节和有关将其与复合组件一起使用的示例应用程序。
编辑:关于您的编辑,您还可以像这样计算受管 Bean 中的 EL 表达式:
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory exprFactory = facesContext.getApplication().getExpressionFactory();
ValueExpression expr = exprFactory.createValueExpression(elContext, "#{expr}", String.class);
String value = (String) expr.getValue(elContext);