1. 程式人生 > >基於註解的引數校驗框架

基於註解的引數校驗框架

近期由於工作的需要,寫了一個簡易的引數校驗框架,雖然市場上有common-validator 和hibernate-validator兩個開源的,但是有些情景他們是無法滿足的,比如引數欄位之間的依賴關係,這在專案中是極其常見的。他們僅僅提供了對欄位的簡單的格式校驗。另外這兩種校驗框架的校驗器都是有狀態的,這樣導致校驗的效能不好,對於錄入還無所謂,但是批量excel 匯入的這種,就非常吃力了。

出於效能和依賴關係校驗的需求,改造下工作的校驗框架為一個通用的引數校驗框架,支援表示式的格式校驗,靈活性極好,程式碼完全複用,思路明瞭,適合複雜的引數校驗場景,希望各位給予指正其中的不足~

下面我貼出來了我寫的框架的程式碼,但是太麻煩搞格式,我也懶的搞,如果有興趣,可以下載原始碼看看~

git地址為:[url]https://github.com/wangxinchun/javaframe-validator[/url]
先看下這個框架的用法:

/**
* 驗證要求:
* 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 [email protected] <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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @date 2013-12-1下午1:03:53
*/
public interface ConditionGroup {

/**
* 邏輯校驗方法
* @param params
* @return
*/
public ValidateResult executeCondition(Map<String, String> params);

}

