javax.faces.application.ViewExpiredException与no saved view state could be found的解决方案

javax.faces.application.ViewExpiredException: /UserManage/UserOpHist.facesNo saved view state could be found for the view identifier: /UserManage/UserOpHist.faces

准确来说出现该异常(视图没有存储的异常,简单来说就是找不到你要跳转的视图)的情况有如下几种:

             1:当重启完tomcat时,去点击主页的任何功能都跳到叫你重新登录的界面,然而点击引导页面,正常来说应该跳到重新登录的界面,但有的功能点击时就抛出该异常了

             2:当注销主页并且重新登录后,点击引导页面(之前操作过的,不是重新打开的)的任一功能都会抛出该异常

             3:当有一段时间没有进行操作,再点击页面上的功能时

             3:同时操作主页和引导页面超过3分钟,也会抛出该异常(这个最后再处理)

为什么会出现该异常呢,为什么找不到你需要跳转的视图,简单来说就是当你跳转视图时,JSF生命周期第一步就是restore view,意思就是说JSF执行生命周期第一步时就去寻找你之前操作过的视图,并将其还原。这时候因为你已经是重新登录了,之前操作过的视图根本找不到,已经被JSF当作过期来处理;或者你根本没有重新登录,而是过了很久才去操作,这样视图一样是不能找到相应的视图标识,所以还原失败,就抛出该异常。

            正当出现该异常的时候,我有了几种想法:第一:直接把viewID过滤掉;第二:阻止前台发送标识viewId;这两种方法如果成功了都相当于一个全新的请求。

            但是基于各种原因,最后我采取的解决办法是:捕获异常

              1:先开启异常处理,进入Web.xml配置文件,添加如下配置

                    <context-param>
                            <description>
                                    Indicate if myfaces is responsible to handle errors
                            </description>
                            <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>
                            <param-value>true</param-value>
                  </context-param>

              2:这里用到javax.faces.context.ExceptionHandlerFactory和ExceptionHandlerWrapper,因为它有个getExceptionHandler()方法可以对异常进行处理,所以这里先用     到了工厂模式,创建工厂实现类并extends ExceptionHandlerFactory代码如下:

               package com.tt.bs.common;

               import javax.faces.context.ExceptionHandler;
               import javax.faces.context.ExceptionHandlerFactory;
               import org.apache.myfaces.shared.context.ExceptionHandlerImpl;

               public class ExceptionHandlerFactoryImpl extends ExceptionHandlerFactory {

                 @Override
                 public ExceptionHandler getExceptionHandler() {
                           return new ExceptionHandlerWrapperImpl(new ExceptionHandlerImpl());
                      }
                 }

             3:接着创建异常捕获的实现类ExceptionHandlerWrapperImpl并extends ExceptionHandlerWrapper,代码如下:

               package com.tt.bs.common;

               import java.io.IOException;

     import javax.faces.FacesException;
     import javax.faces.application.ViewExpiredException;
     import javax.faces.context.ExceptionHandler;
     import javax.faces.context.ExceptionHandlerWrapper;
     import org.apache.log4j.Logger;
     import com.tt.common.bs.jsf.JSF;

     public class ExceptionHandlerWrapperImpl extends ExceptionHandlerWrapper {

          private Logger logger = Logger.getLogger(ExceptionHandlerWrapperImpl.class);

          private ExceptionHandler delegate;

          public ExceptionHandlerWrapperImpl(ExceptionHandler delegate) {
              this.delegate = delegate;
          }

          @Override
          public void handle() throws FacesException {
              try {
                   super.handle();
              } catch (Throwable t) {
                   logger.error(t, t);
                   if (t instanceof ViewExpiredException) {
                       try {
                            String contextPath = JSF.getRequest().getContextPath();
                            JSF.redirectInAction(contextPath + "/ExpiredExceptionHandler.jsp");
                       } catch (IOException e1) {
                            logger.error("Unable redirect to expired page, please check the page url.",t);
                            throw new FacesException(t);
                       }
           return;
                   }
                   throw new FacesException(t);
               }
           }

          @Override
          public ExceptionHandler getWrapped() {
               return delegate;
          }
      }

              4:最后创建ExpiredExceptionHandler.jsp显示错误信息

              这样捕获异常就成功了,每次程序抛出ViewExpiredException时,都会跳到你指定的页面了。

这里还有一点需要注意

                  如果两个页面同时操作时,并且操作时间较长时,再点击任一页面的任何按钮,程序也会报错,也会抛出该异常。这种情况就是存储在JSF的View数目值太小了。应该把值设置大点,进入web.xml配置文件

        <context-param>
                 <description>
                         Only applicable if state saving method is "server" (=
                         default). Defines the amount (default = 20) of the latest
                         views are stored in session.
                 </description>
                 <param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name>
                 <param-value>200</param-value>
        </context-param>

