【问题标题】:JSF 2.0 Custom Exception HandlerJSF 2.0 自定义异常处理程序
【发布时间】:2011-07-13 19:07:14
【问题描述】:

我很难完全理解 JSF 2.0 中何时/如何引发异常。我寻找解决方案的时间比我愿意承认的要长。最终,我想要实现的目标是“处理”未处理的异常。当抛出异常时,我希望能够捕获有关异常的感兴趣信息,并将其通过电子邮件发送给相应的站点管理员。我通过在我的一个支持 bean 的构造函数中抛出一个 new FacesException() 来强制错误。我在 JSF 1.1 中使用 MyFaces 实现的效果很好。我能够通过包装默认生命周期并简单地覆盖 execute() 和 render() 方法来实现这一点。我按照 Hanspeter 的这篇很棒的帖子进行操作:

“http://insights2jsf.wordpress.com/2009/07/20/using-a-custom-lifecycle-implementation-to-handle-exceptions-in-jsf-1-2/#comment-103”

我现在正在使用 Mojarra 将站点升级到 JSF 2.0。但是,只要在 execute() 方法中抛出/捕获异常,事情仍然很好;在我进入 render() 的那一刻,HttpServletResponse.isCommitted() 等于 true,并且阶段是 PhaseId RENDER_RESPONSE,这当然意味着我不能执行重定向或转发。我不明白 JSF 1.1 和 2.0 在何时/如何提交响应方面发生了什么变化。正如我所指出的,我在 1.1 框架中完美地工作。 经过大量搜索,我发现 JSF 2.0 通过自定义 ExceptionHandler 提供了一个很好的异常处理选项。我关注了 Ed Burns 的博客,在 JSF2 中优雅地处理 ViewExpiredException:

“http://weblogs.java.net/blog/edburns/archive/2009/09/03/dealing-gracefully-viewexpiredexception-jsf2”

正如 Ed 所指出的,通过定义标签和异常/服务器错误代码的类型以及想要将错误发送到哪个页面,总是有 web.xml 方式。只要我发现 404 错误,这种方法就很有效。然而,需要注意的一件有趣的事情是,如果我通过输入像 /myApp/9er 这样的非现有 URL 来强制出现 404 错误,错误处理程序就会很好地工作,但是只要我添加“.xhtml”扩展名(即 /myApp/ 9er.xhtml) 然后 web.xml 定义不处理它。

我注意到 Ed 正在做的一件我没有尝试过的事情是,他没有尝试执行 HttpServletRespone.sendRedirect(),而是利用 Navigationhandler.handleNavigation() 将用户转发到自定义错误页面。不幸的是,这种方法与 Faclets 默认对错误所做的没有什么不同。当然,由于与上述相同的问题,我无法执行 HttpServletResponse.sendRedirect() ; response.isCommitted() 等于 true。

我知道这篇文章会越来越长,所以我将简要说明一下尝试将 PhaseListener 用于相同目的。我使用以下帖子作为指南,但这条路线仍然不成功:

“http://ovaraksin.blogspot.com/2010/10/global-handling-of-all-unchecked.html”“http://ovaraksin.blogspot.com/2010/10/jsf-ajax-redirect -after-session-timeout.html"

所有我都遇到了前面提到的问题。抛出此异常时,响应已处于提交阶段,我无法将用户重定向/转发到标准错误页面。

对于这么长的帖子,我深表歉意,我只是想提供尽可能多的信息以帮助消除歧义。任何人都有任何解决方法的想法/想法,我很好奇 JSF 1.1 和 2.0 之间可能有什么不同,这会导致在我进入生命周期的 render() 阶段后立即提交响应。

非常感谢您对此的任何帮助!!!

【问题讨论】:

    标签: exception jsf-2 handler


    【解决方案1】:

    如上所述,我已经使用响应包装器成功实现了一个过滤器,它可以避免提交响应并允许重定向到自定义页面,即使在呈现页面的过程中出现异常也是如此。

    响应包装器在 StringWriter 上设置自己的内部 PrintWriter,该 StringWriter 由 getWriter 方法返回,以便缓冲人脸输出。在快乐路径中,过滤器随后将内部 StringWriter 内容写入实际响应。出现异常时,过滤器会重定向到错误 jsp,该错误 jsp 会写入(尚未提交的)响应。

    对我来说,避免响应提交的关键是拦截 flushBuffer() 方法(来自 ServletResponse,而不是 HttpServletResponse),并避免调用 super.flushBuffer()。我怀疑根据情况和如上所述,可能还需要覆盖其他一些方法,例如设置标题的方法。

    【讨论】:

      【解决方案2】:

      所以这个问题实际上不仅仅是关于自定义异常处理程序(JSF 2 对此有强大的ExceptionHandlerFactory 机制),而是更多关于在响应已经提交时向用户显示自定义错误页面。

      即使最后一位已经写入响应,也始终能够重定向用户的一种通用方法是使用 HttpServletResponse 包装器来缓冲标头和写入其中的内容。

      这确实会产生不利影响,即用户看不到正在逐步构建的页面。

      也许您可以使用这种技术来仅捕获 JSF 2.0 似乎所做的非常早的响应提交。渲染响应开始后,您会发出到目前为止缓冲的标头并直接写出响应内容。

      这样,如果在呈现响应之前发生异常,您仍然可以将用户重定向到自定义错误页面。

      【讨论】:

      • 非常感谢您的回复!这听起来很有趣,我如何让 Faces 使用我的 HttpServletResponseWrapper 实现?我将采取哪些步骤来实现这一点?
      • 对于响应包装器,只需使用 doFilter 方法创建一个标准 servlet 过滤器,其中包含:chain.doFilter(request, new MyResponseWrapper(response));其中 MyResponseWrapper 是 HttpServletResponseWrapper 的子类。
      • 感谢您的帮助!但是,我能够弄清楚您的建议;我被困在哪里实现标题和内容的缓冲以防止响应被提交?再次感谢您的帮助!
      猜你喜欢
      • 2013-03-14
      • 2011-08-19
      • 1970-01-01
      • 2015-10-18
      • 2023-03-04
      • 1970-01-01
      • 2015-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多