/**
* 原子校驗組
* 一個原子校驗組擁有一個校驗器
* @author [email protected]
* @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 [email protected]
* @date 2013-12-1下午1:06:08
*/
public abstract class ConditionGroupAdapter implements ConditionGroup {
protected List<ConditionGroup> list;

}
/**
* 邏輯組校驗AND型別的整合介面卡
* @author [email protected]
* @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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @date 2013-12-1下午1:03:53
*/
public interface LogicGroup {

/**
* 邏輯校驗方法
* @param params
* @return
*/
public LogicValidateResult executeLogic(Map<String, String> params);

}
/**
* 邏輯原子校驗組
* 一個原子校驗組對應一個邏輯校驗規則
* @author [email protected]
* @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 [email protected]
* @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 [email protected]
* @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 [email protected]
* @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);
}
}

相關推薦

基於註解引數框架

近期由於工作的需要,寫了一個簡易的引數校驗框架,雖然市場上有common-validator 和hibernate-validator兩個開源的,但是有些情景他們是無法滿足的,比如引數欄位之間的依賴關係,這在專案中是極其常見的。他們僅僅提供了對欄位的簡單的格式校驗。另外這兩種

【hibernate-validator+SpringMVC】後臺引數框架

hibernate-validator+SpringMVC簡介:簡單說,就是對Entity進行校驗。1、導包,沒有很嚴謹的對應關係,所以我用了比較新的版本,支援更多的註解。  <dependency> <groupId&

學習LayUI時自研的表單引數框架

開發背景&痛點:每次寫前端的表單的時候需要對錶單裡使用者填寫的內容進行校驗,減少伺服器壓力,提前對已知錯誤對使用者提示。每次會要寫很多的if else等等對輸入框中的內容進行判斷,並對為空、格式不正確等情況作出對應提示。需要寫大量重複的if else語句,實在太麻煩,所以自己寫了這個框架用於前端引數的

Spring下基於註解引數

        前段時間,為了校驗介面資料方便,實現了一個簡易的引數校驗功能。通過引數上加註解並且配置spring aop實現的。大概配置如下:public Object ArroundParamCheck(ProceedingJoinPoint pj) throws Thr

自己寫的基於java Annotation(註解)的資料框架

原始碼和UT請見http://download.csdn.net/source/2640884 JavaEE6中提供了基於java Annotation(註解)的Bean校驗框架,Hibernate也有類似的基於Annotation的資料校驗功能,我在工作中,產品也經常需要

手把手寫一個基於Spring Boot框架下的引數元件(JSR-303)

前言           之前參與的新開放平臺研發的過程中,由於不同的介面需要對不同的入參進行校驗,這就涉及到通用引數的校驗封裝,如果不進行封裝,那麼寫出來的校驗程式碼將會風格不統一、校驗工具類不一致、維護風險高等其它因素,於是我對其公共的校驗做了一個封裝,達到了通過註解的方式即可實現引數統一校驗。 遇到的問

SpringMVC自定義註解進行引數

在我的另一篇部落格中(SpringMVC),學習瞭如何使用Spring MVC結合Hibernate的校驗框架validation(它和hibernate沒有任何關係)對引數進行校驗。在實際專案中,引數的校驗邏輯可能比較複雜,這時我們可以自定義註解來實現引數校驗,下面是一個簡單的例子。 po

SpringMVC自定義註解進行引數(以列舉值是否合法為例)

pom引入springMVC依賴,以springboot專案為例 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-

自定義註解完成引數

在現在的專案開發中,經常會用到註解,比如Spring的@Autowired,SpringMVC的@Controller,@RequestMapping等等,大部分人只知道用,不知道這些註解的怎麼發揮作用。有沒有想過手動寫一個註解,完成引數校驗呢? 簡介 註解(

spring註解引數

一般入參我們都會轉為vo物件。那麼直接在物件的屬性上註解即可。 其實spring用的是hibernate的validator. 步驟 1.配置spring.xml <mvc:annotation-driven /> 2.配置

java註解方式引數

1、註解類NotEmpty.java空值校驗 package com.cmbc.umm.core.common.annotation; import java.lang.annotation.Documented; import java.lang.an

springmvc_引數自定義註解

呼叫的例子 @PostMapping("/create") public void create(@RequestBody @Valid ProductSerCreateInput productSerCreateInput, Errors errors) { Api

Spring -- 通過攔截器使用註解方式引數

public class OpenHandlerInterceptor extends HandlerInterceptorAdapter { private static final Logger LOGGER = Logger.getLogger(OpenHandlerInterceptor.c

更加靈活的引數,Spring-boot自定義引數註解

上文[測試開發專題:如何在spring-boot中進行引數校驗](https://www.immortalp.com/articles/2020/05/15/1589509696197.html),我們討論瞭如何使用@Min、@Max等註解進行引數校驗,主要是針對基本資料型別和級聯物件進行引數校驗的演示,但是

Spring Validation-用註解代替程式碼引數

# Spring Validation ## 概念 在原先的編碼中,我們如果要驗證前端傳遞的引數,一般是在接受到傳遞過來的引數後,手動在程式碼中做 if-else 判斷,這種編碼方式會帶來大量冗餘程式碼,十分的不優雅。 因此,推出了用註解的方式,來代替手動判斷的方式,讓編碼更加的簡潔。 ## 使用方式

Java自定義註解反射數據

sda new out 格式 是否 本地 imp 使用範圍 數據類型 package com.annotations.ecargo; import java.lang.annotation.ElementType; import java.lang.annotati

hibernate的框架validation 和 HttpMessageConverter的配置方式

hibernate的校驗框架validation 和 httpmessageconverter的配置方式hibernate的校驗框架validation 和 HttpMessageConverter的配置方式好像是2個不相幹的配置內容,但他們都用到了<mvc:annotation-driven />

SpringMVC中的 JSR 303 數據框架說明

bind 工作 電子 支持 length spring容器 error digits 獲取 JSR 303 是java為Bean數據合法性校驗提供的標準框架,它已經包含在JavaEE 6.0中。 JSR 303 通過在Bean屬性上標註類似於@NotNull、@Max等標

struts2框架中各個驗證器param的值

修改字段 上下文 tor ali 字段名 參數 int r語 多個 struts2校驗框架中各個驗證器param的值 1.required:必填校驗器 fieldName:字段名,如果使用簡單驗證器語法,則字段名稱,如果使用字段驗證器語法不需要 2.required

類Shiro權限框架的設計和實現(2)--對復雜權限表達式的支持

treemap evel 註冊 st3 builder row blog array www. 前言:   我看了下shiro好像默認不支持復雜表達式的權限校驗, 它需要開發者自己去做些功能擴展的工作. 針對這個問題, 同時也會為了彌補上一篇文章提到的支持復雜表示需求,