Map数据验证
背景: 当用Map list 嵌套为数据配置时,存在一个数据验证问题。本文原创,没有深度测试
代码:
import com.fyh.utils.mapt.Mapt; import java.util.*; import java.util.stream.Collectors; public class BValidt { private String nameSpace; private String separator = "\\."; private boolean friendsKeyBL = false; /** * 对由List,map进行嵌套的对象进行数据检验,本质是他们与json相对应。 * * @param ds * @param std * @return code =1,成功; code =0,失败 */ public Map<String, Object> validByPath(Object ds, Map<String, String> std, boolean isStdValid) { Map<String, Object> rst = new LinkedHashMap<>(); rst.put("code", 1); if (std == null) { return rst; } else if (std != null && ds == null) { rst.put("code", 0); return rst; } Map<String, String> resultMap = new LinkedHashMap<>(); rst.put("result", resultMap); Map<String, String> ruleMap = null; if (isStdValid) { ruleMap = new LinkedHashMap<>(); for (Map.Entry<String, String> kv : std.entrySet()) { String ruleStr = kv.getKey().trim(); Map<String, String> tmpPathMap = getPaths(ds, ruleStr); for (String tmpstr : tmpPathMap.keySet()) { ruleMap.put(tmpstr, kv.getValue()); } } } else { ruleMap = std; } for (Map.Entry<String, String> kv : ruleMap.entrySet()) { Object dsObj = Mapt.get(ds, kv.getKey()); String ruleStr = kv.getKey().trim(); Entity rstEntity = doValid(dsObj, kv.getValue()); resultMap = doReturn(resultMap, ruleStr, rstEntity); } resultMap=resultMap.entrySet().stream() .sorted( Map.Entry.comparingByKey()) .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new ) ); return rst; } private Map<String, String> getPaths(Object ds, String ruleStr) { Map<String, String> pathMap = new LinkedHashMap<>();//只存储对数组计算的规则的路径 if (ds == null || ruleStr == null) return pathMap; if (friendsKeyBL) { ruleStr = ruleStr.replaceAll("(?<=[A-Z|a-z|0-9|\\]])(\\[)", ".["); } String[] strs = ruleStr.split(separator); String prePath = ""; for (String str : strs) { if (str.substring(0, 1).equals("[")) { pathMap.put(prePath, "0"); List tmpList = null; if (prePath.equals("") && List.class.isAssignableFrom(ds.getClass())) { tmpList = (List) ds; } else { tmpList = Mapt.getList(ds, prePath); } int count = tmpList.size(); Map<String, String> newPathMap = new LinkedHashMap<>(); for (int i = 0; i < count; i++) { for (String k : pathMap.keySet()) { String tmpStr = "[" + Integer.toString(i) + "]"; if (k.equals("")) { newPathMap.put(tmpStr, "0"); } else { newPathMap.put(k + "." + tmpStr, "0"); } } } pathMap = newPathMap; } else if (pathMap.isEmpty()) { prePath = prePath.equals("") ? str : prePath + "." + str; } else { Map<String, String> newPathMap = new LinkedHashMap<>(); for (String k : pathMap.keySet()) { String tmpstr = k.equals("") ? str : k + "." + str; newPathMap.put(tmpstr, "0"); } pathMap = newPathMap; } } if (pathMap.isEmpty()) pathMap.put(ruleStr, "0"); return pathMap; } private Map<String, String> doReturn(Map<String, String> resultMap, String key, Entity rstEntity) { if (rstEntity == null) return resultMap; if (rstEntity.rst && rstEntity.sonRst != null) { resultMap.put(key, rstEntity.sonRst.toString()); } return resultMap; } /** * 对由List,map进行嵌套的对象进行数据检验,本质是他们与json相对应。 * * @param ds 被验证的数据源,由List,map进行嵌套嵌套构 * @param std 由由List,map进行嵌套构成的验证规则 * @return code =1,成功; code =0,失败 */ public Map<String, Object> valid(Object ds, Object std) { Map<String, Object> rst = new LinkedHashMap<>(); rst.put("code", 1); if (std == null) { return rst; } else if (std != null && ds == null) { rst.put("code", 0); return rst; } Queue<Object> stdQueue = new LinkedList<>(); stdQueue.offer(std); Queue<Object> dsQueue = new LinkedList<>(); dsQueue.offer(ds); Queue<Object> rstQueue = new LinkedList<>(); if (List.class.isAssignableFrom(ds.getClass())) { List list = new ArrayList(); rst.put("result", list); rstQueue.offer(list); } else if (Map.class.isAssignableFrom(ds.getClass())) { Map<String, Object> map = new LinkedHashMap<>(); rst.put("result", map); rstQueue.offer(map); } while (!dsQueue.isEmpty()) { Object stdObj = stdQueue.poll(); Object dsObj = dsQueue.poll(); Object rstObj = rstQueue.poll(); if (stdObj == null) break; if (List.class.isAssignableFrom(dsObj.getClass()) && List.class.isAssignableFrom(stdObj.getClass()) ) { List dsList = (List) dsObj; List stdList = (List) stdObj; List rstList = (List) rstObj; Object sunStdObj = stdList.get(0); for (int i = 0; i < dsList.size(); i++) { Object son = dsList.get(i); Entity rstEntity = doValid(son, sunStdObj); //开始验证 if (rstEntity.rst) { if (rstEntity.sonRst != null) { rst.put("code", 0); rstList.add(rstEntity.sonRst); } } else if (List.class.isAssignableFrom(son.getClass())) { List tmpList = new ArrayList<>(); rstList.add(tmpList); dsQueue.offer(son); if (i < stdList.size()) { stdQueue.offer(stdList.get(i)); } else { stdQueue.offer(stdList.get(0)); } rstQueue.offer(tmpList); } else if (Map.class.isAssignableFrom(son.getClass())) { Map<String, Object> tmpMap = new LinkedHashMap<>(); rstList.add(tmpMap); dsQueue.offer(son); if (i < stdList.size()) { stdQueue.offer(stdList.get(i)); } else { stdQueue.offer(stdList.get(0)); } rstQueue.offer(tmpMap); } } } else if (Map.class.isAssignableFrom(dsObj.getClass()) && Map.class.isAssignableFrom(stdObj.getClass()) ) { Map<String, Object> dsMap = (Map<String, Object>) dsObj; Map<String, Object> stdMap = (Map<String, Object>) stdObj; Map<String, Object> rstMap = (Map<String, Object>) rstObj; for (Map.Entry<String, Object> en1 : dsMap.entrySet()) { Object son = en1.getValue(); Object sunStdObj = stdMap.get(en1.getKey()); Entity rstEntity = doValid(son, sunStdObj);//开始验证 if (rstEntity.rst) { if (rstEntity.sonRst != null) { rst.put("code", 0); rstMap.put(en1.getKey(), rstEntity.sonRst); } } else if (List.class.isAssignableFrom(son.getClass())) { List tmpList = new ArrayList<>(); rstMap.put(en1.getKey(), tmpList); dsQueue.offer(son); stdQueue.offer(stdMap.get(en1.getKey())); rstQueue.offer(tmpList); } else if (Map.class.isAssignableFrom(son.getClass())) { Map<String, Object> tmpMap = new LinkedHashMap<>(); rstMap.put(en1.getKey(), tmpMap); dsQueue.offer(son); stdQueue.offer(stdMap.get(en1.getKey())); rstQueue.offer(tmpMap); } } } } return rst; } /** * @param son * @param sonStdObj * @return Entity.rst 为false-没到底,需要进步处理,true--已经到底并检验了 */ private Entity doValid(Object son, Object sonStdObj) { Entity rst = new Entity(son, sonStdObj); if (son == null || sonStdObj == null) { rst.rst = true; return rst; } if (String.class.isAssignableFrom(sonStdObj.getClass())) { rst.rst = true; // "aa;dd;xx;;;yy".split(";(?!;)") 分割符为分号,如果有连续分号,只有最后一个分号会分割 String[] strs = sonStdObj.toString().split(";(?!;)"); String[] params = Arrays.copyOfRange(strs, 1, strs.length - 1); int lastIndex = strs.length - 1; if (strs[0].toLowerCase().equals("type") && strs[1] == null) { rst.sonRst = "验证类型出错"; if (rst.sonRst != null) rst.sonRst = rst.sonRst + ". 原值为:" + son.toString(); } else if (strs[0].toLowerCase().equals("type") && strs[1] != null) { strs[1] = strs[1].trim(); try { if (!strs[1].contains("java.lang") && ( strs[1].equals("String") || strs[1].equals("Integer") || strs[1].equals("Boolean") || strs[1].equals("String") || strs[1].equals("Double") || strs[1].equals("Long") || strs[1].equals("String") ) ) { strs[1] = "java.lang." + strs[1]; } if (strs[1].equals("Date")) { strs[1] = "java.util.Date"; } if (this.nameSpace != null && !strs[1].contains(".")) { strs[1] = this.nameSpace + "." + strs[1]; } Class cls = Class.forName(strs[1]); if (cls.isAssignableFrom(son.getClass())) { return rst; } else { rst.sonRst = strs[2] != null ? strs[2] : "不是指定类型"; if (rst.sonRst != null) rst.sonRst = rst.sonRst + ". 原值为:" + son.toString(); } } catch (ClassNotFoundException e) { rst.sonRst = strs[2] != null ? strs[2] : "验证类型出错"; if (rst.sonRst != null) rst.sonRst = rst.sonRst + ". 原值为:" + son.toString(); return rst; } } if (Validt.valid(strs[0], son.toString(), params)) { return rst; } else { rst.sonRst = strs[lastIndex] != null ? strs[lastIndex] : "验证" + strs[0] + "出错"; if (rst.sonRst != null) rst.sonRst = rst.sonRst + ". 原值为:" + son.toString(); return rst; } } return rst; } public String getNameSpace() { return nameSpace; } public void setNameSpace(String nameSpace) { this.nameSpace = nameSpace; } class Entity { protected boolean rst = false; protected Object son; protected Object sonRst; protected Object sonStdObj; public Entity() { } public Entity(Object son, Object sonStdObj) { this.son = son; this.sonStdObj = sonStdObj; } public boolean isRst() { return rst; } public void setRst(boolean rst) { this.rst = rst; } public Object getSon() { return son; } public void setSon(Object son) { this.son = son; } public Object getSonStdObj() { return sonStdObj; } public void setSonStdObj(Object sonStdObj) { this.sonStdObj = sonStdObj; } public Object getSonRst() { return sonRst; } public void setSonRst(Object sonRst) { this.sonRst = sonRst; } } }
测试与使用
1 import com.fyh.utils.JackJsonUtils; 2 import org.junit.jupiter.api.Test; 3 4 import java.util.*; 5 6 import static org.junit.jupiter.api.Assertions.*; 7 8 class BValidtTest { 9 private BValidt bValidt = new BValidt(); 10 @Test 11 void validByPath(){ 12 Arrays.asList("a", "b", "c").forEach(i->{System.out.println(i);}); 13 Arrays.asList("a", "b", "c").forEach(System.out::println); 14 15 String dsStr = JackJsonUtils.getStdJsonStr("{no:1,name:'a'}"); 16 Map<String, Object> dsMap = JackJsonUtils.fromJson(dsStr, Map.class); 17 18 Map<String,String> ruleMap=new LinkedHashMap<>(); 19 ruleMap.put("no","num;3;不是数或小数位数出错"); 20 ruleMap.put("name","required; 不能为空"); 21 Map<String, Object> rst = bValidt.validByPath(dsMap, ruleMap,true); 22 23 List<Map<String,Object>> dsList=new ArrayList<>() ; 24 Map<String,Object> dsMapA=new LinkedHashMap<>(); 25 dsList.add(dsMapA); 26 dsMapA.put("no","11"); 27 dsMapA.put("name",""); 28 dsMapA=new LinkedHashMap<>(); 29 dsList.add(dsMapA); 30 dsMapA.put("no","22"); 31 dsMapA.put("name",""); 32 33 34 Map<String,String> stdMapA=new LinkedHashMap<>(); 35 stdMapA.put("[0].no","num;3;不是指定类型"); 36 stdMapA.put("[0].name","required;不能为空"); 37 Map<String, Object> rstList = bValidt.validByPath(dsList, stdMapA,true); 38 39 String dsStr1 = JackJsonUtils.getStdJsonStr("" + 40 "{\n" + 41 " items:[\n" + 42 " {\n" + 43 " no:1,\n" + 44 " name:\"wang\", \n" + 45 " son:{" + 46 " xx:12"+ 47 " }"+ 48 " },\n" + 49 " {\n" + 50 " no:'11',\n" + 51 " name:\"wang\",\n" + 52 " son:{" + 53 " xx:55"+ 54 " }"+ 55 " }\n" + 56 " ]\n" + 57 "}" + 58 ""); 59 Map<String, Object> dsMap1 = JackJsonUtils.fromJson(dsStr1, Map.class); 60 61 Map<String,String> ruleMap1=new LinkedHashMap<>(); 62 ruleMap1.put("items.[0].no","num;3;不是数或小数位数出错"); 63 ruleMap1.put("items.[0].son.xx","num;3;不是数或小数位数出错"); 64 ruleMap1.put("items.[0].name","required; 不能为空"); 65 Map<String, Object> rst1 = bValidt.validByPath(dsMap1, ruleMap1,true); 66 67 String dsStr2 = JackJsonUtils.getStdJsonStr("" + 68 "{\n" + 69 " items:[\n" + 70 " {\n" + 71 " no:1,\n" + 72 " name:\"wang\", \n" + 73 " son:[{" + 74 " xx:12"+ 75 " }," + 76 " {" + 77 " xx:13"+ 78 " }] "+ 79 " },\n" + 80 " {\n" + 81 " no:'11',\n" + 82 " name:\"wang\",\n" + 83 " son:[{" + 84 " xx:22"+ 85 " }," + 86 " {" + 87 " xx:23"+ 88 " }] "+ 89 " }\n" + 90 " ]\n" + 91 "}" + 92 ""); 93 Map<String, Object> dsMap2 = JackJsonUtils.fromJson(dsStr2, Map.class); 94 95 Map<String,String> ruleMap2=new LinkedHashMap<>(); 96 ruleMap2.put("items.[0].no","num;3;不是数或小数位数出错"); 97 ruleMap2.put("items.[0].son.[0].xx","num;3;不是数或小数位数出错"); 98 ruleMap2.put("items.[0].name","required; 不能为空"); 99 Map<String, Object> rst2 = bValidt.validByPath(dsMap2, ruleMap2,true); 100 101 System.out.println(); 102 } 103 // @Test 104 void valid() { 105 //展示通过js对象转标准JSON字符串,再转成Map实例 106 String dsStr = JackJsonUtils.getStdJsonStr("{no:1,name:''}"); 107 Map<String, Object> dsMap = JackJsonUtils.fromJson(dsStr, Map.class); 108 109 String stdStr = JackJsonUtils.getStdJsonStr("{\n" + 110 " name:\"required; 不能为空 \",\n" + 111 " no: \"num;3;不是数或小数位数出错\"\n" + 112 "}"); 113 Map<String, Object> stdMap = JackJsonUtils.fromJson(stdStr, Map.class); 114 115 116 Map<String, Object> rst = bValidt.valid(dsMap, stdMap); 117 118 119 String dsStr1 = JackJsonUtils.getStdJsonStr( 120 "" + 121 "{\n" + 122 " items:[\n" + 123 " {\n" + 124 " no:1,\n" + 125 " name:\"wang\", \n" + 126 " },\n" + 127 " {\n" + 128 " no:'11',\n" + 129 " name:\"wang\",\n" + 130 " }\n" + 131 " ]\n" + 132 "}" + 133 ""); 134 Map<String, Object> dsMap1 = JackJsonUtils.fromJson(dsStr1, Map.class); 135 136 String stdStr1 = JackJsonUtils.getStdJsonStr("" + 137 "{\n" + 138 " items:[\n" + 139 " {\n" + 140 " name:\"required; 不能为空 \",\n" + 141 " no: \"num;2;不是数或小数\"\n" + 142 " },\n" + 143 " {\n" + 144 " name:\"required; 不能为空 \",\n" + 145 " no: \"num;不是数或小数\"\n" + 146 " }\n" + 147 " ]\n" + 148 "}" + 149 ""); 150 Map<String, Object> stdMap1 = JackJsonUtils.fromJson(stdStr1, Map.class); 151 Map<String, Object> rst1 = bValidt.valid(dsMap1, stdMap1); 152 153 String dsStr2 = JackJsonUtils.getStdJsonStr( 154 "" + 155 "{\n" + 156 " no:'11',\n" + 157 " name:'name11',\n" + 158 " items:[\n" + 159 " {\n" + 160 " no:1,\n" + 161 " name:\"wang\",\n" + 162 " son:[\n" + 163 " 'dd','ee'\n" + 164 " ],\n" + 165 " },\n" + 166 " {\n" + 167 " no:11,\n" + 168 " name:\"wang\",\n" + 169 " }\n" + 170 " ]\n" + 171 "}" + 172 ""); 173 Map<String, Object> dsMap2 = JackJsonUtils.fromJson(dsStr2, Map.class); 174 175 String stdStr2 = JackJsonUtils.getStdJsonStr("" + 176 "{\n" + 177 " no:'num;3;不是数或小数',\n" + 178 " items:[\n" + 179 " {\n" + 180 " name:\"required; 不能为空 \",\n" + 181 " no: \"num;3;不是数或小数\",\n" + 182 " son:[\n" + 183 " \"num;不是数或小数\"\n" + 184 " ]\n" + 185 " }\n" + 186 " ]\n" + 187 "}" + 188 ""); 189 Map<String, Object> stdMap2 = JackJsonUtils.fromJson(stdStr2, Map.class); 190 Map<String, Object> rst2 = bValidt.valid(dsMap2, stdMap2); 191 192 193 List<Map<String,Object>> dsList=new ArrayList<>() ; 194 Map<String,Object> dsMapA=new LinkedHashMap<>(); 195 dsList.add(dsMapA); 196 dsMapA.put("no","11"); 197 dsMapA.put("name","name11"); 198 dsMapA=new LinkedHashMap<>(); 199 dsList.add(dsMapA); 200 dsMapA.put("no","22"); 201 dsMapA.put("name","name22"); 202 203 List<Map<String,Object>> stdList=new ArrayList<>() ; 204 Map<String,Object> stdMapA=new LinkedHashMap<>(); 205 stdList.add(stdMapA); 206 207 // stdMapA.put("no","num;不是数字"); 208 stdMapA.put("no","type;String;不是指定类型"); 209 stdMapA.put("name","required;不能为空"); 210 Map<String, Object> rst3 = bValidt.valid(dsList, stdList); 211 212 213 System.out.println(); 214 215 } 216 }