服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - SpringBoot初始教程之统一异常处理详解

SpringBoot初始教程之统一异常处理详解

2020-09-07 09:15尊少 Java教程

本篇文章主要介绍了SpringBoot初始教程之统一异常处理详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

1.介绍

在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。SpringBoot在页面发生异常的时候会自动把请求转到/error,SpringBoot内置了一个BasicErrorController对异常进行统一的处理,当然也可以自定义这个路径

application.yaml

?
1
2
3
4
server:
 port: 8080
 error:
 path: /custom/error

BasicErrorController提供两种返回错误一种是页面返回、当你是页面请求的时候就会返回页面,另外一种是json请求的时候就会返回json错误

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
  HttpServletResponse response) {
 HttpStatus status = getStatus(request);
 Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
   request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
 response.setStatus(status.value());
 ModelAndView modelAndView = resolveErrorView(request, response, status, model);
 return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
 
@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
 Map<String, Object> body = getErrorAttributes(request,
   isIncludeStackTrace(request, MediaType.ALL));
 HttpStatus status = getStatus(request);
 return new ResponseEntity<Map<String, Object>>(body, status);
}

分别会有如下两种返回

SpringBoot初始教程之统一异常处理详解

?
1
2
3
4
5
6
7
{
 "timestamp": 1478571808052,
 "status": 404,
 "error": "Not Found",
 "message": "No message available",
 "path": "/rpc"
}

2.通用Exception处理

通过使用@ControllerAdvice来进行统一异常处理,@ExceptionHandler(value = Exception.class)来指定捕获的异常

下面针对两种异常进行了特殊处理分别返回页面和json数据,使用这种方式有个局限,无法根据不同的头部返回不同的数据格式,而且无法针对404、403等多种状态进行处理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ControllerAdvice
public class GlobalExceptionHandler {
 public static final String DEFAULT_ERROR_VIEW = "error";
 @ExceptionHandler(value = CustomException.class)
 @ResponseBody
 public ResponseEntity defaultErrorHandler(HttpServletRequest req, CustomException e) throws Exception {
  return ResponseEntity.ok("ok");
 }
 @ExceptionHandler(value = Exception.class)
 public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
  ModelAndView mav = new ModelAndView();
  mav.addObject("exception", e);
  mav.addObject("url", req.getRequestURL());
  mav.setViewName(DEFAULT_ERROR_VIEW);
  return mav;
 }
}

3.自定义BasicErrorController 错误处理

在初始介绍哪里提到了BasicErrorController,这个是SpringBoot的默认错误处理,也是一种全局处理方式。咱们可以模仿这种处理方式自定义自己的全局错误处理

下面定义了一个自己的BasicErrorController,可以根据自己的需求自定义errorHtml()和error()的返回值。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
 private final ErrorProperties errorProperties;
 private static final Logger LOGGER = LoggerFactory.getLogger(BasicErrorController.class);
 @Autowired
 private ApplicationContext applicationContext;
 
 /**
  * Create a new {@link org.springframework.boot.autoconfigure.web.BasicErrorController} instance.
  *
  * @param errorAttributes the error attributes
  * @param errorProperties configuration properties
  */
 public BasicErrorController(ErrorAttributes errorAttributes,
        ErrorProperties errorProperties) {
  this(errorAttributes, errorProperties,
    Collections.<ErrorViewResolver>emptyList());
 }
 
 /**
  * Create a new {@link org.springframework.boot.autoconfigure.web.BasicErrorController} instance.
  *
  * @param errorAttributes the error attributes
  * @param errorProperties configuration properties
  * @param errorViewResolvers error view resolvers
  */
 public BasicErrorController(ErrorAttributes errorAttributes,
        ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
  super(errorAttributes, errorViewResolvers);
  Assert.notNull(errorProperties, "ErrorProperties must not be null");
  this.errorProperties = errorProperties;
 }
 
 @Override
 public String getErrorPath() {
  return this.errorProperties.getPath();
 }
 
 @RequestMapping(produces = "text/html")
 public ModelAndView errorHtml(HttpServletRequest request,
         HttpServletResponse response) {
  HttpStatus status = getStatus(request);
  Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
    request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
  response.setStatus(status.value());
  ModelAndView modelAndView = resolveErrorView(request, response, status, model);
  insertError(request);
  return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
 }
 
 
 
 @RequestMapping
 @ResponseBody
 public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
  Map<String, Object> body = getErrorAttributes(request,
    isIncludeStackTrace(request, MediaType.ALL));
  HttpStatus status = getStatus(request);
  insertError(request);
  return new ResponseEntity(body, status);
 }
 
 /**
  * Determine if the stacktrace attribute should be included.
  *
  * @param request the source request
  * @param produces the media type produced (or {@code MediaType.ALL})
  * @return if the stacktrace attribute should be included
  */
 protected boolean isIncludeStackTrace(HttpServletRequest request,
           MediaType produces) {
  ErrorProperties.IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
  if (include == ErrorProperties.IncludeStacktrace.ALWAYS) {
   return true;
  }
  if (include == ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM) {
   return getTraceParameter(request);
  }
  return false;
 }
 
 /**
  * Provide access to the error properties.
  *
  * @return the error properties
  */
 protected ErrorProperties getErrorProperties() {
  return this.errorProperties;
 }
}

SpringBoot提供了一种特殊的Bean定义方式,可以让我们容易的覆盖已经定义好的Controller,原生的BasicErrorController是定义在ErrorMvcAutoConfiguration中的

具体代码如下:

?
1
2
3
4
5
6
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
 return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
   this.errorViewResolvers);
}

可以看到这个注解@ConditionalOnMissingBean 意思就是定义这个bean 当 ErrorController.class 这个没有定义的时候, 意思就是说只要我们在代码里面定义了自己的ErrorController.class时,这段代码就不生效了,具体自定义如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(ResourceProperties.class)
public class ConfigSpringboot {
 @Autowired(required = false)
 private List<ErrorViewResolver> errorViewResolvers;
 private final ServerProperties serverProperties;
 
 public ConfigSpringboot(
   ServerProperties serverProperties) {
  this.serverProperties = serverProperties;
 }
 
 @Bean
 public MyBasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
  return new MyBasicErrorController(errorAttributes, this.serverProperties.getError(),
    this.errorViewResolvers);
 }
}

在使用的时候需要注意MyBasicErrorController不能被自定义扫描Controller扫描到,否则无法启动。

3.总结

一般来说自定义BasicErrorController这种方式比较实用,因为可以通过不同的头部返回不同的数据格式,在配置上稍微复杂一些,但是从实用的角度来说比较方便而且可以定义通用组件

本文代码:SpringBoot-Learn.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/king_is_everyone/article/details/53080851

延伸 · 阅读

精彩推荐