SpringBoot利用ConstraintValidator实现自定义注解校验

一、前言

        ConstraintValidator是Java Bean Validation(JSR-303)规范中的一个接口,用于实现自定义校验注解的校验逻辑。ConstraintValidator定义了两个泛型参数,分别是注解类型和被校验的值类型。在实现ConstraintValidator接口时,需要重写initialize、isValid等方法,并实现具体的校验逻辑。

二、自定义注解校验参数是否为Null

        比如校验参数name不能为null或者空字符串,先编写@interface类ValidNull:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {NullValidator.class})
public @interface ValidNull {
    // 默认错误消息
    String message() default "name不能为空";

    // 分组
    Class<?>[] groups() default {};

    // 负载
    Class<? extends Payload>[] payload() default {};
}

        再编写校验类 NullValidator:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class NullValidator implements ConstraintValidator<ValidNull, String> {
    @Override
    public void initialize(ValidNull constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (null == value || "".equals(value)){
            return false;
        }
        return true;
    }
}

        编写实体类NullTest,并在此加上注解:

import lombok.Data;

@Data
public class NullTest {

    @ValidNull
    private String name;
}

         最后在controller层进行调用校验,注意需要在实体类前面加上@Validated 注解,否则校验是不生效的:

    @PostMapping(value = "/test")
    public RetResult test(@RequestBody @Validated NullTest nullTest) {
        System.err.println(nullTest.getName());
        return RetResult.success();
    }

        测试结果:

        当name有值时,正常通过:

         当name为null时,提示校验错误信息:

        当name为空字符串时, 提示校验错误信息:

三、自定义注解校验参数值大小

        比如一个参数是数字,需要校验其大小,方法如下:

        先编写@interface类:

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {NumValidator.class})
public @interface ValidNum {
    int value();

    // 默认错误消息
    String message() default "num不能大于20";

    // 分组
    Class<?>[] groups() default {};

    // 负载
    Class<? extends Payload>[] payload() default {};
}

        这里有添加value,这个可以在使用该注解时,传参数,下面的默认错误信息,也可以在使用注解时一起使用,只是在没有传参数时默认使用而已。

        编写NumValidator校验类:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class NumValidator implements ConstraintValidator<ValidNum,Integer> {
    private Integer value;

    @Override
    public void initialize(ValidNum constraintAnnotation) {
        this.value = constraintAnnotation.value();
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        if(value > this.value){
            return false;
        }
        return true;
    }
}

        可以看到这里也定义了value,在initialize里面初始化,也就是获取使用该注解的地方传入的值。

        编写实体类NullTest:

import lombok.Data;

@Data
public class NumTest {

    @ValidNum(value = 30, message = "数值不能大于30")
    private Integer num;
}

        在controller层测试:

    @PostMapping(value = "/test")
    public RetResult test(@RequestBody @Validated NumTest numTest) {
        System.err.println(numTest.getNum());
        return RetResult.success();
    }

        测试结果:

        当传入参数小于30时:

        当传入参数大于30时:

猜你喜欢

转载自blog.csdn.net/qq_41061437/article/details/132446337