Skip to content

全局异常处理

框架内置 GlobalExceptionHandler,覆盖 6 类典型异常,业务方零配置即可获得统一的错误返回结构。

默认能处理的异常

异常类型触发场景HTTP 状态码业务 code日志级别
BusinessException业务代码主动抛出200由 BaseErrorEnum 决定warn
MethodArgumentNotValidException@RequestBody + @Valid 校验失败400400warn
ConstraintViolationException@Validated + 单参数校验失败400400warn
BindException表单 / Query 参数绑定失败400400warn
NoResourceFoundExceptionSpring Boot 3.x 静态资源 404404404不记录
RuntimeException未被前面拦下的运行时异常500500error,含堆栈
Exception兜底500500error,含堆栈

BusinessException 走 HTTP 200

业务异常的 HTTP 状态码故意保留 200,错误由 Result 中的 success=false 与 code 表达。这样前端只需要拦截 success 字段,不必再去判别 HTTP 状态码与业务码两套规则。

抛业务异常的标准姿势

BusinessException 用 Builder 模式构造,必须配合一个 BaseErrorEnum

java
import cn.cvking.forge.exception.BaseErrorEnum;

public enum UserErrorEnum implements BaseErrorEnum {

    USER_NOT_FOUND(2001, "用户不存在: id={0}"),
    USER_ALREADY_EXISTS(2002, "用户名已存在: {0}");

    private final int code;
    private final String msg;

    UserErrorEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    @Override public int getCode() { return code; }
    @Override public String getMsg() { return msg; }
}

业务代码里抛:

java
throw BusinessException.of(UserErrorEnum.USER_NOT_FOUND, userId).errThrow();

错误消息支持 {0}{1} 这种 MessageFormat 占位符,由 BusinessException.of(...) 在构造期完成替换。

框架本身在 SystemErrorEnum 里预置了一批系统级错误码(BAD_REQUEST、VALIDATION_ERROR、BUSINESS_ERROR 等),可以直接复用,无需每个项目重复声明。

参数校验异常的返回形态

定义一个 DTO:

java
import jakarta.validation.constraints.*;
import lombok.Data;

@Data
public class UserDTO {

    @NotBlank(message = "用户名不能为空")
    private String username;

    @Min(value = 18, message = "年龄不能小于 18")
    private Integer age;
}

Controller 用 @Valid 接收:

java
@PostMapping
public UserDTO create(@Valid @RequestBody UserDTO dto) {
    return dto;
}

如果传入 {"username": "", "age": 10},框架捕获 MethodArgumentNotValidException,返回:

json
{
  "success": false,
  "code": 400,
  "message": "参数校验失败: 用户名不能为空; 年龄不能小于 18",
  "data": null
}

多个字段的错误信息用 ; 拼接,HTTP 状态码为 400。

系统异常会被脱敏

RuntimeException 与 Exception 兜底返回的消息固定为「服务器开小差了,请稍后重试」,不会把堆栈细节暴露给客户端。完整堆栈仍然以 ERROR 级别记入服务端日志,方便排查。

设计动机与扩展方式见 设计文档 · 异常处理器