自定义注解实现枚举校验

在项目开发中经常会遇到使用枚举值校验的功能,而使用 validation 自带的校验功能较为单一,为了简化开发,需要一个自定义的枚举校验器

注解及枚举校验器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@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;
}
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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);
}
}
1
2
3
4
5
6
7
@ApiModel("UserParam对象")
public class UserParam {

@EnumValue(enumClass = UserStatusEnum.class)
@ApiModelProperty(value = "帐号启用状态:0->禁用;1->启用")
private Integer status;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@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();
}
}

返回结果:

1
2
3
4
{
"status": 100110,
"msg": "updateStatus.status: 无效的值"
}