本文实现自定义注解验证器,主要功能是:
1. 限定字段值只能是指定的几个值
2. 支持单值和多值验证
3. 验证过程中动态更改验证错误信息
自定义注解
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {LimitedValidator.class})
public @interface Limited {
String message() default "只能填写指定的值";
/**
* 备选项
* @return
*/
int[] candidates();
/**
* 枚举单值验证
* 多值验证为false 多值以逗号分隔
* @return
*/
boolean single() default true;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default { };
}
指定验证器
/**
* 枚举注解验证器
*
* @author yuan
* @since 2019-06-25 10:17
*/
public class LimitedValidator implements ConstraintValidator<Limited, Object> {
private Limited limitedAnno;
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
if (null == object) {
return true;
}
String s = String.valueOf(object);
List<String> list = new ArrayList<>();
if (limitedAnno.single()) {
list.add(s);
} else {
String[] intStr = s.split(",");
list = Arrays.asList(intStr);
}
Set<Integer> set = new HashSet<>();
L:
for (String value : list) {
for (int candidate : limitedAnno.candidates()) {
if (!isInteger(value)) {
// errorType for value
return newErrorMsg(context, "类型不正确:" + value);
}
Integer parseInt = Integer.valueOf(value);
if (candidate == parseInt) {
set.add(parseInt);
continue L;
}
}
// no match for value
return newErrorMsg(context, "不规范的输入:" + value);
}
if (list.size() != set.size()) {
return newErrorMsg(context, "有重复值");
}
return true;
}
@Override
public void initialize(Limited constraintAnnotation) {
this.limitedAnno = constraintAnnotation;
}
/**
* 重新填充 error 信息
*
* @param context
* @param newErrorMsg
*/
private boolean newErrorMsg(ConstraintValidatorContext context, String newErrorMsg) {
//禁用默认的message的值
context.disableDefaultConstraintViolation();
//重新添加错误提示语句
context.buildConstraintViolationWithTemplate(newErrorMsg)
.addConstraintViolation();
return false;
}
/**
* 是否是整数
*
* @param s
* @return
*/
private boolean isInteger(String s) {
if (!StringUtils.isNumeric(s)) {
return false;
}
try {
Integer.valueOf(s);
} catch (NumberFormatException e) {
return false;
}
return true;
}
}
Bean对象
@Data
public class PersonDO {
@Limited(candidates = {1,2,5})
private Integer limit;
@Limited(candidates = {1,2,5},single = false)
private String multiStr;
}
总结
- 自定义注解并指定验证器
- 实现验证器接口 ConstraintValidator
- 在bean上使用
BTW
可以写个统一的异常处理方法,处理验证结果
拓展
对 Spring Validation方法实现原理分析 感兴趣的小伙伴可以参考这篇文章