美文网首页
SpringBoot中异常处理

SpringBoot中异常处理

作者: huan1993 | 来源:发表于2022-04-28 16:56 被阅读0次

    一、背景

    在我们编写程序的过程中,程序中可能随时发生各种异常,那么我们如何优雅的处理各种异常呢?

    二、需求

    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是默认自动配置的。

    image.png

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

    image.png

    2、使用ResponseEntityExceptionHandler处理

    1、编写异常处理代码-使用默认的逻辑
    @RestControllerAdvice
    public 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方法直接调用父类的方法,即使用默认的处理方式。

    image.png

    从上图中可以看出返回值是空

    2、编写异常处理代码-返回值返回自定义内容
    @Component
    @RestControllerAdvice
    public 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。

    image.png

    从上图中可以看出,返回了我们自己定义的返回值。

    2、password参数传递exception

    1、使用ResponseEntityExceptionHandler或DefaultHandlerExceptionResolver处理

    image.png

    由上图可知返回结果不对,我们需要自定义返回结果。

    2、返回自定义异常

    1、编写BizException处理代码
    @RestControllerAdvice
    public 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、测试返回结果
    image.png

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

    四、注意事项

    1、如果实现自定义异常处理

    1. 类上使用@RestControllerAdvice注解
    2. 方法上使用@ExceptionHandler来处理特定的异常

    2、ResponseEntityExceptionHandler默认处理那些异常

    image.png

    3、使用了ResponseEntityExceptionHandler后,为什么发生了异常后返回体为空

    image.png

    默认情况下,实现了 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

    七、参考文档

    image.png

    相关文章

      网友评论

          本文标题:SpringBoot中异常处理

          本文链接:https://www.haomeiwen.com/subject/vpddyrtx.html