Подтвердить что ты не робот

Почему срабатывает обратный вызов @PostConstruct каждый раз, даже если bean является @ViewScoped? JSF

Я использую datatable на странице и используя атрибут привязки, чтобы привязать его к моей поддержке bean. Это мой код: -

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

Это мой bean: -

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!!");

    }
}

Скажите, пожалуйста, почему @PostConstruct запускается каждый раз, когда я нажимаю кнопку? Он должен срабатывать только один раз, пока я на той же странице, потому что мой bean - @ViewScoped. Кроме того, если я удаляю атрибут привязки, все работает нормально, а обратный вызов @PostConstruct срабатывает только один раз. Тогда почему каждый раз, когда я использую атрибут привязки? Мне нужен атрибут привязки и вы хотите выполнять задачи инициализации, такие как выборка данных из webservice и т.д. Только один раз. Что мне делать? Где я должен написать свою задачу инициализации?

4b9b3361

Ответ 1

Интересно, что когда вы используете привязку компонента в области с видимым охватом bean, область просмотра ломается.

Я не уверен, что это ошибка в JSF2, сначала мне нужно будет прочитать всю спецификацию JSF2. Пока что лучше всего отказаться от привязки компонента и передать выделенный элемент через новый синтаксис аргумента метода 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>

См. также:


Обновление (декабрь 2012): это действительно ошибка в JSF2. Это проблема с куриным яйцом. Область просмотра beans хранится в состоянии представления JSF. Таким образом, область просмотра beans доступна только после фазы просмотра восстановления. Однако атрибут binding выполняется во время фазы просмотра, в то время как область просмотра beans пока недоступна. Это приводит к созданию нового экземпляра bean с расширенным представлением, который затем заменяется реальным видом scope bean, который был сохранен в восстановленном состоянии представления JSF.

Об этом сообщается как JSF issue 1492 и JSF spec isssue 787, который будет установлен для JSF 2.2. До тех пор вам будет лучше всего использовать binding по запросу beans или искать альтернативные способы для конкретного функционального требования.


Обновление (март 2015 г.): исправление JSF 2.2 было передано в Mojarra 2.1.18. Поэтому, если вы все еще используете JSF 2.0/2.1, вам лучше всего обновить хотя бы эту версию. См. Также a.o. Что такое связывание компонентов в JSF? Когда предпочтительнее использовать? и JSTL в JSF2 Facelets... имеет смысл?

Ответ 2

Как сказал другой, я бы сказал, что лучше всего отказаться от привязки компонента (здесь вам это не нужно).

Но я бы добавил, что вы можете достичь того же, что вы пытаетесь сделать более объектно-ориентированным способом, используя параметры действия, например:

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

... и в вашем java-коде:

  public void action(Item item){
    System.out.println("Clicked!!" + item);
}

Ответ 3

Если у вас есть viewcoped bean, и если вы хотите сохранить значения, которые были введены в форме или не хотите, чтобы postconstruct был запущен, вы должны вернуть null из своего метода действий.

Если вы вернете какой-то результат (например, недопустимый), а затем укажите неверный результат на ту же страницу с помощью faces-config.xml, то viewcoped bean будет воссоздан, и, таким образом, он снова запустит postconstruct.

Ответ 4

Другое решение:

  • Связывание HtmlDataTable в области запроса bean.
  • Внесите эту область запроса bean в область представления bean.

JBoss Seam использует это решение для связывания компонентов JSF с компонентом области разговора.

Ответ 5

Ответ на балус мне очень помог, я бы хотел сказать, что у меня была эта ошибка с версией mojarra 2.1.7, в настоящее время я использую 2.1.29-01, выпущенный в январе 2015 года, и эта ошибка исправлена, моя проблема привязывал tabview к просмотренному bean. С этой версией у меня нет этой ошибки, а привязка и постконструкция работают нормально. Я использую Jboss 5.2, и мне нужно использовать mojarra 2.1.x, поэтому я надеюсь, что этот ответ поможет другим людям в той же ситуации.

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