Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException
Posted
技术标签:
【中文标题】Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException【英文标题】:ViewExpiredException shown in java.lang.Throwable error-page in web.xml 【发布时间】:2011-03-13 12:35:10 【问题描述】:我正在开发一个 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 容器评估这些标签的顺序,以便出现正确的页面?谢谢。
【问题讨论】:
【参考方案1】:这是因为根据 JSF 规范,ViewExpiredException
被包装在 ServletException
中。这是JSF 1.2 specification第10.2.6.2章的摘录:
10.2.6.2 FacesServlet
调用保存的
Lifecycle
实例的execute()
方法,传递FacesContext
此请求的实例作为参数。如果execute()
方法 抛出FacesException
,将其重新作为ServletException
抛出FacesException
是根本原因。
如何分配错误页面在 Servlet API 规范中指定。这是Servlet API specification 2.5第9.9.2章的摘录:
SRV.9.9.2 错误页面
如果 no 包含
exception-type
的error-page
声明适合使用 类层次匹配,抛出的异常是ServletException
或 其子类,容器提取包装的异常,如定义ServletException.getRootCause
方法。 第二次通过 克服错误 页面声明,再次尝试匹配错误页面 声明,但使用包装的异常。
在类层次结构中,ServletException
已经与 Throwable
匹配,因此不会为第二遍提取其根本原因。
要证明此指定行为,请将 javax.faces.application.ViewExpiredException
替换为 javax.servlet.ServletException
为 <exception-type>
并重试。您将看到正在显示的预期错误页面。
要解决此问题,只需删除java.lang.Throwable
或java.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 的(已删除)注释:要可靠地测试这一点,您不能在 bean 构造函数或方法中执行 throw new ViewExpiredException()
左右。反过来,它会被包裹在一些 EL 异常中。您最终可以在Filter
中添加一个打印rootCause
的调试行以自己查看。
如果您使用的是 Eclipse/Tomcat,测试ViewExpiredException
的快速方法如下:
-
使用简单的命令按钮创建一个 JSF 页面,部署并运行它并在 webbrowser 中打开它。
回到 Eclipse,右键单击 Tomcat 服务器并选择 Clean Tomcat Work Directory。这将重新启动 Tomcat并丢弃所有序列化会话(重要!仅重新启动 Tomcat 是不够的)。
返回网络浏览器并按下命令按钮(无需事先重新加载页面!)。
【讨论】:
感谢您的详细解释。不幸的是,该解决方案不起作用。出现技术错误页面而不是会话过期页面。我通过在会话中间重新启动应用程序来终止会话。我发现我可以在该 try 块中执行 response.sendRedirect 而不是引发运行时异常,但是我正在硬编码视图的路径而不是让容器控制它。不是首选,但我不知道还能做什么。 这在 Tomcat 6.0.20 上运行良好。您使用的是什么 servlet 容器?你得到了什么根本原因? 我没有提到我无法删除错误代码 500 的java.lang.Throwable
/java.lang.Exception
并保留 500
作为其他异常的一般后备。另请参阅答案。【参考方案2】:
正如 BylusC 所提到的,部署描述符不能包含任何会捕获 ViewExpiredException(包装在 ServletException 中)的错误页面处理程序,而不是正确的 - ViewExpiredException 的错误页面。
不要忘记验证服务器的部署描述符(例如 TomEE/conf/web.xml)不包含 java.lang.Throwable 或 java.lang.Exception 错误页面定义。因为这两个web.xml基本上是合并的。
是 - 应用程序的 web.xml 优先于服务器的 web.xml,但如果应用程序的 web.xml 包含
错误页面 500 (/error.xhtml)和服务器的 web.xml
500 (/500.html) 和用于 可抛出的 (/bigerror.html)那么应用上下文将包含这两者的合并:
500 (/error.xhtml) 可抛出的 (/bigerror.html)ViewExpiredExcpetion 错误处理将无法正常工作。
【讨论】:
以上是关于Web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException的主要内容,如果未能解决你的问题,请参考以下文章
Tomcat中的Web.xml和servlet.xml的学习
web.xml中的contextConfigLocation在spring中的作用
(转)web.xml中的contextConfigLocation在spring中的作用