Подтвердить что ты не робот

Как написать правильный глобальный обработчик ошибок с помощью Spring MVC/Spring Загрузка

Я пишу веб-приложение с Spring 4.0.4 и Spring Boot 1.0.2 с использованием Tomcat в качестве встроенного веб-контейнера, и я хочу реализовать глобальную обработку исключений, которая перехватывает все исключения и записывает их в определенный путь. Мои простые требования:

  • Я хочу глобально обрабатывать все исключения, которые еще не обрабатываются в другом месте (например, в обработчике исключений контроллера). Я хочу записать сообщение, и я хочу показать пользователю пользовательское сообщение об ошибке.
  • Я не хочу, чтобы Spring или веб-контейнер регистрировали ошибки самостоятельно, потому что я хочу сделать это сам.

До сих пор мое решение выглядело следующим образом (упрощенный, без регистрации и переадресации на просмотр ошибок):

@Controller
@RequestMapping("/errors")
public class ErrorHandler implements EmbeddedServletContainerCustomizer
{
    @Override
    public void customize(final ConfigurableEmbeddedServletContainer factory)
    {
        factory.addErrorPages(new ErrorPage("/errors/unexpected"));
        factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/errors/notfound"));
    }

    @RequestMapping("unexpected")
    @ResponseBody
    public String unexpectedError(final HttpServletRequest request)
    {
        return "Exception: " + request.getAttribute("javax.servlet.error.exception");
    }

    @RequestMapping("notfound")
    @ResponseBody
    public String notFound()
    {
        return "Error 404";
    }
}

В результате исключения, создаваемые контроллерами, корректно обрабатываются методом unexpectedError, а 404 кодов состояния обрабатываются методом notFound. Пока все хорошо, но у меня есть следующие проблемы:

  • Tomcat или Spring (не уверен, кто несет ответственность) все еще регистрирует сообщение об ошибке. Я не хочу этого, потому что я хочу сам регистрировать его (с дополнительной информацией), и я не хочу дублировать сообщения об ошибках в журнале. Как предотвратить эту регистрацию по умолчанию?
  • То, как я обращаюсь к объекту исключения, кажется неправильным. Я извлекаю, если из атрибута request javax.servlet.error.exception. И это даже не исключенное исключение, это экземпляр org.springframework.web.util.NestedServletException, и я должен погрузиться в это вложенное исключение, чтобы получить реальный. Я уверен, что есть более простой способ, но я не могу его найти.

Итак, как я могу решить эти проблемы? Или, может быть, способ, которым я реализовал этот глобальный обработчик исключений, совершенно неверен, и есть лучшая альтернатива?

4b9b3361

Ответ 1

Посмотрите на ControllerAdvice Вы можете сделать что-то вроде этого:

@ControllerAdvice
public class ExceptionHandlerController {

    public static final String DEFAULT_ERROR_VIEW = "error";

    @ExceptionHandler(value = {Exception.class, RuntimeException.class})
    public ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) {
            ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW);

        mav.addObject("datetime", new Date());
        mav.addObject("exception", e);
        mav.addObject("url", request.getRequestURL());
        return mav;
    }
}