SpringBoot教程(九)| SpringBoot统一异常处理@RestControllerAdvice
转载
一缕82年的清风
大佬的文章(仅仅供个人学习用):
SpringBoot教程(九) | SpringBoot统一异常处理
@RestControllerAdvice
是Spring框架(包括Spring MVC和Spring Boot)中提供的一个注解。
它主要用于定义全局异常处理和全局数据绑定的类。
该文主要讲一下如何实现 全局异常处理
全局异常处理
- 统一处理异常:通过在
@RestControllerAdvice
类中定义带有@ExceptionHandler
注解的方法,可以统一处理整个应用程序中抛出的异常。当应用程序中发生指定类型的异常时,会自动调用相应的异常处理方法,并返回处理后的结果给客户端。- 提高代码的可维护性和可读性:通过集中处理异常,可以避免在每个控制器中重复编写相同的异常处理代码,从而简化代码结构,提高代码的可维护性和可读性。
- 自定义错误响应:在异常处理方法中,可以编写自定义的逻辑来处理异常,例如返回自定义的错误消息、状态码等,以提供更加友好的错误响应给客户端。
步骤 1.自定义异常(用于在业务逻辑中抛出特定的错误)
首先,定义一个自定义异常类,例如
BusinessException
,用于在业务逻辑中抛出特定的错误。
public class BizException extends RuntimeException {
private Integer code;
public BizException() {
}
public BizException(String message) {
super(message);
}
public BizException(Integer code, String message) {
super(message);
this.code = code;
}
public BizException(ResultCode resultCode) {
super(resultCode.getMsg());
this.code = resultCode.getCode();
}
public BizException(String message, Throwable cause) {
super(message, cause);
}
public BizException(int code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
public BizException(ResultCode resultCode, Throwable cause) {
super(resultCode.getMsg(), cause);
this.code = resultCode.getCode();
}
public Integer getCode() {
return this.code;
}
public void setCode(Integer code) {
this.code = code;
}
}
步骤 2.创建全局异常处理器
使用
@RestControllerAdvice
注解来定义一个全局异常处理器。
在这个处理器中,我们可以根据抛出的异常类型来定义不同的处理逻辑。
// 定义一个全局异常处理器,
//使用@RestControllerAdvice注解使其能够处理所有Controller中的异常
@RestControllerAdvice
// @Order(1)用于指定异常处理器的优先级,数值越小优先级越高
@Order(1)
public class GlobalExceptionHandler {
// 使用日志框架记录异常信息
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// 构造方法,通常用于初始化资源,但此处为空实现
public GlobalExceptionHandler() {
}
// 私有方法,用于处理表单绑定错误,返回第一个错误的默认消息
// 注意:这个方法目前只在类内部被调用,并未直接暴露为异常处理器
private String handlerErrors(BindingResult bindingResult) {
// 获取所有字段错误
List<FieldError> errors = bindingResult.getFieldErrors();
// 假设至少有一个错误,并获取第一个错误
FieldError error = (FieldError)errors.get(0);
// 返回该错误的默认消息
return error.getDefaultMessage();
}
// 自定义异常BizException的处理器
// 当BizException被抛出时,此方法会被调用
@ExceptionHandler({BizException.class})
public Result<?> bizExceptionHandler(HttpServletRequest request, BizException e) {
// 根据BizException的code属性构建响应结果,如果code为空则使用默认的业务错误码
Result<?> result = Result.error(e.getCode() == null ? ResultCode.BIZ_ERROR.getCode() : e.getCode(), e.getMessage());
// 记录日志并返回处理结果
return this.printLogAndReturn(request, result, e);
}
// 处理不支持的HTTP请求方法或媒体类型异常的处理器
@ExceptionHandler({HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class})
public Result<?> httpRequestMethodNotSupportedExceptionHandler(HttpServletRequest request, Exception e) {
// 构建表示请求方法或媒体类型不支持的响应结果
Result<?> result = Result.error(ResultCode.REQ_MODE_NOT_SUPPORTED);
// 记录日志并返回处理结果
return this.printLogAndReturn(request, result, e);
}
// 处理所有未被上述处理器捕获的异常
@ExceptionHandler({Exception.class})
// 设置HTTP响应状态码为500内部服务器错误
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result<?> exceptionHandler(HttpServletRequest request, Exception e) {
// 构建表示系统错误的响应结果
Result<?> result = Result.error(ResultCode.SYS_ERROR);
// 记录日志并返回处理结果
return this.printLogAndReturn(request, result, e);
}
// 私有方法,用于记录日志并返回处理结果
// 该方法将请求信息、异常信息和处理结果转换为字符串并记录到日志中
private Result<?> printLogAndReturn(HttpServletRequest request, Result<?> result, Exception e) {
// 创建ObjectMapper实例用于JSON序列化
ObjectMapper mapper = new ObjectMapper();
// 获取当前请求的完整URL(包括查询字符串)
String requestUrl = request.getRequestURL().toString() + (!StringUtils.hasLength(request.getQueryString()) ? "" : "?" + request.getQueryString());
// 尝试将Result对象转换为JSON字符串,并记录到日志中,包括请求接口、异常时间和异常结果
try {
log.error("<-异常返回-> 请求接口:{} | 异常时间:{} | 异常结果:{}", new Object[]{requestUrl, System.currentTimeMillis(), mapper.writeValueAsString(result)});
} catch (JsonProcessingException jsonProcessingException) {
// 如果在将Result对象转换为JSON字符串时发生异常,则打印堆栈跟踪信息
jsonProcessingException.printStackTrace();
}
// 记录一条日志,表示即将记录异常堆栈信息
log.error("<--异常堆栈信息-->");
// 创建一个StringWriter实例,用于捕获异常的堆栈跟踪信息
StringWriter stringWriter = new StringWriter();
// 将异常的堆栈跟踪信息写入StringWriter
e.printStackTrace(new PrintWriter(stringWriter));
// 将StringWriter中的堆栈跟踪信息转换为字符串,并记录到日志中
log.error(stringWriter.toString());
// 返回原始的Result对象
return result;
}
}
步骤 3.控制器中抛出自定义异常(进行测试)
@RestController
public class ThirdExceptionController {
@GetMapping("exception")
public User second(){
System.out.println(1);
throw new BizException(ResultCode.BIZ_ERROR.getCode(), "用户名密码错误");
}
}