2010-02-16 6 views
5

Je travaille et j'apprends sur JSF + Facelets ces jours-ci. J'ai un BackingBean et une page Facelet xHTML. Lorsque je demande la page facelet (une seule fois), la méthode backing-bean est appelée plusieurs fois.Pourquoi la méthode BackingBean est-elle appelée plusieurs fois lors de la demande de facelet?

Quelle pourrait être la raison?

Je ne vois rien de spécial. Merci d'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; 
    } 

} 
+0

est-il toujours appelé le même nombre de fois? – volvox

+0

utilisez-vous votre mode de débogage IDE pour vérifier que les méthodes appelées plusieurs fois ou vous le voyez dans les journaux? – Roman

+0

Il semble que, à la première demande, il est appelé 8 fois et ensuite il est appelé 21 fois.J'utilise eclipse + glassfish et l'ai démarré en mode debug. J'ai simplement inséré un sysout dans la méthode et compté les sorties de la console. – c0d3x

Répondre

8

Les getters d'un haricot sont juste là pour accéder données de modèle du côté de vue. Ils peuvent être appelés plusieurs fois. Habituellement, une ou deux fois, mais cela peut se développer jusqu'à des centaines de fois, surtout quand également utilisé dans UIData composants ou dans d'autres attributs que value (comme rendered, disabled, etc.). Cela ne fait normalement pas de mal, car il s'agit simplement d'une simple invocation de méthode et de faire une logique de chargement de données onéreuse ou des calculs qui ne sont généralement pas effectués dans les getters. Le préchargement/l'initialisation est généralement effectué dans le constructeur du bean et/ou dans les méthodes d'action du haricot. Accesseurs doivent en effet que retour les données (si nécessaire aussi faire chargement paresseux).

Si getApplication().getKunden(getNameFilterPattern()); est en train de faire une tâche assez cher, vous devriez vraiment aller à soit le constructeur de haricots, ou méthode haricot @PostConstruct ou bloc d'initialisation de haricots, ou méthode d'action de haricots, ou d'introduire modèle de chargement paresseux 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) est approprié.

Pour en savoir plus sur le cycle de vie JSF, vous pouvez trouver ce self-practice article utile.

+0

Bonne réponse, btw :) http://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times – ewernli

+0

Oui, ce n'est certainement pas la première fois que j'ai répondu comme ça :) Je l'ai répondu au moins 20 fois avant. Non seulement ici, mais aussi sur forums.sun.com et ainsi de suite. – BalusC

2

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

Vous pouvez mettre en cache le dernier modèle de filtre et les clients correspondants. Vous rechargez les clients uniquement si le filtre a changé. De cette façon, vous résolvez ce problème particulier, plus évitez de recharger des données 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; 
} 

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

+0

Merci d'avoir répondu. J'ai changé le bean pour demander la portée. Le comportement est le même. Comment puis-je m'assurer de charger les données uniquement par requête? Comme vous pouvez le voir dans le facelet, la méthode n'est référencée qu'une seule fois. Est-ce que cela peut être lié au truc du template: ui: composition/ui: define? – c0d3x

+0

La réponse de BalusC que vous avez acceptée couvre tout. Je suppose que vous n'avez pas besoin d'explications supplémentaires. – ewernli

Questions connexes