web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException [英] ViewExpiredException shown in java.lang.Throwable error-page in web.xml
问题描述
我正在开发一个 JSF Web 应用程序,如果视图过期,我需要在该应用程序中显示会话已过期"页面,但为所有其他人提供一般技术错误页面.当我触发异常时,应用程序只会转到技术错误页面.这是错误页面定义:
I'm working on a JSF web application in which I need to bring up a "Session Expired" page if the view expires, but a general technical error page for all others. The application only goes to the technical error page when I trigger the exception. Here's the error-page definitions:
<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 容器评估这些标签的顺序,以便出现正确的页面?谢谢.
I removed the technicalError.jsp error page elements and it worked fine, but when I put them back I can't get to the sessionExpired.jsp page. How do I tell the web container the order to evaluate these tags so that the right page comes up? Thanks.
推荐答案
这是因为 ViewExpiredException
被包裹在一个 ServletException
根据 JSF 规范.下面是 JSF 1.2 规范的第 10.2.6.2 章的摘录:
This is because the ViewExpiredException
is been wrapped in a ServletException
as per the JSF specification. Here's an extract of chapter 10.2.6.2 of the JSF 1.2 specification:
调用保存的Lifecycle
实例的execute()
方法,传递此请求的 FacesContext
实例作为参数.如果 execute()
方法抛出一个 FacesException
,将它作为 ServletException
重新抛出,并带有FacesException
作为根本原因.
10.2.6.2 FacesServlet
Call the
execute()
method of the savedLifecycle
instance, passing theFacesContext
instance for this request as a parameter. If theexecute()
method throws aFacesException
, re-throw it as aServletException
with theFacesException
as the root cause.
在 Servlet API 规范中指定了如何分配错误页面.以下是 Servlet API 规范 2.5 的第 9.9.2 章的摘录:
How the error pages are allocated is specified in Servlet API specification. Here's an extract of chapter 9.9.2 of Servlet API specification 2.5:
如果 no error-page
声明包含 exception-type
适合使用class-hierarchy 匹配,并且抛出的异常是 ServletException
或其子类,容器提取包装的异常,如定义ServletException.getRootCause
方法.第二遍纠正错误页面声明,再次尝试匹配错误页面声明,而是使用包装的异常.
SRV.9.9.2 Error Pages
If no
error-page
declaration containing anexception-type
fits using the class-hierarchy match, and the exception thrown is aServletException
or subclass thereof, the container extracts the wrapped exception, as defined by theServletException.getRootCause
method. A second pass is made over the error page declarations, again attempting the match against the error page declarations, but using the wrapped exception instead.
在类层次结构中,ServletException
已经匹配 Throwable
,因此第二遍不会提取其根本原因.
In class hierarchy, ServletException
already matches Throwable
, so its root cause won't be extracted for the second pass.
要证明此指定行为,请将 javax.faces.application.ViewExpiredException
替换为 javax.servlet.ServletException
作为
> 并重试.您将看到显示的预期错误页面.
To prove this specified behaviour, replace javax.faces.application.ViewExpiredException
by javax.servlet.ServletException
as <exception-type>
and retry. You'll see the expected error page being displayed.
要解决此问题,只需删除java.lang.Throwable
或java.lang.Exception
上的错误页面.如果没有一个异常特定的错误页面匹配,那么它无论如何都会回退到错误代码为 500
的那个页面.所以,你只需要这样:
To solve this, simply remove the error page on java.lang.Throwable
or java.lang.Exception
. If no one exception specific error page matches, then it will fall back to the one for error code of 500
anyway. So, all you need is this:
<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
的调试行,以自己查看.
Update: as per the (deleted) comment of the OP: to reliably test this you cannot do a throw new ViewExpiredException()
in a bean constructor or method or so. It would in turn get wrapped in some EL exception. You can eventually add a debug line printing rootCause
in the Filter
to see it yourself.
如果您使用 Eclipse/Tomcat,测试 ViewExpiredException
的快速方法如下:
If you're using Eclipse/Tomcat, a quick way to test ViewExpiredException
is the following:
- 使用简单的命令按钮创建一个 JSF 页面,部署并运行它,然后在网络浏览器中打开它.
- 返回 Eclipse,右键单击 Tomcat 服务器并选择 Clean Tomcat Work Directory.这将重新启动 Tomcat 和垃圾所有序列化会话(重要!仅重新启动 Tomcat 是不够的).
- 返回网络浏览器并按下命令按钮(无需事先重新加载页面!).
- Create a JSF page with a simple command button, deploy and run it and open it in webbrowser.
- Go back to Eclipse, rightclick Tomcat server and choose Clean Tomcat Work Directory. This will restart Tomcat and trash all serialized sessions (important! just restarting Tomcat is not enough).
- Go back to webbrowser and press the command button (without reloading page beforehand!).
这篇关于web.xml 中的 java.lang.Throwable 错误页面中显示的 ViewExpiredException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!