Spring Boot @Size验证失效求助:Postman测试接口不生效
问题:Spring Boot POST接口参数验证规则失效
测试http://localhost:8080/departments POST接口时,发现实体类Department的departmentName字段标注的@Size(min = 2)和@NotBlank验证规则未生效:
- 传入
departmentName为"a"的JSON数据,接口正常执行 - 删除
departmentName字段后,接口依然正常工作
相关代码如下:
实体类代码
package com.dailycodebuffer.Springboottutorial.entity; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; @Entity @Data @NoArgsConstructor @AllArgsConstructor @Builder public class Department { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long departmentId; @NotBlank(message = "Please add Department Name") @Size(min = 2, message = "Department Name must be at least 2 characters long") private String departmentName; private String departmentAdress; private String departmentCode; }
控制器代码
package com.dailycodebuffer.Springboottutorial.controller; import com.dailycodebuffer.Springboottutorial.entity.Department; import com.dailycodebuffer.Springboottutorial.error.DepartmentNotFoundException; import com.dailycodebuffer.Springboottutorial.service.DepartmentService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; import java.util.Optional; @RestController @Validated public class DepartmentController { @Autowired private DepartmentService departmentService; private final Logger LOGGER = LoggerFactory.getLogger(DepartmentController.class); @PostMapping("/departments") public Department saveDepartment(@Valid @RequestBody Department department) { LOGGER.info("Inside saveDepartment of DepartmentController"); return departmentService.saveDepartment(department); } @GetMapping("/departments") public List<Department> fetchDepartmentList() { LOGGER.info("Inside fetchDepartment of DepartmentController"); return departmentService.fetchDepartmentList(); } @GetMapping("/departments/{departmentId}") public Optional<Department> fetchDepartmentById(@PathVariable Long departmentId) throws DepartmentNotFoundException { return departmentService.fetchDepartmentById(departmentId); } @DeleteMapping("/departments/{departmentId}") public String deleteDepartmentById(@PathVariable Long departmentId) { departmentService.deleteDepartmentById(departmentId); return "Succes"; } @PutMapping("/departments/{departmentId}") public Department updateDepartment(@PathVariable Long departmentId, @RequestBody Department department) { return departmentService.updateDepartment(departmentId, department); } @GetMapping("/departments/name/{departmentName}") public Department fetchDepartmentByName(@PathVariable String departmentName) { return departmentService.fetchDepartmentByName(departmentName); } }
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.dailycodebuffer</groupId> <artifactId>Spring-boot-tutorial</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Spring-boot-tutorial</name> <description>Demo project for Spring Boot</description> <properties> <java.version>20</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.28</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
原因分析及解决方案
1. 依赖包版本与Spring Boot 3.x不兼容
Spring Boot 3.x基于Jakarta EE 9规范,当前pom.xml中引入的是旧Java EE规范的javax.validation:validation-api,该包的注解无法被Spring Boot 3.x的验证引擎识别。
解决方案:
- 删除pom.xml中的
javax.validation:validation-api依赖 - 添加Spring Boot官方提供的validation starter依赖,它会自动引入兼容Jakarta EE的验证包:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
2. 实体类注解导入错误
实体类中使用的是javax.validation.constraints下的注解,而Spring Boot 3.x只识别jakarta.validation.constraints下的Jakarta版本注解,导致验证规则不生效。
解决方案:
修改实体类中的注解导入路径,替换为Jakarta版本:
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size;
3. (可选)添加全局异常处理器优化错误返回
验证生效后,Spring Boot会默认返回400状态码,但错误信息不够直观。添加全局异常处理器可以捕获验证异常,返回友好的字段错误提示。
解决方案:
创建全局异常处理类:
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 GlobalValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, String> errorMap = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach(error -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errorMap.put(fieldName, errorMessage); }); return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); } }
内容的提问来源于stack exchange,提问作者GPPiotr
相关产品推荐
相关产品推荐

