全局异常处理方式

Spring Boot 针对全局异常,提供了如下三种处理方式。

实现 ErrorController

Spring Boot 将所有的错误默认映射到 /error 请求, 实现 ErrorController 接口,重写 getErrorPath 方法,跳转到错误页面。

  1. @Controller
  2. @RequestMapping(value = "error")
  3. public class BaseErrorController implements ErrorController {
  4. private static final Logger logger = LoggerFactory.getLogger(BaseErrorController.class);
  5. @Override
  6. public String getErrorPath() {
  7. logger.info("出错啦!进入自定义错误控制器");
  8. return "error/error";
  9. }
  10. @RequestMapping
  11. public String error() {
  12. return getErrorPath();
  13. }
  14. }

添加自定义错误页面

添加自定义错误页面,根据不同的错误情况跳转不同的错误提示页面。

  • html 静态页面:在 resources/public/error/ 下定义,如添加 404 页面: resources/public/error/404.html 页面,中文注意页面编码;
  • 模板引擎页面:在 templates/error/ 下定义,如添加 5xx 页面: templates/error/5xx.ftl;

注:templates/error/ 这个的优先级比较 resources/public/error/ 高。

基于注解 @ControllerAdvice

基于@ControllerAdvice 注解的全局异常统一处理只能针对于 Controller 层的异常,意思是只能捕获到 Controller 层的异常,在 Service 层或者其他层面的异常都不能捕获。

  1. /**
  2. * 全局异常处理
  3. *
  4. * @author yinjianwei
  5. * @date 2018/07/30
  6. */
  7. @ControllerAdvice
  8. public class GlobalExceptionHandler {
  9. /**
  10. * 日志
  11. */
  12. private Logger logger = LoggerFactory.getLogger(getClass());
  13. /**
  14. * 拦截捕捉业务异常
  15. *
  16. * @param ex
  17. * @return
  18. */
  19. @ExceptionHandler(value = ServiceException.class)
  20. @ResponseBody
  21. public DataResponse myErrorHandler(ServiceException e, HttpServletRequest request) {
  22. String userIp = request.getRemoteAddr();
  23. String requestURL = request.getRequestURL().toString();
  24. String params = request.getQueryString();
  25. Date date = new Date();
  26. logger.error(String.format("Service Exception Log, time: %tF %tT|userIp: %s|requestURL: %s|params: %s", date,
  27. date, userIp, requestURL, params), e);
  28. return DataResponse.error(e.getErrorCode(), e.getMessage());
  29. }
  30. /**
  31. * 全局异常捕捉处理
  32. *
  33. * @param ex
  34. * @return
  35. */
  36. @ResponseBody
  37. @ExceptionHandler(value = Exception.class)
  38. public DataResponse errorHandler(Exception e, HttpServletRequest request) {
  39. String userIp = request.getRemoteAddr();
  40. String requestURL = request.getRequestURL().toString();
  41. String params = request.getQueryString();
  42. Date date = new Date();
  43. logger.error(String.format("Exception Log, time:%tF %tT|userIp:%s|requestURL:%s|params:%s", date, date, userIp,
  44. requestURL, params), e);
  45. return DataResponse.error();
  46. }
  47. }

全局异常处理参考

  1. @Controller
  2. @RequestMapping(value = "error")
  3. @EnableConfigurationProperties({ServerProperties.class})
  4. public class ExceptionController implements ErrorController {
  5. private ErrorAttributes errorAttributes;
  6. @Autowired
  7. private ServerProperties serverProperties;
  8. /**
  9. * 初始化ExceptionController
  10. *
  11. * @param errorAttributes
  12. */
  13. @Autowired
  14. public ExceptionController(ErrorAttributes errorAttributes) {
  15. Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
  16. this.errorAttributes = errorAttributes;
  17. }
  18. /**
  19. * 定义404的ModelAndView
  20. *
  21. * @param request
  22. * @param response
  23. * @return
  24. */
  25. @RequestMapping(produces = "text/html", value = "404")
  26. public ModelAndView errorHtml404(HttpServletRequest request, HttpServletResponse response) {
  27. response.setStatus(getStatus(request).value());
  28. Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
  29. return new ModelAndView("error/404", model);
  30. }
  31. /**
  32. * 定义404的JSON数据
  33. *
  34. * @param request
  35. * @return
  36. */
  37. @RequestMapping(value = "404")
  38. @ResponseBody
  39. public ResponseEntity<Map<String, Object>> error404(HttpServletRequest request) {
  40. Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
  41. HttpStatus status = getStatus(request);
  42. return new ResponseEntity<Map<String, Object>>(body, status);
  43. }
  44. /**
  45. * 定义500的ModelAndView
  46. *
  47. * @param request
  48. * @param response
  49. * @return
  50. */
  51. @RequestMapping(produces = "text/html", value = "500")
  52. public ModelAndView errorHtml500(HttpServletRequest request, HttpServletResponse response) {
  53. response.setStatus(getStatus(request).value());
  54. Map<String, Object> model = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
  55. return new ModelAndView("error/500", model);
  56. }
  57. /**
  58. * 定义500的错误JSON信息
  59. *
  60. * @param request
  61. * @return
  62. */
  63. @RequestMapping(value = "500")
  64. @ResponseBody
  65. public ResponseEntity<Map<String, Object>> error500(HttpServletRequest request) {
  66. Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
  67. HttpStatus status = getStatus(request);
  68. return new ResponseEntity<Map<String, Object>>(body, status);
  69. }
  70. /**
  71. * Determine if the stacktrace attribute should be included.
  72. *
  73. * @param request the source request
  74. * @param produces the media type produced (or {@code MediaType.ALL})
  75. * @return if the stacktrace attribute should be included
  76. */
  77. protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
  78. ErrorProperties.IncludeStacktrace include = this.serverProperties.getError().getIncludeStacktrace();
  79. if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
  80. return true;
  81. }
  82. if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
  83. return getTraceParameter(request);
  84. }
  85. return false;
  86. }
  87. /**
  88. * 获取错误的信息
  89. *
  90. * @param request
  91. * @param includeStackTrace
  92. * @return
  93. */
  94. private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
  95. RequestAttributes requestAttributes = new ServletRequestAttributes(request);
  96. return this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace);
  97. }
  98. /**
  99. * 是否包含trace
  100. *
  101. * @param request
  102. * @return
  103. */
  104. private boolean getTraceParameter(HttpServletRequest request) {
  105. String parameter = request.getParameter("trace");
  106. if (parameter == null) {
  107. return false;
  108. }
  109. return !"false".equals(parameter.toLowerCase());
  110. }
  111. /**
  112. * 获取错误编码
  113. *
  114. * @param request
  115. * @return
  116. */
  117. private HttpStatus getStatus(HttpServletRequest request) {
  118. Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
  119. if (statusCode == null) {
  120. return HttpStatus.INTERNAL_SERVER_ERROR;
  121. }
  122. try {
  123. return HttpStatus.valueOf(statusCode);
  124. } catch (Exception ex) {
  125. return HttpStatus.INTERNAL_SERVER_ERROR;
  126. }
  127. }
  128. /**
  129. * 实现错误路径,暂时无用
  130. *
  131. * @see ExceptionMvcAutoConfiguration#containerCustomizer()
  132. * @return
  133. */
  134. @Override
  135. public String getErrorPath() {
  136. return "";
  137. }
  138. }

参考

https://blog.csdn.net/hao_kkkkk/article/details/80538955