Pregunta

Estoy trabajando y aprendiendo sobre JSF + Facelets en estos días. Tengo un BackingBean y una página Facelet xHTML. Cuando solicito el facelet-página (sólo una vez) el respaldo-bean-método es llamado varias veces.

¿Cuál podría ser la razón de esto?

No puedo ver nada especial. Gracias de antemano.

Aquí es el 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>

Y aquí está el respaldo de frijol. El getKunden método es llamado varias veces:

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

}
¿Fue útil?

Solución

Los captadores de un grano sólo están ahí para de acceso los datos del modelo de la vista lateral. Se les puede llamar varias veces. Por lo general, una o dos veces, pero esto puede crecer hasta cientos de veces, especialmente cuando se utiliza también en componentes UIData o en otros atributos que value (como rendered, disabled, etc). Esto normalmente no hace daño, ya que es sólo un simple método de invocación y haciendo cálculos de la lógica o la carga de datos caro es por lo general no se debe hacer en los captadores. Precarga / inicialización es por lo general que se haga en el constructor de frijol y / o métodos de acción de frijol. Compuestos absorbentes deberían de hecho, sólo rendimiento los datos (si es necesario también hacer carga diferida ).

Si getApplication().getKunden(getNameFilterPattern()); está haciendo una tarea bastante caro, que realmente debería mover a cualquiera de las constructor de frijol, o método @PostConstruct frijol, o bloque de inicialización de frijol, o método de acción frijol, o introducir carga diferida patrón en el captador. He aquí un ejemplo que muestra cómo hacer todo esto:

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

En su caso específico, creo que es el @PostConstruct (si el nameFilterPattern debe ser obtenido a partir de un parámetro de petición GET), o simplemente el método de acción frijol (si nameFilterPattern debe ser obtenida de un campo de entrada de forma POST) es adecuado .

Para obtener más información sobre el ciclo de vida de JSF, puede encontrar esta auto- la práctica artículo útil.

Otros consejos

Puede ser llamado de diferente fases de la lifecylce JSF. Mi apuesta sería la RestoreView fases y luego RenderResponse - No he estado usando JSF últimamente, por lo que no recuerde esto en detalle.

Puede almacenar en caché el último patrón del filtro y los clientes correspondientes. Que vuelva a cargar los clientes sólo si el filtro ha cambiado. De esta manera, se resuelve este problema en particular, además de evitar la recarga de datos si el filtro no cambió.

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

O puede utilizar un grano request (en lugar de session) y asegúrese de cargar los datos una sola vez por solicitud.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top