Spring MVC中@Valid注解在Controller的DTO验证中失效问题排查
@Valid注解在非Spring Boot环境下未生效问题
向http://localhost:8080/student发送无效请求时,@Valid注解未生效,无效数据直接进入Controller、Service层级。
相关代码
Controller代码
import org.example.controller.dto.StudentDTO; import org.example.service.interfaces.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.sql.SQLException; @RestController @RequestMapping("/student") public class StudentController{ private final StudentService service; @Autowired public StudentController(StudentService service) { this.service = service; } @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<StudentDTO> doPost(@RequestBody @Valid StudentDTO studentDTO) { try { StudentDTO studentDTOOut = service.saveNewStudent(studentDTO); return new ResponseEntity<>(studentDTOOut, HttpStatus.OK); } catch (SQLException e) { return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } catch (RuntimeException e) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } }
DTO代码
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.util.UUID; public class StudentDTO { @NotNull private UUID id; @NotBlank private String surname; // getters, setters }
pom.xml核心配置
<properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.9</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>3.1.2</version> </dependency> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>6.1.7.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.7.Final</version> </dependency> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>2.0.2</version> </dependency> <!-- 其他依赖省略 --> </dependencies>
已尝试的无效操作
- 在Controller类上添加
@Validated注解 - 给DTO字段添加
@JsonProperty(required = true) - 删除
@PostMapping的produces属性
疑问
在未使用Spring Boot的情况下,@Valid/@Validated注解是否能够正常工作?
问题分析与解决方案
核心原因
非Spring Boot环境下,Spring WebMvc不会自动配置Bean Validation的相关处理器,且当前依赖存在版本兼容性问题:
- Spring 6.x基于Jakarta EE 9+,但使用的
jakarta.validation-api是2.0.2(属于Jakarta EE 8),版本不匹配 hibernate-validator6.1.x仅支持Jakarta Validation 2.0,无法适配Spring 6的规范
修复步骤
更新依赖版本
替换为适配Spring 6的验证依赖:<!-- Jakarta Validation API 3.0.x(适配Jakarta EE 9) --> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.2</version> </dependency> <!-- Hibernate Validator 8.x(适配Jakarta Validation 3.0) --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version> </dependency> <!-- 验证注解处理器 --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator-annotation-processor</artifactId> <version>8.0.1.Final</version> </dependency>手动配置验证器Bean
创建Spring配置类,注册验证相关Bean:import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; @Configuration public class ValidationConfig { // 全局验证器 @Bean public LocalValidatorFactoryBean validator() { return new LocalValidatorFactoryBean(); } // 支持@Validated方法级验证 @Bean public MethodValidationPostProcessor methodValidationPostProcessor() { MethodValidationPostProcessor processor = new MethodValidationPostProcessor(); processor.setValidator(validator()); return processor; } }配置Spring MVC验证器
在WebMvc配置类中绑定验证器:import org.springframework.context.annotation.Configuration; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final LocalValidatorFactoryBean validator; public WebMvcConfig(LocalValidatorFactoryBean validator) { this.validator = validator; } @Override public Validator getValidator() { return validator; } }添加全局异常处理器
捕获验证异常并返回友好响应:import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class GlobalExceptionHandler { @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); } }
验证效果
完成配置后,@Valid会在请求进入Controller方法前触发验证,无效数据会被拦截并抛出异常,不会流转到Service层级。
内容的提问来源于stack exchange,提问作者Vi Vi
相关产品推荐
相关产品推荐

