Проблема с JSF с истекшим сроком действия viewScope

#jakarta-ee #jsf-2 #tomcat6 #jsf-2.2 #omnifaces

#джакарта-ee #jsf-2 #tomcat6 #jsf-2.2 #omnifaces

Вопрос:

Я использую JSF2.2 и Tomcat 6.0.35. У меня есть приложение, в котором мы отображаем и редактируем данные пользователя. Я отправляю запрос ajax, чтобы выполнить некоторую обработку при изменении каждого ввода для редактирования деталей и обновления формы.

Когда я пытаюсь изменить какой-либо ввод после длительного простоя (через 30 минут), я получаю исключение NullPointerException из переменной экземпляра управляемого компонента. Это сервер очистил экземпляры, которые долгое время простаивали, что-то, о чем клиент-браузер не знает?

Вот код.

commonTemplate.xhtml

 <!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title> VSP </title>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="vsp.css" type="text/css" />
<script type="text/javascript">
//<![CDATA[
jQuery("#designForm :input[type='text']:enabled:not([readonly='readonly'])").live('change', function(){
    var componentId = jQuery(this).attr("id");
    validateInputData(componentId);
    var validForm = (jQuery(".errorMsg").length == 0) ? true : false;
    if(validForm){
        jQuery("#submitDesignForm").click();
    }
}); 
</script>
</h:head>
<h:body>
    <div id="header">
        <ui:insert name="commonHeader">
            <ui:include src="header.xhtml" />
        </ui:insert>
    </div>
    <div id="content">
        <ui:insert name="commonBodyContent">
            <h:form id="designForm" prependId="false" autocomplete="off">
                Common Body Content.
            <h:commandLink id="submitDesignForm" style="display:none;"> 
                <f:ajax execute="@form" 
                        render="@form"
                        listener="#{designBean.processDetails}"/>
            </h:commandLink>
            </h:form>           
        </ui:insert>
    </div>
    <div id="footer">
        <ui:insert name="commonFooter">
            <ui:include src="footer.xhtml" />
        </ui:insert>
    </div>
</h:body>
</html>
  

showDetails.xhtml

 <ui:composition 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"
                template="commonTemplate.xhtml">

    <ui:define name="commonBodyContent">
        <table>
            <tr>
                <td>Name</td>
                <td>#{designBean.person.name}</td>
            </tr>
            <tr>
                <td>Age</td>
                <td>#{designBean.person.age}</td>
            </tr>
            <tr>
                <td>Email</td>
                <td>#{designBean.person.email}</td>
            </tr>
            <tr>
                <td>Nationality</td>
                <td>#{designBean.person.nation}</td>
            </tr>
            <tr>
                <td>Date-Of-Birth</td>
                <td>#{designBean.person.dob}</td>
            </tr>
        .........;
        ..........;
        </table>
    </ui:define>

</ui:composition>

editDetails.xhtml
------------------
<ui:composition 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"
                template="commonTemplate.xhtml">

    <ui:define name="commonBodyContent">
        <table>
            <tr>
                <td>Name</td>
                <td><h:inputText value="#{designBean.person.name}" /></td>
            </tr>
            <tr>
                <td>Age</td>
                <td><h:inputText value="#{designBean.person.age}" /></td>
            </tr>
            <tr>
                <td>Email</td>
                <td><h:inputText value="#{designBean.person.email}" disabled="true"/></td>
            </tr>
            <tr>
                <td>Nationality</td>
                <td><h:inputText value="#{designBean.person.nation}" /></td>
            </tr>
            <tr>
                <td>Date-Of-Birth</td>
                <td><h:inputText value="#{designBean.person.dob}" /></td>
            </tr>
        .........;
        ..........;
        </table>
    </ui:define>

</ui:composition>
  

web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.SEPARATOR_CHAR</param-name>
        <param-value>_</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.expressionFactory</param-name>
        <param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>com.sun.faces.disableUnicodeEscaping</param-name>
        <param-value>true</param-value>
    </context-param>
    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter>
        <filter-name>noCacheFilter</filter-name>
        <filter-class>org.omnifaces.filter.CacheControlFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>noCacheFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
    </filter-mapping>
    <filter>
        <filter-name>facesExceptionFilter</filter-name>
        <filter-class>org.omnifaces.filter.FacesExceptionFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>facesExceptionFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
    </filter-mapping>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
    <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/viewExpired.faces</location>
    </error-page>
    <error-page>
        <exception-type>java.sql.SQLException</exception-type>
        <location>/systemUnavailable.faces</location>
    </error-page>
    <error-page>
        <exception-type>java.lang.RuntimeException</exception-type>
        <location>/error.faces</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error.faces</location>
    </error-page>
    <error-page>
        <error-code>403</error-code>
        <location>/invalidAccess.faces</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/notFound.faces</location>
    </error-page>
    <security-constraint>
        <display-name>Restrict raw XHTML Documents</display-name>
        <web-resource-collection>
            <web-resource-name>XHTML</web-resource-name>
            <url-pattern>*.xhtml</url-pattern>
        </web-resource-collection>
        <auth-constraint />
    </security-constraint>
</web-app>
  

DesignBean

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

    @ManagedProperty(value = "#{userBean}")
    private UserBean userBean;

    @ManagedProperty("#{userService}")
    private UserService userService; // This is an application scoped managed bean with eager true.

    private Person person;

    @PostConstruct
    public void initBean(){
        System.out.println("DesignBean created!");
        person = new Person();
        String userEmail = userBean.getUserEmail();
        if(userEmail!=null amp;amp; !userEmail.isEmpty()){
            person = userService.getUserDetails(userEmail);
        }
    }

    public void processDetails(){
        person.setLastUpdateTime(new Date()); // Getting NPE here, person object is null after long idle time.
        userService.updateUser(person);
    }

    public void setUserBean(UserBean userBean) {
        this.userBean = userBean;
    }

    public UserBean getUserBean() {
        return userBean;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public UserService getUserService() {
        return userService;
    }

    public void setPerson(Person person){
        this.person = person;
    }

    public Person getPerson(){
        return person;
    }

}
  

Человек

 public class Person implements Serializable {
    private String name;
    private Integer age;
    private String email;
    private String nation;
    private String dob;
    private Date lastUpdateTime;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getNation() {
        return nation;
    }

    public void setNation(String nation) {
        this.nation = nation;
    }

    public String getDob() {
        return dob;
    }

    public void setDob(String dob) {
        this.dob = dob;
    }

    public void setLastUpdateTime(Date lastUpdateTime){
        this.lastUpdateTime = lastUpdateTime;
    }

    public Date getLastUpdateTime(){
        return lastUpdateTime;
    }

}
  

Комментарии:

1. Какую трассировку исключений вы получаете?

2. Я получаю исключение NullPointerException из метода DesignBean#processDetails(). person.setLastUpdateTime(новая дата()); // Получая NPE здесь, объект person равен нулю после длительного простоя.

3. Есть ли у вас какая-либо особая причина для установки метода сохранения состояния для клиента в вашем web.xml ? Также кажется невозможным, чтобы свойство person было потеряно таким образом. Единственный шанс для этого — это полная DesignBean перестройка, но без вызова @PostConstruct .

4. Причина использования клиентской части в том, что мы не можем использовать общий доступ к сеансу. И я попытался добавить несколько журналов в @PostConstruct и в конструктор по умолчанию тоже. Но журналы не печатаются (т. Е. Не создается какой-либо новый экземпляр этого компонента).

5. Если экземпляр компонента остается тем же самым, есть только один выбор: в какой-то момент вашего кода для свойства устанавливается значение null.