Skip to content

Commit 38989bd

Browse files
authored
Merge pull request Tencent#487 from cloudAndMonkey/master
新增、优化相关功能点
2 parents d0550bd + 4af6322 commit 38989bd

File tree

5 files changed

+182
-35
lines changed

5 files changed

+182
-35
lines changed

APIJSONORM/src/main/java/apijson/JSONObject.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ public JSONObject setUserIdIn(List<Object> list) {
173173
TABLE_KEY_LIST.add(KEY_ORDER);
174174
TABLE_KEY_LIST.add(KEY_RAW);
175175
TABLE_KEY_LIST.add(KEY_JSON);
176+
TABLE_KEY_LIST.add(KEY_METHOD);
176177
}
177178

178179
//@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>>

APIJSONORM/src/main/java/apijson/StringUtil.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public static boolean isNotEmpty(String s, boolean trim) {
354354
PATTERN_ALPHA = Pattern.compile("^[a-zA-Z]+$");
355355
PATTERN_ALPHA_BIG = Pattern.compile("^[A-Z]+$");
356356
PATTERN_ALPHA_SMALL = Pattern.compile("^[a-z]+$");
357-
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_:]+$");//已用55个中英字符测试通过
357+
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_.:]+$");//已用55个中英字符测试通过
358358
//newest phone regex expression reference https://github.com/VincentSit/ChinaMobilePhoneNumberRegex
359359
PATTERN_PHONE = Pattern.compile("^1(?:3\\d{3}|5[^4\\D]\\d{2}|8\\d{3}|7(?:[0-35-9]\\d{2}|4(?:0\\d|1[0-2]|9\\d))|9[0-35-9]\\d{2}|6[2567]\\d{2}|4(?:(?:10|4[01])\\d{3}|[68]\\d{4}|[579]\\d{2}))\\d{6}$");
360360
PATTERN_EMAIL = Pattern.compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");

