Skip to content

Commit

Permalink
Merge pull request #487 from cloudAndMonkey/master
Browse files Browse the repository at this point in the history
新增、优化相关功能点
  • Loading branch information
TommyLemon authored Dec 11, 2022
2 parents d0550bd + 4af6322 commit 38989bd
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 35 deletions.
1 change: 1 addition & 0 deletions APIJSONORM/src/main/java/apijson/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ public JSONObject setUserIdIn(List<Object> list) {
TABLE_KEY_LIST.add(KEY_ORDER);
TABLE_KEY_LIST.add(KEY_RAW);
TABLE_KEY_LIST.add(KEY_JSON);
TABLE_KEY_LIST.add(KEY_METHOD);
}

//@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>>
Expand Down
2 changes: 1 addition & 1 deletion APIJSONORM/src/main/java/apijson/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public static boolean isNotEmpty(String s, boolean trim) {
PATTERN_ALPHA = Pattern.compile("^[a-zA-Z]+$");
PATTERN_ALPHA_BIG = Pattern.compile("^[A-Z]+$");
PATTERN_ALPHA_SMALL = Pattern.compile("^[a-z]+$");
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_:]+$");//已用55个中英字符测试通过
PATTERN_NAME = Pattern.compile("^[0-9a-zA-Z_.:]+$");//已用55个中英字符测试通过
//newest phone regex expression reference https://github.com/VincentSit/ChinaMobilePhoneNumberRegex
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}$");
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})(\\]?)$");
Expand Down
128 changes: 104 additions & 24 deletions APIJSONORM/src/main/java/apijson/orm/AbstractParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@
*/
public abstract class AbstractParser<T extends Object> implements Parser<T>, ParserCreator<T>, VerifierCreator<T>, SQLCreator {
protected static final String TAG = "AbstractParser";
protected Map<Object, RequestMethod> keyMethodMap = new HashMap<>();

/**
* json对象、数组对应的数据源、版本、角色、method等
*/
protected Map<Object, Map<String, Object>> keyObjectAttributesMap = new HashMap<>();
/**
* 可以通过切换该变量来控制是否打印关键的接口请求内容。保守起见,该值默认为false。
* 与 {@link Log#DEBUG} 任何一个为 true 都会打印关键的接口请求内容。
Expand Down Expand Up @@ -1158,7 +1162,8 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
}

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

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

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

private JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception {
JSONObject jsonObject = new JSONObject(true);
List<String> removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等
if (request.keySet() == null || request.keySet().size() == 0) {
throw new IllegalArgumentException("json对象格式不正确 !,例如 \"User\": {}");
}
Expand All @@ -2098,59 +2104,117 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
if (key.startsWith("@")) {
try {
// 如果不匹配,异常不处理即可
RequestMethod l_method = RequestMethod.valueOf(key.substring(1).toUpperCase());
for(String objKey : StringUtil.split(request.getString(key))) {
keyMethodMap.put(objKey, l_method);
RequestMethod _method = RequestMethod.valueOf(key.substring(1).toUpperCase());
removeTmpKeys.add(key);
for (String objKey : request.getJSONObject(key).keySet()) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, _method);
keyObjectAttributesMap.put(objKey, object_attributes_map);
JSONObject objAttrJson = request.getJSONObject(key).getJSONObject(objKey);
for (String objAttr : objAttrJson.keySet()) {
switch (objAttr) {
case apijson.JSONObject.KEY_DATASOURCE:
object_attributes_map.put(apijson.JSONObject.KEY_DATASOURCE, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_SCHEMA:
object_attributes_map.put(apijson.JSONObject.KEY_SCHEMA, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_DATABASE:
object_attributes_map.put(apijson.JSONObject.KEY_DATABASE, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.VERSION:
object_attributes_map.put(apijson.JSONObject.VERSION, objAttrJson.getString(objAttr));
break;
case apijson.JSONObject.KEY_ROLE:
object_attributes_map.put(apijson.JSONObject.KEY_ROLE, objAttrJson.getString(objAttr));
break;
default:
break;
}
}
}
continue;
} catch (Exception e) {
}
}

//

// 1、非crud,对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法
// 2、crud, 没有声明就用 GET
// 3、兼容 sql@ JSONObject,设置 GET方法
// 将method 设置到每个object, op执行会解析
if (request.get(key) instanceof JSONObject) {
if (keyMethodMap.get(key) == null) {
if (keyObjectAttributesMap.get(key) == null) {
// 数组会解析为对象进行校验,做一下兼容
if (keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
if (method == RequestMethod.CRUD || (key.endsWith("@") && request.get(key) instanceof JSONObject)) {
if (keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY) == null) {
if (method == RequestMethod.CRUD || key.endsWith("@")) {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, GET);
keyMethodMap.put(key, GET);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, method);
keyMethodMap.put(key, method);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
}
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key + apijson.JSONObject.KEY_ARRAY));
setRequestAttribute(key, true, apijson.JSONObject.KEY_METHOD, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATASOURCE, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_SCHEMA, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_DATABASE, request);
setRequestAttribute(key, true, apijson.JSONObject.VERSION, request);
setRequestAttribute(key, true, apijson.JSONObject.KEY_ROLE, request);
}
} else {
request.getJSONObject(key).put(apijson.JSONObject.KEY_METHOD, keyMethodMap.get(key));
setRequestAttribute(key, false, apijson.JSONObject.KEY_METHOD, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATASOURCE, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_SCHEMA, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_DATABASE, request);
setRequestAttribute(key, false, apijson.JSONObject.VERSION, request);
setRequestAttribute(key, false, apijson.JSONObject.KEY_ROLE, request);
}
}

if (key.startsWith("@") || key.endsWith("@")) {
jsonObject.put(key, request.get(key));
continue;
}


if (request.get(key) instanceof JSONObject || request.get(key) instanceof JSONArray) {
RequestMethod _method = null;
if (request.get(key) instanceof JSONObject) {
_method = RequestMethod.valueOf(request.getJSONObject(key).getString(apijson.JSONObject.KEY_METHOD).toUpperCase());
} else {
if (keyMethodMap.get(key) == null) {
if (keyObjectAttributesMap.get(key) == null) {
if (method == RequestMethod.CRUD) {
_method = GET;
keyMethodMap.put(key, GET);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, GET);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, GET);
}
} else {
_method = method;
keyMethodMap.put(key, method);
if(keyObjectAttributesMap.get(key) == null) {
Map<String, Object> object_attributes_map = new HashMap<>();
object_attributes_map.put(apijson.JSONObject.KEY_METHOD, method);
keyObjectAttributesMap.put(key, object_attributes_map);
}else {
keyObjectAttributesMap.get(key).put(apijson.JSONObject.KEY_METHOD, method);
}
}
} else {
_method = keyMethodMap.get(key);
_method = (RequestMethod) keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
}
}

Expand Down Expand Up @@ -2179,10 +2243,26 @@ private JSONObject batchVerify(RequestMethod method, String tag, int version, St
throw new Exception(e);
}
}

// 这里是requestObject ref request 的引用, 删除不需要的临时变量
for(String removeKey : removeTmpKeys) {
request.remove(removeKey);
}
return jsonObject;
}

private void setRequestAttribute(String key, boolean isArray, String attrKey, @NotNull JSONObject request) {
Object attrVal = null;
if(isArray) {
attrVal = keyObjectAttributesMap.get(key + apijson.JSONObject.KEY_ARRAY).get(attrKey);
}else {
attrVal = keyObjectAttributesMap.get(key).get(attrKey);
}

if(attrVal != null && request.getJSONObject(key).get(attrKey) == null) {
// 如果对象内部已经包含该属性,不覆盖
request.getJSONObject(key).put(attrKey, attrVal);
}
}
/**
* { "xxx:aa":{ "@tag": "" }}
* 生成规则:
Expand Down Expand Up @@ -2231,8 +2311,8 @@ protected JSONObject objectVerify(RequestMethod method, String tag, int version,
* @return
*/
public RequestMethod getRealMethod(RequestMethod method, String key, Object value) {
if(method == CRUD && (value instanceof JSONObject || value instanceof JSONArray)) {
return this.keyMethodMap.get(key);
if(method == CRUD && key.startsWith("@") == false && (value instanceof JSONObject || value instanceof JSONArray)) {
return (RequestMethod)this.keyObjectAttributesMap.get(key).get(apijson.JSONObject.KEY_METHOD);
}
return method;
}
Expand Down
17 changes: 15 additions & 2 deletions APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import static apijson.RequestMethod.HEADS;
import static apijson.RequestMethod.POST;
import static apijson.RequestMethod.PUT;
import static apijson.JSONObject.KEY_METHOD;
import static apijson.SQL.AND;
import static apijson.SQL.NOT;
import static apijson.SQL.ON;
Expand Down Expand Up @@ -1119,6 +1120,9 @@ public static boolean isTDengine(String db) {

@Override
public String getQuote() {
if(isElasticsearch()) {
return "";
}
return isMySQL() || isMariaDB() || isTiDB() || isClickHouse() || isTDengine() ? "`" : "\"";
}

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

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

cSql = "SELECT " + (config.getCache() == JSONRequest.CACHE_RAM ? "SQL_NO_CACHE " : "") + column + " FROM " + getConditionString(tablePath, config) + config.getLimitString();
cSql = buildWithAsExpreSql(config, cSql);
if(config.isElasticsearch()) { // elasticSearch 不支持 explain
return cSql;
}
return explain + cSql;
}
}
Expand Down Expand Up @@ -4354,7 +4365,8 @@ public String getJoinString() throws Exception {
// <"INNER JOIN User ON User.id = Moment.userId", UserConfig> TODO AS 放 getSQLTable 内
SQLConfig jc = j.getJoinConfig();
jc.setPrepared(isPrepared());

// 将关联表所属数据源配置为主表数据源
jc.setDatasource(this.getDatasource());
String jt = StringUtil.isEmpty(jc.getAlias(), true) ? jc.getTable() : jc.getAlias();
List<On> onList = j.getOnList();

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

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

String database = request.getString(KEY_DATABASE);
Expand Down Expand Up @@ -4835,6 +4847,7 @@ else if (userId instanceof Subquery) {}
request.remove(KEY_ORDER);
request.remove(KEY_RAW);
request.remove(KEY_JSON);
request.remove(KEY_METHOD);


// @null <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Expand Down
Loading

0 comments on commit 38989bd

Please sign in to comment.