在项目开发中经常会遇到使用枚举值校验的功能,而使用 validation 自带的校验功能较为单一,为了简化开发,需要一个自定义的枚举校验器
1. 注解及枚举校验器
@NotNull
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValue.Validator.class)
public @interface EnumValue {
String message() default "无效的值";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
String enumMethod() default "isValid";
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();
Method method;
try {
method = enumClass.getDeclaredMethod(enumMethod, valueClass);
} catch (NoSuchMethodException e) {
throw new RuntimeException(String.format("%s.%s 不存在", enumClass.getName(), enumMethod));
}
if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {
throw new RuntimeException(String.format("%s.%s 返回值不是布尔类型", enumClass.getName(), enumMethod));
}
if (!Modifier.isStatic(method.getModifiers())) {
throw new RuntimeException(String.format("%s.%s 不是静态方法", enumClass.getName(), enumMethod));
}
Boolean result;
try {
method.setAccessible(true);
result = (Boolean) method.invoke(null, value);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(String.format("%s.%s 调用失败:%s", enumClass.getName(), enumMethod, e.getMessage()));
}
return result != null && result;
}
}
}
2. 测试
@AllArgsConstructor
@Getter
public enum UserStatusEnum {
DISABLE(0, "禁用"),
ENABLE(1, "启用"),
;
private int code;
private String value;
private static boolean isValid(Integer code) {
return Arrays.stream(UserStatusEnum .values()).anyMatch(e -> e.getCode() == code);
}
}
@ApiModel("UserParam对象")
public class UserParam {
@EnumValue(enumClass = UserStatusEnum.class)
@ApiModelProperty(value = "帐号启用状态:0->禁用;1->启用")
private Integer status;
}
@Validated
@RestController
@RequestMapping("/user")
public class ResourceCategoryController {
@ApiOperation("更新用户状态 字段")
@PutMapping("/updateStatus/{id}")
public ServerResponse updateStatus(@PathVariable Long userId,
@RequestParam @EnumValue(enumClass = UserStatusEnum.class) Integer status) {
return ServerResponse.createBySuccess();
}
@ApiOperation("更新用户状态 对象")
@PutMapping("/updateStatus/{id}")
public ServerResponse updateStatus(@PathVariable Long userId,
@RequestBody @Validated UserParam userParam) {
return ServerResponse.createBySuccess();
}
}
返回结果:
{
"status": 100110,
"msg": "updateStatus.status: 无效的值"
}
Q.E.D.