APIJSONORM/src/main/java/apijson/orm/AbstractParser.java

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@
4848
*/
4949
public abstract class AbstractParser<T extends Object> implements Parser<T>, ParserCreator<T>, VerifierCreator<T>, SQLCreator {
5050
protected static final String TAG = "AbstractParser";
51-
protected Map<Object, RequestMethod> keyMethodMap = new HashMap<>();
51+
52+
/**
53+
* json对象、数组对应的数据源、版本、角色、method等
54+
*/
55+
protected Map<Object, Map<String, Object>> keyObjectAttributesMap = new HashMap<>();
5256
/**
5357
* 可以通过切换该变量来控制是否打印关键的接口请求内容。保守起见,该值默认为false。
5458
* 与 {@link Log#DEBUG} 任何一个为 true 都会打印关键的接口请求内容。
@@ -1158,7 +1162,8 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
11581162
}
11591163

11601164
//不能允许GETS,否则会被通过"[]":{"@role":"ADMIN"},"Table":{},"tag":"Table"绕过权限并能批量查询
1161-
if (isSubquery == false && RequestMethod.isGetMethod(requestMethod, true) == false) {
1165+
RequestMethod _method = request.get(apijson.JSONObject.KEY_METHOD) == null ? requestMethod : RequestMethod.valueOf(request.getString(apijson.JSONObject.KEY_METHOD));
1166+
if (isSubquery == false && RequestMethod.isGetMethod(_method, true) == false) {
11621167
throw new UnsupportedOperationException("key[]:{} 只支持 GET, GETS 方法!其它方法不允许传 " + name + ":{} 等这种 key[]:{} 格式!");
11631168
}
11641169
if (request == null || request.isEmpty()) { // jsonKey-jsonValue 条件
@@ -1913,7 +1918,7 @@ public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Except
19131918
JSONObject res = getSQLExecutor().execute(config, false);
19141919

19151920
//如果是查询方法,才能执行explain
1916-
if (RequestMethod.isQueryMethod(config.getMethod())){
1921+
if (RequestMethod.isQueryMethod(config.getMethod()) && config.isElasticsearch() == false){
19171922
config.setExplain(explain);
19181923
JSONObject explainResult = config.isMain() && config.getPosition() != 0 ? null : getSQLExecutor().execute(config, false);
19191924

@@ -2083,6 +2088,7 @@ protected JSONObject getRequestStructure(RequestMethod method, String tag, int v
20832088

20842089
private JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception {
20852090
JSONObject jsonObject = new JSONObject(true);
2091+
List<String> removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等
20862092
if (request.keySet() == null || request.keySet().size() == 0) {
20872093
throw new IllegalArgumentException("json对象格式不正确 !,例如 \"User\": {}");
20882094
}
@@ -2098,59 +2104,117 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
20982104
if (key.startsWith("@")) {
20992105
try {
21002106
// 如果不匹配,异常不处理即可
2101-
RequestMethod l_method = RequestMethod.valueOf(key.substring(1).toUpperCase());
2102-
for(String objKey : StringUtil.split(request.getString(key))) {
2103-
keyMethodMap.put(objKey, l_method);
2107+
RequestMethod _method = RequestMethod.valueOf(key.substring(1).toUpperCase());
2108+
removeTmpKeys.add(key);
2109+
for (String objKey : request.getJSONObject(key).keySet()) {
2110+
Map<String, Object> object_attributes_map = new HashMap<>();
2111+
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, _method);
2112+
keyObjectAttributesMap.put(objKey, object_attributes_map);
2113+
JSONObject objAttrJson = request.getJSONObject(key).getJSONObject(objKey);
2114+
for (String objAttr : objAttrJson.keySet()) {
2115+
switch (objAttr) {
2116+
case apijson.JSONObject.KEY_DATASOURCE:
2117+
object_attributes_map.put(apijson.JSONObject.KEY_DATASOURCE, objAttrJson.getString(objAttr));
2118+
break;
2119+
case apijson.JSONObject.KEY_SCHEMA:
2120+
object_attributes_map.put(apijson.JSONObject.KEY_SCHEMA, objAttrJson.getString(objAttr));
2121+
break;
2122+
case apijson.JSONObject.KEY_DATABASE:
2123+
object_attributes_map.put(apijson.JSONObject.KEY_DATABASE, objAttrJson.getString(objAttr));
2124+
break;
2125+
case apijson.JSONObject.VERSION:
2126+
object_attributes_map.put(apijson.JSONObject.VERSION, objAttrJson.getString(objAttr));
2127+
break;
2128+
case apijson.JSONObject.KEY_ROLE:
2129+
object_attributes_map.put(apijson.JSONObject.KEY_ROLE, objAttrJson.getString(objAttr));
2130+
break;
2131+
default:
2132+
break;
2133+
}
2134+
}
21042135
}
2136+
continue;
21052137
} catch (Exception e) {
21062138
}
21072139
}
2108-
2109-
//
2140+
21102141
// 1、非crud,对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法
21112142
// 2、crud, 没有声明就用 GET
21122143
// 3、兼容 sql@ JSONObject,设置 GET方法
21132144
// 将method 设置到每个object, op执行会解析
21142145
if (request.get(key) instanceof JSONObject) {
2115-
if (keyMethodMap.get(key) == null) {
2146+
if (keyObjectAttributesMap.get(key) == null) {
21162147
// 数组会解析为对象进行校验,做一下兼容
2117-
if (keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
2118-
if (method == RequestMethod.CRUD || (key.endsWith("@") && request.get(key) instanceof JSONObject)) {
2148+
if (keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
2149+
if (method == RequestMethod.CRUD || key.endsWith("@")) {
21192150
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, GET);
2120-
keyMethodMap.put(key, GET);
2151+
if(keyObjectAttributesMap.get(key) == null) {
2152+
Map<String, Object> object_attributes_map = new HashMap<>();
2153+
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
2154+
keyObjectAttributesMap.put(key, object_attributes_map);
2155+
}else {
2156+
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
2157+
}
21212158
} else {
21222159
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, method);
2123-
keyMethodMap.put(key, method);
2160+
if(keyObjectAttributesMap.get(key) == null) {
2161+
Map<String, Object> object_attributes_map = new HashMap<>();
2162+
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
2163+
keyObjectAttributesMap.put(key, object_attributes_map);
2164+
}else {
2165+
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
2166+
}
21242167
}
21252168
} else {
2126-
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY));
2169+
setRequestAttribute(key, true, apijson.JSONObject.KEY_METHOD, request);
2170+
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATASOURCE, request);
2171+
setRequestAttribute(key, true, apijson.JSONObject.KEY_SCHEMA, request);
2172+
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATABASE, request);
2173+
setRequestAttribute(key, true, apijson.JSONObject.VERSION, request);
2174+
setRequestAttribute(key, true, apijson.JSONObject.KEY_ROLE, request);
21272175
}
21282176
} else {
2129-
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key));
2177+
setRequestAttribute(key, false, apijson.JSONObject.KEY_METHOD, request);
2178+
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATASOURCE, request);
2179+
setRequestAttribute(key, false, apijson.JSONObject.KEY_SCHEMA, request);
2180+
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATABASE, request);
2181+
setRequestAttribute(key, false, apijson.JSONObject.VERSION, request);
2182+
setRequestAttribute(key, false, apijson.JSONObject.KEY_ROLE, request);
21302183
}
21312184
}
2132-
2185+
21332186
if (key.startsWith("@") || key.endsWith("@")) {
21342187
jsonObject.put(key, request.get(key));
21352188
continue;
21362189
}
21372190

2138-
21392191
if (request.get(key) instanceof JSONObject || request.get(key) instanceof JSONArray) {
21402192
RequestMethod _method = null;
21412193
if (request.get(key) instanceof JSONObject) {
21422194
_method = RequestMethod.valueOf(request.getJSONObject(key).getString(apijson.JSONObject.KEY_METHOD).toUpperCase());
21432195
} else {
2144-
if (keyMethodMap.get(key) == null) {
2196+
if (keyObjectAttributesMap.get(key) == null) {
21452197
if (method == RequestMethod.CRUD) {
21462198
_method = GET;
2147-
keyMethodMap.put(key, GET);
2199+
if(keyObjectAttributesMap.get(key) == null) {
2200+
Map<String, Object> object_attributes_map = new HashMap<>();
2201+
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
2202+
keyObjectAttributesMap.put(key, object_attributes_map);
2203+
}else {
2204+
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
2205+
}
21482206
} else {
21492207
_method = method;
2150-
keyMethodMap.put(key, method);
2208+
if(keyObjectAttributesMap.get(key) == null) {
2209+
Map<String, Object> object_attributes_map = new HashMap<>();
2210+
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
2211+
keyObjectAttributesMap.put(key, object_attributes_map);
2212+
}else {
2213+
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
2214+
}
21512215
}
21522216
} else {
2153-
_method = keyMethodMap.get(key);
2217+
_method = (RequestMethod) keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
21542218
}
21552219
}
21562220

@@ -2179,10 +2243,26 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
21792243
throw new Exception(e);
21802244
}
21812245
}
2182-
2246+
// 这里是requestObject ref request 的引用, 删除不需要的临时变量
2247+
for(String removeKey : removeTmpKeys) {
2248+
request.remove(removeKey);
2249+
}
21832250
return jsonObject;
21842251
}
21852252

2253+
private void setRequestAttribute(String key, boolean isArray, String attrKey, @NotNull JSONObject request) {
2254+
Object attrVal = null;
2255+
if(isArray) {
2256+
attrVal = keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY).get(attrKey);
2257+
}else {
2258+
attrVal = keyObjectAttributesMap.get(key).get(attrKey);
2259+
}
2260+
2261+
if(attrVal != null && request.getJSONObject(key).get(attrKey) == null) {
2262+
// 如果对象内部已经包含该属性,不覆盖
2263+
request.getJSONObject(key).put(attrKey, attrVal);
2264+
}
2265+
}
21862266
/**
21872267
* { "xxx:aa":{ "@tag": "" }}
21882268
* 生成规则:
@@ -2231,8 +2311,8 @@ protected JSONObject objectVerify(RequestMethod method, String tag, int version,
22312311
* @return
22322312
*/
22332313
public RequestMethod getRealMethod(RequestMethod method, String key, Object value) {
2234-
if(method == CRUD && (value instanceof JSONObject || value instanceof JSONArray)) {
2235-
return this.keyMethodMap.get(key);
2314+
if(method == CRUD && key.startsWith("@") == false && (value instanceof JSONObject || value instanceof JSONArray)) {
2315+
return (RequestMethod)this.keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
22362316
}
22372317
return method;
22382318
}

APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import static apijson.RequestMethod.HEADS;
7474
import static apijson.RequestMethod.POST;
7575
import static apijson.RequestMethod.PUT;
76+
import static apijson.JSONObject.KEY_METHOD;
7677
import static apijson.SQL.AND;
7778
import static apijson.SQL.NOT;
7879
import static apijson.SQL.ON;
@@ -1119,6 +1120,9 @@ public static boolean isTDengine(String db) {
11191120

11201121
@Override
11211122
public String getQuote() {
1123+
if(isElasticsearch()) {
1124+
return "";
1125+
}
11221126
return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() ? "`" : "\"";
11231127
}
11241128

@@ -3967,6 +3971,10 @@ public String getSubqueryString(Subquery subquery) throws Exception {
39673971
String range = subquery.getRange();
39683972
SQLConfig cfg = subquery.getConfig();
39693973

3974+
// 子查询 = 主语句 datasource
3975+
if(StringUtil.equals(this.getTable(), subquery.getFrom() ) == false && cfg.hasJoin() == false) {
3976+
cfg.setDatasource(this.getDatasource());
3977+
}
39703978
cfg.setPreparedValueList(new ArrayList<>());
39713979
String withAsExpreSql = withAsExpreSubqueryString(cfg, subquery);
39723980
String sql = (range == null || range.isEmpty() ? "" : range) + "(" + withAsExpreSql + ") ";
@@ -4213,6 +4221,9 @@ public static String getSQL(AbstractSQLConfig config) throws Exception {
42134221

42144222
cSql = "SELECT " + (config.getCache() == JSONRequest.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + getConditionString(tablePath, config) + config.getLimitString();
42154223
cSql = buildWithAsExpreSql(config, cSql);
4224+
if(config.isElasticsearch()) { // elasticSearch 不支持 explain
4225+
return cSql;
4226+
}
42164227
return explain + cSql;
42174228
}
42184229
}
@@ -4354,7 +4365,8 @@ public String getJoinString() throws Exception {
43544365
// <"INNER JOIN User ON User.id = Moment.userId", UserConfig> TODO AS 放 getSQLTable 内
43554366
SQLConfig jc = j.getJoinConfig();
43564367
jc.setPrepared(isPrepared());
4357-
4368+
// 将关联表所属数据源配置为主表数据源
4369+
jc.setDatasource(this.getDatasource());
43584370
String jt = StringUtil.isEmpty(jc.getAlias(), true) ? jc.getTable() : jc.getAlias();
43594371
List<On> onList = j.getOnList();
43604372

@@ -4648,7 +4660,7 @@ public static <T extends Object> SQLConfig newSQLConfig(RequestMethod method, St
46484660

46494661
boolean explain = request.getBooleanValue(KEY_EXPLAIN);
46504662
if (explain && Log.DEBUG == false) { //不在 config.setExplain 抛异常,一方面处理更早性能更好,另一方面为了内部调用可以绕过这个限制
4651-
throw new UnsupportedOperationException("DEBUG 模式下不允许传 " + KEY_EXPLAIN + " !");
4663+
throw new UnsupportedOperationException("非DEBUG模式, 不允许传 " + KEY_EXPLAIN + " !");
46524664
}
46534665

46544666
String database = request.getString(KEY_DATABASE);
@@ -4835,6 +4847,7 @@ else if (userId instanceof Subquery) {}
48354847
request.remove(KEY_ORDER);
48364848
request.remove(KEY_RAW);
48374849
request.remove(KEY_JSON);
4850+
request.remove(KEY_METHOD);
48384851

48394852

48404853
// @null <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

0 commit comments

Comments
 (0)