18

我正在开发一个 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 容器评估这些标签的顺序,以便出现正确的页面?谢谢。

4

2 回答 2

17

这是因为它是按照 JSF 规范ViewExpiredException包装在 a中的。这是JSF 1.2 规范ServletException第 10.2.6.2 章的摘录:

10.2.6.2 FacesServlet

调用已execute()保存实例的方法,将此请求的实例作为参数Lifecycle传递 。FacesContext如果该execute()方法抛出 a FacesException则将其作为 a 重新抛出,并ServletException作为 FacesException根本原因

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

SRV.9.9.2 错误页面

如果没有 error-page包含exception-type使用 类层次结构 match的声明,并且抛出的异常是 aServletException或其子类,则容器提取ServletException.getRootCause方法定义的包装异常。对错误页面声明进行第二次传递,再次尝试匹配错误页面声明,但使用包装的异常。

在类层次结构中,ServletException已经匹配Throwable,因此不会为第二遍提取其根本原因。

要证明此指定行为,请替换javax.faces.application.ViewExpiredExceptionjavax.servlet.ServletExceptionas<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 的(已删除)注释:要可靠地测试这一点,您不能throw new ViewExpiredException()在 bean 构造函数或方法中执行。反过来,它会被包裹在一些 EL 异常中。您最终可以在 中添加调试行打印rootCauseFilter自己查看。

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

  1. 使用简单的命令按钮创建一个 JSF 页面,部署并运行它并在 webbrowser 中打开它。
  2. 返回 Eclipse,右键单击 Tomcat 服务器并选择Clean Tomcat Work Directory。这将重新启动 Tomcat丢弃所有序列化会话(重要!仅重新启动 Tomcat 是不够的)。
  3. 返回网络浏览器并按下命令按钮(无需事先重新加载页面!)。
于 2010-07-08T21:14:32.430 回答
0

正如 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 错误处理将无法正常工作。

于 2020-08-11T16:24:27.350 回答