简易Java注解自动validate工具

对应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, List> ruledFileds = new ConcurrentHashMap<>();
    	
    	private static ConcurrentHashMap> fieldRules = new ConcurrentHashMap<>();
    
    	public static List checkParam(Object param, String group) {
    		List messages = new ArrayList<>();
    		String paramError;
    		if (param == null) {
    			paramError = "入参为空";
    			log.error(paramError);
    			messages.add(paramError);
    			return messages;
    		}
    		Class paramClazz = param.getClass();
    		List fields = ruledFileds.get(paramClazz);
    		if(fields == null) {
    			List 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 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 checkParam = checkParam(param, "create");
    		//-----------
    		param.setName(null);
    		log.info(checkParam.toString());
    		List checkParam2 = checkParam(param, null);
    		log.info(checkParam2.toString());
    		//-----------
    		param.setName("Lydckaasdf");
    		List 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 手机号格式不正确]
    

     

你可能感兴趣的:(自动入参校验,注解,分组)