Бин @SessionScoped, внедренный как @ManagedProperty @ViewScoped, действует как @RequestScoped в MyFaces, отлично работает в Mojarra

Вот мой простой пример:

Index.xhtml в корне:

<?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">
    <h:head>
        <title>Title</title>
    </h:head>
    <h:body>
        <h:form>
            <h:inputText value="#{index.variable}"></h:inputText>
            <h:commandButton action="#{index.submit()}" type="submit"></h:commandButton>
        </h:form>
    </h:body>
</html>

Его ManagedBean:

import java.io.IOException;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

@ManagedBean
@ViewScoped
public class Index implements Serializable {

    @ManagedProperty("#{sessionBean}")
    private SessionBean sessionBean; /*getter&setter*/
    private String variable; /*getter&setter*/

    public void submit() {
        sessionBean.setAsd(variable);
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        try {
            context.redirect("next");
        } catch (IOException ex) {
        }
    }
}

/next/index.xhtml:

<?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">
    <h:head>
        <title>Check variable</title>
    </h:head>
    <h:body>
        #{sessionBean.asd}
    </h:body>
</html>

SessionBean.java:

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class SessionBean implements Serializable {

    private String asd;

    public String getAsd() {
        return asd;
    }

    public void setAsd(String asd) {
        this.asd = asd;
    }
}

Если я использую реализацию mojarra, все работает как положено: после отправки формы пользователь перенаправляется на root/ и увидеть значение, которое было напечатано в виде index.xhtml,

Но если я использую мои лица, asd становится недействительным сразу после отправки существующей формы. SessionScoped бин действует как RequestScoped

Зачем?


вот мой web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <listener>
        <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
        <!--listener-class>com.sun.faces.config.ConfigureListener</listener-class-->
    </listener>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

Сервер: Apache Tomcat 7.0.34

ОБНОВЛЕНИЕ: это работает, если мы изменим ViewScoped аннотация Index.java bean в RequestScoped или же SessionScoped, Но почему?

1 ответ

Решение

В настоящее время у меня есть проект JSF 2.1, написанный с помощью Mojarra. Просто для экспериментов я изменил реализацию на MyFaces и запустил приложение только для того, чтобы увидеть проблемы, похожие на ваши (все мои введенные переменные @ManagedProperty заканчиваются нулевым значением после отправки POST). Я снова переключился на Мохарру, и приложение работает нормально. Так что, в принципе, в реализации MyFaces что-то другое.

Небольшое приближение привело меня к этой нерешенной проблеме - MYFACES-3656. Вот выдержка из репортера проблемы о том, как решить проблему:

Если для org.apache.myfaces.SERIALIZE_STATE_IN_SESSION задано значение false и повторное развертывание приложения, то все работает, как ожидается.

Как это поможет? Ответ в разделе комментариев:

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

То, что происходит здесь, в MyFaces по умолчанию имеет значение true (некоторые старые строки из спецификации JSF 1.0 говорят об этом, даже если RI не реализует это таким образом). В спецификации JSF 2.2 параметр SERIALIZE_STATE_IN_SESSION будет стандартизирован и по умолчанию установлен в значение false.

Сериализация приводит к тому, что все bean-объекты в области видимости фактически "воссоздаются". Если для параметра установлено значение false, бины сохраняются в сеансе и при дальнейших запросах используются, похоже, что все в порядке, но это не так, потому что в конфигурации кластера произойдет сбой того же приложения.

Только в первый раз, когда создается компонент области представления, вступают в силу ссылки из управляемого свойства, но если компонент сериализуется / десериализуется, ссылки не восстанавливаются обратно, поскольку на этапе сериализации даже компоненты области приложения и сеанса работают. Сериализован тоже.

.....

Как это решить? Я не нашел достойного решения этой проблемы. Можно подумать о том, чтобы просто восстановить bean-компонент области видимости и повторно применить аннотации @ManagedProperty или записи, найденные в face-config.xml, но проблема в том, что bean-компонент области видимости по-прежнему хранит информацию, которой не должно быть с самого начала (только отмечая поля как переходный процесс сделает свое дело). Можно определить специальный режим, если этот хак или какой-то другой вариант уже выполнен, но он будет только у меня и не может быть включен по умолчанию.

О подобной проблеме сообщили и ответили с вышеупомянутым объяснением в этом архиве списка рассылки

Теперь, так как в вашем случае вы явно не устанавливаете STATE_SAVING_METHOD По умолчанию это сервер. Как следствие, SERIALIZE_STATE_IN_SESSION вступает в силу и по умолчанию имеет значение true.

Я попробовал ваш код с MyFaces на Tomcat и установил для SERIALIZE_STATE_IN_SESSION значение false, и это работает. Однако в случае, если вы установите клиент STATE_SAVING_METHOD, ничего не будет работать, и вы получите ошибку состояния просмотра не найдена.

Другие вопросы по тегам