简体   繁体   English

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

[英]ViewExpiredException shown in java.lang.Throwable error-page in web.xml

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.我正在开发一个 JSF Web 应用程序,如果视图过期,我需要在其中显示“会话已过期”页面,但对于所有其他应用程序则显示一般技术错误页面。 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>

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.我删除了 TechnicalError.jsp 错误页面元素并且它工作正常,但是当我把它们放回去时我无法进入 sessionExpired.jsp 页面。 How do I tell the web container the order to evaluate these tags so that the right page comes up?我如何告诉 Web 容器评估这些标签的顺序,以便出现正确的页面? Thanks.谢谢。

This is because the ViewExpiredException is been wrapped in a ServletException as per the JSF specification.这是因为按照 JSF 规范, ViewExpiredException被包装在一个ServletException中。 Here's an extract of chapter 10.2.6.2 of the JSF 1.2 specification :这是JSF 1.2 规范第 10.2.6.2 章的摘录:

10.2.6.2 FacesServlet 10.2.6.2 FacesServlet

Call the execute() method of the saved Lifecycle instance, passing the FacesContext instance for this request as a parameter.调用保存的Lifecycle实例的execute()方法,将此请求的FacesContext实例作为参数传递。 If the execute() method throws a FacesException , re-throw it as a ServletException with the FacesException as the root cause .如果execute()方法抛出FacesException则将它作为ServletException重新抛出,并将FacesException作为根本原因

How the error pages are allocated is specified in Servlet API specification.错误页面的分配方式在 Servlet API 规范中指定。 Here's an extract of chapter 9.9.2 of Servlet API specification 2.5 :这是Servlet API 规范 2.5的第 9.9.2 章的摘录:

SRV.9.9.2 Error Pages SRV.9.9.2 错误页面

If no error-page declaration containing an exception-type fits using the class-hierarchy match , and the exception thrown is a ServletException or subclass thereof, the container extracts the wrapped exception, as defined by the ServletException.getRootCause method.如果没有包含exception-type error-page声明适合使用类层次结构 match ,并且抛出的异常是ServletException或其子类,则容器提取包装的异常,如ServletException.getRootCause方法所定义。 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.对错误页面声明进行第二次传递,再次尝试与错误页面声明进行匹配,但使用包装的异常代替。

In class hierarchy, ServletException already matches Throwable , so its root cause won't be extracted for the second pass.在类层次结构中, ServletException已经匹配Throwable ,因此第二遍不会提取其根本原因。

To prove this specified behaviour, replace javax.faces.application.ViewExpiredException by javax.servlet.ServletException as <exception-type> and retry.要证明此指定行为,请将javax.faces.application.ViewExpiredException替换为javax.servlet.ServletException作为<exception-type>并重试。 You'll see the expected error page being displayed.您将看到显示的预期错误页面。

To solve this, simply remove the error page on java.lang.Throwable or java.lang.Exception .要解决这个问题,只需删除java.lang.Throwablejava.lang.Exception上的错误页面。 If no one exception specific error page matches, then it will fall back to the one for error code of 500 anyway.如果没有一个异常特定的错误页面匹配,那么它无论如何都会回退到错误代码为500那个页面。 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>

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.更新:根据 OP 的(已删除)评论:要可靠地测试这一点,您不能在 bean 构造函数或方法等中执行throw new ViewExpiredException() It would in turn get wrapped in some EL exception.反过来,它会被包裹在一些 EL 异常中。 You can eventually add a debug line printing rootCause in the Filter to see it yourself.最终可以在Filter添加调试行打印rootCause自己查看。

If you're using Eclipse/Tomcat, a quick way to test ViewExpiredException is the following:如果您使用 Eclipse/Tomcat,测试ViewExpiredException的快速方法如下:

  1. Create a JSF page with a simple command button, deploy and run it and open it in webbrowser.使用简单的命令按钮创建一个 JSF 页面,部署并运行它并在 webbrowser 中打开它。
  2. Go back to Eclipse, rightclick Tomcat server and choose Clean Tomcat Work Directory .返回 Eclipse,右键单击 Tomcat 服务器并选择Clean Tomcat Work Directory This will restart Tomcat and trash all serialized sessions (important! just restarting Tomcat is not enough).这将重新启动 Tomcat删除所有序列化会话(重要!仅重新启动 Tomcat 是不够的)。
  3. Go back to webbrowser and press the command button (without reloading page beforehand!).返回浏览器并按下命令按钮(无需事先重新加载页面!)。

As mentioned by BylusC, deployment descriptor must not contain any error-page handler that will catch ViewExpiredException (wrapped inside ServletException) instead of the correct one - error-page for ViewExpiredException.正如 BylusC 所提到的,部署描述符不能包含任何错误页面处理程序来捕获 ViewExpiredException(包装在 ServletException 中)而不是正确的一个 - ViewExpiredException 的错误页面。

Do not forget to verify that server's deployment descriptor (eg TomEE/conf/web.xml) does not contain java.lang.Throwable or java.lang.Exception error-page definitions.不要忘记验证服务器的部署描述符(例如 TomEE/conf/web.xml)不包含 java.lang.Throwable 或 java.lang.Exception 错误页面定义。 Because these two web.xml are basically merged.因为这两个 web.xml 基本合并了。

Yes - application's web.xml has precedence over server's web.xml, but if application's web.xml contains是 - 应用程序的 web.xml 优先于服务器的 web.xml,但如果应用程序的 web.xml 包含

  • error-page for 500 (/error.xhtml) 500 的错误页面 (/error.xhtml)

and server's web.xml for和服务器的 web.xml 用于

  • 500 (/500.html) and for 500 (/500.html) 和
  • Throwable (/bigerror.html) Throwable (/bigerror.html)

then application context will contain merge of those two:那么应用程序上下文将包含这两者的合并:

  • 500 (/error.xhtml) 500 (/error.xhtml)
  • Throwable (/bigerror.html) Throwable (/bigerror.html)

and ViewExpiredExcpetion error handling will not work correctly.和 ViewExpiredExcpetion 错误处理将无法正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM