SpringBoot全局异常处理与统一响应

目录

 

前言

一、@ControllerAdvice实现全局异常捕获

1.1 什么是@ControllerAdvice?

二、自定义业务异常类

2.1 为什么需要自定义异常?

2.2 实现自定义异常

2.3 异常使用示例

三、统一响应体设计(ResultVO)

3.1 响应体结构设计

3.2 Controller层统一返回

3.3 响应示例

四、进阶优化技巧

4.1 状态码枚举管理

4.2 自动记录异常日志

4.3 处理第三方异常(如Feign调用异常)

五、常见问题与解决方案

5.1 异常处理不生效?

5.2 如何区分不同异常响应状态码?

5.3 如何处理文件上传大小限制异常?


 

前言

在实际项目中,异常处理和接口响应规范化是保障系统健壮性和可维护性的关键。本文将手把手教你用SpringBoot实现:

  1. 全局异常捕获:通过@ControllerAdvice统一处理所有异常

  2. 自定义业务异常:优雅区分系统错误与业务错误

  3. 统一响应体:标准化接口返回格式,告别杂乱响应

一、@ControllerAdvice实现全局异常捕获

1.1 什么是@ControllerAdvice?

@ControllerAdvice是Spring提供的全局增强控制器注解,可结合@ExceptionHandler捕获所有Controller层抛出的异常。

1.2 创建全局异常处理器

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理系统异常(兜底处理)
    @ExceptionHandler(Exception.class)
    public ResultVO handleException(Exception e) {
        log.error("系统异常: {}", e.getMessage());
        return ResultVO.error(500, "系统繁忙,请稍后再试");
    }

    // 处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public ResultVO handleBusinessException(BusinessException e) {
        log.warn("业务异常: {}", e.getMessage());
        return ResultVO.error(e.getCode(), e.getMessage());
    }

    // 处理参数校验异常(需配合@Validated使用)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO handleValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return ResultVO.error(400, message);
    }
}

关键注解说明

  • @RestControllerAdvice = @ControllerAdvice + @ResponseBody

  • @ExceptionHandler:指定要捕获的异常类型

二、自定义业务异常类

2.1 为什么需要自定义异常?

  • 区分系统异常与业务异常(如订单不存在、库存不足)

  • 携带特定错误码,方便前端处理

  • 统一异常信息格式

2.2 实现自定义异常

public class BusinessException extends RuntimeException {

    private final int code;

    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }

    public int getCode() {
        return code;
    }
}

 

2.3 异常使用示例

在Service层抛出业务异常:

public User getUserById(Long id) {
    User user = userRepository.findById(id);
    if (user == null) {
        throw new BusinessException(1001, "用户不存在");
    }
    return user;
}

三、统一响应体设计(ResultVO)

3.1 响应体结构设计

标准化响应应包含:状态码、消息、数据三要素。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO<T> {

    private int code;    // 状态码(200=成功)
    private String msg;  // 提示信息
    private T data;      // 响应数据

    // 成功响应(无数据)
    public static <T> ResultVO<T> success() {
        return new ResultVO<>(200, "success", null);
    }

    // 成功响应(带数据)
    public static <T> ResultVO<T> success(T data) {
        return new ResultVO<>(200, "success", data);
    }

    // 错误响应
    public static <T> ResultVO<T> error(int code, String msg) {
        return new ResultVO<>(code, msg, null);
    }
}

 

3.2 Controller层统一返回

修改Controller方法返回值类型为ResultVO

@GetMapping("/user/{id}")
public ResultVO<User> getUser(@PathVariable Long id) {
    User user = userService.getUserById(id);
    return ResultVO.success(user);
}

 

3.3 响应示例

成功响应

{
  "code": 200,
  "msg": "success",
  "data": {
    "id": 1,
    "name": "张三"
  }
}

 异常响应

 

{
  "code": 1001,
  "msg": "用户不存在",
  "data": null
}

 

四、进阶优化技巧

4.1 状态码枚举管理

使用枚举统一管理错误码,避免魔法数字:

public enum ResultCode {
    SUCCESS(200, "操作成功"),
    USER_NOT_FOUND(1001, "用户不存在"),
    PARAM_INVALID(400, "参数错误");

    private final int code;
    private final String msg;

    // 构造方法、getter省略
}

修改ResultVO的error方法:

public static <T> ResultVO<T> error(ResultCode resultCode) {
    return new ResultVO<>(resultCode.getCode(), resultCode.getMsg(), null);
}

4.2 自动记录异常日志

通过AOP在异常发生时自动记录日志(可选):

@Aspect
@Component
public class ExceptionLogAspect {

    @AfterThrowing(pointcut = "execution(* com.example..*.*(..))", throwing = "e")
    public void logException(JoinPoint joinPoint, Exception e) {
        String method = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getName();
        log.error("类 {} 的方法 {} 发生异常: {}", className, method, e.getMessage());
    }
}

4.3 处理第三方异常(如Feign调用异常)

通过实现ErrorDecoder自定义Feign异常解析:

public class FeignErrorDecoder implements ErrorDecoder {
    @Override
    public Exception decode(String methodKey, Response response) {
        String message = "Feign调用异常: " + response.status();
        return new BusinessException(5001, message);
    }
}

 

五、常见问题与解决方案

5.1 异常处理不生效?

  • 检查全局异常处理器是否被Spring扫描到(是否在启动类同级或子包)

  • 确认Controller方法没有用try-catch局部捕获

5.2 如何区分不同异常响应状态码?

  • 系统异常统一返回500系列状态码

  • 业务异常使用400或自定义业务码(如1001)

  • 参数校验异常返回400

5.3 如何处理文件上传大小限制异常?

application.properties中配置:

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

 捕获MaxUploadSizeExceededException

@ExceptionHandler(MaxUploadSizeExceededException.class)
public ResultVO handleFileSizeLimitExceeded() {
    return ResultVO.error(400, "文件大小超过限制");
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YY...yy

你的鼓励将是我创作的最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值