参数规则校验-限定枚举值的校验

2019-03-01  本文已影响0人  木果渣
api中,有个字段为订单状态,限定为“开启”和“关闭”,不满足条件了一律不接受。要实现,可以在处理方法中增加条件判断,但是如何做的通用一点呢?🤭或许可以用validation试一下。

首先,定义一个基础的枚举接口,只要实现了此接口的枚举方可校验枚举值。

public interface BaseIntEnum {

    Integer getCode();

    String getDesc();
}

接下来定义我们自己的枚举值

public enum OrderStatusEnum implements BaseIntEnum{

    OPEN(1,"开启"),
    CLOSE(2, "关闭");

    private Integer code;
    private String desc;

    OrderStatusEnum(int code, String desc){
        this.code = code;
        this.desc = desc;
    }
    public Integer getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

}

定义枚举校验注解

@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckEnumValidator.class)
@Documented
public @interface CheckEnum {
    String message() default "枚举不合规范";

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

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

    Class<?> enumClass();
}

然后是枚举校验器

public class CheckEnumValidator implements ConstraintValidator<CheckEnum, Integer> {
    private Class<?> enumClass;

    @Override
    public void initialize(CheckEnum constraintAnnotation) {
        enumClass = constraintAnnotation.enumClass();
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        Type[] types = enumClass.getGenericInterfaces();
        if (!needValidate(types)) {
            return true;
        }
        try {
            return validate(value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 是否需要校验
     * 只有implements接口BaseIntEnum,才能校验
     * @return
     */
    private boolean needValidate(Type[] types){
        boolean needValidate = false;//是否需要校验
        for (Type type : types) {
            if (type.getTypeName().equals(BaseIntEnum.class.getName())) {
                needValidate = true;
            }
        }
        return needValidate;
    }

    /**
     * 遍历枚举code值,校验value是否存在其中
     * @param value
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private boolean validate(Integer value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method valuesMethod = enumClass.getMethod("values");
        if (null == valuesMethod) {
            return true;
        }
        BaseIntEnum inter[] = (BaseIntEnum[]) valuesMethod.invoke(null);
        for(BaseIntEnum iter : inter){
            if(iter.getCode().equals(value)){
                return true;
            }
        }
        return false;
    }
}

最后,写个实体类验证一下

@Getter
@Setter
public class EnumDTO {
    @CheckEnum(enumClass = OrderStatusEnum.class)
    Integer orderStatus;
}
 public static void main(String[] args) {
        EnumDTO enumDTO = new EnumDTO();
        enumDTO.setOrderStatus(3);
        ValidateCheckUtils.check(enumDTO);
    }

此方法比较通用,只要实现了BaseIntEnum接口的枚举类,都可以被校验,但也局限。code必须为Integer类型,如果为String类型,需要重新定义接口,并重写枚举注解和校验器。一般实际生产中,字符串用的比较多。

后续:我有点傻,直接把基础枚举改为这样就不纠结是int还是String了。

@Getter
@Setter
public class EnumDTO {

    @CheckEnum(enumClass = OrderStatusEnum.class)
    Integer orderStatus;
}
上一篇下一篇

猜你喜欢

热点阅读