简体   繁体   English

JSF ui:片段渲染性能

[英]JSF ui:fragment rendered performance

I have a set of jsf components that are statically generated from a set of excel files (they are updated by business people). 我有一组jsf组件,这些组件是从一组excel文件静态生成的(它们由业务人员更新)。 Each generated file represents a business object that has slightly different data, and all of them belong to a same class. 每个生成的文件表示一个业务对象,该业务对象具有稍微不同的数据,并且它们都属于同一个类。

In order to render this dynamically, the only solution I found was to set up a bunch of ui:fragment and dispatch to the right component at runtime: 为了动态渲染,我找到的唯一解决方案是在运行时设置一堆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>

But I found out that the perfomance of this is terrible. 但我发现这种表现非常糟糕。 I tought that JSF would only render a single component, but it seems that it is rendering all of them and "hiding" the others at runtime. 我认为JSF只会渲染一个组件,但它似乎正在渲染所有这些组件并在运行时“隐藏”其他组件。

Is there a more efficient way of achieving my goal? 有没有更有效的方法来实现我的目标? I want to render a single component based on runtime information about a business class (much like an if-then-else), but I can only determine what is the component to render at runtime. 我想基于有关业务类的运行时信息呈现单个组件 (很像if-then-else),但我只能确定在运行时呈现的组件是什么。


Clarification: what happens is that each component referenced by limites:limites* is a huge complex page with lots of other components. 澄清:发生的事情是limites:limites*引用的每个组件limites:limites*是一个包含许多其他组件的巨大复杂页面。 At runtime, the parameter named type' will decide what component to render. But my tests show that if I only render one component, but leave the other 在运行时,名为type' will decide what component to render. But my tests show that if I only render one component, but leave the other的参数type' will decide what component to render. But my tests show that if I only render one component, but leave the other type' will decide what component to render. But my tests show that if I only render one component, but leave the other ui:fragments` (even knowing that they will not be rendered), it will render much slower than if I remove the components. type' will decide what component to render. But my tests show that if I only render one component, but leave the other UI:fragments`(甚至不知道他们会不会被渲染),它会呈现比如果我删除的组件慢得多。

So if my page is exactly like this: 所以如果我的页面完全像这样:

<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>

it will render much (around 10x) faster than the initial version, even though the parameters are the same. 即使参数相同,它也会比初始版本渲染更多 (大约10倍)。 I suspect that JSF will create the entire component tree and only at runtime it will decide (depending on the supplied parameter) if it will render each other or not. 我怀疑JSF将创建整个组件树,并且仅在运行时它将决定(取决于提供的参数)它是否将相互渲染。


Edit 编辑

Almost there. 快好了。 I just need to include my composite component dynamically . 我只需要动态地包含我的复合组件 I tried evaluating an ELExpression but that didn't work. 我尝试评估ELExpression,但这不起作用。 What I need is a way of accessing the current scope within the component creation, and using that to generate the proper file name: 我需要的是一种在组件创建中访问当前范围的方法,并使用它来生成正确的文件名:

//obviously, ELExpressions don't work here
Resource resource = application.getResourceHandler().createResource("file-#{varStatus.loop}.xhtml", "components/dynamicfaces");

Yes, the rendered attribute evaluates during render time, not during build time. 是的, rendered属性在渲染时评估,而不是在构建时。 Yes, it is relatively terrible. 是的,这是相对可怕的。 Imagine that one such a condition costs 1ms, evaluating ten of them would take in total 10 times longer, 10ms. 想象一下这样一个条件花费1毫秒,评估其中十个将总共花费10倍,10毫秒。 If you in turn have ten of those components in a paginated table, the webapp loading time would take 0,1 second longer. 如果您在分页表中依次拥有10个组件,则webapp加载时间将延长0.1秒。 About one eyeblink longer. 关于一个眨眼更长。 But if you don't paginate and/or are using MSIE as reference browser, then it would take much longer. 但是如果你没有分页和/或使用MSIE作为参考浏览器,那么它需要更长的时间。 Are you paginating the data and testing in proper browsers? 您是否在适当的浏览器中对数据进行分页并进行测试?

Best what you could do is to replace the <ui:fragment> by JSTL tags like <c:if> / <c:choose> so that it evaluates during build time, not during render time. 最好的方法是用<c:if> / <c:choose>等JSTL标签替换<ui:fragment> ,使其在构建期间而不是在渲染时评估。 Or, alternatively, build the component tree in the backing bean constructor instead of in the view. 或者,或者,在支持bean构造函数中而不是在视图中构建组件树。

One possibility might be to use the binding attribute to access a container component from inside your managed bean and build the component tree from the java side. 一种可能性是使用binding属性从托管bean内部访问容器组件,并从java端构建组件树。 That way you could include only the needed components, unneeded components won't be evaluated at all. 这样,您可以只包含所需的组件,根本不会评估不需要的组件。

JSP: JSP:

<h:panelGroup binding="#{managedBean.panel}"/>

Managed Bean: 托管Bean:

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";
}

I haven't used this together with composite components yet, this question seems to have some more details and an example application regarding using this with composite components. 我还没有将它与复合组件一起使用, 这个问题似乎有更多的细节和一个关于将它与复合组件一起使用的示例应用程序

Edit: Regarding your edit, you can also evaluate EL expressions in your managed bean like this: 编辑:关于您的编辑,您还可以在托管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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM