对应Java后端开发来说,Hibernate Validator参数自动化校验非常熟悉了,结合Spring Aop在接口入参自动校验功能非常强大,可配置的校验规则也非常多。不过在一些体量不是那么大的项目里,业务规则也不是特别复杂,结合Java注解,实现了一个非常简易的入参校验工具。主要包含了参数规则注解定义,以及校验逻辑实现两部分。
- 规则注解定义Rule
@Target({ ElementType.TYPE, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Repeatable(ParamRules.class) public @interface Rule { /** * 业务场景即分组名称 * * @return */ String group() default ""; /** * 是否为空标签 * * @return */ NotNull notNull() default @NotNull; /** * 字段长度 * * @return */ Length len() default @Length; /** * 长度范围 * * @return */ Size size() default @Size; /** * 区间 * * @return */ Rang rang() default @Rang; /** * 字段校验规则,正则表达式 * * @return */ Regex regex() default @Regex; }
将每个单独的规则另外定义为注解。
- NotNull
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
String message() default "";
}
- Length
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Length {
int length() default 0;
String message() default "";
}
- Size
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Size {
String message() default "";
int min() default 0;
int max() default Integer.MAX_VALUE;
}
- Range
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Rang {
String message() default "";
int min() default 0;
int max() default Integer.MAX_VALUE;
}
- Regex
@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Regex { String message() default ""; String regex() default ""; }
校验逻辑处理类ParamChecker
/** class类型中所有被Rule注解的属性列表*/ private static ConcurrentHashMap<Class<?>, List<Field>> ruledFileds = new ConcurrentHashMap<>(); private static ConcurrentHashMap<Field, List<Rule>> fieldRules = new ConcurrentHashMap<>(); public static List<String> checkParam(Object param, String group) { List<String> messages = new ArrayList<>(); String paramError; if (param == null) { paramError = "入参为空"; log.error(paramError); messages.add(paramError); return messages; } Class<?> paramClazz = param.getClass(); List<Field> fields = ruledFileds.get(paramClazz); if(fields == null) { List<Field> allFields = FieldUtil.getAllFields(paramClazz); fields = allFields.stream().filter(e -> { Rule[] annotationsByType = e.getAnnotationsByType(Rule.class); if(annotationsByType.length == 0) { return false; } fieldRules.put(e, Arrays.asList(annotationsByType)); return true; }).collect(Collectors.toList()); } ruledFileds.put(paramClazz, fields); BeanMap beanMap = ToString.getBeanMap(param); // 遍历属性,校验规则 for(Field field : fields) { Object value = beanMap.get(field.getName()); // 获取field上的rule注解信息 List<Rule> ruleList = fieldRules.get(field); Rule rule = null; // 有多个规则分组 if(ruleList.size() > 1) { for(Rule r : ruleList) { String multiGroup = r.group(); // 取默认分组 if(group == null) { if("".equals(multiGroup)) { rule = r; break; } } else { if(group.equals(multiGroup)) { rule = r; break; } } } } else { rule = ruleList.get(0); } if(rule != null) { // 非空判断 NotNull notNull = rule.notNull(); String notMsg = notNull.message(); if(value == null && !"".equals(notMsg)) { messages.add(notMsg); } // 字段长度 Length len = rule.len(); String lenMsg = len.message(); if(value != null && !"".equals(lenMsg)) { int valueLen = value.toString().length(); if(valueLen != len.length()) { messages.add(lenMsg); } } // 字段长度范围 Size size = rule.size(); String sizeMsg = size.message(); if(value != null && !"".equals(sizeMsg)) { int valueLen = value.toString().length(); if(valueLen < size.min() || valueLen > size.max()) { messages.add(sizeMsg); } } // 区间 Rang rang = rule.rang(); String rangMsg = rang.message(); if(value != null && !"".equals(rangMsg)) { int valueInt = Integer.parseInt(value.toString()); if(valueInt < rang.min() || valueInt > rang.max()) { messages.add(rangMsg); } } // 正则 Regex regex = rule.regex(); String regMsg = regex.message(); if(value != null && !"".equals(regMsg)) { String valueStr = value.toString(); if(!valueStr.matches(regex.regex())) { messages.add(regMsg); } } } } return messages; } public static void main(String[] args) { ParamA param = new ParamA(); param.setName("Lydcka"); param.setAge(28); param.setPhone("188115882474"); List<String> checkParam = checkParam(param, "create"); //----------- param.setName(null); log.info(checkParam.toString()); List<String> checkParam2 = checkParam(param, null); log.info(checkParam2.toString()); //----------- param.setName("Lydckaasdf"); List<String> checkParam3 = checkParam(param, "create"); log.info(checkParam3.toString()); }
标记入参对象
@Data public class ParamA { @Rule(notNull = @NotNull(message = "name 不能为空")) @Rule(group = "create", notNull = @NotNull(message = "name 不能为空"), len = @Length(length = 6, message = "name 长度为6")) private String name; @Rule(rang = @Rang(min = 1, max = 120, message = "age 年龄区间为1-120岁之间")) private int age; @Rule(regex = @Regex(regex = "1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}", message = "phone 手机号格式不正确")) private String phone; }
-
自此,简易入参自动校验完成
16:54:10.441 [main] INFO comm.param.ParamChecker - [phone 手机号格式不正确] 16:54:10.460 [main] INFO comm.param.ParamChecker - [name 不能为空, phone 手机号格式不正确] 16:54:10.461 [main] INFO comm.param.ParamChecker - [name 长度为6, phone 手机号格式不正确]