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");