| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -568,6 +568,8 @@ public void onTableArrayParse(String key, JSONArray value) throws Exception { | |||
| 568 | 568 | int maxUpdateCount = parser.getMaxUpdateCount(); | |
| 569 | 569 | ||
| 570 | 570 | String idKey = parser.createSQLConfig().getIdKey(); //Table[]: [{}] arrayConfig 为 null | |
| 571 | + boolean isNeedVerifyContent = parser.isNeedVerifyContent(); | ||
| 572 | + | ||
| 571 | 573 | for (int i = 0; i < valueArray.size(); i++) { //只要有一条失败,则抛出异常,全部失败 | |
| 572 | 574 | //TODO 改成一条多 VALUES 的 SQL 性能更高,报错也更会更好处理,更人性化 | |
| 573 | 575 | JSONObject item; | |
@@ -580,13 +582,13 @@ public void onTableArrayParse(String key, JSONArray value) throws Exception { | |||
| 580 | 582 | JSONRequest req = new JSONRequest(childKey, item); | |
| 581 | 583 | ||
| 582 | 584 | //parser.getMaxSQLCount() ? 可能恶意调用接口,把数据库拖死 | |
| 583 | - JSONObject result = (JSONObject) onChildParse(0, "" + i, parser.parseCorrectRequest(method, childKey, version, "", req, maxUpdateCount, parser)); | ||
| 585 | + JSONObject result = (JSONObject) onChildParse(0, "" + i, isNeedVerifyContent == false ? req : parser.parseCorrectRequest(method, childKey, version, "", req, maxUpdateCount, parser)); | ||
| 584 | 586 | result = result.getJSONObject(childKey); | |
| 585 | 587 | // | |
| 586 | 588 | boolean success = JSONResponse.isSuccess(result); | |
| 587 | 589 | int count = result == null ? null : result.getIntValue(JSONResponse.KEY_COUNT); | |
| 588 | 590 | ||
| 589 | - if (success == false || count != 1) { //如果 code = 200 但 count != 1,不能算成功,掩盖了错误为不好排查问题 | ||
| 591 | + if (success == false || count != 1) { //如果 code = 200 但 count != 1,不能算成功,掩盖了错误不好排查问题 | ||
| 590 | 592 | throw new ServerException("批量新增/修改失败!" + key + "/" + i + ":" + (success ? "成功但 count != 1 !" : (result == null ? "null" : result.getString(JSONResponse.KEY_MSG)))); | |
| 591 | 593 | } | |
| 592 | 594 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,12 +14,15 @@ | |||
| 14 | 14 | import java.sql.Savepoint; | |
| 15 | 15 | import java.util.ArrayList; | |
| 16 | 16 | import java.util.Arrays; | |
| 17 | + import java.util.Comparator; | ||
| 17 | 18 | import java.util.HashMap; | |
| 18 | 19 | import java.util.LinkedHashSet; | |
| 19 | 20 | import java.util.List; | |
| 20 | 21 | import java.util.Map; | |
| 21 | 22 | import java.util.Map.Entry; | |
| 22 | 23 | import java.util.Set; | |
| 24 | + import java.util.SortedMap; | ||
| 25 | + import java.util.TreeMap; | ||
| 23 | 26 | import java.util.concurrent.TimeoutException; | |
| 24 | 27 | ||
| 25 | 28 | import javax.activation.UnsupportedDataTypeException; | |
@@ -472,7 +475,7 @@ public JSONObject parseCorrectRequest(RequestMethod method, String tag, int vers | |||
| 472 | 475 | JSONObject object = null; | |
| 473 | 476 | String error = ""; | |
| 474 | 477 | try { | |
| 475 | - object = getStructure("Request", JSONRequest.KEY_TAG, tag, version); | ||
| 478 | + object = getStructure("Request", method.name(), tag, version); | ||
| 476 | 479 | } catch (Exception e) { | |
| 477 | 480 | error = e.getMessage(); | |
| 478 | 481 | } | |
@@ -665,34 +668,91 @@ public JSONObject parseCorrectResponse(String table, JSONObject response) throws | |||
| 665 | 668 | ||
| 666 | 669 | /**获取Request或Response内指定JSON结构 | |
| 667 | 670 | * @param table | |
| 668 | - * @param key | ||
| 669 | - * @param value | ||
| 671 | + * @param method | ||
| 672 | + * @param tag | ||
| 670 | 673 | * @param version | |
| 671 | 674 | * @return | |
| 672 | 675 | * @throws Exception | |
| 673 | 676 | */ | |
| 674 | 677 | @Override | |
| 675 | - public JSONObject getStructure(@NotNull String table, String key, String value, int version) throws Exception { | ||
| 676 | - //获取指定的JSON结构 <<<<<<<<<<<<<< | ||
| 677 | - SQLConfig config = createSQLConfig().setMethod(GET).setTable(table); | ||
| 678 | - config.setPrepared(false); | ||
| 679 | - config.setColumn(Arrays.asList("structure")); | ||
| 680 | - | ||
| 681 | - Map<String, Object> where = new HashMap<String, Object>(); | ||
| 682 | - where.put("method", requestMethod.name()); | ||
| 683 | - if (key != null) { | ||
| 684 | - where.put(key, value); | ||
| 685 | - } | ||
| 686 | - if (version > 0) { | ||
| 687 | - where.put(JSONRequest.KEY_VERSION + "{}", ">=" + version); | ||
| 688 | - } | ||
| 689 | - config.setWhere(where); | ||
| 690 | - config.setOrder(JSONRequest.KEY_VERSION + (version > 0 ? "+" : "-")); | ||
| 691 | - config.setCount(1); | ||
| 692 | - | ||
| 693 | - //too many connections error: 不try-catch,可以让客户端看到是服务器内部异常 | ||
| 694 | - JSONObject result = getSQLExecutor().execute(config, false); | ||
| 695 | - return getJSONObject(result, "structure");//解决返回值套了一层 "structure":{} | ||
| 678 | + public JSONObject getStructure(@NotNull String table, String method, String tag, int version) throws Exception { | ||
| 679 | + // TODO 目前只使用 Request 而不使用 Response,所以这里写死用 REQUEST_MAP,以后可能 Response 表也会与 Request 表合并,用字段来区分 | ||
| 680 | + String cacheKey = AbstractVerifier.getCacheKeyForRequest(method, tag); | ||
| 681 | + SortedMap<Integer, JSONObject> versionedMap = AbstractVerifier.REQUEST_MAP.get(cacheKey); | ||
| 682 | + | ||
| 683 | + JSONObject result = versionedMap == null ? null : versionedMap.get(Integer.valueOf(version)); | ||
| 684 | + if (result == null) { // version <= 0 时使用最新,version > 0 时使用 > version 的最接近版本(最小版本) | ||
| 685 | + Set<Entry<Integer, JSONObject>> set = versionedMap == null ? null : versionedMap.entrySet(); | ||
| 686 | + | ||
| 687 | + if (set != null && set.isEmpty() == false) { | ||
| 688 | + Entry<Integer, JSONObject> maxEntry = null; | ||
| 689 | + | ||
| 690 | + for (Entry<Integer, JSONObject> entry : set) { | ||
| 691 | + if (entry == null || entry.getKey() == null || entry.getValue() == null) { | ||
| 692 | + continue; | ||
| 693 | + } | ||
| 694 | + | ||
| 695 | + if (version <= 0 || version == entry.getKey()) { // 这里应该不会出现相等,因为上面 versionedMap.get(Integer.valueOf(version)) | ||
| 696 | + maxEntry = entry; | ||
| 697 | + break; | ||
| 698 | + } | ||
| 699 | + | ||
| 700 | + if (entry.getKey() < version) { | ||
| 701 | + break; | ||
| 702 | + } | ||
| 703 | + | ||
| 704 | + maxEntry = entry; | ||
| 705 | + } | ||
| 706 | + | ||
| 707 | + result = maxEntry == null ? null : maxEntry.getValue(); | ||
| 708 | + } | ||
| 709 | + | ||
| 710 | + if (result != null) { // 加快下次查询,查到值的话组合情况其实是有限的,不属于恶意请求 | ||
| 711 | + if (versionedMap == null) { | ||
| 712 | + versionedMap = new TreeMap<>(new Comparator<Integer>() { | ||
| 713 | + | ||
| 714 | + @Override | ||
| 715 | + public int compare(Integer o1, Integer o2) { | ||
| 716 | + return o2 == null ? -1 : o2.compareTo(o1); // 降序 | ||
| 717 | + } | ||
| 718 | + }); | ||
| 719 | + } | ||
| 720 | + | ||
| 721 | + versionedMap.put(Integer.valueOf(version), result); | ||
| 722 | + AbstractVerifier.REQUEST_MAP.put(cacheKey, versionedMap); | ||
| 723 | + } | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + if (result == null) { | ||
| 727 | + if (AbstractVerifier.REQUEST_MAP.isEmpty() == false) { | ||
| 728 | + return null; // 已使用 REQUEST_MAP 缓存全部,但没查到 | ||
| 729 | + } | ||
| 730 | + | ||
| 731 | + //获取指定的JSON结构 <<<<<<<<<<<<<< | ||
| 732 | + SQLConfig config = createSQLConfig().setMethod(GET).setTable(table); | ||
| 733 | + config.setPrepared(false); | ||
| 734 | + config.setColumn(Arrays.asList("structure")); | ||
| 735 | + | ||
| 736 | + Map<String, Object> where = new HashMap<String, Object>(); | ||
| 737 | + where.put("method", method); | ||
| 738 | + where.put(JSONRequest.KEY_TAG, tag); | ||
| 739 | + | ||
| 740 | + if (version > 0) { | ||
| 741 | + where.put(JSONRequest.KEY_VERSION + "{}", ">=" + version); | ||
| 742 | + } | ||
| 743 | + config.setWhere(where); | ||
| 744 | + config.setOrder(JSONRequest.KEY_VERSION + (version > 0 ? "+" : "-")); | ||
| 745 | + config.setCount(1); | ||
| 746 | + | ||
| 747 | + //too many connections error: 不try-catch,可以让客户端看到是服务器内部异常 | ||
| 748 | + result = getSQLExecutor().execute(config, false); | ||
| 749 | + | ||
| 750 | + // version, method, tag 组合情况太多了,JDK 里又没有 LRUCache,所以要么启动时一次性缓存全部后面只用缓存,要么每次都查数据库 | ||
| 751 | + // versionedMap.put(Integer.valueOf(version), result); | ||
| 752 | + // AbstractVerifier.REQUEST_MAP.put(cacheKey, versionedMap); | ||
| 753 | + } | ||
| 754 | + | ||
| 755 | + return getJSONObject(result, "structure"); //解决返回值套了一层 "structure":{} | ||
| 696 | 756 | } | |
| 697 | 757 | ||
| 698 | 758 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,11 +34,13 @@ | |||
| 34 | 34 | import java.util.Collection; | |
| 35 | 35 | import java.util.HashMap; | |
| 36 | 36 | import java.util.HashSet; | |
| 37 | + import java.util.LinkedHashMap; | ||
| 37 | 38 | import java.util.LinkedHashSet; | |
| 38 | 39 | import java.util.List; | |
| 39 | 40 | import java.util.Map; | |
| 40 | 41 | import java.util.Map.Entry; | |
| 41 | 42 | import java.util.Set; | |
| 43 | + import java.util.SortedMap; | ||
| 42 | 44 | import java.util.regex.Pattern; | |
| 43 | 45 | ||
| 44 | 46 | import javax.activation.UnsupportedDataTypeException; | |
@@ -83,9 +85,17 @@ public abstract class AbstractVerifier<T> implements Verifier<T>, IdCallback { | |||
| 83 | 85 | ||
| 84 | 86 | // <TableName, <METHOD, allowRoles>> | |
| 85 | 87 | // <User, <GET, [OWNER, ADMIN]>> | |
| 88 | + @NotNull | ||
| 86 | 89 | public static final Map<String, Map<RequestMethod, RequestRole[]>> SYSTEM_ACCESS_MAP; | |
| 90 | + @NotNull | ||
| 87 | 91 | public static final Map<String, Map<RequestMethod, RequestRole[]>> ACCESS_MAP; | |
| 92 | + | ||
| 93 | + // <method tag, <version, Request>> | ||
| 94 | + // <PUT Comment, <1, { "method":"PUT", "tag":"Comment", "structure":{ "MUST":"id"... }... }>> | ||
| 95 | + @NotNull | ||
| 96 | + public static final Map<String, SortedMap<Integer, JSONObject>> REQUEST_MAP; | ||
| 88 | 97 | ||
| 98 | + @NotNull | ||
| 89 | 99 | public static final Map<String, Pattern> COMPILE_MAP; | |
| 90 | 100 | static { | |
| 91 | 101 | SYSTEM_ACCESS_MAP = new HashMap<String, Map<RequestMethod, RequestRole[]>>(); | |
@@ -110,6 +120,8 @@ public abstract class AbstractVerifier<T> implements Verifier<T>, IdCallback { | |||
| 110 | 120 | } | |
| 111 | 121 | ||
| 112 | 122 | ACCESS_MAP = new HashMap<>(SYSTEM_ACCESS_MAP); | |
| 123 | + | ||
| 124 | + REQUEST_MAP = new HashMap<>(ACCESS_MAP.size()*6); // 单个与批量增删改 | ||
| 113 | 125 | ||
| 114 | 126 | COMPILE_MAP = new HashMap<String, Pattern>(); | |
| 115 | 127 | } | |
@@ -689,7 +701,7 @@ public static JSONObject verifyResponse(@NotNull final RequestMethod method, fin | |||
| 689 | 701 | + "\n response = \n" + JSON.toJSONString(response)); | |
| 690 | 702 | ||
| 691 | 703 | if (target == null || response == null) {// || target.isEmpty() { | |
| 692 | - Log.i(TAG, "verifyRequest target == null || response == null >> return response;"); | ||
| 704 | + Log.i(TAG, "verifyResponse target == null || response == null >> return response;"); | ||
| 693 | 705 | return response; | |
| 694 | 706 | } | |
| 695 | 707 | ||
@@ -1424,5 +1436,9 @@ public static void verifyRepeat(String table, String key, Object value, long exc | |||
| 1424 | 1436 | } | |
| 1425 | 1437 | } | |
| 1426 | 1438 | ||
| 1439 | + public static String getCacheKeyForRequest(String method, String tag) { | ||
| 1440 | + return method + " " + tag; | ||
| 1441 | + } | ||
| 1442 | + | ||
| 1427 | 1443 | ||
| 1428 | 1444 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -74,7 +74,7 @@ JSONObject parseCorrectRequest(RequestMethod method, String tag, int version, St | |||
| 74 | 74 | ||
| 75 | 75 | JSONObject parseCorrectResponse(String table, JSONObject response) throws Exception; | |
| 76 | 76 | ||
| 77 | - JSONObject getStructure(String table, String key, String value, int version) throws Exception; | ||
| 77 | + JSONObject getStructure(String table, String method, String tag, int version) throws Exception; | ||
| 78 | 78 | ||
| 79 | 79 | ||
| 80 | 80 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments