`

基于注解的参数校验框架

阅读更多
近期由于工作的需要,写了一个简易的参数校验框架,虽然市场上有common-validator 和hibernate-validator两个开源的,但是有些情景他们是无法满足的,比如参数字段之间的依赖关系,这在项目中是极其常见的。他们仅仅提供了对字段的简单的格式校验。另外这两种校验框架的校验器都是有状态的,这样导致校验的性能不好,对于录入还无所谓,但是批量excel 导入的这种,就非常吃力了。

出于性能和依赖关系校验的需求,改造下工作的校验框架为一个通用的参数校验框架,支持表达式的格式校验,灵活性极好,代码完全复用,思路明了,适合复杂的参数校验场景,希望各位给予指正其中的不足~

下面我贴出来了我写的框架的代码,但是太麻烦搞格式,我也懒的搞,如果有兴趣,可以下载源码看看~

git地址为:https://github.com/wangxinchun/javaframe-validator
先看下这个框架的用法:
/**
 * 验证要求:
 * 1、begin 可以为空,end 也可以为空,如果不为空,那么他们必须是yyyy-MM-dd的时间格式
 * 2、如果end不为空,那么end的时间必须大于当前时间
 * 3、如果begin不为空,并且end不为空,end 必须大于begin的时间
 * @author wangxinchun
 *
 */
public class DateVO {
	@Rules(
			conditionList = {
				@ConditionRule(id = "A",type = RuleType.empty),
				@ConditionRule(id = "B",type = RuleType.not_empty)
			},
			conclusionList = {
					@ConclusionRule(id = "C",type =RuleType.date_format ,value = "yyyy-MM-dd",tip = "格式错误")
			},
			logicList = {
					 //如果为空,那么直接success,如果失败继续下一个规则的校验
					@LogicRule(conclusion = "A",successNextStep = NextStepType.returnSuccess,failNextStep = NextStepType.goNext),
					@LogicRule(condition = "B", conclusion = "C") //此次的B配置可以去掉,因A成功,已经返回,所以B条件肯定成立
			},
			text = "开始时间")
	private Date begin;
	
	@Rules(
			conditionList = {
					@ConditionRule(id = "A",type = RuleType.empty),
					//@ConditionRule(id = "B",type = RuleType.not_empty),
					@ConditionRule(id = "C",type = RuleType.not_empty,dependProperty = "begin")
				},
			conclusionList = {
					@ConclusionRule(id = "D",type = RuleType.date_format,value = "yyyy-MM-dd",tip = "格式错误"),
					@ConclusionRule(id = "E",type = RuleType.date_compare_now,value = ">=,yyyy-MM-dd",tip = "必须大于当前时间"),
					@ConclusionRule(id = "F",type = RuleType.date_compare_refer,value = "begin,>=,yyyy-MM-dd",tip = "结束时间必须大于开始时间")
			},
			logicList = {
					//如果为空,那么直接返回,如果不为空,那么直接进入下一个校验
					@LogicRule(conclusion = "A",successNextStep = NextStepType.returnSuccess,failNextStep = NextStepType.goNext),
					@LogicRule(conclusion = "D&&E"),// 此次的验证可以分开也可以合并
					@LogicRule(condition= "C", conclusion = "F") //依赖验证
			},
			text = "结束时间")
	private Date end;

	public Date getBegin() {
		return begin;
	}

	public void setBegin(Date begin) {
		this.begin = begin;
	}

	public Date getEnd() {
		return end;
	}

	public void setEnd(Date end) {
		this.end = end;
	}

}


测试用例:
@Test
	public void testValidateDate() {
		CommonValidateService service = new CommonValidateService();
		Map<String,String> params = new HashMap<String,String>();
		params.put("begin", "2013-12-09");
		params.put("end", "2013-12-08");
		ValidateResult result = service.validate(params, DateVO.class);
		Assert.assertEquals(result.isSuccess(), false);
	}
	
	@Test
	public void testValidateDate2() {
		CommonValidateService service = new CommonValidateService();
		Map<String,String> params = new HashMap<String,String>();
		params.put("begin", "2013-12-09");
		params.put("end", "2013-12-10");
		ValidateResult result = service.validate(params, DateVO.class);
		Assert.assertEquals(result.isSuccess(), true);
	}




引用术语:
一个对象有多个属性
每个属性对应一个校验规则集合
一个校验规则集合对于多个校验规则
每个校验规则有一个或者多个校验条件和结论组成。

基于以上的分析,定义对以上角色的注解抽象:

/**
 * 验证规则集
 * @author wangxinchun1988@163.com  <br>
 * 配置在bean的成员上,代表一组校验规则集
 */
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Rules {

	/**
	 * 结论规则集合 */
	ConclusionRule[] conclusionList();
	
	/**
	 * 条件规则集合 */
	ConditionRule[] conditionList() default {};
	
	/**
	 * 逻辑验证规则集合  */
	LogicRule[] logicList() default {};
	
	/** 成员字段名称*/
	String text() default "";
	
	/** 校验顺序,默认同一order值,按照在bean中出现的先后顺序校验*/
	int order() default Integer.MIN_VALUE;
	
	/** LogicRule的组合模式,默认为AND组合*/
	LogicAssembleType assembleType() default LogicAssembleType.AND;
	
}



/**
 * 逻辑项注解
 * @author wangxinchun1988@163.com
 * @date 2013-12-2下午1:37:47
 */
public @interface LogicRule {

	/** 条件:逻辑条件表达式。<BR>
	 *  tips:简单逻辑没有条件的,推导逻辑才有条件*/
	public String condition() default "";

	/** 结论:要验证的结论表达式 <br>
	 * eg:(A&&B)||C 
	 * */
	public String conclusion();
	
	/** 逻辑验证成功的下一步执行逻辑  <br/>
	 *  1、NextStepType.goNext 默认进行下一个校验规则的验证。(如果词条为最后一个逻辑项,那么等同于NextStepType.returnSuccess)<br/>
	 *  2、NextStepType.returnSuccess 表示此验证完成之后,不再进行下一个校验规则的验证 ,直接返回校验成功
	 * */
	public NextStepType successNextStep() default NextStepType.goNext;
	
	/** 逻辑校验失败后下一步执行逻辑
	 * 1、NextStepType.returnFail 默认校验失败时,直接返回校验失败
	 * 2、NextStepType.goNext 校验继续下一个词条的校验(如果词条为最后一个逻辑项,那么等同于NextStepType.returnSuccess)
	 * */
	public NextStepType failNextStep() default NextStepType.returnFail;
	
	/** 条件验证失败的下一步返回类型 <br>
	 * 1、NextStepType.goNext 默认条件校验失败,进入下一个逻辑词条的校验(如果词条为最后一个逻辑项,那么等同于NextStepType.returnSuccess)<br>
	 * 2、NextStepType.returnFail 不进行下一个词条的校验,直接返回校验失败 <br>
	 * 3、NextStepType.returnSuccess 不进行下一个词条的校验,直接返回校验成功
	 * */
	public NextStepType conditionFailNextStep() default NextStepType.goNext;
	
	/**
	 * 验证失败后的提醒信息,此提醒信息优先级最高
	 */
	public String tip() default "";
	
	/**
	 * 提醒类型
	 */
	public TipType tipType() default TipType.combine;
}




/**
 * 条件项注解 
 * @author wangxinchun1988@163.com
 * @date 2013-12-2下午9:45:20
 * 
 * tip: 条件项的注解,不需要包括 字段验证的失败信息。
 */
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ConditionRule {

	public String id();
	
	/**
	 * 验证规则名字
	 */
	public RuleType type() default RuleType.local_type;

	/**
	 * 验证规则值
	 */
	public String value() default "";

	
	/** 依赖参照熟悉*/
	public String dependProperty() default "";
	
	/**
	 * 扩展本地校验规则
	 * @return
	 */
	public String local() default "";
	
}



/**
 * 推导结果项注解
 * @author xinchun.wang
 *
 */
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ConclusionRule {

	/** 规则项的位唯一id属性*/
	public String id();
	
	/**
	 * 验证规则名字
	 */
	public RuleType type() default RuleType.local_type;

	/**
	 * 验证规则值
	 */
	public String value() default "";

	/**
	 * 此验证失败后的提醒信息,如果没有配置那么从ConclusionItem 取tip信息
	 */
	public String tip() default "";
	
	/**
	 * 提醒类型
	 * @return
	 */
	public TipType tipType() default TipType.combine;
	
	/**
	 * 扩展本地校验规则
	 * @return
	 */
	public String local() default "";
	
}



规则定义完毕,下面就是解析校验规则了:

/**
 * 验证服务接口
 * @author xinchun.wang
 *
 */
public interface IValidateService {
	/**
	 * 校验params中的参数以及对应的值是否有效
	 * @param params
	 * @return
	 */
	ValidateResult validate(Map<String, String> params,Class<?> cls);
}

/**
 * 验证接口的抽象实现
 * 
 * @author xinchun.wang
 * 
 */
public abstract class AbstractValidateService implements IValidateService {
	protected static final Logger logger= LoggerFactory.getLogger(AbstractValidateService.class);
	
	/**持有Rules到其上所有校验器的缓存。结构:  Rules ->(id,ValidatorVO)的映射*/
	final private static ConcurrentHashMap<Rules,Map<String,RuleVO> > rulesCacheMap = new ConcurrentHashMap<Rules, Map<String,RuleVO>>();
	/** 持有Rules上逻辑校验逻辑的缓存。结构:Rules->LogicGroup 的映射*/
	final private static ConcurrentHashMap<Rules,LogicGroup > rulesLogicGroupCacheMap = new ConcurrentHashMap<Rules, LogicGroup>();

	/**
	 * 规则处理集合接口
	 * 
	 * @param rule   规则
	 * @param value  参数值
	 * @param params 依赖参考对象
	 * @return
	 */
	final protected ValidateResult processRules(Rules rules, String name, Map<String, String> params) {
		LogicRule[] logicArr = rules.logicList();
		if(logicArr == null || logicArr.length <=0 ){
			return ValidateResult.SUCCESS; //如果没有配置验证逻辑项,默认返回success
		}
		LogicGroup execute = rulesLogicGroupCacheMap.get(rules);
		if(execute == null){
			for(LogicRule item : logicArr) {
				String conclusion = item.conclusion();//逻辑校验规则的结论表达式
				String condition = item.condition();
				if(condition == null || condition.trim().isEmpty()){ //如果是简单逻辑,只有结论没有条件
					if(conclusion == null || conclusion.trim().isEmpty()){
						throw new LogicConfigException("没有配置conclusion逻辑" + item);
					}
					LogicRuleVO logic = initLogicVO(rules,item ,name);
					LogicGroup atomicLogicGroup = new AtomicLogicGroup(logic);
					if(execute == null){
						execute = atomicLogicGroup;
					}else {
						if(rules.assembleType() == LogicAssembleType.AND){
							execute = new AndLogicGroupAdapter(Arrays.asList(execute, atomicLogicGroup));
						} else{
							execute = new OrLogicGroupAdapter(Arrays.asList(execute, atomicLogicGroup));
						}
					}
				}else {//推导验证逻辑项
					if(conclusion != null && !conclusion.trim().isEmpty() && condition != null && !condition.trim().isEmpty()){
						/* 没有缓存的逻辑组*/
						LogicRuleVO logic = initLogicVO(rules,item,name);
						LogicGroup deduceLogic = new DeduceAtomicLogicGroup(logic);
						if(execute == null) {
							execute = deduceLogic;
						}else{
							if(rules.assembleType() == LogicAssembleType.AND){
								execute = new AndLogicGroupAdapter(Arrays.asList(execute,deduceLogic));
							} else{
								execute = new OrLogicGroupAdapter(Arrays.asList(execute,deduceLogic));
							}
						}
					} else{
						throw new LogicConfigException(item+ " 推导逻辑配置错误 ");
					}
				}
			}
		}
		LogicValidateResult result = execute.executeLogic(params);
		if(result.isSuccess()){
			return ValidateResult.SUCCESS;
		}else{
			return ValidateResult.errorInstance(result.getMessage());
		}
	}
	
	/**
	 * 初始化逻辑VO
	 * @param item
	 * @param validatorMap
	 * @return
	 */
	private LogicRuleVO initLogicVO(Rules rules,LogicRule item,String name) {
		LogicRuleVO logic = new LogicRuleVO();
		Map<String, RuleVO> validatorMap = rulesCacheMap.get(rules);
		if (validatorMap == null) {
			validatorMap = resolveValidatorMapByRules(rules, name);
			rulesCacheMap.putIfAbsent(rules, validatorMap);
		}
		String conclusion = item.conclusion();
		if(conclusion != null && !conclusion.trim().isEmpty()){
			ConditionGroup conclusionGroup = ConditionGroupResolver.resolve(conclusion,validatorMap);
			logic.setConclusionGroup(conclusionGroup);
		}
		String condition = item.condition();
		if(condition != null && !condition.trim().isEmpty()){
			ConditionGroup conditionGroup = ConditionGroupResolver.resolve(condition,validatorMap);
			logic.setConditionGroup(conditionGroup);
		}
		if(item.tipType() == TipType.just_rule){
			logic.setTip(item.tip());
		}else{
			if(item.tip() != null && !item.tip().isEmpty()){
				logic.setTip(rules.text() + item.tip());
			}
		}
		
		logic.setFailNextStep(item.failNextStep());
		logic.setSuccessNextStep(item.successNextStep());
		logic.setConditionFailNextStep(item.conditionFailNextStep());
		return logic;
	}
	
	/**
	 * 解析rules上所有的校验器
	 * @param rules
	 * @param name
	 * @return
	 */
	private Map<String,RuleVO> resolveValidatorMapByRules(Rules rules ,String name){
		Map<String,RuleVO> ruleMap = new HashMap<String,RuleVO>();
		for(ConclusionRule item : rules.conclusionList()){
			RuleVO vo = new RuleVO();
			IValidator validator = null;
			/* 找到验证器*/
			if(RuleType.local_type == item.type()){
				String localRule = item.local();
				validator = ValidatorFactory.getLocalValidator(localRule);
			} else {
				validator = ValidatorFactory.getCommonValidator(item.type());
			}
			if(validator == null){
				throw new IllegalStateException(item + "没有注册有效的验证器");
			}
			
			vo.setProperty(name);
			if(item.tipType() == TipType.combine){
				vo.setTip(rules.text()+item.tip());
			}else{
				vo.setTip(item.tip());
			}
			vo.setRuleType(item.type());
			vo.setRule(item.value());
			ruleMap.put(item.id(), vo);
		}
		
		for(ConditionRule item : rules.conditionList()){
			RuleVO vo = new RuleVO();
			if(item.dependProperty()== null || item.dependProperty().isEmpty()){
				vo.setProperty(name);
			}else {
				vo.setProperty(item.dependProperty());
			}
			vo.setRuleType(item.type());
			vo.setRule(item.value());
			ruleMap.put(item.id(), vo);
		}
		return ruleMap;
	}
	
}


/**
 * 通用规则验证器 <br>
 * 
 * 根据cls 检索其字段上的注解,解析注解,然后校验params的信息。
 * @author xinchun.wang
 * 
 */
public class CommonValidateService extends AbstractValidateService {
	final private static ConcurrentHashMap<String, Map<Field, Rules>> cacheMap = new ConcurrentHashMap<String, Map<Field, Rules>>();
	
	/*
	 * (non-Javadoc)m
	 * 
	 * @see
	 * com.qunar.flight.tts.policy.client.validator.impl.AbstractValidateServiceImpl
	 * #validate(java.util.Map)
	 */
	@Override
	public ValidateResult validate(Map<String, String> params,Class<?> cls) {
		Map<Field, Rules> fieldRuleMap = cacheMap.get(cls.getName());
		if (fieldRuleMap == null) {
			fieldRuleMap = ClassHelper.getFieldsAndRules(cls);
			cacheMap.putIfAbsent(cls.getName(), fieldRuleMap);
		}

		for (Map.Entry<Field, Rules> item : fieldRuleMap.entrySet()) {
			Field itemField = item.getKey();
			String name = itemField.getName();
			Rules rules = item.getValue();
			if(rules == null){
				continue;
			}
			ValidateResult result = processRules(rules, name, params);
			if(!result.isSuccess()){
				return result;
			}
		}
		return new ValidateResult(true,null);
	}
}

public class ClassHelper {

	/**
	 * 检索cls类的所有Field字段以及其上的验证信息
	 * 
	 * @param cls
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<Field, Rules> getFieldsAndRules(Class<?> cls) {
		if (cls == null) {
			return Collections.EMPTY_MAP;
		}

		final Field[] fields = cls.getDeclaredFields();
		if (fields == null) {
			return Collections.EMPTY_MAP;
		}
		
		Map<Field, Rules> fieldRulesMap = new TreeMap<Field, Rules>(
				new Comparator<Field>() {
					@Override
					public int compare(Field o1, Field o2) {
						Rules rules1 = o1.getAnnotation(Rules.class);
						Rules rules2 = o2.getAnnotation(Rules.class);
						if (rules1.order() != Integer.MIN_VALUE && rules2.order() != Integer.MIN_VALUE) { //如果两个都有配置顺序
							if(rules1.order() == rules2.order()) { //都配置,但是配置的order顺序相等
								int index1 = ArrayUtils.indexOf(fields,o1);
								int index2 = ArrayUtils.indexOf(fields,o2);
								return index1 - index2;
							}
							return rules1.order() - rules2.order(); //都配置,order小的排在前面
						} else if (rules1.order() == Integer.MIN_VALUE) { //o1 没有配置,o2配置了
							return 1;
						} else if (rules2.order() == Integer.MIN_VALUE) { //o1 配置了,o2没有配置了
							return -1;
						}else {
							int index1 = ArrayUtils.indexOf(fields,o1);
							int index2 = ArrayUtils.indexOf(fields,o2);
							return index1 - index2;
						}
					}
				});

		for (Field item : fields) {
			Rules rules = item.getAnnotation(Rules.class);
			if (rules == null) {
				continue;
			}
			fieldRulesMap.put(item,rules);
		}
		return fieldRulesMap;
	}
}


逻辑条件 和 逻辑结论的解析和组装

/**
 * 条件逻辑组校验接口
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:03:53
 */
public interface ConditionGroup {

	/**
	 * 逻辑校验方法 
	 * @param params
	 * @return
	 */
	public ValidateResult executeCondition(Map<String, String> params);

}

/**
 * 原子校验组
 * 一个原子校验组拥有一个校验器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:04:48
 */
public class AtomitConditionGroup implements ConditionGroup {
	private RuleVO ruleVo;
	public AtomitConditionGroup(final RuleVO ruleVo) {
		this.ruleVo = ruleVo;
	}
	
	@Override
	public ValidateResult executeCondition(Map<String, String> params) {
		if(ruleVo == null){
			throw new ValidatorConfigException();
		}
		IValidator validator = null;
		/* 找到验证器*/
		if(RuleType.local_type == ruleVo.getRuleType()){
			String localRule = ruleVo.getLocal();
			validator = ValidatorFactory.getLocalValidator(localRule);
		} else {
			validator = ValidatorFactory.getCommonValidator(ruleVo.getRuleType());
		}
		if(validator == null){
			throw new IllegalStateException(ruleVo + "没有注册有效的验证器");
		}
		
		ValidateResult result = validator.validate(ruleVo, params);
		return result;
	}

}

/**
 * 逻辑组校验适配器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:06:08
 */
public abstract class ConditionGroupAdapter implements ConditionGroup {
	protected List<ConditionGroup> list;
	
}
/**
 * 逻辑组校验AND类型的集成适配器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:06:55
 */
public  class AndConditionGroupAdapter extends ConditionGroupAdapter {

	public AndConditionGroupAdapter(List<ConditionGroup> list) {
		this.list = list;
	}
	@Override
	public ValidateResult executeCondition(Map<String, String> params) {
		if(list == null || list.size() <= 0){
			return ValidateResult.SUCCESS;
		}else {
			for(ConditionGroup item : list){
				ValidateResult result = item.executeCondition(params);
				if(!result.isSuccess()){
					return result;
				}
			}
			return ValidateResult.SUCCESS;
		}
	}
	
}
/**
 * 逻辑组校验OR类型的集成适配器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:05:36
 */
public class OrConditionGroupAdapter extends ConditionGroupAdapter {

	public OrConditionGroupAdapter(List<ConditionGroup> list) {
		this.list = list;
	}
	@Override
	public ValidateResult executeCondition(Map<String, String> params) {
		if(list == null || list.size() <= 0){
			return ValidateResult.SUCCESS;
		}else {
			StringBuilder failBuilder = new StringBuilder();
			for(ConditionGroup item : list){
				ValidateResult result = item.executeCondition(params);
				if(result.isSuccess()){
					return ValidateResult.SUCCESS;
				}else {
					failBuilder.append(result.getMessage()).append(item.equals(list.get(list.size()-1))? "":",或者");
				}
			}
			return ValidateResult.errorInstance(failBuilder.toString());
		}
	}
}
/**
 * 条件表达式解析器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午12:07:48
 */
public class ConditionGroupResolver {
	private static final char AND = '&';
	private static final String ANDAND = "&&";
	private static final char OR = '|';
	private static final String OROR = "||";

	private static final char left = '(';
	private static final char right = ')';

	/**
	 * 逻辑表达是的解析
	 * 
	 * @param logic  ((A||B)&&(C||D))||(F&&H)
	 * @param ruleMap 校验器id->ValidatorVO
	 * @return 返回逻辑表达式对应校验封装实现
	 */
	public static ConditionGroup resolve(String logic, Map<String, RuleVO> validatorMap) {
		logic = trimLogic(logic);
		if (logic == null || logic.trim().isEmpty()) {
			return null;
		}
		if (!logic.contains(ANDAND) && !logic.contains(OROR)) {
			RuleVO logicVO = validatorMap.get(logic);
			if (logicVO == null) {
				if(logic.indexOf(""+AND)!=-1 || logic.indexOf(""+OR)!= -1){
					throw new LogicConfigException(logic + "配置错误,与和或的逻辑请使用 && || 表达 ");
				}
				throw new LogicConfigException(logic + "没有对应的Rule");
			}
			return new AtomitConditionGroup(logicVO);
		}
		int leftCount = 0;
		int rightCount = 0;
		boolean andFlag = false;
		boolean orFlag = false;
		int lastSubIndex = 0;
		List<String> subLogicList = new ArrayList<String>();
		for (int i = 0; i < logic.length(); i++) {
			char tempChar = logic.charAt(i);
			if (tempChar == left) {
				leftCount++;
			} else if (tempChar == right) {
				rightCount++;
				if(i == logic.length()-1){
					subLogicList.add(logic.substring(lastSubIndex));
				}
			} else if (tempChar == AND && logic.charAt(i + 1) == AND) {
				if (leftCount == rightCount) {//保证操作的id不再括弧内
					andFlag = true;
					subLogicList.add(logic.substring(lastSubIndex, i));
					i++;
					lastSubIndex = i+1;
				}
			} else if (tempChar == OR && logic.charAt(i + 1) == OR) {
				if (leftCount == rightCount) { //保证操作的id不再括弧内
					orFlag = true;
					subLogicList.add(logic.substring(lastSubIndex, i));
					i++;
					lastSubIndex = i+1;
				}
			} else{
				if(i == logic.length()-1){
					subLogicList.add(logic.substring(lastSubIndex));
				}
			}
		}
		if(andFlag == orFlag){
			throw new LogicConfigException(logic+ "配置错误,最外层必须配置同一类型的逻辑分割符合");
		}
		List<ConditionGroup> listGroup = new ArrayList<ConditionGroup>();
		if (subLogicList.size() > 0) {
			for (String item : subLogicList) {
				ConditionGroup logicGroup = resolve(item, validatorMap);
				if (logicGroup != null) {
					listGroup.add(logicGroup);
				}
			}
		} else {
			throw new LogicConfigException(logic+ " ()配对不全或者 缺少逻辑符号||, && ");
		}
		ConditionGroup returnGroup;
		if (andFlag) {
			returnGroup = new AndConditionGroupAdapter(listGroup);
		} else {
			returnGroup = new OrConditionGroupAdapter(listGroup);
		}
		return returnGroup;
	}

	/**
	 * 过滤外括号
	 * @param logic
	 * @return
	 */
	public static String trimLogic(String logic) {
		if (logic == null || logic.trim().isEmpty()) {
			return null;
		}
		if (logic.charAt(0) != left || logic.charAt(logic.length() - 1) != right) {
			return logic;
		} else {
			int leftCount = 0;
			for (int i = 0; i < logic.length(); i++) {
				if (logic.charAt(i) == left) {
					leftCount++;
				} else if (logic.charAt(i) == right) {
					leftCount--;
					if (leftCount == 0 && i == logic.length() - 1) { //如果第一次和(匹配的是最后一个字符),那么去除外括号
						return trimLogic(logic.substring(1, logic.length() - 1));
					}else if(leftCount == 0){ //如果第一次和第一个(匹配的不是最后一个字符),那么直接返回
						return logic;
					}
				}
			}
			return logic;
		}
	}

}

/**
 * 逻辑组校验接口
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:03:53
 */
public interface LogicGroup {

	/**
	 * 逻辑校验方法 
	 * @param params
	 * @return
	 */
	public LogicValidateResult executeLogic(Map<String, String> params);

}
/**
 * 逻辑原子校验组
 * 一个原子校验组对应一个逻辑校验规则
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:04:48
 */
public class AtomicLogicGroup implements LogicGroup {
	private LogicRuleVO logic;
	public AtomicLogicGroup(final LogicRuleVO logic) {
		this.logic = logic;
	}
	
	@Override
	public LogicValidateResult executeLogic(Map<String, String> params) {
		if(logic == null){
			throw new ValidatorConfigException();
		}

		LogicValidateResult logicResult = null;
		ValidateResult result = logic.getConclusionGroup().executeCondition(params);
		//结论逻辑成功,那么设置成功的下一步
		if(result.isSuccess()){
			logicResult = LogicValidateResult.successInstance();
			logicResult.setSuccessNextStep(logic.getSuccessNextStep());
		}else {//如果失败,那么继续失败的下一步,并且设置失败原因
			logicResult = LogicValidateResult.errorInstance(logic.getTip());
			logicResult.setFailNextStep(logic.getFailNextStep());
			logicResult.setConditionFailNextStep(logic.getConditionFailNextStep());
			if(logic.getTip()== null || logic.getTip().isEmpty()){
				logicResult.setMessage(result.getMessage());
			}
		}
		return logicResult;
	}

}
/**
 * 推导原子校验组
 * 一个推导原子校验组拥有一个校验器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:04:48
 */
public class DeduceAtomicLogicGroup implements LogicGroup {
	private LogicRuleVO logic;
	public DeduceAtomicLogicGroup(final LogicRuleVO logic) {
		this.logic = logic;
	}
	
	@Override
	public LogicValidateResult executeLogic(Map<String, String> params) {
		if(logic == null){
			throw new ValidatorConfigException();
		}
		LogicValidateResult logicResult = null;
		ValidateResult conditionResult = logic.getConditionGroup().executeCondition(params);
		//条件验证成功,那么验证结论逻辑
		if(conditionResult.isSuccess()){
			ValidateResult conclusionResult = logic.getConclusionGroup().executeCondition(params);
			//结论逻辑成功,那么设置成功的下一步
			if(conclusionResult.isSuccess()){
				logicResult = LogicValidateResult.successInstance(); 
				logicResult.setSuccessNextStep(logic.getSuccessNextStep());
			}else {//如果失败,那么继续失败的下一步,并且设置失败原因
				logicResult = LogicValidateResult.errorInstance(logic.getTip()); //TODO
				logicResult.setFailNextStep(logic.getFailNextStep());
				if(logic.getTip()== null || logic.getTip().isEmpty()){
					logicResult.setMessage(conclusionResult.getMessage());
				}
			}
		}else { //如果条件失败,那么判断条件失败的下一步
			if(logic.getConditionFailNextStep() == NextStepType.goNext){
				logicResult = LogicValidateResult.successInstance(); 
				logicResult.setFailNextStep(NextStepType.goNext);
			}else if(logic.getConditionFailNextStep() == NextStepType.returnFail){
				//如果条件失败,那么返回此逻辑验证的失败message
				logicResult = LogicValidateResult.errorInstance(logic.getTip());
				logicResult.setFailNextStep(NextStepType.returnFail);
			}
		}
		return logicResult;
	}

}
/**
 * 逻辑组校验AND类型的集成适配器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:06:55
 */
public  class AndLogicGroupAdapter extends LogicGroupAdapter {

	public AndLogicGroupAdapter(List<LogicGroup> list) {
		this.list = list;
	}
	@Override
	public LogicValidateResult executeLogic(Map<String, String> params) {
		if(list == null || list.size() <= 0){
			return LogicValidateResult.SUCCESS;
		}else {
			for(LogicGroup item : list){
				LogicValidateResult result = item.executeLogic(params);
				if(!result.isSuccess()){ 
					//AND类型的逻辑的组合,如果第一个失败,并且 result.getConditionFailNextStep() == NextStepType.returnFail 直接返回
					if(result.getFailNextStep() == NextStepType.returnFail){
						return result;
					}else if(result.getFailNextStep() == NextStepType.goNext){ //如果goNext 那么判断下一个and逻辑组
						continue;
					}
				}else {
					//如果当前研究组合成功,那么
					if(result.getSuccessNextStep() == NextStepType.returnSuccess){
						return result;
					}
				}
			}
			return LogicValidateResult.SUCCESS;
		}
	}
	
}



具体的校验器 接口定义(实现略):
/**
 * 校验器
 * @author wangxinchun1988@163.com
 * @date 2013-12-1下午1:08:55
 */
public interface IValidator {
	/**
	 * 校验器统一校验接口
	 * @param rule 校验规则
	 * @param name 参数名字
	 * @param params 待校验的参数集合
	 * @return 返回此验证结果
	 */
	public ValidateResult validate(RuleVO validator, Map<String, String> params);

}
/**
 * 数字范围校验校验
 * 
 * @author xinchun.wang
 *  eg: value = "[2,12]", 
    	 *     value = "(2,12)",
    	 *     value = "[2,12)"
    	 *     value = "(2,12)"
 */
public class NumberLimitValidator extends AbstractValidator {

	@Override
	public ValidateResult validate(RuleVO validator, Map<String, String> params) {
		//校验name对应的值不能为空
			String paramValue = params.get(validator.getProperty());
			try {
				String ruleValue = validator.getRule();
				boolean leftContains = false;
				boolean rightContains = false;
				if(ruleValue.startsWith("[")){
					leftContains = true;
				}
				if(ruleValue.endsWith("]")){
					rightContains = true;
				}
				ruleValue = removeRangeFlag(ruleValue);
				String[] valueArr = ruleValue.split(",");
				BigDecimal min = new BigDecimal(valueArr[0].trim());
				BigDecimal max = new BigDecimal(valueArr[1].trim());
				BigDecimal paramDecimal = new BigDecimal(paramValue);
				if(leftContains == true && rightContains == true){
					if(min.compareTo(paramDecimal) <=0 &&  max.compareTo(paramDecimal) >=0){
						return ValidateResult.SUCCESS;
					}else {
						return ValidateResult.errorInstance(validator.getTip());
					}
				}else if(leftContains = true && rightContains == false){
					if(min.compareTo(paramDecimal) <=0 &&  max.compareTo(paramDecimal) >0){
						return ValidateResult.SUCCESS;
					}else {
						return ValidateResult.errorInstance(validator.getTip());
					}
				}else if(leftContains == false && rightContains == true){
					if(min.compareTo(paramDecimal) <0 &&  max.compareTo(paramDecimal) >=0){
						return ValidateResult.SUCCESS;
					}else {
						return ValidateResult.errorInstance(validator.getTip());
					}
				}else {
					if(min.compareTo(paramDecimal) <0 &&  max.compareTo(paramDecimal) >0){
						return ValidateResult.SUCCESS;
					}else {
						return ValidateResult.errorInstance(validator.getTip());
					}
				}

			} catch (Exception e) {
				logWarn(e, validator.getProperty(),params.get(validator.getProperty()),validator.getRule(),this.getClass().getName());
				return ValidateResult.errorInstance(validator.getTip());
			}

	}
}

/**
 * 验证器工厂
 * @author xinchun.wang
 *
 */
public class ValidatorFactory {
	/**
	 * 保存通用验证器缓存*/
	private static final Map<RuleType, IValidator> commonValidatorCacheMap = new HashMap<RuleType, IValidator>();
	/**
	 * 本地验证器缓存*/
	private static final ConcurrentHashMap<String, IValidator> localValidatorCacheMap = new ConcurrentHashMap<String, IValidator>();
	
	/**
	 * 通用验证器
	 */
	private static StringNotEmptyValidator notEmptyValidator = new StringNotEmptyValidator();
    private static StringEmptyValidator emptyValidator = new StringEmptyValidator();
    private static  StringRegxValidator stringRegxValidator = new StringRegxValidator();
    
    
    private static StringLimitLengthValidator stringLimitLengthValidator = new StringLimitLengthValidator();
    
    /** 格式型验证*/
	private static DateFormatValidator dateFormatValidator = new DateFormatValidator();
    private static NumberFormatValidator numberFormatValidator =new NumberFormatValidator();
    
    private static NumberModValidator numberModValidator = new NumberModValidator();
    private static NumberLimitValidator numberLimitValidator = new NumberLimitValidator();
    
    /** 参考型验证*/
    private static NumberReferCompareValidator numberReferCompareValidator = new NumberReferCompareValidator();
    private static DateReferCompareValidator dateReferCompareValidator = new DateReferCompareValidator();
    private static DateCompareNowValidator dateCompareNowValidator = new DateCompareNowValidator();

    private static ValuesLimitValidator valuesLimitValidator = new ValuesLimitValidator();
    
    
    static {
    	/** 通用验证器的注册*/
		commonValidatorCacheMap.put(RuleType.empty, emptyValidator);
		commonValidatorCacheMap.put(RuleType.not_empty, notEmptyValidator);
		commonValidatorCacheMap.put(RuleType.string_regex, stringRegxValidator);
		
		commonValidatorCacheMap.put(RuleType.number_format, numberFormatValidator);
		commonValidatorCacheMap.put(RuleType.date_format, dateFormatValidator);
		
		commonValidatorCacheMap.put(RuleType.string_length_limit, stringLimitLengthValidator);
		
		commonValidatorCacheMap.put(RuleType.number_value_limit, numberLimitValidator);
		commonValidatorCacheMap.put(RuleType.number_value_mod, numberModValidator);
		
		commonValidatorCacheMap.put(RuleType.number_compare_refer, numberReferCompareValidator);
		commonValidatorCacheMap.put(RuleType.date_compare_refer, dateReferCompareValidator);
		commonValidatorCacheMap.put(RuleType.date_compare_now, dateCompareNowValidator);
		
		commonValidatorCacheMap.put(RuleType.values_collection_limit, valuesLimitValidator);
		
	}

	public static IValidator getCommonValidator(RuleType ruleName) {
		return commonValidatorCacheMap.get(ruleName);
	}
	
	/**
	 * 返回本地自定义的验证器
	 */
	public static IValidator getLocalValidator(String name){
		return localValidatorCacheMap.get(name);
	}

	/** 注册自定义验证器
	 */
	public static void registerLocalValidator(String name,IValidator validator){
		localValidatorCacheMap.putIfAbsent(name, validator);
	}
}

1
0
分享到:
评论

相关推荐

    自定义校验注解框架(validator)

    综上所述,自定义校验注解框架"monkey-validator"可能包括了上述步骤的实现,提供了方便快捷的方式来创建和管理项目特定的参数校验规则。通过学习和使用这个框架,开发者可以更好地理解Java的注解机制以及如何构建...

    基于Annotation写的简单数据校验框架

    在工作中,我看到JavaEE6中提供了一个基于注解的Bean校验框架,另外Hibernate也提供了类似功能的基于java注解的校验,我们产品也需要这种功能,无奈用的是JavaEE5,因此我自己写了一个简单的基于注解的校验框架,...

    注解+AOP优雅的实现java项目的接口参数校验(含源码)

    基于Spring boot + maven,以注解+AOP方式实现的java后端项目接口参数校验框架。迄今为止使用最简单、最容易理解的参数校验方案。博客地址:https://blog.csdn.net/weixin_42686388/article/details/104009771

    ssm基于注解的项目搭建

    在“ssm基于注解的项目搭建”中,我们主要会涉及到以下几个关键知识点: 1. **Spring框架**:Spring是Java企业级应用的核心框架,它提供了依赖注入(DI)和面向切面编程(AOP)等功能,通过管理对象的生命周期和...

    MyBatis基于注解简单案例

    在这个基于注解的简单案例中,我们将深入探讨如何使用MyBatis进行基本的数据操作:增加、删除、修改和查询。 首先,我们需要在项目中引入MyBatis的依赖库。通常,这可以通过Maven或Gradle的配置来完成。在Maven的...

    mybatis-demo12-动态SQL语句2-基于注解配置.zip

    本项目“mybatis-demo12-动态SQL语句2-基于注解配置”是针对MyBatis动态SQL功能的一个示例,主要探讨如何通过注解方式来实现动态SQL。 1. **动态SQL**: 动态SQL是MyBatis的核心特性之一,它允许我们在运行时根据...

    基于注解的Spring JdbcTemplate

    **基于注解的Spring JdbcTemplate** 在Java世界中,Spring框架是企业级应用开发的首选。Spring JDBC模絫提供了一种简洁的方式来处理数据库操作,而`Spring JdbcTemplate`是这个模絫的核心组件。本教程将深入探讨...

    基于注解的spring3+hibernate3的springMVC框架

    本项目基于注解的实现方式,使得配置更为简洁,同时也展现了现代Java开发的便利性。以下将详细讲解这三个框架及其注解的使用。 **Spring 3.x** Spring是一个全面的后端开发框架,它提供了依赖注入(DI)、面向切面...

    基于注解的 java 加签验.zip

    在Java编程中,基于注解(Annotation)的加签验是一种常见的代码管理和验证技术,它允许程序员通过在源代码中添加元数据来实现特定的功能或逻辑。这些注解可以用于各种目的,包括但不限于数据验证、依赖注入、编译时...

    基于注解的springmvc进行form表单操作

    在Spring MVC框架中,基于注解的编程方式极大地简化了Web应用的开发,尤其是在处理HTTP请求,如form表单提交时。本篇文章将深入探讨如何使用注解来实现在Spring MVC中处理form表单的数据,以及如何将这些数据保存到...

    数据校验框架在hybris中的使用

    Hybris的验证框架是基于JSR 303(Java Bean Validation)标准,允许开发者直接在模型的字段上添加注解来进行数据校验。这使得数据校验的实现更加简洁且易于理解。 2.1. Hybris验证框架特性 - 自动校验:在Hybris中...

    Java密码学API注解及模板生成框架.pdf

    该框架能够根据用户参数和应用场景的模板自动生成加解密代码,同时对开发者代码进行校验,在编译阶段发现并报出错误。这样可以确保开发者正确地使用密码学 API,减少安全漏洞的出现。 除了 SecureCrypto 框架外,...

    基于注解的 SpringMVC 简单介绍

    基于注解的SpringMVC是Spring框架中的一个关键模块,用于构建Web应用程序。SpringMVC以其松耦合、模块化和高度可配置性而受到广大开发者的欢迎。在这个框架中,注解扮演着核心角色,使得开发者无需编写大量的XML配置...

    基于注解的spring+hibernate+struts2源码.rar

    本资料将详细解析这三个框架的整合,并重点探讨基于注解的配置方式。 一、Spring框架 Spring的核心特性是依赖注入(DI),它通过控制反转(IoC)实现了对象之间的解耦。在基于注解的配置中,我们可以使用`@...

    hibernate验证框架学习

    ### hibernate验证框架学习 #### 一、简介与入门 **Hibernate Validator** 是一个流行的 Java 验证框架,它实现了 **JSR 349**(即 Java Bean Validation API)规范,提供了强大的验证功能,帮助开发者确保应用...

    Java后台验证框架

    本文将详细介绍一种基于Java的后台验证框架设计思路及其应用场景,旨在为开发者提供一种高效、可扩展且易于使用的验证方案。 #### 二、应用场景 在实际开发过程中,特别是在action或facade层,我们需要实现统一的...

    (SSM框架)memcached整合Spring基于Cache注解.

    同时,通过`&lt;cache:annotation-driven&gt;`标签启用基于注解的缓存处理。 7. **MyBatis与Memcached结合**: 虽然MyBatis本身不支持缓存,但可以通过Spring的缓存抽象层与Memcached进行整合。在MyBatis的Mapper接口...

    基于注解的Spring mvc增删改DEMO

    在本文中,我们将深入探讨基于注解的Spring MVC在实现增删改操作中的应用。Spring MVC是Spring框架的一部分,主要用于构建Web应用程序。它利用注解简化了开发过程,使得开发者无需编写大量的XML配置文件,就能实现...

    java源码:Java对象验证框架 OVal.zip

    在实际开发中,OVal常用于表单验证、API参数校验、业务对象验证等场景,帮助提升代码质量和用户体验。 总结,Java对象验证框架OVal以其便捷的注解使用、强大的自定义能力、灵活的验证策略和良好的扩展性,成为Java...

    基于注解的aop的小DEMO

    本小DEMO将演示如何在Spring MVC环境中集成并使用基于注解的AOP。 首先,我们来理解AOP的核心概念。AOP的目标是将那些影响多个类的代码(如日志、事务管理、性能监控等)抽取出来,形成独立的模块,称为切面。切点...

Global site tag (gtag.js) - Google Analytics