Dlaczego @ PostConstruct callback odpala się za każdym razem, mimo że bean to @ViewScoped? JSF

Używam datatable on page i używam atrybutu binding, aby powiązać go z moim backing bean. To jest mój kod: -

<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
            <h:form prependId="false">

                <h:dataTable var="item" value="#{testBean.stringCollection}" binding="#{testBean.dataTable}">
                    <h:column>
                        <h:outputText value="#{item}"/>
                    </h:column>
                    <h:column>
                        <h:commandButton value="Click" actionListener="#{testBean.action}"/>
                    </h:column>
                </h:dataTable>

            </h:form>

    </h:body>
</html>

To moja fasola:-

package managedBeans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.html.HtmlDataTable;

@ManagedBean(name="testBean")
@ViewScoped
public class testBean implements Serializable {

    private List<String> stringCollection;

    public List<String> getStringCollection() {
        return stringCollection;
    }

    public void setStringCollection(List<String> stringCollection) {
        this.stringCollection = stringCollection;
    }

    private HtmlDataTable dataTable;

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }

    @PostConstruct
    public void init(){
        System.out.println("Post Construct fired!!");
        stringCollection = new ArrayList<String>();
        stringCollection.add("a");
        stringCollection.add("b");
        stringCollection.add("c");

    }

    public void action(){
        System.out.println("Clicked!!");

    }
}

Powiedz mi, dlaczego @PostConstruct odpala za każdym razem, gdy klikam na przycisk? Powinien odpalić tylko raz, tak długo, jak jestem na tej samej stronie beacause moja fasola jest @ ViewScoped. Co więcej, jeśli usunę atrybut wiążący, to wszystko działa dobrze i wywołanie zwrotne @ PostConstruct zostanie wywołane tylko raz. To dlaczego za każdym razem kiedy używam wiązania / align = "left" / Potrzebuję atrybutu wiążącego i chcę wykonać zadania inicjalizacji, takie jak pobieranie danych z webservice, itp tylko raz. Co mam zrobić? Gdzie powinienem napisać zadanie inicjalizacji?

Author: BalusC, 2010-05-09

5 answers

Interesujące, gdy używasz wiązania komponentów na widoku fasoli, zakres widoku się łamie.

Nie jestem pewien, czy to błąd w JSF2, musiałbym najpierw przeczytać całą specyfikację JSF2. Na razie najlepszym rozwiązaniem jest porzucenie wiązania komponentu i przekazanie wybranego elementu za pomocą nowej składni argumentu metody EL 2.2:

<h:dataTable var="item" value="#{testBean.stringCollection}">
    <h:column>
        <h:outputText value="#{item}"/>
    </h:column>
    <h:column>
        <h:commandButton value="Click" action="#{testBean.action(item)}"/>
    </h:column>
</h:dataTable>

Zobacz też:


Update (grudzień 2012): jest to rzeczywiście błąd w JSF2. To kwestia jaj kurzych. Zakresy widoku są przechowywane w stanie widoku JSF. Tak więc fasolki z lunetą widoku są dostępne tylko po fazie przywracania widoku. Jednak atrybut binding działa podczas fazy przywracania widoku, podczas gdy fasolki z zakresem widoku nie są jeszcze dostępne. Powoduje to tworzenie zupełnie nowej instancji view scoped bean, która jest później zastąpiona przez real view scoped bean, która została zapisana w przywróconym stanie widoku JSF.

Jest to zgłoszone jakoJSF issue 1492 iJSF spec isssue 787 , które zostaną ustalone dla JSF 2.2. Do tego czasu najlepiej jest używać binding wyłącznie na życzenie, lub szukać alternatywnych sposobów na konkretne wymagania funkcjonalne.


Aktualizacja (Marzec 2015): poprawka JSF 2.2 była powrót do Mojarra 2.1.18. Więc jeśli nadal używasz JSF 2.0/2.1, najlepiej uaktualnić do co najmniej tej wersji. Zobacz także a. o. Co to jest Wiązanie komponentów w JSF? Kiedy jest preferowany do stosowania? i JSTL w Jsf2... to ma sens?

 32
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:28

Jak powiedział inny, powiedziałbym, że najlepszą rzeczą do zrobienia jest porzucenie wiązania komponentów (nie potrzebujesz go tutaj).

Ale dodam, że możesz osiągnąć to samo, co próbujesz zrobić w bardziej obiektowy sposób, używając parametrów akcji, takich jak:

<h:commandButton value="Click" action="#{testBean.action(item)}"/>

... oraz w kodzie Javy:

  public void action(Item item){
    System.out.println("Clicked!!" + item);
}
 4
Author: ymajoros,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 15:10:16

Jeśli masz viewscoped bean i chcesz zachować wartości, które zostały wprowadzone w formularzu lub nie chcesz, aby postconstruct został zwolniony, powinieneś zwrócić null Z metody akcji.

Jeśli zwrócisz jakiś wynik (np. nieprawidłowy), a następnie skierujesz nieprawidłowy wynik na tę samą stronę za pomocą faces-config.xml, następnie zostaje odtworzony widok i tym samym powoduje ponowne odpalenie postconstruct.

 0
Author: Pramod Kankure,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-26 17:39:20

Inne rozwiązanie:

  • Wiązanie HtmlDataTable w zakresie żądania.
  • Wprowadź ten zakres żądania Bean do widoku scope Bean.

JBoss Seam użyj tego rozwiązania, aby powiązać komponent JSF z komponentem zakresu konwersacji.

 0
Author: Juan Miguel Bernal González,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 15:50:49

Odpowiedź balusca bardzo mi pomogła, chciałbym powiedzieć, że miałem ten błąd z mojarra w wersji 2.1.7, obecnie używam 2.1.29-01 wydanej w styczniu 2015 i ten błąd został naprawiony, mój problem polegał na powiązaniu widoku tabview z viewscoped bean. Z tą wersją Nie mam tego błędu i bindowanie i postconstruct działa dobrze. Używam Jboss 5.2 i muszę użyć mojarra 2.1.x więc mam nadzieję, że ta odpowiedź pomoże innym ludziom w tym samym sytuacja.

Http://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.1.29-01 http://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.1.29-01

 0
Author: Luis Vidal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-20 12:54:40