springboot:validator之自定义注解校验

一、依赖

		<dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.16.Final</version>
            <scope>compile</scope>
        </dependency>

二、自定义注解

1、校验字符串类型的枚举类

加入到需要校验的字段上

 /**
     * 	信号属性(AI,DI,Other,DO)
     * 	AI:普通数据
     * 	DI:输入开关
     * 	DO:输出开关
     */
    @NotBlank(message = "信号属性不可以为空")
    @ContainsDataValid(message = "信号属性不正确",values = {"AI","DI","Other","DO"})
    private String propertyType;

自定义注解

package com.mye.cloudboxdcim.framework.engine.validator.anno;

import com.mye.cloudboxdcim.framework.engine.validator.method.ContainsDataValidator;

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;

/**
 * @ClassName ContainsValidata
 * @Description 自定义注解,判断枚举是否包含
 * @Author hl
 * @Date 2022/11/3 15:52
 * @Version 1.0
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ContainsDataValidator.class})// 标明由哪个类执行校验逻辑
public @interface ContainsDataValid {

    // 校验出错时默认返回的消息
    String message() default "字段值不正确";

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

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

    String[] values() default {}; // 指定值

    /**
     * 同一个元素上指定多个该注解时使用
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        ContainsDataValid[] value();
    }

}

具体实现类

package com.mye.cloudboxdcim.framework.engine.validator.method;

import cn.hutool.core.util.StrUtil;
import com.mye.cloudboxdcim.framework.engine.validator.anno.ContainsDataValid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ContainsDataValidator implements ConstraintValidator<ContainsDataValid,String> {
	// 全局变量存放值集合
    private List<String> values = new ArrayList<>();
	
	// 注解初始化时执行
    @Override
    public void initialize(ContainsDataValid constraintAnnotation) {
		// 获取注解中的值
        String[] strList = constraintAnnotation.values();
		// 赋值给全局变量
        values = Arrays.stream(strList).collect(Collectors.toList());
    }

	// 自定义的校验规则
    @Override
    public boolean isValid(String o, ConstraintValidatorContext constraintValidatorContext) {
    	// o 为实体属性的值
    	// 判断值是否属于集合中的元素,true 检验通过,false校验不通过
        if (StrUtil.isBlank(o)){
            return true;
        }
        return values.contains(o.trim());
    }
}

2、校验数字类型的枚举类

加入到需要校验的字段上

    /**
     * 优先级(最高2,高1,中0 -1低,-2最低)
     */
    @NotNull(message = "优先级不能为空")
    @ContainsIntegerDataValid(message = "优先级不合法",values = {-2,-1,0,1,2})
    private Integer priority;

自定义注解

package com.mye.cloudboxdcim.framework.engine.validator.anno;

import com.mye.cloudboxdcim.framework.engine.validator.method.ContainsIntegerDataValidator;
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.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * @ClassName ContainsIntegerDataValid
 * @Description 校验数字类型的枚举类
 * @Author hl
 * @Date 2022/11/7 16:58
 * @Version 1.0
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ContainsIntegerDataValidator.class})// 标明由哪个类执行校验逻辑
public @interface ContainsIntegerDataValid {

    // 校验出错时默认返回的消息
    String message() default "字段值不正确";

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

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

    int[] values() default {}; // 指定值

    /**
     * 同一个元素上指定多个该注解时使用
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        ContainsIntegerDataValid[] value();
    }
}

具体实现类

package com.mye.cloudboxdcim.framework.engine.validator.method;


import cn.hutool.core.util.ObjectUtil;
import com.mye.cloudboxdcim.framework.engine.validator.anno.ContainsIntegerDataValid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName ContainsIntegerDataValidator
 * @Description 自定义校验类
 * @Author hl
 * @Date 2022/11/7 16:59
 * @Version 1.0
 */
public class ContainsIntegerDataValidator implements ConstraintValidator<ContainsIntegerDataValid,Integer> {

    private List<Integer> list = new ArrayList<>();

    @Override
    public void initialize(ContainsIntegerDataValid constraintAnnotation) {
        // 获取注解中的值
        int[] values= constraintAnnotation.values();
        // 赋值给全局变量
        list = Arrays.stream(values).boxed().collect(Collectors.toList());
    }

    @Override
    public boolean isValid(Integer s, ConstraintValidatorContext constraintValidatorContext) {
        if (ObjectUtil.isNull(s)){
            return true;
        }
        return list.contains(s);
    }
}

3、校验不为必填的字符串

加入到需要校验的字段上

