之前会根据业务,自定义注解和扩展validation的校验器来实现基于注解进行通用校验。后面某一天想能不能整个枚举校验- -
注解定义:
/**
* 枚举校验 标识注解
* @Author:cyw
* @CreateTime: 2020年11月7日14:14:25
**/
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = CheckEnumLegalValidator.class)
public @interface CheckEnumLegal {
String message() default "非法类型值";
Class<? extends Enum<?>> enumClass();
/**
* 1、强制方法返回值为Boolean
* 2、强制方法为静态方法
* 3、默认校验方法名 validate,后续自己设置
* 4、entity数据类型要和validate方法参数数据类型要一致 !
* 5、调用validate方法时,不能抛出异常...
* 6、最好在枚举类的validate方法上,加上 @CannotDelete 注解标识下...避免被删除 {@link CannotDelete}
*/
String checkLegalMethodName() default "validate";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
另一个标识注解定义- -
/**
* 该注解标注的地方,不要删除[即使没有任何调用链路]
* 敬畏之心...
* @Author:cyw
* @CreateTime: 2020/12/15 11:46
**/
public @interface CannotDelete {
}
validation校验器
/**
* 枚举校验 校验器
* @Author:cyw
* @CreateTime: 2020/11/11 15:00
**/
public class CheckEnumLegalValidator implements ConstraintValidator<CheckEnumLegal, Object> {
private Class<? extends Enum<?>> enumClass;
private String enumMethod;
@Override
public void initialize(CheckEnumLegal constraintAnnotation) {
enumClass = constraintAnnotation.enumClass();
enumMethod = constraintAnnotation.checkLegalMethodName();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (isAnyNull(value, enumClass, enumMethod)) {
return 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(enumClass + "类中" + enumMethod + "方法返回不是Boolean值");
}
if(!Modifier.isStatic(method.getModifiers())) {
throw new RuntimeException(enumClass + "类中" + enumMethod + "方法不是静态方法");
}
method.setAccessible(true);
Boolean result = (Boolean)method.invoke(null, value);
return result == null ? false : result;
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
if (e instanceof InvocationTargetException){
throw new ConstraintDeclarationException(((InvocationTargetException) e).getTargetException().getMessage());
}
throw new RuntimeException(e);
}
}
}
枚举定义示范
/**
* 佣金结算类型
*
* @Author:cyw
* @CreateTime: 2021/1/15 16:39
*/
@Getter
@AllArgsConstructor
public enum CommissionSettlementTypeEnum {
/**
* 结算类型 1 xxx
*/
XXX(Byte.valueOf("1"), "xxx"),
;
/**
* 字段数值
*/
private final Byte value;
/**
* 字段描述
*/
private final String description;
private static final Map<Byte, CommissionSettlementTypeEnum> MAP = new HashMap<>(values().length);
static {
for (CommissionSettlementTypeEnum enumItem : values()) {
MAP.put(enumItem.value, enumItem);
}
}
public static CommissionSettlementTypeEnum of(Byte value) {
BaseUtils.isNullThr(value, "类型不能为空");
CommissionSettlementTypeEnum enumItem = MAP.get(value);
BaseUtils.isNullThr(enumItem, "CommissionSettlementType 非法类型值 [" + value + "]");
return enumItem;
}
@CannotDelete
public static Boolean validate(Byte code) {
return BaseUtils.isNull(code) ? false : CommissionSettlementTypeEnum.of(code) != null;
}
}
在VO对象中使用示范
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class XxxCreateVO implements Serializable {
private static final long serialVersionUID = -17987079543000987L;
xxx
/**
* 佣金码结算类型
* @see xxx.CommissionSettlementTypeEnum#value
*/
@CheckEnumLegal(enumClass = CommissionSettlementTypeEnum.class, message = "结算类型 非法类型值")
@NotNull(message = "结算类型 不能为空")
private Byte settlementType;
xxx
}
controller使用
@Validated
@RestController
@RequestMapping("/xxx")
public class XxxController {
@PostMapping
public Response<Long> create(@Valid @RequestBody XxxCreateVO vo) {
xxxxx
}
}