如何无需@Email注解实现Validator的邮箱验证及默认约束校验?
Hibernate Validator 无注解验证相关问题
场景重现
Student 实体类
@Data @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "student") public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "full_name") private String fullName; @Column(name = "email") @Email private String email; @Column(name = "new_age") private Integer newAge; }
验证代码
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .buildValidatorFactory(); Validator validator = validatorFactory.getValidator(); Student student = new Student(1L,"wec","D23d",15); validator.validate(student);
预期验证结果
ConstraintViolationImpl{interpolatedMessage='must be a well-formed email address', propertyPath=email, rootBeanClass=class com.example.SomeMainClass.model.Student, messageTemplate='{jakarta.validation.constraints.Email.message}'}
咨询问题
- 是否可以不在Student类的email字段上添加@Email注解,就能实现上述邮箱格式验证?
- 能否让Validator对所有未添加@Email、@NotNull等注解的字段执行默认约束验证?
解决方案
问题1:无@Email注解实现邮箱格式验证
完全可以,用约束映射XML文件就能脱离实体类注解完成验证,步骤如下:
- 在
META-INF下创建validation.xml,指定约束映射文件路径:
<?xml version="1.0" encoding="UTF-8"?> <validation-config xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/validation-config_3_0.xsd" version="3.0"> <constraint-mapping>META-INF/student-constraints.xml</constraint-mapping> </validation-config>
- 再创建
META-INF/student-constraints.xml,给Student的email字段绑定@Email约束:
<?xml version="1.0" encoding="UTF-8"?> <constraint-mappings xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/validation-mapping_3_0.xsd" version="3.0"> <default-package>com.example.SomeMainClass.model</default-package> <bean class="Student"> <field name="email"> <constraint annotation="jakarta.validation.constraints.Email"/> </field> </bean> </constraint-mappings>
- 移除Student类email字段上的@Email注解,运行原验证代码,就能得到和之前一致的邮箱格式校验结果。
问题2:给未加注解的字段添加默认约束验证
Hibernate Validator没有内置全局默认约束,但可以通过两种方式实现:
方式1:自定义类级约束批量校验
创建一个类级注解,配合校验器对指定字段自动应用默认规则:
@Target({TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = DefaultValidationValidator.class) public @interface DefaultValidation { String message() default "默认约束验证失败"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } public class DefaultValidationValidator implements ConstraintValidator<DefaultValidation, Object> { private Validator validator; @Override public void initialize(DefaultValidation constraintAnnotation) { validator = Validation.buildDefaultValidatorFactory().getValidator(); } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { Set<ConstraintViolation<Object>> violations = new HashSet<>(); if (value instanceof Student student) { // 对email字段自动加@Email验证 if (student.getEmail() != null) { violations.addAll(validator.validateValue(Student.class, "email", student.getEmail(), Email.class)); } // 对newAge字段自动加@Min(10)验证 if (student.getNewAge() != null) { violations.addAll(validator.validateValue(Student.class, "newAge", student.getNewAge(), Min.class)); } } // 将违规信息同步到校验上下文 for (ConstraintViolation<Object> violation : violations) { context.buildConstraintViolationWithTemplate(violation.getMessage()) .addPropertyNode(violation.getPropertyPath().toString()) .addConstraintViolation(); } return violations.isEmpty(); } }
给Student类加上@DefaultValidation注解,运行验证代码就能自动触发默认约束校验。
方式2:SPI扩展动态添加约束(高级用法)
实现ConstraintMappingContributor接口,在Validator启动时自动给字段绑定约束:
public class DefaultConstraintContributor implements ConstraintMappingContributor { @Override public void createConstraintMappings(ConstraintMappingBuilder builder) { builder.type(Student.class) .field("email") .constraint(Email.class); // 可批量给多个实体类的字段添加默认约束 } }
然后在META-INF/services/jakarta.validation.spi.ConstraintMappingContributor文件中写入该类的全限定名,Hibernate Validator启动时会自动加载并应用这些约束。
内容的提问来源于stack exchange,提问作者Muhamed Risvan M S
相关产品推荐
相关产品推荐