把值设到200都已经够大了,一般情况下都不会再抛出这种异常了。


下面这几种方法是在网上找到的:

摘抄一[没有试过,看起来是处理异常(捕获异常再重定向),而不是避开异常]

javax.faces.application.ViewExpiredException: viewId:/pages/gardeninfo/envRiskEditForm.faces - View /pages/gardeninfo/envRiskEditForm.faces could not be restored.对于用户来说是不懂的,那只要在重写生命周期便可处理

第一种【没有试过】:

1. 重写一个类,继承Lifecycle类,重写父类的execute方法,捕捉该异常,然后进行处理(如设置跳转到登录页面)。
2. 重写一个类,继承LifecycleFactoryImpl类,添加SessionLifecycleImpl的实例到工厂中,假设重写的子类为project.jsf.test.SessionLifecycleFactoryImpl。
3.在faces-config.xml中注册JSFLifecycleFactory类。
4.在web.xml中指定JSFLifecycleFactory工厂中创建的JSFLifecycle实例的键(key)。

public class JSFLifecycleFactory extends LifecycleFactoryImpl {
 private static Logger LOGGER = FacesLogger.LIFECYCLE.getLogger();

 public static final String JSF_LIFECYCLE = "JSF";

 public JSFLifecycleFactory() {
  super();
 
  lifecycleMap.put(JSF_LIFECYCLE, new JSFLifecycle());
  if (LOGGER.isLoggable(Level.FINE)) {
   LOGGER.fine("Created EJS JSF Lifecycle");
  }
 }
}

public class JSFLifecycle extends Lifecycle {

 private static Logger LOGGER = FacesLogger.LIFECYCLE.getLogger();

 private Phase response = new RenderResponsePhase();

 private Phase[] phases = {
   null, // ANY_PHASE placeholder, not a real Phase
   new RestoreViewPhase(), new ApplyRequestValuesPhase(),
   new ProcessValidationsPhase(), new UpdateModelValuesPhase(),
   new InvokeApplicationPhase(), response };

 private List<PhaseListener> listeners = new CopyOnWriteArrayList<PhaseListener>();

 public void execute(FacesContext context) throws FacesException {
  try {
   if (context == null) {
    throw new NullPointerException(MessageUtils
      .getExceptionMessageString(
        MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
        "context"));
   }

   if (LOGGER.isLoggable(Level.FINE)) {
    LOGGER.fine("execute(" + context + ")");
   }

   for (int i = 1, len = phases.length - 1; i < len; i++) {
    if (context.getRenderResponse()
      || context.getResponseComplete()) {
     break;
    }
    phases[i].doPhase(context, this, listeners.listIterator());
   }
  }
  catch (ViewExpiredException e) {
   JSFMessageUtils.removeMessage();
   JSFMessageUtils.showAndLogException("信息","操作错误", e
       .getMessage(), null, JSFMessageUtils.WARN,
     JSFMessageUtils.OK);
  }
  catch (Exception e) {
   JSFMessageUtils.removeMessage();
   JSFMessageUtils.showAndLogException("信息","操作错误", e
     .getMessage(), null, JSFMessageUtils.WARN,
   JSFMessageUtils.OK);
  }
 }

 public void render(FacesContext context) throws FacesException {
  try {
   if (context == null) {
    throw new NullPointerException(MessageUtils
      .getExceptionMessageString(
        MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
        "context"));
   }

   if (LOGGER.isLoggable(Level.FINE)) {
    LOGGER.fine("render(" + context + ")");
   }
   if (!context.getResponseComplete()) {
    response.doPhase(context, this, listeners.listIterator());
   }
  }
  catch (FacesException e) {
   JSFMessageUtils.removeMessage();
   JSFMessageUtils.showAndLogException("信息","操作错误", e
     .getMessage(), null, JSFMessageUtils.WARN,
   JSFMessageUtils.OK);
  }
  catch (Exception e) {
   JSFMessageUtils.showAndLogException("信息","操作错误", e
     .getMessage(), null, JSFMessageUtils.WARN,
   JSFMessageUtils.OK);
  }
 }

