JSF 2 Глобальная обработка исключений, переход на страницу ошибок не происходит
Я разрабатываю веб-приложение на основе JSF 2.0. Я пытаюсь реализовать глобальный обработчик исключений, который перенаправляет пользователя на общую страницу ошибки всякий раз, когда возникает какое-либо исключение (например, NullPointerException, ServletException, ViewExpiredException и т.д.).
Всякий раз, когда NPE появляется в моем приложении, удаляется моя контрольная точка Customnavhandler и выполняется код NavigationHandler, но каким-то образом перенаправление на страницу с ошибкой не происходит, запрошенная страница остается частично визуализированной. Любая идея, что может быть неправильно здесь? Одна информация заключается в том, что я бросаю NPE намеренно на запрошенную страницу (которая была частично предоставлена после NPE)
Запись моих лиц-config.xml
<factory>
<exception-handler-factory>
com.common.exceptions.CustomExceptionHandlerFactory
</exception-handler-factory>
</factory>
Мой CustomNavHandler
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 factory
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
. Вы можете найти полный исходный код здесь и пример витрины здесь. Он использует стандартные объявления servlet API <error-page>
в web.xml
. Таким образом, страницы ошибок также могут использоваться повторно для синхронных запросов с небольшой помощью FacesExceptionFilter
, также предоставляемой OmniFaces.
См. также:
Ответ 2
Унифицированный способ обработки исключений ajax и non ajax запросов может быть упрощен для вашего кода. Вместо
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
достаточно для использования:
fc.getExternalContext().redirect("/TestPRoject/error.xhtml");