Bean Validator之自定义入参枚举校验
前一篇文章Bean Validator详解中详细介绍了Bean Validator的相关用法。
此时,会发现如果想要校验入参是否在我们定义的某个枚举范围内,Bean Validator好像并没有对应的注解可以使用。
现在,让我们来讲讲如何实现一个基于枚举的自定义入参校验。
一、自定义注解
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
import java.lang.reflect.Field;
/**
1. @author qudian
2. 枚举值校验
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {EnumValueValidator.class})
public @interface EnumValue {
String message() default "入参不在枚举范围内";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* 目标枚举类
*/
Class<? extends Enum<?>> enumClass();
/**
* 目标枚举属性
*/
String enumField();
}
- enumClass:指定校验的入参属于哪个枚举类
- enumField:指定校验的入参属于枚举类中哪个field
- @Constraint:指明具体的校验类
二、实现枚举属性校验
public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {
private Class<? extends Enum<?>> enumClass;
private String enumField;
@Override
public void initialize(EnumValue enumValue) {
enumClass = enumValue.enumClass();
enumField = enumValue.enumField();
}
/**
* 枚举值校验
* @param value
* @param constraintValidatorContext
* @return 匹配返回true,不匹配返回false
*/
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
if (null == value || null == enumClass || null == enumField || "".equals(enumField)) {
return false;
}
try {
Field field = enumClass.getDeclaredField(enumField);
Object[] objects = enumClass.getEnumConstants();
if (null != objects){
field.setAccessible(true);
for (Object object : objects) {
if (value.equals(field.get(object))){
return true;
}
}
}
return false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
- isValid(Object value, ConstraintValidatorContext constraintValidatorContext)中的value代表入参值
- 校验逻辑中我们先通过反射拿到具体的field,如果枚举中不存在该field,则会报NoSuchFieldException
- 第二步再通过enumClass.getEnumConstants()拿到该枚举中所有已定义好的常量数组
- 第三步,需要设置field的访问权限为true,否则会报异常:can not access a member of class xx with modifiers “private”
- 最后一步,遍历EnumConstants,通过反射拿到具体值,并进行入参对比
三、注解使用
- 定义枚举
public enum StatusEnum {
DEFAULT(0),
ACTIVE(1),
INACTIVE(2);
private Integer status;
public Integer getStatus() {
return status;
}
StatusEnum(Integer status) {
this.status = status;
}
}
- 定义入参实体vo
public class DemoVo {
@EnumValue(enumClass = StatusEnum.class, enumField = "status")
private Integer status;
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public DemoVo(Integer status) {
this.status = status;
}
}
- 请求校验
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/validate")
public void validate(@Valid @RequestBody DemoVo demoVo){
System.out.println("demoVo = " + demoVo.getStatus());
}
}
现在,可以就可以根据枚举中的field,任意校验入参了。