Почему метод BackingBean вызывается несколько раз при запросе facelet?

StackOverflow https://stackoverflow.com/questions/2272289

  •  20-09-2019
  •  | 
  •  

Вопрос

В эти дни я работаю и изучаю JSF + Facelets.У меня есть BackingBean и страница Facelet xHTML.Когда я запрашиваю facelet-страницу (только один раз), метод 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;
    }

}
Это было полезно?

Решение

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

Если getApplication().getKunden(getNameFilterPattern()); выполняет довольно дорогостоящую задачу, вам действительно следует переместить ее либо в конструктор bean, либо в bean @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 параметр запроса), или просто метод bean action (если nameFilterPattern должен быть получен из POST поле ввода формы) подходит.

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

Другие советы

Он может быть вызван из разных фазы из цикла жизненного цикла 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) и убедитесь, что вы загружаете данные только один раз за запрос.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top