Spring boot 全局异常处理
前言
@ControllerAdvice
注解是Spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。
- 结合方法型注解
@ExceptionHandler
,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。- 结合方法型注解
@InitBinder
,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。- 结合方法型注解
@ModelAttribute
,表示其注解的方法将会在目标Controller方法执行之前执行。在启动应用之后,被
@ExceptionHandler
、@InitBinder
和@ModelAttribute
注解的方法都会作用在被@RequestMappping
注解的方法上。@PostMapping
其实也是被@RequestMappping
修饰的注解这里主要介绍 全局异常的使用
涉及注解 | 描述 |
---|---|
@RestControllerAdvice |
该注解其实是 @ControllerAdvice + @ResponseBody 的组合注解,其中@ControllerAdvice 包含 @Component ,因此被该注解修饰的Java类也是一个被Spring 管理的Bean。 |
@ExceptionHandler |
拦截异常并统一处理,主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。 |
@ResponseStatus |
设置响应状态码 详情参考:Spring @ResponseStatus |
方便代码案例的演示 提前配置 好swagger。具体配置 参考: Spring boot 整合 Swagger使用swagger-bootstrap-ui
代码案例
作为全局异常处理,需要:
自定义一些业务异常
异常的返回码枚举
通用的返回格式
全局的异常捕捉Bean
(一)自定义一些业务异常
/**
* @author lvzb
* @date 2022/09/14 16:57
**/
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -8165592277866289665L;
private final int errorCode;
public BusinessException() {
super("发生业务异常!");
this.errorCode = 200;
}
public BusinessException(String message) {
super(message);
this.errorCode = 200;
}
public BusinessException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
this.errorCode = 200;
}
public BusinessException(Throwable cause) {
super("发生业务异常!", cause);
this.errorCode = 200;
}
public BusinessException(int errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public int getErrorCode() {
return this.errorCode;
}
}
(二)异常的返回枚举
public enum ErrorCode {
SUCCESS(0, "成功"),
ERROR(-1, "失败"),
ERROR_500(500,"失败"),
ERROR_200(200,"失败");
@Getter
private int code;
@Getter
private String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
}
(三)通用的返回格式
package com.zlv11.exception;
@Data
@Builder
public class CommonResponse<T> {
private static final long serialVersionUID = -8713837118340960775L;
private T data;
private int code;
private String message;
public static CommonResponse success() {
return CommonResponse.builder()
.code(ErrorCode.SUCCESS.getCode())
.message(ErrorCode.SUCCESS.getMessage())
.build();
}
public static <T> CommonResponse success(T data) {
return CommonResponse.builder()
.code(ErrorCode.SUCCESS.getCode())
.data(data)
.message(ErrorCode.SUCCESS.getMessage())
.build();
}
public static CommonResponse error(ErrorCode errorCode) {
return CommonResponse.builder()
.code(errorCode.getCode())
.message(errorCode.getMessage())
.build();
}
public static CommonResponse error(ErrorCode errorCode, String message) {
return CommonResponse.builder()
.code(errorCode.getCode())
.message(StringUtils.isEmpty(message) ? errorCode.getMessage() : message)
.build();
}
}
(四)全局的异常捕捉Bean
/**
* 全局异常处理
*
* @author zlv11
* @date 2022/08/05 19:17
*/
@Slf4j
@RestControllerAdvice
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CommonResponse<String> handleException(Exception e) {
log.error("系统内部异常,异常信息:{}", e);
return CommonResponse.error(ErrorCode.ERROR_500, "系统内部异常");
}
@ExceptionHandler(value = BusinessException.class)
@ResponseStatus(code = HttpStatus.OK,reason = "业务异常")
public CommonResponse<String> BusinessExceptionHandler(BusinessException e) {
log.error("业务异常,异常信息:{}", e);
return CommonResponse.error(ErrorCode.ERROR_200, e.getMessage());
}
/**
* 统一处理请求参数校验(实体对象传参)
*
* @param e BindException
* @return CommonResponse
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse validExceptionHandler(BindException e) {
StringBuilder message = new StringBuilder();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError error : fieldErrors) {
message.append("[").append(error.getField()).append("]").append(error.getDefaultMessage()).append(StringPool.COMMA);
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return CommonResponse.error(ErrorCode.ERROR, message.toString());
}
/**
* 统一处理请求参数校验(实体对象传参)
*
* @param e MethodArgumentNotValidException
* @return CommonResponse
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse validExceptionHandler(MethodArgumentNotValidException e) {
StringBuilder message = new StringBuilder();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError error : fieldErrors) {
message.append("[").append(error.getField()).append("]").append(error.getDefaultMessage()).append(StringPool.COMMA);
}
message = new StringBuilder(message.substring(0, message.length() - 1));
log.error("请求入参异常,异常信息:{}", message);
return CommonResponse.error(ErrorCode.ERROR, message.toString());
}
/**
* 统一处理请求参数校验(普通传参)
*
* @param e ConstraintViolationException
* @return CommonResponse
*/
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public CommonResponse handleConstraintViolationException(ConstraintViolationException e) {
StringBuilder message = new StringBuilder();
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
for (ConstraintViolation<?> violation : violations) {
Path path = violation.getPropertyPath();
String[] pathArr = StringUtils.splitByWholeSeparatorPreserveAllTokens(path.toString(), StringPool.DOT);
message.append(pathArr[1]).append(violation.getMessage()).append(StringPool.COMMA);
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return CommonResponse.error(ErrorCode.ERROR, message.toString());
}
}
(五)测试的controller层
/**
* @author lvzb
* @date 2022/11/15 17:37
**/
@Slf4j
@RestController
@Api(tags = "控制层")
@RequestMapping("/swagger")
public class SwaggerTestController {
@PostMapping("/test")
public EchoResponse echo(@RequestBody EchoRequest request) {
return EchoResponse.builder().resp1("Hello world!").build();
}
@PostMapping("/runtimeException")
public CommonResponse<String> runtimeException(@RequestBody EchoRequest request) {
throw new RuntimeException("运行时异常 runtimeException");
}
@PostMapping("/businessException")
public CommonResponse<String> businessException(@RequestBody EchoRequest request) {
throw new BusinessException("业务异常 businessException");
}
}
参考资料
- spring的@ControllerAdvice注解
- Spring @ResponseStatus
- @ControllerAdvice 的介绍及三种用法
- SpringBoot 全局异常处理进阶:使用 @ControllerAdvice 对不同的 Controller 分别捕获异常并处理
转载:https://blog.csdn.net/LvQiFen/article/details/127888303
查看评论