springboot项目中如何优雅的实现异常处理
通过逐行解析自定义异常类和全局异常处理器,我们深入理解了 Spring Boot 中异常处理的实现细节。这种机制不仅提高了代码的可维护性,还为用户提供了友好的错误提示。希望本文对您有所帮助!
Spring Boot 中的异常处理机制
在项目中我们可以通过自定义异常类 QLException、全局异常处理器 GlobalExceptionHandler 和响应数据封装类 ResSerialization,我们实现了一个统一的异常处理机制。这种机制不仅提高了代码的整洁度和可维护性,还确保了系统的健壮性和用户体验的一致性。日志配置的合理使用,也为后续的故障排查提供了有力支持。
1. 自定义异常类 QLException
代码内容
@Data
public class QLException extends RuntimeException {
private String msg;
private int code = 1001;
private int status = 404;
public QLException(BaseExecptionEnum execptionEnum) {
super(execptionEnum.getValue());
this.status = execptionEnum.getStatus();
this.code = execptionEnum.getCode();
this.msg = execptionEnum.getValue();
}
public QLException(String msg) {
super(msg);
this.msg = msg;
this.code = QLHttpStatus.NOT_FOUND.value();
}
public QLException(String msg, int code, int status) {
super(msg);
this.msg = msg;
this.code = code;
this.status = status;
}
public QLException(BaseExecptionEnum execptionEnum, Throwable err) {
super(execptionEnum.getValue(), err);
this.status = execptionEnum.getStatus();
this.code = execptionEnum.getCode();
this.msg = execptionEnum.getValue();
}
}
逐行解析
-
@Data:- 这是 Lombok 注解,自动生成
getter、setter、toString等方法,减少样板代码。
@Data - 这是 Lombok 注解,自动生成
-
public class QLException extends RuntimeException:- 定义了一个自定义异常类
QLException,继承自RuntimeException,因此它是一个运行时异常,不需要在方法签名中声明。
public class QLException extends RuntimeException { - 定义了一个自定义异常类
-
private String msg;:- 定义一个字段
msg,用于存储异常的错误信息。
private String msg; - 定义一个字段
-
private int code = 1001;:- 定义一个字段
code,用于存储业务状态码,默认值为1001。
private int code = 1001; - 定义一个字段
-
private int status = 404;:- 定义一个字段
status,用于存储 HTTP 状态码,默认值为404。
private int status = 404; - 定义一个字段
-
public QLException(BaseExecptionEnum execptionEnum):- 构造方法,接收一个
BaseExecptionEnum枚举对象。 super(execptionEnum.getValue());: 调用父类RuntimeException的构造方法,传入枚举中的错误信息。this.status = execptionEnum.getStatus();: 从枚举中获取 HTTP 状态码并赋值给status字段。this.code = execptionEnum.getCode();: 从枚举中获取业务状态码并赋值给code字段。this.msg = execptionEnum.getValue();: 从枚举中获取错误信息并赋值给msg字段。
public QLException(BaseExecptionEnum execptionEnum) { super(execptionEnum.getValue()); this.status = execptionEnum.getStatus(); this.code = execptionEnum.getCode(); this.msg = execptionEnum.getValue(); } - 构造方法,接收一个
-
public QLException(String msg):- 构造方法,接收一个错误信息字符串。
super(msg);: 调用父类RuntimeException的构造方法,传入错误信息。this.msg = msg;: 将传入的错误信息赋值给msg字段。this.code = QLHttpStatus.NOT_FOUND.value();: 设置默认的业务状态码为404。
public QLException(String msg) { super(msg); this.msg = msg; this.code = QLHttpStatus.NOT_FOUND.value(); } -
public QLException(String msg, int code, int status):- 构造方法,接收错误信息、业务状态码和 HTTP 状态码。
super(msg);: 调用父类RuntimeException的构造方法,传入错误信息。this.msg = msg;: 将传入的错误信息赋值给msg字段。this.code = code;: 将传入的业务状态码赋值给code字段。this.status = status;: 将传入的 HTTP 状态码赋值给status字段。
public QLException(String msg, int code, int status) { super(msg); this.msg = msg; this.code = code; this.status = status; } -
public QLException(BaseExecptionEnum execptionEnum, Throwable err):- 构造方法,接收一个
BaseExecptionEnum枚举对象和一个Throwable异常对象。 super(execptionEnum.getValue(), err);: 调用父类RuntimeException的构造方法,传入枚举中的错误信息和原始异常。this.status = execptionEnum.getStatus();: 从枚举中获取 HTTP 状态码并赋值给status字段。this.code = execptionEnum.getCode();: 从枚举中获取业务状态码并赋值给code字段。this.msg = execptionEnum.getValue();: 从枚举中获取错误信息并赋值给msg字段。
public QLException(BaseExecptionEnum execptionEnum, Throwable err) { super(execptionEnum.getValue(), err); this.status = execptionEnum.getStatus(); this.code = execptionEnum.getCode(); this.msg = execptionEnum.getValue(); } - 构造方法,接收一个
2. 全局异常处理器 GlobalExceptionHandler
代码内容
@RestControllerAdvice("com.qingluo.pay")
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
public Serializable handleHttpMediaTypeNotAcceptableException(HttpMediaTypeNotAcceptableException e) {
log.error("不支持的媒体类型异常 --> {} ", e);
return ResSerialization.error(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "不支持的媒体类型");
}
@ExceptionHandler
public Serializable handle(IllegalArgumentException e) {
if (ObjectUtil.isNotEmpty(e.getMessage())) {
log.error("Assert参数断言异常 --> {} ", e);
}
return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), "参数异常");
}
@ExceptionHandler
public Serializable handle(ValidationException e) {
List<String> errors = null;
if (e instanceof ConstraintViolationException) {
ConstraintViolationException exs = (ConstraintViolationException) e;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
errors = violations.stream()
.map(ConstraintViolation::getMessage).collect(Collectors.toList());
}
if (ObjectUtil.isNotEmpty(e.getCause())) {
log.error("参数校验失败异常 -> {} ", e);
}
return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), errors.toString());
}
@ExceptionHandler
public Serializable handle(QLException e) {
if (ObjectUtil.isNotEmpty(e.getStatus())) {
log.error("自定义异常 --> {} ", e.getMsg());
}
return ResSerialization.error(e.getCode(), e.getMessage());
}
@ExceptionHandler
public Serializable handle(Exception e) {
if (ObjectUtil.isNotEmpty(e.getCause())) {
log.error("未知异常 --> {} ", e.getMessage());
}
return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), e.getMessage());
}
}
逐行解析
-
@RestControllerAdvice("com.qingluo.pay"):- 这是一个 Spring 注解,表示这是一个全局异常处理器,处理
com.qingluo.pay包下的所有控制器抛出的异常。
@RestControllerAdvice("com.qingluo.pay") - 这是一个 Spring 注解,表示这是一个全局异常处理器,处理
-
@Slf4j:- 这是 Lombok 注解,自动生成日志对象
log,用于记录日志。
@Slf4j - 这是 Lombok 注解,自动生成日志对象
-
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class):- 这是一个异常处理方法,专门处理
HttpMediaTypeNotAcceptableException异常。 log.error("不支持的媒体类型异常 --> {} ", e);: 记录异常日志。return ResSerialization.error(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "不支持的媒体类型");: 返回一个错误响应,HTTP 状态码为415,错误信息为 “不支持的媒体类型”。
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class) public Serializable handleHttpMediaTypeNotAcceptableException(HttpMediaTypeNotAcceptableException e) { log.error("不支持的媒体类型异常 --> {} ", e); return ResSerialization.error(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "不支持的媒体类型"); } - 这是一个异常处理方法,专门处理
-
@ExceptionHandler:- 这是一个通用的异常处理方法,处理
IllegalArgumentException异常。 if (ObjectUtil.isNotEmpty(e.getMessage())) { ... }: 如果异常信息不为空,则记录日志。return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), "参数异常");: 返回一个错误响应,HTTP 状态码为400,错误信息为 “参数异常”。
@ExceptionHandler public Serializable handle(IllegalArgumentException e) { if (ObjectUtil.isNotEmpty(e.getMessage())) { log.error("Assert参数断言异常 --> {} ", e); } return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), "参数异常"); } - 这是一个通用的异常处理方法,处理
-
@ExceptionHandler:- 这是一个通用的异常处理方法,处理
ValidationException异常。 List<String> errors = null;: 定义一个列表,用于存储校验失败的错误信息。if (e instanceof ConstraintViolationException) { ... }: 如果异常是ConstraintViolationException类型,则提取校验失败的具体信息。return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), errors.toString());: 返回一个错误响应,HTTP 状态码为400,错误信息为校验失败的具体信息。
@ExceptionHandler public Serializable handle(ValidationException e) { List<String> errors = null; if (e instanceof ConstraintViolationException) { ConstraintViolationException exs = (ConstraintViolationException) e; Set<ConstraintViolation<?>> violations = exs.getConstraintViolations(); errors = violations.stream() .map(ConstraintViolation::getMessage).collect(Collectors.toList()); } if (ObjectUtil.isNotEmpty(e.getCause())) { log.error("参数校验失败异常 -> {} ", e); } return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), errors.toString()); } - 这是一个通用的异常处理方法,处理
-
@ExceptionHandler:- 这是一个通用的异常处理方法,处理
QLException异常。 if (ObjectUtil.isNotEmpty(e.getStatus())) { ... }: 如果异常的状态码不为空,则记录日志。return ResSerialization.error(e.getCode(), e.getMessage());: 返回一个错误响应,业务状态码和错误信息来自异常对象。
@ExceptionHandler public Serializable handle(QLException e) { if (ObjectUtil.isNotEmpty(e.getStatus())) { log.error("自定义异常 --> {} ", e.getMsg()); } return ResSerialization.error(e.getCode(), e.getMessage()); } - 这是一个通用的异常处理方法,处理
-
@ExceptionHandler:- 这是一个通用的异常处理方法,处理所有未知异常。
if (ObjectUtil.isNotEmpty(e.getCause())) { ... }: 如果异常的原始原因不为空,则记录日志。return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), e.getMessage());: 返回一个错误响应,HTTP 状态码为400,错误信息为异常的具体信息。
@ExceptionHandler public Serializable handle(Exception e) { if (ObjectUtil.isNotEmpty(e.getCause())) { log.error("未知异常 --> {} ", e.getMessage()); } return ResSerialization.error(HttpStatus.BAD_REQUEST.value(), e.getMessage()); }
3. 总结
通过逐行解析自定义异常类 QLException 和全局异常处理器 GlobalExceptionHandler,我们深入理解了 Spring Boot 中异常处理的实现细节。这种机制不仅提高了代码的可维护性,还为用户提供了友好的错误提示。希望本文对您有所帮助!
更多推荐



所有评论(0)