 public void addPhaseListener(PhaseListener listener) {
  if (listener == null) {
   throw new NullPointerException(MessageUtils
     .getExceptionMessageString(
       MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
       "listener"));
  }

  if (listeners == null) {
   listeners = new CopyOnWriteArrayList<PhaseListener>();
  }

  if (listeners.contains(listener)) {
   if (LOGGER.isLoggable(Level.FINE)) {
    LOGGER.log(Level.FINE,
      "jsf.lifecycle.duplicate_phase_listener_detected",
      listener.getClass().getName());
   }
  }
  else {
   if (LOGGER.isLoggable(Level.FINE)) {
    LOGGER.log(Level.FINE, "addPhaseListener({0},{1})",
      new Object[] { listener.getPhaseId().toString(),
        listener.getClass().getName() });
   }
   listeners.add(listener);
  }
 }

 public PhaseListener[] getPhaseListeners() {
  return listeners.toArray(new PhaseListener[listeners.size()]);

 }

 public void removePhaseListener(PhaseListener listener) {
  if (listener == null) {
   throw new NullPointerException(MessageUtils
     .getExceptionMessageString(
       MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
       "listener"));
  }

  if (listeners.remove(listener) && LOGGER.isLoggable(Level.FINE)) {
   LOGGER.log(Level.FINE, "removePhaseListener({0})",
     new Object[] { listener.getClass().getName() });
  }
 }
}

 

faces-config.xml:

<factory>
  <lifecycle-factory>org.ejs.jsf.JSFLifecycleFactory</lifecycle-factory>
</factory>

web.xml

<context-param>
  <param-name>javax.faces.LIFECYCLE_ID</param-name>
  <param-value>JSF</param-value>
</context-param>

 

第二种网上搜的【没有试过】:

1. 重写一个类,继承LifecycleImpl类,重写父类的execute方法,捕捉该异常,然后进行处理(如设置跳转到登录页面),假设重写的子类名为project.jsf.test.SessionLifecycleImpl。
2. 重写一个类,继承LifecycleFactoryImpl类,添加SessionLifecycleImpl的实例到工厂中,假设重写的子类为project.jsf.test.SessionLifecycleFactoryImpl。
3.在faces-config.xml中注册SessionLifecycleFactoryImpl类。
4.在web.xml中指定SessionLifecycleFactoryImpl工厂中创建的SessionLifecycleImpl实例的键(key)。

具体如下:
1.project.jsf.test.SessionLifecycleImpl类:

import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import com.sun.faces.lifecycle.LifecycleImpl;

public class SessionLifecycleImpl extends LifecycleImpl {
public final static String SESSION_TIMEOUT_PAGES = "/pages/sessionTimeOut.faces";
public SessionLifecycleImpl() {
super();
}

public void execute(FacesContext context) {
try {
super.execute(context);
}catch(ViewExpiredException vee) {
redirect(context);
}catch(FacesException fe) {
throw fe;
}
}

private void redirect(FacesContext context) {
try {
context.responseComplete();
context.renderResponse();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
String url = context.getExternalContext().getRequestContextPath()+ SESSION_TIMEOUT_PAGES;
response.sendRedirect(url);
}catch(Exception e) {
System.out.println(" Error: session timeout url redirect ");
}
}
}

2. project.jsf.test.SessionLifecycleFactoryImpl类:

import com.sun.faces.lifecycle.LifecycleFactoryImpl;

public class SessionLifecycleFactoryImpl extends LifecycleFactoryImpl {
public static final String SESSION_LIFECYCLE = "SessionLifecycle";
public SessionLifecycleFactoryImpl(){
super();
addLifecycle(SESSION_LIFECYCLE, new SessionLifecycleImpl());
}
}

3. faces-config.xml中注册SessionLifecycleFactoryImpl类
<faces-config>
<factory>
<lifecycle-factory>project.jsf.test.SessionLifecycleFactoryImpl</lifecycle-factory>
</factory>
.........
</faces-config>

4. web.xml中指定SessionLifecycleImpl实例的键(key):
<context-param>
<param-name>javax.faces.LIFECYCLE_ID</param-name>
<param-value>SessionLifecycle</param-value>
</context-param>

 

第三种:网上搜的【没有试过】

现这个错误是因为session 超时。当然关掉页面重新打开就不会有这个问题,但是在可用性方面就很差。作为开发人员看见这个错误会知道为什么,普通浏览者肯定会觉得出了什么问题。所以还是解决一下好。

如果是 sun appplication server

解决办法是在web.xml中添加
<error-page>
     <exception-type>javax.faces.application.ViewExpiredException</exception-type>
     <location>/sessionExpired.jsp</location>
</error-page>

sessionExpired.jsp:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<c:redirect url="/login.jsf" />

如果web容器是tomcat,解决办法如下:

package com.jsf.util;

import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import com.sun.faces.lifecycle.LifecycleImpl;

public class TeleLifecycleImpl extends LifecycleImpl
{
 public TeleLifecycleImpl()
 {
  super();
 }
 
