Зачем использовать перенаправление JSF ExceptionHandlerFactory вместо перенаправления <error-page>?
Все примеры ExceptionHandlerFactory
, с которыми я столкнулся, перенаправляют пользователя на страницу 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
?
Ответы
Ответ 1
В конкретном примере реализована только одна полезная вещь: она сохраняет идентификатор вида как атрибут запроса, так что вы можете использовать, например,
<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>
Однако одна вещь, для которой пользовательский ExceptionHandler
действительно полезен, заключается в том, что он позволяет вам обрабатывать исключения во время ajax-запросов. По умолчанию у них нет единственной формы полезной обратной связи на стороне клиента. Только в Mojarra с этапом проекта, установленным в "Development", вы увидите сообщение с предупреждением о появлении JavaScript с сообщением об исключении. Но это так. На этапе "Производство" нет единой формы обратной связи. С помощью настраиваемого ExceptionHandler
вы сможете проанализировать web.xml
, чтобы найти местоположения страниц ошибок, создать с ним новый UIViewRoot
и заставить JSF установить ajax-рендеринг на @all
.
Итак, в основном:
String errorPageLocation = "/WEB-INF/errorpages/500.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
См. также этот связанный вопрос: Каков правильный способ справиться с исключениями JSF 2.0 для компонентов AJAXified? и этот блог: Полный обработчик исключений Ajax.
Ответ 2
Это зависит от того, что вы хотите сделать, когда будете получать ViewExpiredException
.
Если вы просто хотите отобразить страницу пользовательской ошибки, вы можете сделать это, как вы сказали.
Этот post показывает вам, как программно перехватывать
ViewExpiredException
и сделайте с ним что-нибудь хорошее.