SpringBoot+Java17中@Valid注解无法校验POJO的问题排查
Spring Boot 请求参数校验不生效问题解决
问题描述
我之前只用过Dropwizard和Java 11,最近在学习Spring和Java 17,想要在POST/PUT请求中对POJO做参数校验。参考示例实现后,本地测试发现校验完全未生效,一开始以为是Records的问题,换成普通Class后依然无法触发校验。
控制器代码
@RestController public class HelloWorldController { //... 其他GET接口 @PostMapping("/userProfile") @ResponseStatus(HttpStatus.CREATED) public ResponseEntity<UserProfileClass> addUserProfile(@RequestBody @Valid UserProfileClass userProfile) { System.out.println("Inserting in the database: " + userProfile); return ResponseEntity.ok(userProfile); } }
POJO代码
public class UserProfileClass { @NotNull @NotBlank String name; @NotBlank @NotNull String address; //... getters and setters }
依赖配置
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
测试请求与结果
发送请求:
POST http://localhost:8080/userProfile Content-Type: application/json { "name": "some Name" }
返回结果始终为200状态码,address字段为null也未触发校验,按预期应该返回4XX状态码,请问问题出在哪里?
原因分析
- 依赖冲突:Java 17搭配的Spring Boot 3.x版本基于Jakarta EE 9+,校验API已从
javax.validation迁移到jakarta.validation,手动引入的javax.validation:validation-api会和spring-boot-starter-validation自带的Jakarta版本校验API冲突,导致校验器无法正常加载。 - 字段访问权限问题:POJO中的字段是默认包访问权限(无修饰符),JSR-380校验框架默认需要能够访问被注解的字段或对应的getter方法,包私有字段可能无法被校验器正确读取注解信息。
解决方案
1. 移除冲突的依赖
删除pom.xml中手动引入的javax.validation:validation-api依赖,spring-boot-starter-validation已经包含了适配当前Spring Boot版本的校验API(Jakarta版本)。
2. 调整POJO的字段访问权限与注解位置
将POJO字段改为private,并确保getter/setter方法存在,注解可以放在字段上(推荐)或者getter方法上,示例:
public class UserProfileClass { @NotNull @NotBlank private String name; @NotNull @NotBlank private String address; // 标准getter和setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
3. (可选)添加全局异常处理器(增强错误返回)
如果需要自定义校验失败的返回格式,可以添加全局异常处理器捕获MethodArgumentNotValidException:
@RestControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach(error -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); } }
验证步骤
修改后重新启动服务,发送同样的测试请求,此时应该返回400 Bad Request,并携带校验错误信息,说明校验已生效。
内容的提问来源于stack exchange,提问作者Dany
相关产品推荐
相关产品推荐

