文章目录
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);
}
}