一、背景

在咱们编写程序的过程中,程序中可能随时产生各种异样,那么咱们如何优雅的解决各种异样呢?

二、需要

1、拦挡零碎中局部异样,返回自定义的响应。

比方:
零碎产生HttpRequestMethodNotSupportedException异样,咱们须要返回如下信息。
http的状态码:返回 405

{    code: 自定义异样码,    message: 谬误音讯}

2、实现自定义异样的拦挡

拦挡咱们本人写的 BizException

三、编写一些异样根底代码

1、引入jar包

<dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-validation</artifactId>    </dependency></dependencies>

留神:
引入spring-boot-starter-validation是为了验证申请的中的参数,而后当参数不满足时抛出异样。

2、定义一个自定义异样

public class BizException extends RuntimeException {    public BizException() {    }    public BizException(String message) {        super(message);    }    public BizException(String message, Throwable cause) {        super(message, cause);    }    public BizException(Throwable cause) {        super(cause);    }    public BizException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {        super(message, cause, enableSuppression, writableStackTrace);    }}

3、编写一个简略的管制层

@RestController@RequestMapping("exception")public class ExceptionTestController {    static class Req {        @NotBlank        public String password;    }    @PostMapping("password")    public String checkPassword(@Validated @RequestBody Req req) {        if (Objects.equals(req.password, "exception")) {            throw new BizException("明码传递的是exception字符串");        }        return "以后明码,password: " + req.password;    }}

解释
提供一个 /exception/password api,须要传递一个password参数
1、当不传递 password 参数时将抛出MethodArgumentNotValidException异样。
2、当password传递exception参数时,则抛出BizException异样。

4、测试

1、不传递password参数响应是什么

1、应用默认的DefaultHandlerExceptionResolver解决

这个类DefaultHandlerExceptionResolver是默认主动配置的。

从上图中能够看出有一个默认字段的返回值

2、应用ResponseEntityExceptionHandler解决
1、编写异样解决代码-应用默认的逻辑
@RestControllerAdvicepublic class RestExceptionHandler extends ResponseEntityExceptionHandler {    @Override    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {        // 此处自定义返回值        return super.handleMethodArgumentNotValid(ex, headers, status, request);    }}

能够看到handleMethodArgumentNotValid办法间接调用父类的办法,即应用默认的解决形式。

从上图中能够看出返回值是空

2、编写异样解决代码-返回值返回自定义内容
@Component@RestControllerAdvicepublic class RestExceptionHandler extends ResponseEntityExceptionHandler {    @Override    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {        // 此处自定义返回值        return super.handleMethodArgumentNotValid(ex, headers, status, request);    }            @Override    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {        Set<HttpMethod> supportedMethods = ex.getSupportedHttpMethods();        // 自定义申请返回值        Map<String, Object> body = new HashMap<>(4);        body.put("code", "错误码");        body.put("message", "以后申请的办法不反对,反对的申请办法为:" + supportedMethods);        return new ResponseEntity<>(body, headers, status);    }}

由下面的代码可知handleHttpRequestMethodNotSupported办法返回了自定义的body。

从上图中能够看出,返回了咱们本人定义的返回值。

2、password参数传递exception

1、应用ResponseEntityExceptionHandler或DefaultHandlerExceptionResolver解决


由上图可知返回后果不对,咱们须要自定义返回后果。

2、返回自定义异样
1、编写BizException解决代码
@RestControllerAdvicepublic class BizExceptionHandler {    @ExceptionHandler(BizException.class)    public ResponseEntity<Object> handleBizException(BizException exception) {        // 自定义申请返回值        Map<String, Object> body = new HashMap<>(4);        body.put("code", "错误码");        body.put("message", "异样信息为:" + exception.getMessage());        return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);    }}
2、测试返回后果


从上图可知返回了自定义信息

四、注意事项

1、如果实现自定义异样解决

  1. 类上应用@RestControllerAdvice注解
  2. 办法上应用@ExceptionHandler来解决特定的异样

2、ResponseEntityExceptionHandler默认解决那些异样

3、应用了ResponseEntityExceptionHandler后,为什么产生了异样后返回体为空


默认状况下,实现了 ResponseEntityExceptionHandler这个类后,这个类解决的所有异样的响应后果都是 null,如果想返回别的值须要咱们本人去解决。

五、总结

1、如果咱们想解决自定义异样,则能够应用 @RestControllerAdvice || @ControllerAdvice 配置@ExceptionHandler来应用。
2、如果咱们实现了ResponseEntityExceptionHandler来解决异样,那么默认的异样的响应后果为空,如果想不为空,则须要咱们本人解决。
3、默认状况下,规范的Spring MVC异样会通过DefaultHandlerExceptionResolver来解决。

六、代码实现

https://gitee.com/huan1993/spring-cloud-parent/tree/master/springboot/springboot-exception-handler

七、参考文档