当前位置 主页 > 网站技术 > 代码类 >

    springboot validator枚举值校验功能实现

    栏目:代码类 时间:2020-01-06 18:09

    这篇文章主要介绍了springboot validator枚举值校验功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    一、前言

    在spring项目中,校验参数功能使用hibernate validator是一个不错的选择,我们的项目中也是使用它来进行校验的,省去了很多难看的校验逻辑,使代码的可读性也大大增加,本章将带你使用hibernate validator自定义注解功能实现一个 枚举值校验的逻辑。

    二、需求

    我们先明确下我们的需求,在程序开发过程中,我们经常会有一个对象的属性值只能出现在一组常量中的校验需求,例如:用户性别字段gender只能等于MALE/FEMALE这两个其中一个值,用户账号的状态status只能等于:

    NORMAL/DISABLED/DELETED其中一个等等,那么我们怎么能更好的校验这个参数呢?我们想拥有一个java注解,把它标记在所要校验的字段上,当开启hibernate validator校验时,就可以校验其字段值是否正确。

    三、实现方案

    上面提到的一组常量值,我们第一反应应该是定义一个枚举类,尽量不要放在一个统一的constants类下,这样当系统一旦庞大起来,常量是很难维护和查找的,所以前期代码也应该有一些规范性约束,这里我们约定一组常量值时使用枚举,并把该枚举类放在对应的类对象里(以上述所说的用户功能为例,我们应该把GenerEnum、UserStatusEnum枚举放在User.java下,方便查找)

    这里我们定义一个叫EnumValue.java的注解类,其下有两个主要参数一个是enumClass用于指定枚举类,enumMethod指定要校验的方法,下面我们看代码实现。

    四、代码实现

    package com.zhuma.demo.annotation;
     
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
     
    import javax.validation.Constraint;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    import javax.validation.Payload;
     
    import org.assertj.core.util.Strings;
     
    /**
     * @desc 校验枚举值有效性
     *
     * @author zhumaer
     * @since 10/17/2017 3:13 PM
     */
    @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = EnumValue.Validator.class)
    public @interface EnumValue {
     
      String message() default "{custom.value.invalid}";
     
      Class<?>[] groups() default {};
     
      Class<? extends Payload>[] payload() default {};
     
      Class<? extends Enum<?>> enumClass();
     
      String enumMethod();
     
      class Validator implements ConstraintValidator<EnumValue, Object> {
     
        private Class<? extends Enum<?>> enumClass;
        private String enumMethod;
     
        @Override
        public void initialize(EnumValue enumValue) {
          enumMethod = enumValue.enumMethod();
          enumClass = enumValue.enumClass();
        }
     
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
          if (value == null) {
            return Boolean.TRUE;
          }
     
          if (enumClass == null || enumMethod == null) {
            return Boolean.TRUE;
          }
     
          Class<?> valueClass = value.getClass();
     
          try {
            Method method = enumClass.getMethod(enumMethod, valueClass);
            if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {
              throw new RuntimeException(Strings.formatIfArgs("%s method return is not boolean type in the %s class", enumMethod, enumClass));
            }
     
            if(!Modifier.isStatic(method.getModifiers())) {
              throw new RuntimeException(Strings.formatIfArgs("%s method is not static method in the %s class", enumMethod, enumClass));
            }
       
            Boolean result = (Boolean)method.invoke(null, value);
            return result == null ? false : result;
          } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            throw new RuntimeException(e);
          } catch (NoSuchMethodException | SecurityException e) {
            throw new RuntimeException(Strings.formatIfArgs("This %s(%s) method does not exist in the %s", enumMethod, valueClass, enumClass), e);
          }
        }
     
      }
    }