Spring Boot 3.7要求Starter默认启用Jakarta EE 9+,@ControllerAdvice需配合Jakarta Validation及@RestControllerAdvice才能正确拦截异常;pom.xml中须替换javax.为jakarta.,Result的code必须为Integer,全局异常处理器需按业务异常、参数校验异常、系统异常顺序捕获,并在DTO参数前加@Valid触发校验。

Spring Boot 3.7版本中,Starter默认启用Jakarta EE 9+规范,@ControllerAdvice必须配合Jakarta Validation和@RestControllerAdvice才能正确拦截参数校验异常与业务异常,否则400错误会直接透出原始堆栈。
确认项目依赖是否兼容Jakarta EE 9+
打开pom.xml,检查spring-boot-starter-web版本是否为3.7.x且无javax.*包残留:
若存在javax.validation或javax.servlet依赖,必须全部替换为jakarta.validation和jakarta.servlet;否则@Valid注解失效,@ExceptionHandler无法捕获MethodArgumentNotValidException。
这一步不可跳过——Spring Boot 3.7已彻底移除Java EE 8命名空间,残留javax包会导致异常处理器静默失效。
定义统一响应结构Result
创建Result.java,使用泛型封装code、msg、data字段:
code字段必须为Integer类型(不能是int),否则Jackson序列化时null值会报错;msg字段建议设为非空字符串,避免前端解析失败。
提供success()和error()静态工厂方法,减少重复构造调用。
编写全局异常处理器
方法一:基础版@RestControllerAdvice(适用于纯REST接口)
新建GlobalExceptionHandler.java,类上同时标注@RestControllerAdvice和@Order(1);@Order确保它优先于其他AOP切面执行。
@ExceptionHandler(MethodArgumentNotValidException.class)方法内,从BindingResult提取第一个FieldError的 defaultMessage,作为msg返回;code固定设为400。
【注意】不要直接e.getBindingResult().getFieldErrors().get(0).getDefaultMessage()——若校验对象为空,会抛NPE;必须先判空再取。
方法二:分层捕获(推荐用于混合场景)
第一步:捕获业务自定义异常(如UserNotFoundException)→ 返回code=404,msg="用户不存在"
第二步:捕获参数校验异常(MethodArgumentNotValidException)→ 提取首个错误字段提示
第三步:捕获系统级异常(Exception)→ 记录日志 + 返回code=500 + 固定msg="系统繁忙,请稍后再试"
这三步顺序不能颠倒,否则更具体的异常会被Exception兜底捕获,失去区分度。
方法三:适配WebMvcConfigurer(仅当需兼容传统视图渲染时)
若项目同时提供HTML页面和JSON接口,改用@ControllerAdvice + 手动添加@ResponseBody到每个@ExceptionHandler方法;否则返回ModelAndView会被视图解析器误处理。
启用参数校验自动触发
在Controller方法的DTO参数前添加@Valid注解,例如:@PostMapping public Result create(@Valid @RequestBody UserCreateDTO dto)。
若DTO中字段已加@NotBlank、@Email等约束,但未加@Valid,校验逻辑不会启动,异常也不会进入GlobalExceptionHandler。
这一步漏掉,整个全局异常体系就形同虚设。

















