显示在web.xml中的java.lang.Throwable错误页面中的ViewExpiredException

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (59)

我正在开发一个JSF Web应用程序,在该应用程序中,如果视图到期,需要显示“会话已过期”页面,但是对于其他所有人而言,这是一个通用技术错误页面。当我触发异常时,应用程序仅进入技术错误页面。以下是错误页面定义:

<error-page> 
    <exception-type>javax.faces.application.ViewExpiredException</exception-type> 
    <location>/jsps/utility/sessionExpired.jsp</location> 
</error-page> 
<error-page> 
    <exception-type>java.lang.Throwable</exception-type> 
    <location>/jsps/utility/technicalError.jsp</location> 
</error-page> 
<error-page>
    <error-code>500</error-code>
    <location>/jsps/utility/technicalError.jsp</location>
</error-page>

我删除了technicalError.jsp错误页面元素并且它工作正常,但是当我将它们放回时,我无法进入sessionExpired.jsp页面。如何告诉Web容器评估这些标签的顺序,以便出现正确的页面?谢谢。

提问于
用户回答回答于

这是因为根据JSF规范,ViewExpiredException它被包装在一个ServletException。以下是JSF 1.2规范第10.2.6.2章节的摘录:

10.2.6.2 FacesServlet 调用已execute()保存Lifecycle实例的方法,FacesContext将此请求的实例作为参数传递 。如果execute()方法引发FacesException重新把它作为一个ServletExceptionFacesException为根本原因

在Servlet API规范中指定了如何分配错误页面。以下是Servlet API规范2.5的第9.9.2章的摘录:

SRV.9.9.2错误页面 如果没有 error-page包含exception-type使用类层次结构匹配的拟合的 声明,并且抛出的异常是其中的ServletException子类或其子类,那么容器将提取由ServletException.getRootCause方法定义的包装的异常。第二遍是通过错误页面声明,再次尝试匹配错误页面声明,但使用包装的异常。

在类层次结构中,它们ServletException已经匹配Throwable,所以它的根本原因不会被提取用于第二遍。

为了证明这一点指定的行为,取代javax.faces.application.ViewExpiredExceptionjavax.servlet.ServletException作为<exception-type>重试。您会看到正在显示的预期错误页面。

要解决这个问题,只需错误页面移除java.lang.Throwablejava.lang.Exception。如果没有一个异常特定的错误页面匹配,那么它将回退到错误代码的那个500。所以,你需要的是这样的:

<error-page> 
    <exception-type>javax.faces.application.ViewExpiredException</exception-type> 
    <location>/jsps/utility/sessionExpired.jsp</location> 
</error-page> 
<error-page>
    <error-code>500</error-code>
    <location>/jsps/utility/technicalError.jsp</location>
</error-page>

按照OP的(已删除)注释:为了可靠地测试这个,你不能throw new ViewExpiredException()在bean构造器或方法等中做一个。它会反过来被包裹在一些EL异常中。你最终可以添加一个调试行打印rootCauseFilter自己看。

如果您使用的是Eclipse / Tomcat,快速测试ViewExpiredException方法如下:

  1. 用一个简单的命令按钮创建一个JSF页面,部署并运行它并在webbrowser中打开它。
  2. 返回Eclipse,右键单击Tomcat服务器并选择清理Tomcat工作目录。这将重新启动Tomcat 垃圾所有序列化的会话(重要!仅重新启动Tomcat是不够的)。
  3. 返回网页浏览器并按下命令按钮(无需事先重新加载页面!)。

扫码关注云+社区