JSF 2全局异常处理,导航到错误页面没有发生
Posted
技术标签:
【中文标题】JSF 2全局异常处理,导航到错误页面没有发生【英文标题】:JSF 2 Global exception handling, navigation to error page not happening 【发布时间】:2013-08-26 22:17:24 【问题描述】:我正在开发一个基于 JSF 2.0 的 Web 应用程序。我正在尝试实现一个全局异常处理程序,只要发生任何异常(例如 NullPointerException、ServletException、ViewExpiredException 等),就会将用户重定向到通用错误页面
每当我的应用程序中发生 NPE 时,我的 customnavhandler 断点被命中并执行 NavigationHandler 代码,但不知何故重定向到错误页面没有发生,请求的页面仍然部分呈现。知道这里有什么问题吗?一个信息是我故意在请求的页面上抛出 NPE(在 NPE 之后部分呈现)
我的 faces-config.xml 条目
<factory>
<exception-handler-factory>
com.common.exceptions.CustomExceptionHandlerFactory
</exception-handler-factory>
</factory>
我的自定义导航处理程序
public class CustomExceptionHandler extends ExceptionHandlerWrapper
private static final Logger logger = Logger.getLogger("com.gbdreports.common.exception.CustomExceptionHandler");
private final ExceptionHandler wrapped;
public CustomExceptionHandler(ExceptionHandler wrapped)
this.wrapped = wrapped;
@Override
public ExceptionHandler getWrapped()
return this.wrapped;
public void handle() throws FacesException
final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
while (i.hasNext())
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context =
(ExceptionQueuedEventContext) event.getSource();
// get the exception from context
Throwable t = context.getException();
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
final ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) fc.getApplication().getNavigationHandler();
//here you do what ever you want with exception
try
//log error ?
logger.error("Severe Exception Occured");
//log.log(Level.SEVERE, "Critical Exception!", t);
//redirect error page
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
// remove the comment below if you want to report the error in a jsf error message
//JsfUtil.addErrorMessage(t.getMessage());
finally
//remove it from queue
i.remove();
//parent hanle
getWrapped().handle();
我的 customNavhandler 工厂
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory
private ExceptionHandlerFactory parent;
public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent)
this.parent = parent;
@Override
public ExceptionHandler getExceptionHandler()
return new CustomExceptionHandler (parent.getExceptionHandler());
【问题讨论】:
【参考方案1】:这很可能是因为当前请求是一个 ajax(异步)请求。您拥有的异常处理程序是为常规(同步)请求而设计的。
在ajax异常的情况下更改视图的正确方法如下:
String viewId = "/error.xhtml";
ViewHandler viewHandler = context.getApplication().getViewHandler();
context.setViewRoot(viewHandler.createView(context, viewId));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
然而这有点幼稚。如果在呈现 ajax 响应的过程中抛出 ajax 异常,这将不起作用。
我建议不要重新发明***。 JSF 实用程序库OmniFaces 具有FullAjaxExceptionHandler
风格的完整工作解决方案。您可以找到完整的源代码here 和展示示例here。它利用web.xml
中的标准servlet API <error-page>
声明。这样,错误页面也可用于同步请求,在FacesExceptionFilter
的帮助下,同样由 OmniFaces 提供。
另见:
using ExternalContext.dispatch in JSF error handler causes corrupt page rendering What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?【讨论】:
【参考方案2】:处理 ajax 和非 ajax 请求异常的统一方法可以简化您的代码。而不是
requestMap.put("exceptionMessage", t.getMessage()); nav.performNavigation("/TestPRoject/error.xhtml"); fc.renderResponse();
够用了:
fc.getExternalContext().redirect("/TestPRoject/error.xhtml");
【讨论】:
这种方法有两个主要问题: 1) 错误页面变得幂等(它的 URL 反映在浏览器地址栏中,出于安全原因,这不适用于放置在/WEB-INF
中的错误页面)。 2) 请求属性丢失(连同异常详细信息)。
恕我直言,向用户显示有关 NullPointerException、ViewExpiredException 或 ServletException 的信息是没有意义的。因此,使用一个通用错误页面(幂等)似乎就足够了。将错误页面隐藏到 WEB-INF 中似乎也没有多大意义。开发人员应查看日志以获取异常详细信息。这种方法完全满足我目前的项目要求。但可能不会满足你的...但这并不意味着方法不好。
这至少不是标准 Servlet API <error-page>
的工作方式,这会使它们在 JSF ajax 请求中无法重用。以上是关于JSF 2全局异常处理,导航到错误页面没有发生的主要内容,如果未能解决你的问题,请参考以下文章
处理 AJAXified 组件的 JSF 2.0 异常的正确方法是啥?