RestController中@Valid注解始终返回200状态码问题求助
Spring Boot 请求参数校验不生效问题
在Spring Boot 3.1.3项目中,按教程在@RequestBody前添加@Valid注解实现请求参数校验,但实际请求始终返回200/201状态码,JUnit测试却能正常校验约束。即使添加BindingResult参数,其错误数也显示为0。
DTO类
package practice.corejava.validators.dto; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; @Data @NoArgsConstructor @AllArgsConstructor public class UserData { @NotBlank(message = "Name should not be blank") private String name; @NotNull(message = "Age should not be null") @Positive(message = "Age should be positive") private Integer age; }
Controller类(Postman请求始终返回201)
package practice.corejava.validators.controller; import practice.corejava.validators.dto.UserData; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import jakarta.validation.Valid; import java.net.URI; @RestController @RequestMapping("api/v1/validations") public class ValidationsController { @PostMapping(value = "/user-data", consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<UserData> createUserData(@Valid @RequestBody UserData userData) { URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{name}").buildAndExpand(userData.getName()).toUri(); return ResponseEntity.created(location).build(); } }
JUnit测试类(测试用例执行成功)
package practice.corejava.validators.dto; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import jakarta.validation.ConstraintViolation; import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; public class UserDataTest { private static Validator validator; @BeforeAll public static void setUp() { try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { validator = factory.getValidator(); } } @Test void all_validation_success() { UserData userData = new UserData("SomeName", 30); Set<ConstraintViolation<UserData>> constraintViolations = validator.validate(userData); assertEquals(0, constraintViolations.size()); } @Test void name_blank() { UserData userData = new UserData("", 30); Set<ConstraintViolation<UserData>> constraintViolations = validator.validate(userData); assertEquals(1, constraintViolations.size()); assertEquals("Name should not be blank", constraintViolations.iterator().next().getMessage()); } }
Postman请求体(预期返回400,实际返回201)
{ "name" : null, "age" : 30 }
依赖及版本信息
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.3</version> <relativePath/> </parent> <properties> <java.version>17</java.version> </properties> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.2</version> </dependency>
问题原因及解决方案
1. 依赖冲突问题
手动引入的jakarta.validation-api 3.0.2与spring-boot-starter-validation内置的依赖版本不兼容,导致Spring校验机制无法正常触发。Spring Boot的starter已经包含适配版本的validation-api,无需手动指定。
解决方法:移除手动添加的jakarta.validation-api依赖:
<!-- 删除以下依赖配置 --> <!-- <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.2</version> </dependency> -->
2. 全局异常处理器检查
若项目存在@RestControllerAdvice或@ControllerAdvice注解的全局异常处理类,可能错误捕获了MethodArgumentNotValidException并返回2xx状态码。可添加自定义校验异常处理:
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.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice 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); } }
3. 验证注解导入
确保使用的是jakarta.validation.Valid而非旧版javax.validation.Valid(Spring Boot 3.x基于Jakarta EE规范,不再支持javax包)。
4. 重启测试
修改依赖并重启项目后,再次发送无效请求,应返回400状态码及对应错误信息。
内容的提问来源于stack exchange,提问作者ViRaS
相关产品推荐
相关产品推荐