 public void execute(FacesContext context)
 {
  try
  {
   super.execute(context);
  }
  catch (ViewExpiredException  vee)
  {
   redirect(context);
  }
  catch (FacesException fe)
  {
   throw fe;
  }
 }
 
 private void redirect(FacesContext context)
 {
  try
  {
   context.responseComplete();
   context.renderResponse();
   HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
   String url = context.getExternalContext().getRequestContextPath() + "/faces/error.jsp";
   response.sendRedirect(url);
  }
  catch (Exception e)
  {
   System.out.println("url redirect wrong ");
  }

 }
}

 在jsf配置文件 faces-config.xml 中添加如下内容

<factory>
     <lifecycle-factory>trackingmap.TeleLifecycleFactoryImpl</lifecycle-factory>
</factory>

在web.xml 中添加如下内容

<context-param>
     <param-name>javax.faces.LIFECYCLE_ID</param-name>
     <param-value>TELEEPOCH</param-value>
</context-param>


摘抄二[实践证明好像无效,看起来需要多种方案组合]

后台页面以JSF编写,当客户端的session失效后,再去点击JSF页面中的操作时,会要求用户再次输入用户名、密码,然后重定向到之前点击操作的页面,在此重定向时产生了异常:

  1. javax.faces.application.ViewExpiredException: viewId:/jsf/profile/editProfileRedirect.xhtml - View /jsf/profile/editProfileRedirect.xhtml could not be restored.  
  2.     at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:186)  
  3.     at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)  
  4.     at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:104)  
  5.     at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)  
  6.     at org.jboss.portletbridge.AjaxPortletBridge.execute(AjaxPortletBridge.java:836)  
  7.     at org.jboss.portletbridge.AjaxPortletBridge.doFacesRequest(AjaxPortletBridge.java:343)  
  8.     at javax.portlet.faces.GenericFacesPortlet.processAction(GenericFacesPortlet.java:323)  
  9.     at org.jboss.portal.portlet.impl.jsr168.PortletContainerImpl$Invoker.doFilter(PortletContainerImpl.java:557)  
  10.     at org.jboss.portal.portlet.impl.jsr168.api.FilterChainImpl.doFilter(FilterChainImpl.java:109)  
  11.     at org.jboss.portlet.filter.JBossPortletFilter.doFilter(JBossPortletFilter.java:59
  12. .。。。。。。。。。。。

原因是JSF页面会保存一个状态,默认是在服务端,当客户端的session失效后通过<h:commandLink><h:commandButton>访问JSF页面时,就会出现这个异常。

The ViewExpiredException will be thrown whenever the javax.faces.STATE_SAVING_METHOD is set toserver (default) and the enduser sends a HTTP POST request using<h:commandLink> or<h:commandButton> on a view, while the associated view state isn't available in the session anymore.

修改方法之一是在项目的web.xml配置文件中将javax.faces.STATE_SAVING_METHOD的值配置为“client”,即将页面的状态保存在客户端中。这样客户端的页面就会更复杂了一些。可能会稍微影响到页面的性能。


摘抄三【这种情况好像不是很通用】

javax.faces.application.ViewExpiredException: viewId xxx- View xxx could not be restored.

项目中老出现这样的异常。都是在session过期之后的自动跳转时出现,检查代码,有一块跳转 在sessioni == null情况下仍然调用FilterChain.doFilter..。加上判断。

另外将RequestDispatcher 修改为response.sendRedirect....

问题解决~~


摘抄四【实践证明好像无效,不过session-config倒是可以借鉴】

运行jsf页面出现javax.faces.application.ViewExpiredException - /*.jsp No saved view state could be found for the view identifier: /*.jsp问题的解决方法
 
出现此问题的原因我也不是太清楚,看了相关资料说是因为session的保存时间造成了。所以下面的两个方法都是针对时间来修正。
在web.xml中新增下列节点

方法1.   

1  <web-app>
2            <context-param> 
3              <param-name>facelets.BUILD_BEFORE_RESTORE</param-name> 
4            <param-value>true</param-value> 
5          </context-param> 
6  </web-app>
方法2.
  增加保存时间为600分钟
1  <web-app>       
2        <session-config>
3            <session-timeout>600</session-timeout>
4        </session-config>
5  </web-app>

摘抄五[stackoverflow上的大杂烩,值得借鉴]

I have written simple application with container-managed security. The problem is when I log in and open another page on which I logout, then I come back to first page and I click on any link etc or refresh page I get this exception. I guess it's normal (or maybe not:)) because I logged out and session is destroyed. What should I do to redirect user to for example index.xhtml or login.xhtml and save him from seeing that error page/message?

In other words how can I automatically redirect other pages to index/login page after I log out?

Here it is:

<code><span class="pln">javax</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">application</span><span class="pun">.</span><span class="typ">ViewExpiredException</span><span class="pun">:</span><span class="pln"> viewId</span><span class="pun">:/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">xhtml </span><span class="pun">-</span><span class="pln"> </span><span class="typ">View</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">xhtml could not be restored</span><span class="pun">.</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">lifecycle</span><span class="pun">.</span><span class="typ">RestoreViewPhase</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">RestoreViewPhase</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">212</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">lifecycle</span><span class="pun">.</span><span class="typ">Phase</span><span class="pun">.</span><span class="pln">doPhase</span><span class="pun">(</span><span class="typ">Phase</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">101</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">lifecycle</span><span class="pun">.</span><span class="typ">RestoreViewPhase</span><span class="pun">.</span><span class="pln">doPhase</span><span class="pun">(</span><span class="typ">RestoreViewPhase</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">110</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">lifecycle</span><span class="pun">.</span><span class="typ">LifecycleImpl</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">LifecycleImpl</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">118</span><span class="pun">)</span><span class="pln">
    at javax</span><span class="pun">.</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">webapp</span><span class="pun">.</span><span class="typ">FacesServlet</span><span class="pun">.</span><span class="pln">service</span><span class="pun">(</span><span class="typ">FacesServlet</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">312</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">StandardWrapper</span><span class="pun">.</span><span class="pln">service</span><span class="pun">(</span><span class="typ">StandardWrapper</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">1523</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">internalDoFilter</span><span class="pun">(</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">343</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">doFilter</span><span class="pun">(</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">215</span><span class="pun">)</span><span class="pln">
    at filter</span><span class="pun">.</span><span class="typ">HttpHttpsFilter</span><span class="pun">.</span><span class="pln">doFilter</span><span class="pun">(</span><span class="typ">HttpHttpsFilter</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">66</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">internalDoFilter</span><span class="pun">(</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">256</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">doFilter</span><span class="pun">(</span><span class="typ">ApplicationFilterChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">215</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">StandardWrapperValve</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">StandardWrapperValve</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">277</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">StandardContextValve</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">StandardContextValve</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">188</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">StandardPipeline</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">StandardPipeline</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">641</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">enterprise</span><span class="pun">.</span><span class="pln">web</span><span class="pun">.</span><span class="typ">WebPipeline</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">WebPipeline</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">97</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">enterprise</span><span class="pun">.</span><span class="pln">web</span><span class="pun">.</span><span class="typ">PESessionLockingStandardPipeline</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">PESessionLockingStandardPipeline</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">85</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">core</span><span class="pun">.</span><span class="typ">StandardHostValve</span><span class="pun">.</span><span class="pln">invoke</span><span class="pun">(</span><span class="typ">StandardHostValve</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">185</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">connector</span><span class="pun">.</span><span class="typ">CoyoteAdapter</span><span class="pun">.</span><span class="pln">doService</span><span class="pun">(</span><span class="typ">CoyoteAdapter</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">325</span><span class="pun">)</span><span class="pln">
    at org</span><span class="pun">.</span><span class="pln">apache</span><span class="pun">.</span><span class="pln">catalina</span><span class="pun">.</span><span class="pln">connector</span><span class="pun">.</span><span class="typ">CoyoteAdapter</span><span class="pun">.</span><span class="pln">service</span><span class="pun">(</span><span class="typ">CoyoteAdapter</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">226</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">enterprise</span><span class="pun">.</span><span class="pln">v3</span><span class="pun">.</span><span class="pln">services</span><span class="pun">.</span><span class="pln">impl</span><span class="pun">.</span><span class="typ">ContainerMapper</span><span class="pun">.</span><span class="pln">service</span><span class="pun">(</span><span class="typ">ContainerMapper</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">165</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">http</span><span class="pun">.</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">invokeAdapter</span><span class="pun">(</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">791</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">http</span><span class="pun">.</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">doProcess</span><span class="pun">(</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">693</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">http</span><span class="pun">.</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">process</span><span class="pun">(</span><span class="typ">ProcessorTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">954</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">http</span><span class="pun">.</span><span class="typ">DefaultProtocolFilter</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">DefaultProtocolFilter</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">170</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">executeProtocolFilter</span><span class="pun">(</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">135</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">102</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">DefaultProtocolChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">88</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">http</span><span class="pun">.</span><span class="typ">HttpProtocolChain</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="typ">HttpProtocolChain</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">76</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">ProtocolChainContextTask</span><span class="pun">.</span><span class="pln">doCall</span><span class="pun">(</span><span class="typ">ProtocolChainContextTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">53</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">SelectionKeyContextTask</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="typ">SelectionKeyContextTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">57</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="typ">ContextTask</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="typ">ContextTask</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">69</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">AbstractThreadPool$Worker</span><span class="pun">.</span><span class="pln">doWork</span><span class="pun">(</span><span class="typ">AbstractThreadPool</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">330</span><span class="pun">)</span><span class="pln">
    at com</span><span class="pun">.</span><span class="pln">sun</span><span class="pun">.</span><span class="pln">grizzly</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">AbstractThreadPool$Worker</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="typ">AbstractThreadPool</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">309</span><span class="pun">)</span><span class="pln">
    at java</span><span class="pun">.</span><span class="pln">lang</span><span class="pun">.</span><span class="typ">Thread</span><span class="pun">.</span><span class="pln">run</span><span class="pun">(</span><span class="typ">Thread</span><span class="pun">.</span><span class="pln">java</span><span class="pun">:</span><span class="lit">619</span><span class="pun">)</span><span class="pln">
</span></code>
share | improve this question

56% accept rate
 
feedback

2 Answers

up vote 34 down vote accepted

The ViewExpiredException will be thrown whenever the javax.faces.STATE_SAVING_METHOD is set toserver (default) and the enduser sends a HTTP POST request using<h:commandLink> or<h:commandButton> on a view, while the associated view state isn't available in the session anymore. The view state is identified by a hidden input fieldjavax.faces.ViewState of the<h:form>. With the state saving method set toserver, this contains only the view state ID which references a serialized view state in the session. With the state saving method set toclient, this is instead the whole serialized view state, so the enduser won't get aViewExpiredException when the session expires.

In order to prevent ViewExpiredException when the state saving is set toserver, only redirecting the POST request after logout is not sufficient. You also need to instruct the browser tonot cache the dynamic JSF pages, otherwise the browser may show them from the cache instead of requesting a fresh one from the server when you send a GET request on it (e.g. by back button). If you're using POST for page-to-page navigation, this will in turn fail.

To fire a redirect after logout in JSF 2.0, either add <redirect /> to the<navigation-case> in question (if any), or add?faces-redirect=true to theoutcome value.

<code><span class="tag"><h:commandButton</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Logout"</span><span class="pln"> </span><span class="atn">action</span><span class="pun">=</span><span class="atv">"logout?faces-redirect=true"</span><span class="pln"> </span><span class="tag">/></span><span class="pln">
</span></code>

or

<code><span class="kwd">public</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> logout</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"index?faces-redirect=true"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span></code>

To instruct the browser to not cache the dynamic JSF pages, create a Filter which is mapped on the servlet name of theFacesServlet and adds the needed response headers to disable the browser cache. E.g.

<code><span class="lit">@WebFilter</span><span class="pun">(</span><span class="pln">servletNames</span><span class="pun">={</span><span class="str">"Faces Servlet"</span><span class="pun">})</span><span class="pln"> </span><span class="com">// Must match <servlet-name> of your FacesServlet.</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">NoCacheFilter</span><span class="pln"> </span><span class="kwd">implements</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="lit">@Override</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> doFilter</span><span class="pun">(</span><span class="typ">ServletRequest</span><span class="pln"> request</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ServletResponse</span><span class="pln"> response</span><span class="pun">,</span><span class="pln"> </span><span class="typ">FilterChain</span><span class="pln"> chain</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throws</span><span class="pln"> </span><span class="typ">IOException</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ServletException</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">HttpServletRequest</span><span class="pln"> req </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">HttpServletRequest</span><span class="pun">)</span><span class="pln"> request</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">HttpServletResponse</span><span class="pln"> res </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">HttpServletResponse</span><span class="pun">)</span><span class="pln"> response</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">req</span><span class="pun">.</span><span class="pln">getRequestURI</span><span class="pun">().</span><span class="pln">startsWith</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">getContextPath</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">ResourceHandler</span><span class="pun">.</span><span class="pln">RESOURCE_IDENTIFIER</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// Skip JSF resources (CSS/JS/Images/etc)</span><span class="pln">
            res</span><span class="pun">.</span><span class="pln">setHeader</span><span class="pun">(</span><span class="str">"Cache-Control"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"no-cache, no-store, must-revalidate"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTTP 1.1.</span><span class="pln">
            res</span><span class="pun">.</span><span class="pln">setHeader</span><span class="pun">(</span><span class="str">"Pragma"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"no-cache"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// HTTP 1.0.</span><span class="pln">
            res</span><span class="pun">.</span><span class="pln">setDateHeader</span><span class="pun">(</span><span class="str">"Expires"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln"> </span><span class="com">// Proxies.</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        chain</span><span class="pun">.</span><span class="pln">doFilter</span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span></code>

When you want to handle the ViewExpiredException on an arbitrary page which was already opened in some browser tab/window while you're logged out in another tab/window, then you'd like to specify anerror-page for that inweb.xml which goes to index/login page or maybe a "Your session is timed out" page. E.g.

<code><span class="tag"><error-page></span><span class="pln">
    </span><span class="tag"><exception-type></span><span class="pln">javax.faces.application.ViewExpiredException</span><span class="tag"></exception-type></span><span class="pln">
    </span><span class="tag"><location></span><span class="pln">/login.xhtml</span><span class="tag"></location></span><span class="pln">
</span><span class="tag"></error-page></span><span class="pln">
</span></code>

See also:


That said and unrelated to the concrete problem, using HTTP POST for pure page-to-page navigation isn't very user/SEO friendly. In JSF 2.0 you should really prefer<h:link> or<h:button> over the<h:commandXxx> ones for plain vanilla page-to-page navigation.

See also

share | improve this answer
 
How can I do it with implicit navigation in java ee 6? I don't use faces-config. –  l245c4l Sep 4 '10 at 16:01
 
Oh, you're using JSF 2.0? You should have mentioned that in your question! Add?faces-redirect=true to theoutcome. I've updated the answer accordingly. –  BalusC Sep 4 '10 at 16:02
 
Yes I just started with java ee:) and I'm using faces-redirect=true in all my navigations. I use h:commandLink only when I have actions assosciated with it. For example Logout link... I have action String logout() where I invalidate session and redirect to login, but it doesn't work on page where I was logged in and being at the moment logged out and throws that exception :( –  l245c4l Sep 4 '10 at 16:13
 
As said, only redirecting is not enough. You also need to disable browser cache. Btw: in Java EE 6 you can use@WebFilter to register the filter. Update: I think I understand your new problem, you want to handle it for an arbitrary already-opened page as well? See the answer update. –  BalusC Sep 4 '10 at 16:22
1 
@LS: The filter is however still mandatory for the case whenever one presses the back button after an expired POST and tries to invoke another POST request on it. This would otherwise unintuitively result in this exception. –  BalusC Jun 12 at 18:15
show9 more comments
feedback

Have you tried adding lines below to your web.xml?<context-param> <param-name>com.sun.faces.enableRestoreView11Compatibility</param-name> <param-value>true</param-value></context-param>I found this to be very effective when I encountered this issue. 【这个证明有效,但是貌似只适用于SUN RI】

share | improve this answer
 
it worked for me too. Thanks for the answer. What is the purpose of this? –  MartK May 17 at 10:56
1 
Don't recall exactly, but I found this solution on ICEFaces website. –  Mike GH May 22 at 12:18


摘抄六[还没有试过]

重写ViewHandler

Preventing ViewExpiredException in JSF

http://www.gregbugaj.com/?p=164



PFYU总结

[正如BalusC说的那样,解决这个问题可能需要解决三方面:服务端浏览器端处理异常(重定位)]

导致ViewExpiredException的原因有多种,常见的有:

这里有一段stackoverflow上的解释:

This exception will be thrown whenever the enduser fires a POST request on a view which does not exist anymore in the server side, because the session has been expired. The view states are by default stored in the session, so they are lost whenever the session expires. A POST request will be fired when the enduser clicks a command button or command link or fires a JSF ajax request.

This can happen when you keep a page open in browser and untouch it for too long so that the session expires (usually, that is 30 minutes, depending on server configuration). Firing a POST request on such a view after session expiration will then result in ViewExpiredException. This can also happen when the browser loads the page from its cache instead of from the server.

They can be handled by <error-page> inweb.xml or a customExceptionHandler. They can if necessary be avoided by setting the context parameterjavax.faces.STATE_SAVING_METHOD toclient instead of (default)server which would then save the serialized view state as a hidden input field value of the POST form. With server side state saving, the browser also needs to be instructed to not cache the dynamic JSF pages.


1. session expiration (invalidate/timeout)。session timeout可以在web.xml中显示指定。

重现:可以在web.xml中设置session-timeout到1分钟来重现

SUNRI: [避开]貌似只能设置STATE_SAVING_METHOD, 设置numberOfViewsInSession/numberOfLogicalViewsenableRestoreView11Compatibilty都无效

               [处理]设置error-page,重写LifeCycle,重写ExceptionHandler (推荐处理,而不是避开)

MyFaces: [避开]貌似只能设置STATE_SAVING_METHOD, 设置NUMBER_OF_VIEWS_IN_SESSION无效

                  [处理]设置error-page,重写LifeCycle,重写ExceptionHandler(推荐处理,而不是避开)

2. The enduser has requested/created too much views within a session and is submitting to an old view. The default max views per session is 15. In other words, if the enduser opens 16 browser windows/tabs on a page with a form within the same session and submits to the first one, then the user can get ViewExpiredException.TherealViewExpiredException is usually only thrown when you send a HTTP POST request to the server while the HTTP session is expired. 可以在web.xml中显示指定session中的最大view数目。MyFaces和SUN RI的配置参数不一样。

重现:可以在web.xml中设置NUMBER_OF_VIEWS_IN_SESSION来重现[MyFaces],设置numberOfViewsInSession/numberOfLogicalViews[SUNRI]貌似没法重现

SUNRI: [避开]没法重现,一旦重现了解决方法应该是同MyFaces

MyFaces: [避开]貌似设置STATE_SAVING_METHOD或设置NUMBER_OF_VIEWS_IN_SESSION都有效

3. browser loads the page from its cache instead of from the server.

这种情况,貌似必须要采取NoCacheFileter+清空浏览器。即使设置STATE_SAVING_METHOD都无效

SUNRI: [避开]貌似只能设置NoCacheFilter或页面中添加头,同时清空浏览器

MyFaces: [避开]目前好像还没遇到浏览器Cache的问题,一旦遇到了解决方法应该是同SUNRI


1 针对MyFaces

1.1 从web.xml中的引擎参数入手(避免异常)

1.1.1 javax.faces.STATE_SAVING_METHOD

You can solve it by setting the state saving method toclient instead ofserver so that views are stored (in serialized form, of course) in a hidden input field of the POST form, instead of in the session in the server side (which is in turn to be referenced byJSESSIONID cookie; so all views will basically get lost when you delete the session cookie or when the session expires).

将参数从默认的server改为client,实际测试过,有效?

1.1.1 org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION

将这个参数设大一点,比如设成500,实际测试过,有效?


1.2 创建Filter设置HTTP Response的Header,通知浏览器不要Cache。同时如果异常已经发生了,则需要清空浏览器缓存。(避免异常)

当然也可以把这些内容挨个加到每个页面中

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse res = (HttpServletResponse) response;

 res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
 res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
 res.setDateHeader("Expires", 0); // Proxies.

 chain.doFilter(request, response);

}

    <filter>
        <display-name>NoCacheFilter</display-name>
        <filter-name>NoCacheFilter</filter-name>
        <filter-class>filters.NoCacheFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>
        *.faces</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>
        /faces/*</url-pattern>
    </filter-mapping>

实际测试过,有效?


1.3 重写LifeCycle(处理异常)

代码见上面,看起来要复杂一点。没有试过。


1.4 在web.xml中写error-page (处理异常)

<error-page>
     <exception-type>javax.faces.application.ViewExpiredException</exception-type>
     <location>/sessionExpired.jsp</location>
</error-page>


2 针对SUN RI

2.1 从web.xml中的引擎参数入手(避免异常)

2.1.1 javax.faces.STATE_SAVING_METHOD

将参数从默认的server改为client,实际测试过,好像无效?(不稳定,似乎需要多种方案组合)

2.1.2 com.sun.faces.numberOfViewsInSession和com.sun.faces.numberOfLogicalViews

将这个参数设大一点,比如设成500,实际测试过,好像无效?(不稳定,似乎需要多种方案组合)

2.1.3 com.sun.faces.enableRestoreView11Compatibilty

将参数设置成true,实际测试过,好像无效??(不稳定,似乎需要多种方案组合)


2.2 创建Filter设置HTTP Response的Header,通知浏览器不要Cache。同时如果异常已经发生了,则需要清空浏览器缓存。(避免异常)

当然也可以把这些内容挨个加到每个页面中

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse res = (HttpServletResponse) response;

 res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
 res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
 res.setDateHeader("Expires", 0); // Proxies.

 chain.doFilter(request, response);

}

    <filter>
        <display-name>NoCacheFilter</display-name>
        <filter-name>NoCacheFilter</filter-name>
        <filter-class>filters.NoCacheFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>
        *.faces</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>
        /faces/*</url-pattern>
    </filter-mapping>

实际测试过,有效?(不稳定,似乎需要多种方案组合)


2.3 重写LifeCycle(处理异常)

代码见上面,看起来要复杂一点。没有试过。


2.4 在web.xml中写error-page (处理异常)

<error-page>
     <exception-type>javax.faces.application.ViewExpiredException</exception-type>
     <location>/sessionExpired.jsp</location>
</error-page>






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值