一、通点?
比如订单状态、性别、用户类型等枚举参数,在作值有效性校验时,我们可不可以使用 validator 统一在controller层进行处理呢?
二、实现方案
1. 定义枚举值数组获取接口
public interface IntArrayValuable {
int[] array();
}
2. 定义用户枚举类型,并实现IntArrayValuable 接口
public enum UserTypeEnum implements IntArrayValuable {
USER(1, "用户"),
ADMIN(2, "管理员");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(UserTypeEnum::getValue).toArray();
/** 类型 */
private final Integer value;
/** 类型名 */
private final String name;
UserTypeEnum(Integer value, String name) {
this.value = value;
this.name = name;
}
public Integer getValue() {
return value;
}
public String getName() {
return name;
}
@Override
public int[] array() {
return ARRAYS;
}
}
3. 定义 UserVo
public class UserVo {
@NotEmpty(message = "用户名不能为空")
@Length(min = 4, max = 16, message = "用户名不能为空 4-16 位")
@Pattern(regexp = "^[0-9]+$", message = "用户名全部为数字")
private String name;
@Mobile()
private String mobile;
/** 用户类型 */
@NotNull(message = "用户类型不能为空")
@InEnum(value = UserTypeEnum.class, message = "用户类型必须是 {value}")
private Integer userType;
//.....省略set get 方法
}
4. 定义InEnum注解
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER,
ElementType.TYPE_USE
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = InEnumValidator.class
)
public @interface InEnum {
/**
* @return 实现 EnumValuable 接口的
*/
Class<? extends IntArrayValuable> value();
String message() default "必须在指定范围 {value}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
5. 定义 InEnumValidator 验证器
public class InEnumValidator implements ConstraintValidator<InEnum, Integer> {
private List<Integer> values;
@Override
public void initialize(InEnum annotation) {
IntArrayValuable[] values = annotation.value().getEnumConstants();
if (values.length == 0) {
this.values = Collections.emptyList();
} else {
this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList());
}
}
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
// 为空时,默认不校验,即认为通过
if (value == null) {
return true;
}
// 校验通过
if (values.contains(value)) {
return true;
}
// 校验不通过,自定义提示语句(因为,注解上的 value 是枚举类,无法获得枚举类的实际值)
context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()
.replaceAll("\\{value}", values.toString())).addConstraintViolation(); // 重新添加错误提示语句
return false;
}
}
validator 使用参考:
01.spring-mvc 结合 Java Validation Api 提升web开发效能