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(), "用户名密码错误");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值