Почему метод BackingBean вызывается несколько раз при запросе facelet? - PullRequest
5 голосов
/ 16 февраля 2010

Я работаю и узнаю о JSF + Facelets в эти дни. У меня есть страница BackingBean и Facelet xHTML. Когда я запрашиваю лицевую страницу (только один раз), метод backing-bean-метода вызывается несколько раз.

В чем может быть причина этого?

Я не вижу ничего особенного. Заранее спасибо.

Вот лицо:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Insert title here</title>
</head>
<body>
<ui:composition template="index.xhtml">
    <ui:define name="content">
        <h:form>Name: <h:inputText id="nameFilterPattern" value="#{kundenBackingBean.nameFilterPattern}" /><h:commandButton value="Suchen"/></h:form>
        <h:dataTable var="kunde" value="#{kundenBackingBean.kunden}" rowClasses="rowHighlight, rowOrdinary">
            <h:column> 
                <f:facet name="header">
                    <h:outputText value="Kundennr" />
                </f:facet>
                <h:outputText value="#{kunde.kundenNr}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Name" />
                </f:facet>
                <h:outputText value="#{kunde.name}"/>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Vorname" />
                </f:facet>
                <h:outputText value="#{kunde.vorname}"/>
            </h:column>
            <h:column>
                <h:outputLink>Details</h:outputLink>
            </h:column>
        </h:dataTable>
    </ui:define>
</ui:composition>
</body>
</html>

А вот и бэк-бин. Метод getKunden вызывается несколько раз:

@ManagedBean
@SessionScoped
public class KundenBackingBean extends AbstractBackingBean {

    private String nameFilterPattern;

    public List<Kunde> getKunden(){
        System.out.println("getKunden");
        return getApplication().getKunden(getNameFilterPattern());
    }

    public String getNameFilterPattern() {
        return nameFilterPattern;
    }

    public void setNameFilterPattern(String nameFilterPattern) {
        System.out.println("Name filter: " + nameFilterPattern);
        this.nameFilterPattern = nameFilterPattern;
    }

}

Ответы [ 2 ]

8 голосов
/ 16 февраля 2010

Получатели компонента только для доступа к данным модели со стороны вида. Их можно вызывать несколько раз. Обычно один или два раза, но это может возрасти в сотни раз, особенно когда оно также используется в UIData компонентах или в других атрибутах, отличных от value (например, rendered, disabled и т. Д.). Обычно это не наносит вреда, так как это простой вызов метода и выполнение дорогостоящей логики загрузки данных или вычислений, как правило, не выполняется в методах получения. Предварительная загрузка / инициализация обычно выполняется в конструкторе компонентов и / или в методах действия компонента. Фактически, получатели должны только возвращать данные (при необходимости также выполнять отложенная загрузка ).

Если getApplication().getKunden(getNameFilterPattern()); выполняет довольно дорогое задание, вам действительно следует переместить его либо в конструктор компонента, либо в метод @PostConstruct компонента, либо в блок инициализации компонента, либо в метод действия компонента, либо ввести отложенную загрузку шаблон в геттере. Вот пример, который показывает, как сделать все это:

public class Bean {
    private String nameFilterPattern;
    private List<Kunde> kunden;

    // Load during bean construction.
    public Bean() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR load during @PostConstruct (will be invoked AFTER construction and resource injection.
    @PostConstruct
    public void init() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean initialization (this is invoked BEFORE construction and will apply to ALL constructors).
    {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
    }

    // OR during bean action method (invoked from h:commandLink/Button).
    public String submit() {
        this.kunden = getApplication().getKunden(getNameFilterPattern());
        return "navigationCaseOutcome";
    }

    // OR using lazy loading pattern in getter method.
    public List<Kunde> getKunden() {
        if (this.kunden == null) 
            this.kunden = getApplication().getKunden(getNameFilterPattern());
        }
        return this.kunden;
    }

В вашем конкретном случае я думаю, что это @PostConstruct (если nameFilterPattern должен быть получен из параметра запроса GET), или просто метод действия компонента (если nameFilterPattern должен быть получен из POST поле ввода формы).

Чтобы узнать больше о жизненном цикле JSF, вы можете найти эту полезную статью полезной.

2 голосов
/ 16 февраля 2010

Может вызываться из разных фаз жизненного цикла JSF. Моя ставка была бы фазы RestoreView, а затем RenderResponse - я не использовал JSF в последнее время, поэтому я не помню это подробно.

Вы можете кэшировать последний шаблон фильтра и соответствующие клиенты. Вы перезагружаете клиентов, только если фильтр изменился. Таким образом, вы решаете эту конкретную проблему, а также избегаете перезагрузки данных, если фильтр не изменился.

private String nameFilterPattern;
private String lastNameFilterPatternLoaded;
private List<Kunde> clients;

public List<Kunde> getKunden(){
    System.out.println("getKunden");
    if( nameFilterPattern.equals( lastNameFilterPatternLoaded ) )
    {
        clients = getApplication().getKunden(getNameFilterPattern());
        lastNameFilterPatternLoaded = nameFilterPattern
    }
    return clients;
}

Или вы можете использовать компонент request (вместо session) и убедиться, что вы загружаете данные только один раз за запрос.

...