    /**
     * 	描述信息
     */
    @HaveNoBlankValid(message = "描述长度最大为200",value = "description")
    private String description;

自定义注解

package com.mye.cloudboxdcim.framework.engine.validator.anno;

import com.mye.cloudboxdcim.framework.engine.validator.method.HaveNoBlankValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotBlank;
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;

/**
 * @ClassName HaveNoNullValid
 * @Description 自定义注解校验 String 类型的值
 * @Author hl
 * @Date 2022/11/7 14:39
 * @Version 1.0
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {HaveNoBlankValidator.class})// 标明由哪个类执行校验逻辑
public @interface HaveNoBlankValid {
    
    // 校验出错时默认返回的消息
    String message() default "字符串不合法";

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

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

    String value() default ""; // 指定值

    /**
     * 同一个元素上指定多个该注解时使用
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        NotBlank[] value();
    }
}

具体实现类

package com.mye.cloudboxdcim.framework.engine.validator.method;

import cn.hutool.core.util.StrUtil;
import com.mye.cloudboxdcim.framework.engine.validator.anno.HaveNoBlankValid;
import com.mye.cloudboxdcim.util.StringUtil;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashMap;
import java.util.Map;


public class HaveNoBlankValidator implements ConstraintValidator<HaveNoBlankValid, String> {

    private String initValue = "";

    /**
       * @MethodName initialize
       * @Description  注解初始化时执行
       * @param haveNoBlankValid  自定义注解
       * @Author hl
       * @Date 17:05 17:05
       */
    @Override
    public void initialize(HaveNoBlankValid haveNoBlankValid) {
        // 获取注解中的值
        initValue = haveNoBlankValid.value();
    }

    /**
       * @MethodName isValid
       * @Description  自定义校验规则
       * @param value 具体值
       * @param context
       * @return: boolean true 通过校验 false 没有通过校验
       * @Author hl
       * @Date 17:04 17:04
       */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // null 不做检验
        if (StrUtil.isBlank(value)) {
            //true 通过校验
            return true;
        }

        if (StrUtil.isNotBlank(initValue)){
            switch (initValue) {
                case "description":
                    //检查描述长度
                    return checkDescription(value);
                case "unit":
                    //检查信号单位长度
                    return checkUnit(value);
                case "enumConstant":
                    //检查信号枚举值
                    return checkEnumConstant(value);
                case "place":
                    return checkCloudBoxPlace(value);
            }
        }

        return true;
    }

    private boolean checkCloudBoxPlace(String value) {
        return value.length() <= 50;
    }

    /**
       * @MethodName checkEnumConstant
       * @Description  检查信号枚举值
       * @param value 具体值
       * @return: boolean
       * @Author hl
       * @Date 17:31 17:31
       */
    private boolean checkEnumConstant(String value) {
        String[] enumConstants = value.split(",");
        if (enumConstants.length < 1 ) {
            return false;
        }
        Map<Integer, String> hashMap = new HashMap<>();
        for (String data : enumConstants) {
            if (!data.contains(":")) {
                return false;
            }
            String[] map = data.split(":");
            if (map.length != 2) {
                return false;
            }
            try {
                Integer key = Integer.valueOf(map[0]);
                if (hashMap.containsKey(key)) {
                    return false;
                }
                hashMap.put(key, map[1]);
            } catch (Exception e) {
                return false;
            }
            if (StringUtil.isBlank(map[1])) {
                return false;
            }
        }
        return true;
    }

    /**
       * @MethodName checkUnit
       * @Description  检查单位长度
       * @param value 具体值
       * @return: boolean
       * @Author hl
       * @Date 17:09 17:09
       */
    private boolean checkUnit(String value) {
        return value.length() <= 10;
    }

    /**
       * @MethodName checkDescription
       * @Description  检查描述长度
       * @param value 具体值
       * @return: java.lang.Boolean
       * @Author hl
       * @Date 16:51 16:51
       */
    private Boolean checkDescription(String value) {
        return value.length() <= 200;
    }
}

4、校验不为必填的数字

加入到需要校验的字段上

    /**
     * 闪断周期(单位秒)
     */
    @HaveNoNullValid(message = "闪断周期是 1~3600",value = "period")
    private Integer flashPeriod;

自定义注解

package com.mye.cloudboxdcim.framework.engine.validator.anno;

import com.mye.cloudboxdcim.framework.engine.validator.method.HaveNoNullValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
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;

