Spring Boot 2.7.5升级后javax.validation.ValidationException失效问题
问题分析
Spring Boot 2.7.x 对Spring Security和校验模块的默认配置做了调整,尤其是集成Spring Security的场景下,自定义的javax.validation.ValidationException可能会被Security的异常处理器优先捕获,导致你的全局异常处理器无法拦截到目标异常,转而返回401 Unauthorized错误,而不是你预期的自定义提示。
解决方案
1. 调整Spring Security异常处理逻辑
如果项目用了Spring Security,需要在Security配置里让自定义的ValidationException绕过默认的401处理,交给全局异常处理器:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // 其他原有配置... .exceptionHandling() .authenticationEntryPoint((request, response, authException) -> { // 判断异常根源是否是自定义的ValidationException if (authException.getCause() instanceof ValidationException) { throw (ValidationException) authException.getCause(); } // 其他情况走默认401响应 response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage()); }); } }
2. 确保全局异常处理器配置正确
检查全局异常处理器的注解和异常捕获方法是否正确:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ValidationException.class) public ResponseEntity<Map<String, Object>> handleValidationException(ValidationException ex) { Map<String, Object> errorResponse = new HashMap<>(); errorResponse.put("code", HttpStatus.BAD_REQUEST.value()); errorResponse.put("message", ex.getMessage()); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } // 其他异常处理方法... }
如果你的异常是ValidationException的子类,需要在@ExceptionHandler里指定子类类型,或者确保父类类型能覆盖到。
3. 清理依赖冲突
Spring Boot 2.7.x的spring-boot-starter-validation已经包含了校验API和hibernate-validator实现,检查pom.xml里是否有重复引入的javax.validation依赖,避免冲突:
<!-- 保留官方starter即可 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- 移除单独引入的validation-api依赖 --> <!-- <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> </dependency> -->
4. 检查业务代码的异常抛出逻辑
确保业务代码中是直接抛出ValidationException,没有被其他逻辑包装成Security相关异常:
@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { return userRepository.findById(id) .orElseThrow(() -> new ValidationException("User not Found in the System")); }
核心原因
Spring Boot 2.7.x升级了Spring Security版本,其中ExceptionTranslationFilter的异常处理逻辑有调整:当请求经过Security过滤器链时,若抛出的异常被判定为认证相关,会直接触发401响应,不会传递到全局异常处理器。通过上述配置可以让自定义的ValidationException绕过这个拦截,回到全局处理器处理。
内容的提问来源于stack exchange,提问作者Rose

