You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:54:27