Spring Boot 统一异常处理与统一返回封装

为什么需要统一异常处理

没有统一异常处理时,Controller 里到处是 try-catch,前端拿到的错误格式五花八门:有的返回字符串,有的返回 500 裸异常,有的把堆栈直接抛给用户。Spring Boot 用 @RestControllerAdvice + @ExceptionHandler 可以把异常在一处收口,再配合统一返回体,前后端对接会清爽很多。

一、先定义统一返回结构

public class Result<T> {
    private int code;
    private String msg;
    private T data;

    public static <T> Result<T> ok(T data) {
        Result<T> r = new Result<>();
        r.code = 0; r.msg = "success"; r.data = data;
        return r;
    }
    public static Result<?> fail(int code, String msg) {
        Result<?> r = new Result<>();
        r.code = code; r.msg = msg;
        return r;
    }
    // getter/setter 省略
}

二、全局异常处理器

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 业务异常
    @ExceptionHandler(BusinessException.class)
    public Result<?> handleBiz(BusinessException e) {
        return Result.fail(e.getCode(), e.getMessage());
    }

    // 参数校验失败
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> handleValid(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(400, msg);
    }

    // 兜底:未知异常
    @ExceptionHandler(Exception.class)
    public Result<?> handleOther(Exception e) {
        // 生产环境不要暴露堆栈
        return Result.fail(500, "系统异常,请稍后重试");
    }
}

三、业务异常与校验

自定义异常携带业务码:

public class BusinessException extends RuntimeException {
    private int code;
    public BusinessException(int code, String msg) {
        super(msg); this.code = code;
    }
    // getter
}

Controller 里直接抛,不用自己包:

@PostMapping("/order")
public Result<Order> create(@Valid @RequestBody CreateOrderReq req) {
    if (req.getCount() <= 0)
        throw new BusinessException(1001, "购买数量必须大于0");
    return Result.ok(orderService.create(req));
}

@Valid 触发 Bean Validation,校验失败自动进 MethodArgumentNotValidException,返回字段级的友好提示。

四、几个注意点

  • 生产环境别把异常堆栈返回前端,统一返回”系统异常”即可,细节记日志。
  • 全局处理器建议放在独立的 package,确保被 Spring 扫描到。
  • 如果用了 Filter/Interceptor 里抛的异常,@RestControllerAdvice 拦不到,需要在 Filter 层单独处理。

小结

统一异常处理的核心就一句话:异常在一处收口,返回格式只有一种。配合 Result<T> 和分层异常,前端再也不用写一堆 if 判断错误结构,联调效率直接翻倍。

上一篇 NIFI 配置密钥
下一篇 SQL Server 执行计划解读与索引优化实战