Java 如何使用 Spring MVC / Spring Boot 编写适当的全局错误处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23580509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to write a proper global error handler with Spring MVC / Spring Boot
提问by kayahr
I'm writing a web application with Spring 4.0.4 and Spring Boot 1.0.2 using Tomcat as embedded web container and I want to implement a global exception handling which intercepts all exceptions and logs them in a specific way. My simple requirements are:
我正在编写一个带有 Spring 4.0.4 和 Spring Boot 1.0.2 的 Web 应用程序,使用 Tomcat 作为嵌入式 Web 容器,我想实现一个全局异常处理,它拦截所有异常并以特定方式记录它们。我的简单要求是:
- I want to globally handle all exceptions which are not already processed somewhere else (In a controller exception handler for example). I want to log the message and I want to display a custom error message to the user.
- I don't want Spring or the web container to log any errors by itself because I want to do this myself.
- 我想全局处理其他地方尚未处理的所有异常(例如在控制器异常处理程序中)。我想记录该消息,并且我想向用户显示自定义错误消息。
- 我不希望 Spring 或 Web 容器自己记录任何错误,因为我想自己这样做。
So far my solution looks like this (Simplified, no logging and no redirection to an error view):
到目前为止,我的解决方案看起来像这样(简化,没有日志记录,也没有重定向到错误视图):
@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";
}
}
The result is that exceptions thrown in controllers are correctly handled by the unexpectedError
method and 404 status codes are handled by the notFound
method. So far so good, but I have the following problems:
结果是控制器中抛出的异常被unexpectedError
方法正确处理,404状态码被notFound
方法处理。到目前为止一切顺利,但我有以下问题:
- Tomcat or Spring (not sure who is responsible) is still logging the error message. I don't want that because I want to log it myself (with additional information) and I don't want duplicate error messages in the log. How can I prevent this default logging?
- The way I access the exception object doesn't seem right. I fetch if from the request attribute
javax.servlet.error.exception
. And that's not even the thrown exception, it is an instance oforg.springframework.web.util.NestedServletException
and I have to dive into this nested exception to fetch the real one. I'm pretty sure there is an easier way but I can't find it.
- Tomcat 或 Spring(不确定谁负责)仍在记录错误消息。我不希望这样,因为我想自己记录它(带有附加信息),并且我不想在日志中出现重复的错误消息。如何防止此默认日志记录?
- 我访问异常对象的方式似乎不对。我从请求属性中获取 if
javax.servlet.error.exception
。这甚至不是抛出的异常,它是一个实例,org.springframework.web.util.NestedServletException
我必须深入研究这个嵌套异常以获取真正的异常。我很确定有更简单的方法,但我找不到。
So how can I solve these problems? Or maybe the way I implemented this global exception handler is completely wrong and there is a better alternative?
那么我该如何解决这些问题呢?或者我实现这个全局异常处理程序的方式是完全错误的,有更好的选择吗?
采纳答案by Michiel
Have a look at ControllerAdvice You could do something like this:
看看 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;
}
}