Пользовательский интерфейс JSF: представление с фрагментами - PullRequest
2 голосов
/ 16 мая 2011

У меня есть набор компонентов jsf, которые статически генерируются из набора файлов Excel (они обновляются деловыми людьми).Каждый сгенерированный файл представляет бизнес-объект, который имеет немного разные данные, и все они принадлежат одному и тому же классу.

Для динамического рендеринга единственное решение, которое я нашел, было настроить группу * 1003.* и отправка в нужный компонент во время выполнения:

<!-- 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*, представляет собой огромную сложную страницу с множеством других компонентов.Во время выполнения, параметр с именем type' will decide what component to render. But my tests show that if I only render one component, but leave the other ui: фрагменты (даже зная, что они не будут отображаться), будет рендерить намного медленнее, чем если бы я удалил компоненты.

Так что еслимоя страница выглядит примерно так:

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

Ответы [ 2 ]

8 голосов
/ 16 мая 2011

Да, атрибут rendered оценивается во время визуализации, а не во время сборки.Да, это относительно ужасно.Представьте, что одно такое условие стоит 1 мс, оценка десяти из них займет в 10 раз больше, 10 мс.Если у вас есть десять таких компонентов в разбивке по страницам, время загрузки веб-приложения займет 0,1 секунды дольше.Около одной дужки.Но если вы не разбираетесь в страницах и / или не используете MSIE в качестве эталонного браузера, это займет гораздо больше времени.Вы разбиваете на страницы данные и тестируете в соответствующих браузерах?

Лучшее, что вы можете сделать, - это заменить <ui:fragment> на JSTL-теги, такие как <c:if> / <c:choose>, чтобы они оценивались во время сборки, а не во времявремя рендеринга.Или, в качестве альтернативы, создайте дерево компонентов в конструкторе базового компонента, а не в представлении.

2 голосов
/ 16 мая 2011

Одной из возможностей может быть использование атрибута binding для доступа к контейнеру компонент внутри вашего управляемого компонента и построить дерево компонентов из Ява сторона Таким образом, вы можете включить только необходимые компоненты, ненужные компоненты не будут оцениваться вообще.

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

Я еще не использовал это вместе с составными компонентами, этот вопрос , похоже, содержит некоторые дополнительные детали и пример приложения относительно использования этого с составными компонентами.

Редактировать: Что касается вашего редактирования, вы также можете оценивать выражения 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...