Spring Boot项目Bean Validation验证失效问题求助
Spring Boot Bean Validation 验证规则完全失效问题
我在Spring Boot项目中使用Bean Validation时遇到问题,已尝试更换项目依赖、重建项目(怀疑项目损坏)、在其他机器运行项目,但仍出现相同错误——DTO中的验证规则完全不起作用。以下是相关代码信息:
POM文件
<?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.0.7</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>sustenapp</groupId> <artifactId>sustenApp</artifactId> <version>0.0.1-SNAPSHOT</version> <name>sustenApp_API</name> <description>sustenApp</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>br.com.caelum.stella</groupId> <artifactId>caelum-stella-core</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.5.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.5.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.0</version> </dependency> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
实体类 EnderecoModel
import java.io.Serial; import java.io.Serializable; import java.util.UUID; @Data @AllArgsConstructor @NoArgsConstructor @DynamicUpdate @Builder @Entity @Table(name = "endereco") public class EnderecoModel implements Serializable { @Serial private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String logradouro, complemento, cep, cidade, estado; private UUID usuario; }
DTO类 EnderecoDto
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Builder; import lombok.Data; import sustenapp_api.component.constraint.annotation.EnderecoVerify; import sustenapp_api.component.constraint.annotation.UsuarioVerify; import java.util.UUID; @Data @Builder @EnderecoVerify public class EnderecoDto { @NotNull @NotEmpty private String logradouro, complemento, cep, cidade, estado; @NotNull @UsuarioVerify private UUID usuario; }
测试代码
@Test @DisplayName("Testes de Cobertura e Validação do Metodo Save") public void save(){ var atual = service.save(factoryDto(usuario)); var esperado = factoryDto(usuario); assertAll( () -> assertEquals(esperado.getUsuario(), atual.getUsuario()), () -> assertEquals(esperado.getCep(), atual.getCep()), () -> assertEquals(esperado.getCidade(), atual.getCidade()), () -> assertEquals(esperado.getEstado(), atual.getEstado()), () -> assertEquals(esperado.getLogradouro(), atual.getLogradouro()), () -> assertEquals(esperado.getComplemento(), atual.getComplemento()), () -> assertThrows( // @NotNull - OBSERVACAO Exception.class, () -> service.save(EnderecoDto.builder().build()) ), () -> assertThrows( // @NotEmpty - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO), LOGRADOURO, COMPLEMENTO, "", CIDADE, ESTADO)) ), () -> assertThrows( // @NotEmpty - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO),"", COMPLEMENTO, CEP, CIDADE, ESTADO)) ), () -> assertThrows( // @NotEmpty - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO), LOGRADOURO, "", CEP, CIDADE, ESTADO)) ), () -> assertThrows( // @NotEmpty - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO), LOGRADOURO, COMPLEMENTO, CEP, "", ESTADO)) ), () -> assertThrows( // @NotEmpty - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO), LOGRADOURO, COMPLEMENTO, CEP, CIDADE, "")) ), () -> assertThrows( // @UserVerify - OBSERVACAO Exception.class, () -> service.save(EnderecoUtil.factoryDto(UUID.fromString(USUARIO), LOGRADOURO, COMPLEMENTO, CEP, CIDADE, ESTADO)) ) ); }
问题排查与解决方案
1. 验证触发点缺失
Bean Validation不会自动执行,必须显式触发:
- 控制器层:在接收DTO的参数上添加
@Valid或@Validated注解:@PostMapping("/enderecos") public ResponseEntity<?> createEndereco(@Valid @RequestBody EnderecoDto dto) { // 业务逻辑 } - 服务层:注入
Validator手动触发验证:@Service public class EnderecoService { private final Validator validator; public EnderecoService(Validator validator) { this.validator = validator; } public EnderecoDto save(EnderecoDto dto) { Set<ConstraintViolation<EnderecoDto>> violations = validator.validate(dto); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } // 后续保存逻辑 } }
2. 自定义注解实现检查
确认@EnderecoVerify和@UsuarioVerify的实现:
- 注解需标注
@Constraint(validatedBy = 对应验证器.class) - 验证器类必须实现
ConstraintValidator<自定义注解, 目标类型>接口,且正确实现isValid方法
3. 测试类中补充验证逻辑
当前测试直接调用service.save(),若服务层未触发验证,测试不会抛出预期异常。可在测试中手动验证:
@Test public void testInvalidDto() { EnderecoDto invalidDto = EnderecoDto.builder().build(); Set<ConstraintViolation<EnderecoDto>> violations = validator.validate(invalidDto); assertFalse(violations.isEmpty()); }
4. 依赖兼容性确认
Spring Boot 3.x 使用Jakarta EE规范,你已正确使用jakarta.validation.constraints.*包,spring-boot-starter-validation依赖也已引入,这部分无需调整。
内容的提问来源于stack exchange,提问作者Kauan Gabriel
相关产品推荐
相关产品推荐