/**
 * @ClassName HaveNoNullValid
 * @Description 自定义注解校验 Integer 类型的值
 * @Author hl
 * @Date 2022/11/7 14:39
 * @Version 1.0
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {HaveNoNullValidator.class})// 标明由哪个类执行校验逻辑
public @interface HaveNoNullValid {

    // 校验出错时默认返回的消息
    String message() default "数据不合法";

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

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

    String value() default ""; // 指定值

    /**
     * 同一个元素上指定多个该注解时使用
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        NotNull value();
    }
}

具体实现类

package com.mye.cloudboxdcim.framework.engine.validator.method;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mye.cloudboxdcim.framework.engine.validator.anno.HaveNoNullValid;

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

/**
 * @ClassName HaveNoNullValidator
 * @Description 实现注解 HaveNoNullValid 的具体实现逻辑
 * @Author hl
 * @Date 2022/11/7 14:41
 * @Version 1.0
 */
public class HaveNoNullValidator implements ConstraintValidator<HaveNoNullValid, Integer> {

    private String initValue = "";

    @Override
    public void initialize(HaveNoNullValid haveNoNullValid) {
        // 获取注解中的值
        initValue = haveNoNullValid.value();
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        // null 不做检验
        if (ObjectUtil.isNull(value)) {
            //true 通过校验
            return true;
        }

        if (StrUtil.isNotBlank(initValue)){
            switch (initValue) {
                case "state":
                    return checkFlashState(value);
                case "period":
                    return checkPeriod(value);
            }
        }

        return true;
    }

    private boolean checkPeriod(Integer value) {
        return value >= 1 && value <= 3600;
    }

    private boolean checkFlashState(Integer value) {
        return value == 0 || value == 1;
    }
}

5、校验Integer 类型的集合

加入到需要校验的字段上

    /**
     * 告警级别(默认0提示,1次要,2重要,3紧急)
     */
    @NotEmpty(message = "告警级别集合不能为空")
    @VerifyIntegerCollectionDataValid(message = "告警级别不合法",values = {0,1,2,3})
    private List<Integer> levelList;

自定义注解

package com.mye.cloudboxdcim.framework.engine.validator.anno;

import com.mye.cloudboxdcim.framework.engine.validator.method.VerifyIntegerCollectionDataValidator;
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;

/**
 * @ClassName VerifyCollectionDataValid
 * @Description 自定义注解校验 Integer 类型的集合数据是否合法
 * @Author hl
 * @Date 2022/11/8 10:25
 * @Version 1.0
 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {VerifyIntegerCollectionDataValidator.class})// 标明由哪个类执行校验逻辑
public @interface VerifyIntegerCollectionDataValid {

    // 校验出错时默认返回的消息
    String message() default "字段值不正确";

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

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

    int[] values() default {}; // 指定值

    /**
     * 同一个元素上指定多个该注解时使用
     */
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    public @interface List {
        VerifyIntegerCollectionDataValid[] value();
    }
}

具体实现类

package com.mye.cloudboxdcim.framework.engine.validator.method;

import cn.hutool.core.util.ObjectUtil;
import com.mye.cloudboxdcim.framework.engine.validator.anno.ContainsIntegerDataValid;
import com.mye.cloudboxdcim.framework.engine.validator.anno.VerifyIntegerCollectionDataValid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @ClassName VerifyIntegerCollectionDataValidator
 * @Description 自定义校验类,校验List<Integer> 数据是否合法
 * @Author hl
 * @Date 2022/11/8 10:27
 * @Version 1.0
 */
public class VerifyIntegerCollectionDataValidator implements ConstraintValidator<VerifyIntegerCollectionDataValid, List<Integer>> {

    private List<Integer> list = new ArrayList<>();

    @Override
    public void initialize(VerifyIntegerCollectionDataValid verifyIntegerCollectionDataValid) {
        // 获取注解中的值
        int[] values= verifyIntegerCollectionDataValid.values();
        // 赋值给全局变量
        list = Arrays.stream(values).boxed().collect(Collectors.toList());
    }

    @Override
    public boolean isValid(List<Integer> integers, ConstraintValidatorContext constraintValidatorContext) {
        if (ObjectUtil.isNull(integers)){
            return true;
        }

        Integer level = integers.stream().filter(Objects::nonNull).filter(s -> !list.contains(s)).findAny().orElse(null);
        return ObjectUtil.isNull(level);
    }
}
12-06 04:16