Frage

Ich arbeite und das Lernen über JSF + Facelets in diesen Tagen. Ich habe einen BackingBean und eine Facelet xHTML Seite. Als ich die Facelet-Seite (nur einmal) der Träger-Bean-Methode aufrufen, wird mehrmals aufgerufen.

Was ist der Grund dafür sein könnte?

Ich kann nichts Besonderes sehen. Vielen Dank im Voraus.

Hier ist die Facelet:

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

Und hier ist die Träger-Bohne. Das Verfahren getKunden wird mehrmals aufgerufen:

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

}
War es hilfreich?

Lösung

Die Getter einer Bohne sind nur dort zu Zugriff Modelldaten aus der Sichtseite. Sie können mehrfach aufgerufen werden. In der Regel ein oder zwei Mal, aber dies kann bis zu mehrere hundert Mal wachsen, vor allem, wenn auch in UIData Komponenten oder in anderen Attributen als value verwendet (wie rendered, disabled, etc). Dies gilt normalerweise nicht schaden, da es nur ein einfacher Methode-Aufruf und teure Datenladelogik oder Berechnungen zu tun ist in der Regel nicht in den Getter zu tun. Preloading / Initialisierung wird in der Regel in dem Bean-Konstruktor und / oder Bean Action-Methode durchgeführt werden. Getter sollte in der Tat nur zurück die Daten (falls notwendig auch tun verzögertes Laden ).

Wenn getApplication().getKunden(getNameFilterPattern()); ist eine ziemlich teure Aufgabe zu tun, sollten Sie wirklich es entweder auf die Bohne Konstruktor bewegen, oder Bohnen @PostConstruct Methode oder Bohnen Initialisierungsbaustein oder Bohnenaktionsmethode oder einführen verzögertes Laden Muster in dem Getter. Hier ist ein Beispiel dafür, wie das alles tun:

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

In Ihrem speziellen Fall, ich denke, es das @PostConstruct ist (wenn die nameFilterPattern von einem GET Anforderungsparameter erhalten werden soll), oder einfach nur die Bohne Aktionsmethode (wenn nameFilterPattern von einem POST Form Eingabefeld erhalten werden soll) geeignet ist, .

mehr über den JSF-Lebenszyklus zu lernen, können Sie dieses Selbst Praxis-Artikel nützlich.

Andere Tipps

Es kann aus verschiedenen Phasen des JSF Lifecylce. Meine Wette würde die Phasen RestoreView und dann RenderResponse - ich habe nicht gewesen in letzter Zeit JSF verwenden, so dass ich das kann mich nicht erinnern im Detail.

Sie können die neueste Filtermuster-Cache und die entsprechenden Clients. Sie laden Sie die Kunden nur dann, wenn die Filter gewechselt. Auf diese Weise lösen Sie dieses besondere Problem, und vermeidet, dass Daten neu geladen, wenn die Filter nicht ändern.

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

Sie können auch eine request Bohne (statt session) verwenden und stellen Sie sicher, dass Sie die Daten pro Anfrage nur einmal geladen werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top