Question

Je travaille et l'apprentissage JSF + Facelets ces jours-ci. J'ai un BackingBean et une page xHTML Facelet. Lorsque je demande la Facelet pages (une seule fois) le procédé de support de haricots est appelée à plusieurs reprises.

Quelle pourrait être la raison?

Je ne vois rien de spécial. Merci à l'avance.

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

Et voici le soutien-haricot. La méthode getKunden est appelée plusieurs fois:

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

}
Était-ce utile?

La solution

Les getters d'un haricot sont juste là pour accès données de modèle à partir du côté de la vue. Ils peuvent être appelés à plusieurs reprises. Habituellement, une ou deux fois, mais cela peut se développer jusqu'à des centaines de fois, surtout quand également utilisé dans les composants de UIData ou dans d'autres attributs que value (comme rendered, disabled, etc.). Cela ne normalement pas de mal, car il est juste une méthode simple invocation et de faire coûteuse logique de chargement de données ou le calcul est généralement pas à faire dans les apporteurs. Préchargement / initialisation est habituellement à faire dans le constructeur de haricots et / ou des méthodes d'action de haricots. Getters devrait en effet que retour les données (si nécessaire aussi faire chargement paresseux ).

Si getApplication().getKunden(getNameFilterPattern()); fait une tâche assez cher, vous devriez vraiment aller à soit le constructeur de haricots, ou la méthode de @PostConstruct de haricots, ou le bloc d'initialisation de haricots, ou méthode d'action de haricots, ou d'introduire chargement paresseux modèle dans le getter. Voici un exemple qui montre comment faire tout cela:

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

Dans votre cas, je pense qu'il est le @PostConstruct (si le nameFilterPattern doit être obtenu à partir d'un paramètre de requête GET), ou tout simplement la méthode d'action de haricot (si nameFilterPattern doit être obtenu à partir d'un champ de saisie de formulaire POST) convient .

Pour en savoir plus sur le cycle de vie JSF, vous pouvez trouver ce auto article pratique utile.

Autres conseils

Il peut être appelé de différentes phases du lifecylce JSF. Mon pari serait les phases RestoreView puis RenderResponse - Je ne l'ai pas été en utilisant JSF ces derniers temps, donc je ne me souviens pas en détail.

Vous pouvez mettre en cache le dernier modèle de filtre et les clients correspondants. Vous rechargerez les clients que si le filtre a changé. De cette façon, vous résoudre ce problème particulier, ainsi que d'éviter les données rechargeant si le filtre n'a pas changé.

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

Vous pouvez aussi utiliser un grain de request (au lieu de session) et assurez-vous de charger les données qu'une seule fois par demande.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top