乐趣区

关于java:SpringBoot中异常处理

一、背景

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

二、需要

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、编写异样解决代码 - 应用默认的逻辑
@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 办法间接调用父类的办法,即应用默认的解决形式。

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

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。

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

2、password 参数传递 exception

1、应用 ResponseEntityExceptionHandler 或 DefaultHandlerExceptionResolver 解决


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

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、测试返回后果


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

四、注意事项

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

七、参考文档

退出移动版