2010-02-16 22 views
5

Bugünlerde JSF + Facelets hakkında çalışıyorum ve çalışıyorum. Bir BackingBean ve bir Facelet xHTML sayfam var. Facelet sayfası istediğimde (sadece bir kez) destek-fasulye yöntemi birden çok kez çağrılır.Neden facelet isterken BackingBean yöntemi birden çok kez çağrıldı?

Bunun nedeni ne olabilir?

Özel bir şey göremiyorum. Şimdiden teşekkürler. İşte

facelet geçerli:

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

Ve burada sırt-fasulye olduğunu. yöntem getKunden birden çok kez verilir:

@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

Her zaman aynı sayıda çağrılır mı? – volvox

+0

IDE hata ayıklama modunuzu birden çok kez denilen yöntemleri doğrulamak için mi yoksa günlüklerde mi görüyorsunuz? – Roman

+0

İlk istekte 8 kez denir ve bundan sonra 21 kez denir.Eclipse + glassfish kullanıyorum ve hata ayıklama modunda başlattım. Yönteme sadece bir sysout ekledim ve konsol çıktılarını saydım. – c0d3x

cevap

8

Fasulye tokmakları, görünümden erişim model verilerinin yanındadır. Birden çok kez çağrılabilirler. Genellikle bir veya iki kez, ancak bu yüzlerce kez, özellikle de UIData bileşenlerinde veya value (rendered, disabled, vb. Gibi) diğer özelliklerde kullanıldığında büyüyebilir. Bu normalde zarar vermez, çünkü sadece basit bir yöntem-çağırma ve pahalı veri yükleme mantığı ya da hesaplamalar yapmak genellikle alıcılarda yapılmaz. Ön yükleme/başlatma genellikle fasülye yapımcısı ve/veya fasülye eylem yöntemlerinde yapılır. Getters aslında sadece veri döndürmelidir (gerekirse tembel yükleme). getApplication().getKunden(getNameFilterPattern()); oldukça pahalı bir görev yapıyorsa

, gerçekten fasulye yapıcısı veya fasulye @PostConstruct yöntemini veya fasulye başlatma bloğu veya fasulye eylem yöntemi ya taşıyın ya gaz giderici içinde geç yükleme desen tanıtmalıdır. İşte bunu nasıl yapacağınızı gösteren bir örnek bu hepsi:

özel durumda
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; 
    } 

, ben @PostConstruct olduğunu düşünüyorum (ya da sadece fasulye eylem yöntemi (nameFilterPattern bir GET istek parametresinden elde edilecek ise) nameFilterPattern'un POST form giriş alanından alınması durumunda) uygundur.

JSF yaşam döngüsü hakkında daha fazla bilgi için, bu self-practice article yararlı bulabilirsiniz.

+0

Güzel cevap, btw :) http://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times – ewernli

+0

Evet, kesinlikle böyle ilk defa cevap vermedim :) en az 20 kere önce. Sadece burada değil, forums.sun.com'da da var. – BalusC

2

Bu MTU lifecylce farklı phases çağrılabilir. Bahislerim RestoreView ve RenderResponse aşamaları olacaktı - son zamanlarda JSF kullanmıyorum, bu yüzden bunu ayrıntılı olarak hatırlamıyorum.

En son filtre desenini ve ilgili istemcileri önbelleğe alabilirsiniz. İstemcileri sadece filtre değiştiyse yeniden yüklersiniz. Bu şekilde, bu sorunu çözüyorsunuz, ayrıca filtre değişmediyse verileri yeniden yüklemekten kaçının.

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

Yoksa (yerine session ait) bir request fasulye kullanmak ve istek başına sadece bir kez veri yüklemek emin olabiliriz.

+0

Yanıtladığınız için teşekkür ederiz. Fasulyeyi kapsam isteyecek şekilde değiştirdim. Davranış aynıdır. Verileri yalnızca istek başına yedeklemeyi nasıl yüklerim? Facelet'te de görebileceğiniz gibi, yöntem sadece bir kez referans alınır. Bu şema şablonla ilgili olabilir: ui: composition/ui: define? – c0d3x

+0

Kabul ettiğiniz BalusC'nin cevabı her şeyi kapsar. Daha fazla açıklamaya ihtiyacın yok sanırım. – ewernli

İlgili konular