2011-03-11 93 views
2

我很努力地完全理解何时/如何在JSF 2.0中抛出异常。我寻找的解决方案比我想承认的要长。最终,我想实现的目标是“处理”未处理的异常。当引发异常时,我希望能够捕获有关异常的感兴趣的信息,并将其发送给相应的网站管理员。我通过在我的一个支持bean的构造函数中抛出一个新的FacesException()来强制引发错误。在JSF 1.1中,我使用MyFaces实现了这个工作。我能够通过包装默认生命周期并简单地覆盖execute()和render()方法来实现这个工作。我跟着这个由Hanspeter真棒发布得到这个工作:JSF 2.0自定义异常处理程序

“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这样的非exsitant 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()阶段后立即提交响应。

非常感谢任何帮助!

回答

3

所以这个问题其实不只是一个自定义异常处理程序(其中JSF 2具有强大的ExceptionHandlerFactory机制),但更多的显示用户自定义错误页时的响应已经提交。

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

这确实有该用户不会看到页是逐渐建立的不利影响。

也许你可以使用这种技术来只捕获很早就响应承诺的是JSF 2.0似乎做。一旦渲染响应开始,你就发出缓冲的标题直到目前为止,并直接写出响应内容。

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

+0

非常感谢您的回复!这听起来很有趣,我如何让Faces使用我的HttpServletResponseWrapper实现?我会采取什么步骤来实现这一点? – Mickelback 2011-03-14 15:11:12

+0

对于响应包装,只创建与含有doFilter方法标准Servlet过滤器:chain.doFilter(请求,新MyResponseWrapper(响应)); MyResponseWrapper是HttpServletResponseWrapper的子类。 – 2011-03-14 22:08:47

+0

谢谢你的帮助!然而,我能够弄清楚你的建议。我坚持在哪里实施缓冲标题和内容以防止响应被提交?再次感谢你的帮助! – Mickelback 2011-03-15 21:28:38

1

我已经成功实施使用响应包装作为如上所述这避免被COMMITED响应,并允许重定向到自定义页面甚至在呈现页面的中间一个异常的过滤器。

的响应包装设置在StringWriter的,这是由的getWriter方法,使得面输出进行缓冲返回其自身的内部的PrintWriter。在快乐路径中,过滤器随后将内部StringWriter内容写入实际响应。在例外情况下,过滤器重定向到写入(尚未提交)响应的错误jsp。

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