Java custom annotation verification enumeration value

Business scenario: In interface development, sometimes our input parameters correspond to the enumerations in the project, which requires that the parameter values ​​passed in by others when calling the interface must correspond to the enumeration values ​​in the project. However, there is no verification annotation for enumeration values ​​in the verification provided by spring-boot-validation. Although we can also verify parameter values ​​​​by asserting Assert, this is not elegant enough, and if an entity object is in different If the interface is used as an input parameter, parameter verification needs to be done on each interface, which is very cumbersome and troublesome. So just write an annotation that acts on the field.

1. Customized verification annotations

/**
 * 枚举参数校验注解
 */

@Target({
    
    ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {
    
    EnumIntegerValidator.class})
@Documented
public @interface ValidateEnum {
    
    
    String message() default "invalid parameter";

    String keyMethod() default "getKey";// 默认属性名称为key,可自定义

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

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

    /**
     * 允许的枚举
     * @return
     */
    Class<? extends Enum<?>> enumClass();

    /**
     * 允许的枚举值, 约定为int类型, 判断优先级高于enumClass
     * @return
     */
    int[] enumValues() default {
    
    };

}

@Constraint(validatedBy = {EnumIntegerValidator.class}): A class that implements logical verification,

message, groups(), and payload() are the three parameters of annotation type variables and must be defined because @Constraint is used

keyMethod: method to obtain enumeration values, can be customized

enumClass: Verified enumeration

enumValuess(): allowed enumeration value, agreed to be int type, judgment priority is higher than enumClass

2. Customize the validation class to implement the ConstraintValidator interface

public class EnumIntegerValidator implements ConstraintValidator<ValidateEnum, Integer> {
    
    
    private Class<? extends Enum> enumClass;
    private int[] enumValues;

    private String keyMethod;

    @Override
    public void initialize(ValidateEnum validateEnum) {
    
    
        enumClass = validateEnum.enumClass();
        enumValues = validateEnum.enumValues();
        keyMethod = validateEnum.keyMethod();
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
    
    
        if (value == null) {
    
    
            return false;
        }
        try {
    
    
            if(enumValues.length ==0 ){
    
     //enumValues 优先级高
                Enum[] enumArr = enumClass.getEnumConstants();
                if(enumArr.length>0){
    
    
                    for (Enum e : enumArr) {
    
    
                        Method method = e.getDeclaringClass().getMethod(keyMethod);
                        Object keyValue = method.invoke(e);
                        if(keyValue != null){
    
    
                            if(value.equals(keyValue)){
    
    
                                return true;
                            }
                        }
                    }
                    return false;
                }

            }else {
    
    
                for (int enumValue : enumValues) {
    
    
                    if(enumValue == value){
    
    
                        return true;
                    }
                }
                return false;
            }
            return true;
        }catch (Exception e){
    
    
            return false;
        }

    }
}

The generic parameters of ConstraintValidator are: custom annotations, and the type of verification value required

initialize: Initialization method, inject the value of the annotation

isValid: A method to implement business verification. Returning false means that the verification fails. The value of the message will be output. Returning true means that the verification passes.

The parameters of enumValue are checked first. If the value is restricted, the enumeration value will not be controlled. Secondly, through reflection, the enumeration attribute value will be obtained through the value of keyMethod and then verified and compared.

3. Add annotations to the parameters

Enumeration class definition

public enum ExpenseApprovalStatusEnum {
    
    
    EXPENSE_UNSUBMIT(0, "待提交"),
    EXPENSE_UNAPPROVAL(1, "待审核"),
    EXPENSE_ADOPTED(2, "审核通过"),
    EXPENSE_REJECT(3, "驳回");

    private Integer key;
    private String value;

    ExpenseApprovalStatusEnum(Integer key, String value) {
    
    
        this.key = key;
        this.value = value;
    }

    public static String getValue(Integer key) {
    
    
        for (ExpenseApprovalStatusEnum c : ExpenseApprovalStatusEnum.values()) {
    
    
            if (c.getKey().equals(key)) {
    
    
                return c.getValue();
            }
        }
        return null;
    }

    public static Integer getKey(String value) {
    
    
        for (ExpenseApprovalStatusEnum c : ExpenseApprovalStatusEnum.values()) {
    
    
            if (c.getValue().equals(value)) {
    
    
                return c.getKey();
            }
        }
        return null;
    }

    public static Map<String, String> getOption() {
    
    
        Map<String, String> option = new LinkedHashMap<>();
        for (ExpenseApprovalStatusEnum c : ExpenseApprovalStatusEnum.values()) {
    
    
            option.put(c.getKey().toString(), c.getValue());
        }
        return option;
    }

    public static ExpenseApprovalStatusEnum getEnum(Integer key) {
    
    
        for (ExpenseApprovalStatusEnum c : ExpenseApprovalStatusEnum.values()) {
    
    
            if (c.getKey().equals(key)) {
    
    
                return c;
            }
        }
        return null;
    }

    public Integer getKey() {
    
    
        return key;
    }

    public void setKey(Integer key) {
    
    
        this.key = key;
    }

    public String getValue() {
    
    
        return value;
    }

    public void setValue(String value) {
    
    
        this.value = value;
    }

}

@ApiModelProperty(value = "审核状态(0待提交,1审核中,2审核通过,3驳回)")
    @ValidateEnum(enumClass = ExpenseApprovalStatusEnum.class,enumValues = {
    
    1,2},
                  message = "枚举值不正确",keyMethod = "getKey")
    private Integer approvalStatus;

Focus on the value of keyMethod, because getKey() of the ExpenseApprovalStatusEnum enumeration is the method for obtaining attribute values. If the enumeration method you want to verify is getCode(), then keyMethod should pass getCode, because the default definition is The value is getKey. I don’t need to pass this parameter here, just to demonstrate the effect.

4. Turn on annotation verification (very important)

Be sure to add @Valid to the parameters, because the verification of @ValidateEnum implements the ConstraintValidator interface. If @Valid is not added, the parameter verification will not be performed.

public void test(@Valid  ExpenseQueryBo expenseQueryBo){
    
    
    ....
}
public JsonResult<?> approval(@RequestBody @Valid  ExpenseQueryBo expenseQueryBo) {
    
    
    ....
}

5. Call the interface to view the effect

Insert image description here

Guess you like

Origin blog.csdn.net/qq798867485/article/details/131512807