26

ExceptionHandlerFactory到目前为止,我遇到的所有示例都会在捕获a 时将用户重定向到viewExpired.jsf页面:ViewExpiredException

public class ViewExpiredExceptionExceptionHandler extends ExceptionHandlerWrapper {
    private ExceptionHandler wrapped;

    public ViewExpiredExceptionExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.wrapped;
    }

    @Override
    public void handle() throws FacesException {
        for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();

            Throwable t = context.getException();
            if (t instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) t;
                FacesContext facesContext = FacesContext.getCurrentInstance();
                Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
                NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();
                try {
                    // Push some useful stuff to the request scope for use in the page
                    requestMap.put("currentViewId", vee.getViewId());
                    navigationHandler.handleNavigation(facesContext, null, "/viewExpired");
                    facesContext.renderResponse();
                } finally {
                    i.remove();
                }
            }
        }

        // At this point, the queue will not contain any ViewExpiredEvents. Therefore, let the parent handle them.
        getWrapped().handle();
    }
}

在我看来,下面的简单web.xml配置基本上是相同的,而且要简单得多:

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/viewExpired.jsf</location>
</error-page>

这就提出了一个问题——为什么要使用ExceptionHandlerFactory?

4

2 回答 2

29

这个特定的例子只做了一件有用的事情:它将视图 ID 保存为请求属性,以便您可以使用例如

<h:link value="Go back to previous page" outcome="#{currentViewId}" />

但这并不是非常有用,因为原始请求 URI 已经可以通过<error-page>默认请求属性获得javax.servlet.error.request_uri

<h:outputLink value="#{requestScope['javax.servlet.error.request_uri']}">Go back to previous page</h:outputLink>

然而,自定义真正有用的一件事是它允许您在ajax 请求ExceptionHandler期间处理异常。默认情况下,他们在客户端没有单一形式的有用反馈。只有在项目阶段设置为“开发”的 Mojarra 中,您才会看到带有异常消息的纯 JavaScript 警报消息。但就是这样。“生产”阶段没有单一形式的反馈。使用自定义,您将能够解析以查找错误页面位置,使用它创建一个新页面并强制 JSF 将 ajax 渲染设置为.ExceptionHandlerweb.xmlUIViewRoot@all

所以,基本上

String errorPageLocation = "/WEB-INF/errorpages/500.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();

另请参阅此相关问题:处理 AJAX 化组件的 JSF 2.0 异常的正确方法是什么?和这个博客:完整的 Ajax 异常处理程序

于 2012-05-12T14:22:32.107 回答
3

这取决于您在接受时想做什么ViewExpiredException

如果您只想向用户显示错误页面,您可以按照您所说的进行操作。

这篇文章向您展示了如何以编程方式拦截 ViewExpiredException并用它做一些好事。

于 2012-05-12T07:35:28.993 回答