如何使用ConstraintValidator校验带有javax.validation注解的StudentDTO
如何用ConstraintValidator校验带JSR-380注解的StudentDTO?
嘿,我来给你一步步捋清楚怎么操作~首先得明确:你给StudentDTO加的@NotEmpty、@Positive这些都是JSR-380(也就是javax.validation)的标准注解,它们本身已经自带了对应的ConstraintValidator实现,所以大部分场景下你不用自己写校验器,直接用标准校验框架触发校验就行。如果需要自定义跨字段或者特殊规则的校验,再自己实现ConstraintValidator,下面分两种情况说:
一、基础用法:触发标准注解的校验
1. 先确保依赖到位
如果是Maven项目,要引入Hibernate Validator(JSR-380的主流实现)和validation-api:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.5.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
2. 使用标准Validator执行校验
通过校验工厂获取Validator实例,然后调用validate()方法就能触发所有标注的注解校验:
import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import javax.validation.ConstraintViolation; import java.util.Set; public class StudentValidationDemo { public static void main(String[] args) { // 初始化Validator工厂和实例 ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); // 创建一个不符合规则的StudentDTO对象 StudentDTO badStudent = new StudentDTO(); badStudent.setName(""); // 违反@NotEmpty badStudent.setStudentId(-5L); // 违反@Positive // 执行校验 Set<ConstraintViolation<StudentDTO>> violations = validator.validate(badStudent); // 处理校验结果 for (ConstraintViolation<StudentDTO> violation : violations) { System.out.printf("校验失败:%s -> %s%n", violation.getPropertyPath(), violation.getMessage()); } } }
运行这段代码,你会得到两条错误提示,分别对应name为空和studentId为负数的问题。
二、进阶用法:自定义ConstraintValidator实现特殊规则
如果你的StudentDTO需要一些跨字段或者标准注解覆盖不了的校验规则(比如“name不能和studentId的字符串形式相同”),就需要自己写ConstraintValidator了:
1. 自定义校验注解
先定义一个类级别的注解,用来标记需要我们自定义校验的DTO:
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target(ElementType.TYPE) // 标注在类上,因为是跨字段校验 @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = StudentCustomValidator.class) // 指定对应的校验器实现类 public @interface ValidStudent { // 校验失败时的提示信息 String message() default "学生信息不合法:姓名不能与学号的字符串形式相同"; // 分组校验用,默认空即可 Class<?>[] groups() default {}; // 负载信息,一般用不到 Class<? extends Payload>[] payload() default {}; }
2. 实现ConstraintValidator接口
这是核心的校验逻辑实现类,要实现ConstraintValidator<自定义注解, 目标DTO类>:
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class StudentCustomValidator implements ConstraintValidator<ValidStudent, StudentDTO> { @Override public void initialize(ValidStudent constraintAnnotation) { // 初始化操作,比如获取注解里的参数,这里我们不需要,留空就行 } @Override public boolean isValid(StudentDTO student, ConstraintValidatorContext context) { // 先判空,避免空指针(非空校验交给@NotNull等标准注解) if (student == null || student.getName() == null || student.getStudentId() == null) { return true; } // 自定义校验规则:姓名不能等于学号的字符串形式 return !student.getName().equals(student.getStudentId().toString()); } }
3. 给StudentDTO加上自定义注解
把我们的@ValidStudent加到DTO类上:
@JsonIgnoreProperties(ignoreUnknown = true) @ValidStudent // 加上自定义的类级校验注解 public class StudentDTO { @NotEmpty private String name; @Positive private Long studentId; // 必须给字段加getter方法!Validator是通过getter获取字段值的,不是直接访问字段 public String getName() { return name; } public void setName(String name) { this.name = name; } public Long getStudentId() { return studentId; } public void setStudentId(Long studentId) { this.studentId = studentId; } }
4. 再次执行校验
现在用之前的Validator代码测试一个符合自定义违规规则的对象:
StudentDTO invalidStudent = new StudentDTO(); invalidStudent.setName("12345"); invalidStudent.setStudentId(12345L); Set<ConstraintViolation<StudentDTO>> violations = validator.validate(invalidStudent); // 这时候会输出我们自定义的错误提示信息
几个注意点
- 一定要给DTO的字段加getter方法,否则Validator无法获取字段值进行校验
- 如果是在Spring Boot项目里,你可以直接注入
Validator实例,不用自己创建工厂,Spring已经帮你配置好了 - 标准注解的默认校验器都是Hibernate Validator实现的,除非特殊需求,一般不需要替换它们
内容的提问来源于stack exchange,提问作者Cork Kochi
相关产品推荐
相关产品推荐

