SpringBoot使用自定义Validation注解实现字符串必须包含在指定的内容内

677 阅读1分钟

背景

项目中我们会经常使用JSR进行参数校验,配合SpringBoot的全局异常拦截,不要太方便,虽然JSR已经提供了需要很常用的注解,我们可以直接使用,但是需求是千变万化的,总会出现默认的注解无法满足的情况,这个时候我们就可以使用自定义Validation注解来进行实现,完成参数校验。

创建注解@inteface类,代码如下:

package com.test.common.validation;

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.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 校验一个字符串是否包含在指定字符数组内
 * @author test
 */
@Documented
@Constraint(validatedBy = StringContainsValidator.class)
@Target({ FIELD })
@Retention(RUNTIME)
public @interface StringContains {

  String message() default "字符串不符合规则";

  String[] limitValues() default {};

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

  Class<? extends Payload>[] payload() default { };
}
类中相关注解解释:
名称解释
@Documented文档注释
@Constraint指定改注解的具体校验方式有那个类实现,一定要指定,否则会出现HV000030: No validator could be found错误
@Target注解可使用的位置,常用的有Type:可使用在类,接口,枚举类上,FIELD:可使用在类的字段属性上,METHOD:可使用在方法上,PARAMETER:可使用在参数上
@Retention注解生效范围,SOURCE:源码中,编译后丢失,CLASS:编译后保留,但JVM运行时丢失,RUNTIME:JVM运行中保留

创建注解的具体校验方式的实现类,代码如下:

package com.test.common.validation;

import cn.hutool.core.util.StrUtil;

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

/**
 * @author test
 */
public class StringContainsValidator implements ConstraintValidator<StringContains, String> {

  private Set<String> limitValues;

  @Override
  public void initialize (StringContains constraintAnnotation) {
    limitValues = Arrays.stream(constraintAnnotation.limitValues()).map(String::toUpperCase).collect(Collectors.toSet());
  }

  @Override
  public boolean isValid (String value, ConstraintValidatorContext context) {
    if (StrUtil.isBlank(value)) {
      return true;
    }
    return limitValues.contains(value.toUpperCase());
  }
}

在类中使用,限定该字符串必须是指定的内容,为空和null不进行校验

public class Test{
    
    @StringContains(limitValues = {"DESC", "ASC"})
    private String direction;
}