實現背景
在實際開發過程中,往往也需要對某些參數進行枚舉合法值校驗。如果在代碼中大量充斥者if else check代碼,實現不夠優雅。借鑒Hibernate其他優秀驗證器的實現,Enum校驗也可以擁有自己的驗證器!
實現原理
1. 定義枚舉檢查注解@EnumCheck,方便在請求對象參數上使用;
2. 定義接口EnumValidator,讓需要驗證的Enum類實現getValue()方法,主要目的是獲取枚舉的比較值;
3. 實現接口ConstraintValidator的isValid()方法,實現具體的枚舉校驗邏輯。
代碼實現
1. @EnumCheck注解類:
/** * 枚舉檢查注解 * * @author binglang * @date 2021/8/31 11:41 */ @Documented @Constraint(validatedBy = EnumConstraintValidator.class) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Repeatable(EnumCheck.List.class) public @interface EnumCheck { /** * 提示信息 * */ String message() default "{javax.validation.constraints.EnumCheck.message}"; /** * 分組 * */ Class<?>[] groups() default { }; /** * 擴展對象 * */ Class<? extends Payload>[] payload() default { }; /** * 必須實現EnumValidator接口的枚舉類 * */ Class<? extends EnumValidator> clazz(); /** * 調用的方法名稱 */ String method() default "getValue"; /** * Defines several {@code @In} constraints on the same element. * * @see EnumCheck */ @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Documented @interface List { /** * In數組 */ EnumCheck[] value(); } }
2. EnumValidator接口定義:
/** * 枚舉驗證接口 * * @author binglang * @date 2021/8/31 11:43 */ public interface EnumValidator { Object getValue(); }
3. EnumConstraintValidator驗證器具體實現:
/** * 枚舉驗證器實現 * * @author binglang * @date 2021/8/31 11:44 */ public class EnumConstraintValidator implements ConstraintValidator<EnumCheck, Object> { /** * 注解對象 */ private EnumCheck annotation; /** * 初始化方法 * * @param constraintAnnotation 注解對象 */ @Override public void initialize(EnumCheck constraintAnnotation) { this.annotation = constraintAnnotation; } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { if (Objects.isNull(value)) { return false; } Object[] enumConstants = annotation.clazz().getEnumConstants(); try { // 核心代碼實現 Method method = annotation.clazz().getMethod(annotation.method()); for (Object enumConstant : enumConstants) { if (value.equals(method.invoke(enumConstant))) { return true; } } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } return false; } }
如何使用
1. 需要校驗的枚舉類實現上面的EnumValidator接口:
/** * 引用節點類型 * * @author binglang * @date 2021/7/13 20:12 */ public enum RefNodeType implements EnumValidator { FIELD("field", "field"), FUNC("func", "func"); private final String code; private final String label; RefNodeType(String code, String label) { this.code = code; this.label = label; } public String getCode() { return code; } public String getLabel() { return label; } // 實現getValue()邏輯 @Override public Object getValue() { return code; }
2. 請求對象使用@EnumCheck注解:
@Data public class TestDto { @ApiModelProperty(value = "變量類型") @NotBlank(message = "變量類型不能為空") @EnumCheck(clazz = RefNodeType.class, message = "變量類型不合法") private String refNodeType; }
