From 22a9406af592f171dc4a630d572fa3fd8d79b508 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 28 Aug 2023 22:02:42 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E7=94=9F=E6=80=81=EF=BC=9AAPIJSON=20?= =?UTF-8?q?=E5=92=8C=20RuoYi=20=E6=A1=86=E6=9E=B6=E6=95=B4=E5=90=88?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=A1=B5=E9=9D=A2=E6=A8=A1=E6=9D=BF=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E5=9C=A8=E7=BA=BF=E7=BB=B4=E6=8A=A4=20APIJSON=20?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E9=85=8D=E7=BD=AE=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 创作不易,为热心的作者打开链接点亮 ⭐️ Star 支持/收藏 下吧~ https://gitee.com/TommyLemon/apijson-ruoyi --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0dd54b28..9a53bc6f 100644 --- a/README.md +++ b/README.md @@ -646,6 +646,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-examples](https://gitee.com/drone/apijson-examples) APIJSON 的前端、业务后端、管理后端 Demo +[apijson-ruoyi](https://gitee.com/yxiedd/apijson-ruoyi) APIJSON 和 RuoYi 框架整合,实现零代码生成页面模板接口,在线维护 APIJSON 数据库配置等 + [light4j](https://github.com/xlongwei/light4j) 整合 APIJSON 和微服务框架 light-4j 的 Demo,同时接入了 Redis [SpringServer1.2-APIJSON](https://github.com/Airforce-1/SpringServer1.2-APIJSON) 智慧党建服务器端,提供 上传 和 下载 文件的接口 From da15edb94b4faa7b614bac7012833a94570a5659 Mon Sep 17 00:00:00 2001 From: Jarrod Quan Date: Fri, 1 Sep 2023 22:19:20 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index e7268931..60378cbd 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -5,7 +5,7 @@ com.github.Tencent APIJSON - 6.1.0 + 6.2.0 jar APIJSONORM From 2a6b81816ad43725d7236a5aadec7b746123eb02 Mon Sep 17 00:00:00 2001 From: Jarrod Quan Date: Fri, 1 Sep 2023 22:19:59 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0source=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E6=96=B9=E4=BE=BF=E4=BD=BF=E7=94=A8=E8=80=85?= =?UTF-8?q?=E6=8B=89=E5=8F=96=E6=BA=90=E7=A0=81=E6=9F=A5=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/pom.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index 60378cbd..b29887e0 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -36,6 +36,20 @@ 1.8 + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + package + + jar-no-fork + + + + From d4675cd1c56b5de37d93193ea283582c3330ddf7 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sat, 2 Sep 2023 21:42:51 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E4=BA=8B=E5=8A=A1=E5=86=85=E6=9C=89=E5=A4=9A=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93/=E5=A4=9A=E4=B8=AA=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5=E6=9C=89?= =?UTF-8?q?=E6=97=B6=E4=B8=8D=E8=83=BD=E5=90=8C=E6=AD=A5=E6=8F=90=E4=BA=A4?= =?UTF-8?q?/=E5=9B=9E=E6=BB=9A=EF=BC=9B=E8=A7=A3=E5=86=B3=E7=89=B9?= =?UTF-8?q?=E5=AE=9A=E7=89=88=E6=9C=AC=E7=9A=84=20MySQL=20=E7=AD=89?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=95=B0=E6=8D=AE=E5=BA=93=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=20setAutoCommit/setTransactionIsolation=20=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apijson/orm/AbstractFunctionParser.java | 4 + .../java/apijson/orm/AbstractSQLExecutor.java | 116 ++++++++++-------- 2 files changed, 71 insertions(+), 49 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java index afb1fb6b..dc40ac41 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java @@ -511,6 +511,10 @@ public class AbstractFunctionParser implements FunctionParser { } public static String extractSchema(String sch, String table) { + if (StringUtil.isEmpty(sch)) { + return sch; + } + if (table == null) { table = "Table"; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index 7b10b319..d11638bd 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -9,7 +9,7 @@ import java.io.BufferedReader; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; -import java.util.Date; +import java.util.*; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -22,14 +22,7 @@ import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.Month; import java.time.Year; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.regex.Pattern; import com.alibaba.fastjson.JSON; @@ -1202,7 +1195,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut this.transactionIsolation = transactionIsolation; } - private boolean isIsolationStatusSet = false; //已设置事务等级 + protected Map isolationMap = new LinkedHashMap<>(); @Override public void begin(int transactionIsolation) throws SQLException { Log.d("\n\n" + TAG, "<<<<<<<<<<<<<< TRANSACTION begin transactionIsolation = " + transactionIsolation + " >>>>>>>>>>>>>>>>>>>>>>> \n\n"); @@ -1210,27 +1203,20 @@ public abstract class AbstractSQLExecutor implements SQLExecut // if (connection == null || connection.isClosed()) { // return; // } - if (! isIsolationStatusSet) { //只设置一次Isolation等级 PG重复设置事务等级会报错 - isIsolationStatusSet = true; - connection.setTransactionIsolation(transactionIsolation); // 这句导致 TDengine 驱动报错 - } - connection.setAutoCommit(false); //java.sql.SQLException: Can''t call commit when autocommit=true - } - @Override - public void rollback() throws SQLException { - Log.d("\n\n" + TAG, "<<<<<<<<<<<<<< TRANSACTION rollback >>>>>>>>>>>>>>>>>>>>>>> \n\n"); - //权限校验不通过,connection 也不会生成,还是得判断 //不做判断,如果掩盖了问题,调用层都不知道为啥事务没有提交成功 - if (connection == null) { // || connection.isClosed()) { - return; - } - // 将所有连接进行回滚 - Collection connections = connectionMap.values(); + // 将所有连接设置隔离级别,且禁止自动提交,需要以下代码来 commit/rollback + Collection connections = connectionMap.values(); if (connections != null) { for (Connection connection : connections) { try { - if (connection != null && connection.isClosed() == false) { - connection.rollback(); + Integer isolation = isolationMap.get(connection); + if (isolation == null || isolation != transactionIsolation) { // 只设置一次 Isolation 等级 PG 及 MySQL 某些版本重复设置事务等级会报错 + isolationMap.put(connection, transactionIsolation); + + connection.setTransactionIsolation(transactionIsolation); // 这句导致 TDengine 驱动报错 + if (isolation == null) { + connection.setAutoCommit(false); // java.sql.SQLException: Can''t call commit when autocommit=true + } } } catch (SQLException e) { @@ -1239,50 +1225,83 @@ public abstract class AbstractSQLExecutor implements SQLExecut } } } + + @Override + public void rollback() throws SQLException { + Log.d("\n\n" + TAG, "<<<<<<<<<<<<<< TRANSACTION rollback >>>>>>>>>>>>>>>>>>>>>>> \n\n"); + //权限校验不通过,connection 也不会生成,还是得判断 //不做判断,如果掩盖了问题,调用层都不知道为啥事务没有提交成功 +// if (connection == null) { // || connection.isClosed()) { +// return; +// } + + // 将所有连接进行回滚 + Collection connections = connectionMap.values(); + if (connections != null) { + for (Connection connection : connections) { + try { + if (connection != null && connection.isClosed() == false) { + connection.rollback(); + connection.setAutoCommit(true); + + isolationMap.remove(connection); + } + } + catch (SQLException e) { + e.printStackTrace(); + } + } + } + } + @Override public void rollback(Savepoint savepoint) throws SQLException { Log.d("\n\n" + TAG, "<<<<<<<<<<<<<< TRANSACTION rollback savepoint " + (savepoint == null ? "" : "!") + "= null >>>>>>>>>>>>>>>>>>>>>>> \n\n"); - //权限校验不通过,connection 也不会生成,还是得判断 //不做判断,如果掩盖了问题,调用层都不知道为啥事务没有提交成功 - if (connection == null) { // || connection.isClosed()) { + if (savepoint == null) { + rollback(); return; } - - if(StringUtil.isEmpty(savepoint)) { - // 将所有连接进行回滚 - Collection connections = connectionMap.values(); - if (connections != null) { - for (Connection connection : connections) { - try { - if (connection != null && connection.isClosed() == false) { - connection.rollback(); - } - } - catch (SQLException e) { - e.printStackTrace(); + //权限校验不通过,connection 也不会生成,还是得判断 //不做判断,如果掩盖了问题,调用层都不知道为啥事务没有提交成功 +// if (connection == null) { // || connection.isClosed()) { +// return; +// } + + // 将所有连接进行回滚 + Collection connections = connectionMap.values(); + if (connections != null) { + for (Connection connection : connections) { + try { + if (connection != null && connection.isClosed() == false) { + connection.rollback(savepoint); + connection.setAutoCommit(true); + + isolationMap.remove(connection); } } + catch (SQLException e) { + e.printStackTrace(); + } } - } else { - connection.rollback(savepoint); } } + @Override public void commit() throws SQLException { Log.d("\n\n" + TAG, "<<<<<<<<<<<<<< TRANSACTION commit >>>>>>>>>>>>>>>>>>>>>>> \n\n"); //权限校验不通过,connection 也不会生成,还是得判断 //不做判断,如果掩盖了问题,调用层都不知道为啥事务没有提交成功 - if (connection == null) { // || connection.isClosed()) { - return; - } +// if (connection == null) { // || connection.isClosed()) { +// return; +// } // 将所有连接进行提交 Collection connections = connectionMap.values(); - if (connections != null) { for (Connection connection : connections) { try { if (connection != null && connection.isClosed() == false) { connection.commit(); + + isolationMap.remove(connection); } } catch (SQLException e) { @@ -1309,7 +1328,6 @@ public abstract class AbstractSQLExecutor implements SQLExecut } Collection connections = connectionMap.values(); - if (connections != null) { for (Connection connection : connections) { try { @@ -1334,7 +1352,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut Connection conn = getConnection(config); Statement stt = conn.createStatement(); - //Statement stt = config.isTDengine() + // Statement stt = config.isTDengine() // ? conn.createStatement() // fix Presto: ResultSet: Exception: set type is TYPE_FORWARD_ONLY, Result set concurrency must be CONCUR_READ_ONLY // : conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT); From 1d6307887b98aa3a9bd0a634bace3b8d70cdf261 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sat, 2 Sep 2023 21:55:46 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E6=9D=83=E9=99=90=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=88=A0=E6=94=B9=E4=B8=8D=E6=94=AF=E6=8C=81=20String?= =?UTF-8?q?=20=E7=B1=BB=E5=9E=8B=E4=B8=BB=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractVerifier.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java index 3429640f..79c1d119 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java @@ -376,18 +376,18 @@ public abstract class AbstractVerifier implements Verifier, break; case CONTACT: case CIRCLE: - //TODO 做一个缓存contactMap,提高[]:{}查询性能, removeAccessInfo时map.remove(visitorId) - //不能在Visitor内null -> [] ! 否则会导致某些查询加上不需要的条件! + // TODO 做一个缓存contactMap,提高[]:{}查询性能, removeAccessInfo时map.remove(visitorId) + // 不能在 Visitor内null -> [] ! 否则会导致某些查询加上不需要的条件! List list = visitor.getContactIdList() == null ? new ArrayList() : new ArrayList(visitor.getContactIdList()); if (CIRCLE.equals(role)) { list.add(visitorId); } - //key!{}:[] 或 其它没有明确id的条件 等 可以和key{}:list组合。类型错误就报错 - requestId = config.getWhere(visitorIdKey, true);//JSON里数值不能保证是Long,可能是Integer + // key!{}:[] 或 其它没有明确id的条件 等 可以和 key{}:[] 组合。类型错误就报错 + requestId = config.getWhere(visitorIdKey, true); // JSON 里数值不能保证是 Long,可能是 Integer @SuppressWarnings("unchecked") - Collection requestIdArray = (Collection) config.getWhere(visitorIdKey + "{}", true);//不能是 &{}, |{} 不要传,直接{} + Collection requestIdArray = (Collection) config.getWhere(visitorIdKey + "{}", true); // 不能是 &{}, |{} 不要传,直接 {} if (requestId != null) { if (requestIdArray == null) { requestIdArray = new JSONArray(); @@ -395,20 +395,29 @@ public abstract class AbstractVerifier implements Verifier, requestIdArray.add(requestId); } - if (requestIdArray == null) {//可能是@得到 || requestIdArray.isEmpty()) {//请求未声明key:id或key{}:[...]条件,自动补全 - config.putWhere(visitorIdKey+"{}", JSON.parseArray(list), true); //key{}:[]有效,SQLConfig里throw NotExistException + if (requestIdArray == null) { // 可能是 @ 得到 || requestIdArray.isEmpty()) { // 请求未声明 key:id 或 key{}:[...] 条件,自动补全 + config.putWhere(visitorIdKey+"{}", JSON.parseArray(list), true); // key{}:[] 有效,SQLConfig 里 throw NotExistException } - else {//请求已声明key:id或key{}:[]条件,直接验证 + else { // 请求已声明 key:id 或 key{}:[] 条件,直接验证 for (Object id : requestIdArray) { if (id == null) { continue; } - if (id instanceof Number == false) {//不能准确地判断Long,可能是Integer - throw new UnsupportedDataTypeException(table + ".id类型错误,id类型必须是Long!"); + + if (id instanceof Number) { // 不能准确地判断 Long,可能是 Integer + if (((Number) id).longValue() <= 0 || list.contains(Long.valueOf("" + id)) == false) { // Integer等转为 Long 才能正确判断,强转崩溃 + throw new IllegalAccessException(visitorIdKey + " = " + id + " 的 " + table + + " 不允许 " + role + " 用户的 " + method.name() + " 请求!"); + } } - if (list.contains(Long.valueOf("" + id)) == false) {//Integer等转为Long才能正确判断。强转崩溃 - throw new IllegalAccessException(visitorIdKey + " = " + id + " 的 " + table - + " 不允许 " + role + " 用户的 " + method.name() + " 请求!"); + else if (id instanceof String) { + if (StringUtil.isEmpty(id) || list.contains(id) == false) { + throw new IllegalAccessException(visitorIdKey + " = " + id + " 的 " + table + + " 不允许 " + role + " 用户的 " + method.name() + " 请求!"); + } + } + else { + throw new UnsupportedDataTypeException(table + ".id 类型错误,类型必须是 Long/String!"); } } } From d748641814ccfe340597239f81927aba2bfc35d4 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sat, 2 Sep 2023 22:00:36 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=E6=9F=A5=E4=B8=8D=E5=88=B0=E5=80=BC=E6=97=B6?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E4=BC=A0=E5=85=A5=E8=B7=AF=E5=BE=84=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E6=9F=A5=E8=AF=A2=E3=80=81=E6=9D=83=E9=99=90=E7=AD=89?= =?UTF-8?q?=E5=90=84=E7=A7=8D=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/orm/AbstractParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 92bdfaba..685f1c8a 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -1850,8 +1850,8 @@ public abstract class AbstractParser implements Parser, Par return target; } - Log.i(TAG, "getValueByPath return valuePath;"); - return valuePath; + Log.i(TAG, "getValueByPath return null;"); + return null; } //依赖引用关系 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> From d4be7ce52ae94768fce21909d31a124416eb72f7 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 3 Sep 2023 02:56:48 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=9A=E4=B8=B0=E5=AF=8C=E5=8F=96=E5=B8=B8=E7=94=A8=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8F=82=E6=95=B0=E5=80=BC=E7=9A=84=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apijson/orm/AbstractFunctionParser.java | 135 ++++++++++++++++-- 1 file changed, 126 insertions(+), 9 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java index dc40ac41..75f0d261 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java @@ -5,12 +5,10 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; -import apijson.Log; -import apijson.NotNull; -import apijson.RequestMethod; -import apijson.StringUtil; +import apijson.*; import apijson.orm.exception.UnsupportedDataTypeException; import apijson.orm.script.ScriptExecutor; +import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.util.TypeUtils; @@ -18,6 +16,7 @@ import com.alibaba.fastjson.util.TypeUtils; import java.lang.invoke.WrongMethodTypeException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.math.BigDecimal; import java.util.*; import static apijson.orm.AbstractSQLConfig.PATTERN_SCHEMA; @@ -44,6 +43,7 @@ public class AbstractFunctionParser implements FunctionParser { // > public static Map SCRIPT_EXECUTOR_MAP; public static Map FUNCTION_MAP; + static { FUNCTION_MAP = new HashMap<>(); SCRIPT_EXECUTOR_MAP = new HashMap<>(); @@ -53,9 +53,11 @@ public class AbstractFunctionParser implements FunctionParser { private String tag; private int version; private JSONObject request; + public AbstractFunctionParser() { this(null, null, 0, null); } + public AbstractFunctionParser(RequestMethod method, String tag, int version, @NotNull JSONObject request) { setMethod(method == null ? RequestMethod.GET : method); setTag(tag); @@ -64,10 +66,12 @@ public class AbstractFunctionParser implements FunctionParser { } private Parser parser; + @Override public Parser getParser() { return parser; } + @Override public AbstractFunctionParser setParser(Parser parser) { this.parser = parser; @@ -78,85 +82,198 @@ public class AbstractFunctionParser implements FunctionParser { public RequestMethod getMethod() { return method; } + @Override public AbstractFunctionParser setMethod(RequestMethod method) { this.method = method; return this; } + @Override public String getTag() { return tag; } + @Override public AbstractFunctionParser setTag(String tag) { this.tag = tag; return this; } + @Override public int getVersion() { return version; } + @Override public AbstractFunctionParser setVersion(int version) { this.version = version; return this; } - + private String key; + @Override public String getKey() { return key; } + @Override public AbstractFunctionParser setKey(String key) { this.key = key; return this; } - + private String parentPath; + @Override public String getParentPath() { return parentPath; } + @Override public AbstractFunctionParser setParentPath(String parentPath) { this.parentPath = parentPath; return this; } + private String currentName; + @Override public String getCurrentName() { return currentName; } + @Override public AbstractFunctionParser setCurrentName(String currentName) { this.currentName = currentName; return this; } - + @NotNull @Override public JSONObject getRequest() { return request; } + @Override public AbstractFunctionParser setRequest(@NotNull JSONObject request) { this.request = request; return this; } - + private JSONObject currentObject; - @NotNull + + @NotNull @Override public JSONObject getCurrentObject() { return currentObject; } + @Override public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject) { this.currentObject = currentObject; return this; } + /**根据路径取 Boolean 值 + * @param path + * @return + */ + public Boolean getArgBool(String path) { + return getArgVal(path, Boolean.class); + } + + /**根据路径取 Integer 值 + * @param path + * @return + */ + public Integer getArgInt(String path) { + return getArgVal(path, Integer.class); + } + + /**根据路径取 Long 值 + * @param path + * @return + */ + public Long getArgLong(String path) { + return getArgVal(path, Long.class); + } + + /**根据路径取 Float 值 + * @param path + * @return + */ + public Float getArgFloat(String path) { + return getArgVal(path, Float.class); + } + + /**根据路径取 Double 值 + * @param path + * @return + */ + public Double getArgDouble(String path) { + return getArgVal(path, Double.class); + } + + /**根据路径取 Number 值 + * @param path + * @return + */ + public Number getArgNum(String path) { + return getArgVal(path, Number.class); + } + + /**根据路径取 BigDecimal 值 + * @param path + * @return + */ + public BigDecimal getArgDecimal(String path) { + return getArgVal(path, BigDecimal.class); + } + + /**根据路径取 String 值 + * @param path + * @return + */ + public String getArgStr(String path) { + Object obj = getArgVal(path); + return JSON.toJSONString(obj); + } + + /**根据路径取 JSONObject 值 + * @param path + * @return + */ + public JSONObject getArgObj(String path) { + return getArgVal(path, JSONObject.class); + } + + /**根据路径取 JSONArray 值 + * @param path + * @return + */ + public JSONArray getArgArr(String path) { + return getArgVal(path, JSONArray.class); + } + + /**根据路径取 List 值 + * @param path + * @return + */ + public List getArgList(String path) { + return getArgList(path, null); + } + + /**根据路径取 List 值 + * @param path + * @return + */ + public List getArgList(String path, Class clazz) { + String s = getArgStr(path); + return JSON.parseArray(s, clazz); + } + /**根据路径取值 * @param path * @return From eccf2524669d390dcadd9ab1caaa07fab19330bb Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 3 Sep 2023 03:52:49 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E8=AF=B7=E6=B1=82=E5=86=85=E5=A4=9A=E7=A7=8D=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E6=93=8D=E4=BD=9C=E7=9A=84=E5=85=B3=E9=94=AE=E8=AF=8D?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20@post:=20"User"?= =?UTF-8?q?,=20@gets:=20{=20"Privacy":=20"Privacy-phone"=20}=20=E7=AD=89?= =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/JSONObject.java | 28 +++- .../src/main/java/apijson/RequestMethod.java | 22 ++- .../main/java/apijson/orm/AbstractParser.java | 144 +++++++++++------- .../java/apijson/orm/AbstractSQLConfig.java | 78 +++++++--- 4 files changed, 185 insertions(+), 87 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java index a7320359..571c0aed 100755 --- a/APIJSONORM/src/main/java/apijson/JSONObject.java +++ b/APIJSONORM/src/main/java/apijson/JSONObject.java @@ -6,6 +6,7 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -151,7 +152,16 @@ public class JSONObject extends com.alibaba.fastjson.JSONObject { public static final String KEY_ORDER = "@order"; //排序方式 public static final String KEY_RAW = "@raw"; // 自定义原始 SQL 片段 public static final String KEY_JSON = "@json"; //SQL Server 把字段转为 JSON 输出 - public static final String KEY_METHOD = "@method"; //json对象配置操作方法 + public static final String KEY_METHOD = "@method"; // json 对象配置操作方法 + public static final String KEY_GET = "@get"; // json 对象配置操作方法 + public static final String KEY_GETS = "@gets"; // json 对象配置操作方法 + public static final String KEY_HEAD = "@head"; // json 对象配置操作方法 + public static final String KEY_HEADS = "@heads"; // json 对象配置操作方法 + public static final String KEY_POST = "@post"; // json 对象配置操作方法 + public static final String KEY_PUT = "@put"; // json 对象配置操作方法 + public static final String KEY_DELETE = "@delete"; // json 对象配置操作方法 + + public static final Map KEY_METHOD_ENUM_MAP; public static final List TABLE_KEY_LIST; static { @@ -174,6 +184,22 @@ public class JSONObject extends com.alibaba.fastjson.JSONObject { TABLE_KEY_LIST.add(KEY_RAW); TABLE_KEY_LIST.add(KEY_JSON); TABLE_KEY_LIST.add(KEY_METHOD); + TABLE_KEY_LIST.add(KEY_GET); + TABLE_KEY_LIST.add(KEY_GETS); + TABLE_KEY_LIST.add(KEY_HEAD); + TABLE_KEY_LIST.add(KEY_HEADS); + TABLE_KEY_LIST.add(KEY_POST); + TABLE_KEY_LIST.add(KEY_PUT); + TABLE_KEY_LIST.add(KEY_DELETE); + + KEY_METHOD_ENUM_MAP = new LinkedHashMap<>(); + KEY_METHOD_ENUM_MAP.put(KEY_GET, RequestMethod.GET); + KEY_METHOD_ENUM_MAP.put(KEY_GETS, RequestMethod.GETS); + KEY_METHOD_ENUM_MAP.put(KEY_HEAD, RequestMethod.HEAD); + KEY_METHOD_ENUM_MAP.put(KEY_HEADS, RequestMethod.HEADS); + KEY_METHOD_ENUM_MAP.put(KEY_POST, RequestMethod.POST); + KEY_METHOD_ENUM_MAP.put(KEY_PUT, RequestMethod.PUT); + KEY_METHOD_ENUM_MAP.put(KEY_DELETE, RequestMethod.DELETE); } //@key关键字都放这个类 >>>>>>>>>>>>>>>>>>>>>> diff --git a/APIJSONORM/src/main/java/apijson/RequestMethod.java b/APIJSONORM/src/main/java/apijson/RequestMethod.java index 9e2f09be..410775c1 100755 --- a/APIJSONORM/src/main/java/apijson/RequestMethod.java +++ b/APIJSONORM/src/main/java/apijson/RequestMethod.java @@ -5,6 +5,9 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson; +import java.util.Arrays; +import java.util.List; + /**请求方法,对应org.springframework.web.bind.annotation.RequestMethod,多出GETS,HEADS方法 * @author Lemon */ @@ -40,18 +43,21 @@ public enum RequestMethod { */ PUT, - /** - * json包含多条语句,支持增删改查,函数调用 - */ - CRUD, - /** * 删除数据 */ - DELETE; - - public static final RequestMethod[] ALL = new RequestMethod[]{ GET, HEAD, GETS, HEADS, POST, PUT, CRUD, DELETE}; + DELETE, + + /** + * json 包含多条语句,支持增删改查、函数调用 + */ + CRUD; + public static final RequestMethod[] ALL = new RequestMethod[]{ GET, HEAD, GETS, HEADS, POST, PUT, DELETE, CRUD }; + public static final List ALL_NAME_LIST = Arrays.asList( + GET.name(), HEAD.name(), GETS.name(), HEADS.name(), POST.name(), PUT.name(), DELETE.name(), CRUD.name() + ); + /**是否为GET请求方法 * @param method * @param containPrivate 包含私密(非明文)获取方法GETS diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 685f1c8a..c731b02c 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -410,11 +410,12 @@ public abstract class AbstractParser implements Parser, Par requestObject = request; try { setVersion(requestObject.getIntValue(JSONRequest.KEY_VERSION)); + requestObject.remove(JSONRequest.KEY_VERSION); + if (getMethod() != RequestMethod.CRUD) { setTag(requestObject.getString(JSONRequest.KEY_TAG)); requestObject.remove(JSONRequest.KEY_TAG); } - requestObject.remove(JSONRequest.KEY_VERSION); } catch (Exception e) { return extendErrorResult(requestObject, e, requestMethod, getRequestURL(), isRoot); } @@ -2089,7 +2090,7 @@ public abstract class AbstractParser implements Parser, Par } protected JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception { - JSONObject jsonObject = new JSONObject(true); + JSONObject correctRequest = new JSONObject(true); List removeTmpKeys = new ArrayList<>(); // 请求json里面的临时变量,不需要带入后面的业务中,比如 @post、@get等 Set reqSet = request == null ? null : request.keySet(); @@ -2098,49 +2099,82 @@ public abstract class AbstractParser implements Parser, Par } for (String key : reqSet) { - // key重复直接抛错(xxx:alias, xxx:alias[]) - if (jsonObject.containsKey(key) || jsonObject.containsKey(key + apijson.JSONObject.KEY_ARRAY)) { - throw new IllegalArgumentException("对象名重复,请添加别名区分 ! ,重复对象名为: " + key); + // key 重复直接抛错(xxx:alias, xxx:alias[]) + if (correctRequest.containsKey(key) || correctRequest.containsKey(key + apijson.JSONObject.KEY_ARRAY)) { + throw new IllegalArgumentException("对象名重复,请添加别名区分 ! 重复对象名为: " + key); } - // @post、@get等RequestMethod + // @post、@get 等 RequestMethod try { - if (key.startsWith("@") && getEnum(RequestMethod.class, key.substring(1).toUpperCase(), null) != null) { + RequestMethod keyMethod = apijson.orm.JSONRequest.KEY_METHOD_ENUM_MAP.get(key); + if (keyMethod != null) { // 如果不匹配,异常不处理即可 - RequestMethod _method = RequestMethod.valueOf(key.substring(1).toUpperCase()); removeTmpKeys.add(key); - JSONObject obj = request.getJSONObject(key); - Set set = obj == null ? new HashSet<>() : obj.keySet(); + Object val = request.get(key); + JSONObject obj = val instanceof JSONObject ? request.getJSONObject(key) : null; + if (obj == null) { + if (val instanceof String) { + String[] tbls = StringUtil.split((String) val); + if (tbls != null && tbls.length > 0) { + obj = new JSONObject(true); + for (int i = 0; i < tbls.length; i++) { + String tbl = tbls[i]; + if (obj.containsKey(tbl)) { + throw new ConflictException(key + ": value 中 " + tbl + " 已经存在,不能重复!"); + } + obj.put(tbl, new JSONObject(true)); + } + } + } + else { + throw new IllegalArgumentException(key + ": value 中 value 类型错误,只能是 String 或 JSONObject {} !"); + } + } - for (String objKey : set) { + Set> set = obj == null ? new HashSet<>() : obj.entrySet(); + + for (Entry objEntry : set) { + String objKey = objEntry == null ? null : objEntry.getKey(); if (objKey == null) { continue; } Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, _method); + objAttrMap.put(apijson.JSONObject.KEY_METHOD, keyMethod); keyObjectAttributesMap.put(objKey, objAttrMap); - JSONObject objAttrJson = obj.getJSONObject(objKey); - Set> objSet = objAttrJson == null ? new HashSet<>() : objAttrJson.entrySet(); - for (Entry entry : objSet) { - String objAttrKey = entry == null ? null : entry.getKey(); - if (objAttrKey == null) { - continue; + Object objVal = objEntry.getValue(); + JSONObject objAttrJson = objVal instanceof JSONObject ? obj.getJSONObject(objKey) : null; + if (objAttrJson == null) { + if (objVal instanceof String) { + objAttrMap.put(JSONRequest.KEY_TAG, objVal); } + else { + throw new IllegalArgumentException(key + ": { " + objKey + ": value 中 value 类型错误,只能是 String 或 JSONObject {} !"); + } + } + else { + Set> objSet = objAttrJson == null ? new HashSet<>() : objAttrJson.entrySet(); - switch (objAttrKey) { - case apijson.JSONObject.KEY_DATASOURCE: - case apijson.JSONObject.KEY_SCHEMA: - case apijson.JSONObject.KEY_DATABASE: - case JSONRequest.KEY_VERSION: - case apijson.JSONObject.KEY_ROLE: - case JSONRequest.KEY_TAG: - objAttrMap.put(objAttrKey, entry.getValue()); - break; - default: - break; + for (Entry entry : objSet) { + String objAttrKey = entry == null ? null : entry.getKey(); + if (objAttrKey == null) { + continue; + } + + switch (objAttrKey) { + case apijson.JSONObject.KEY_DATASOURCE: + case apijson.JSONObject.KEY_SCHEMA: + case apijson.JSONObject.KEY_DATABASE: + case JSONRequest.KEY_VERSION: + case apijson.JSONObject.KEY_ROLE: + case JSONRequest.KEY_TAG: + objAttrMap.put(objAttrKey, entry.getValue()); + break; + default: + break; + } } } } @@ -2189,15 +2223,17 @@ public abstract class AbstractParser implements Parser, Par } if (key.startsWith("@") || key.endsWith("@")) { - jsonObject.put(key, obj); + correctRequest.put(key, obj); continue; } if (obj instanceof JSONObject || obj instanceof JSONArray) { - RequestMethod _method = null; + RequestMethod _method; if (obj instanceof JSONObject) { - _method = RequestMethod.valueOf(request.getJSONObject(key).getString(apijson.JSONObject.KEY_METHOD).toUpperCase()); - String combine = request.getJSONObject(key).getString(KEY_COMBINE); + JSONObject tblObj = request.getJSONObject(key); + String mn = tblObj == null ? null : tblObj.getString(apijson.JSONObject.KEY_METHOD); + _method = mn == null ? null : RequestMethod.valueOf(mn); + String combine = _method == null ? null : tblObj.getString(KEY_COMBINE); if (combine != null && RequestMethod.isPublicMethod(_method) == false) { throw new IllegalArgumentException(key + ":{} 里的 @combine:value 不合法!开放请求 GET、HEAD 才允许传 @combine:value !"); } @@ -2207,22 +2243,14 @@ public abstract class AbstractParser implements Parser, Par if (attrMap == null) { if (method == RequestMethod.CRUD) { _method = GET; - if (attrMap == null) { - Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, GET); - keyObjectAttributesMap.put(key, objAttrMap); - } else { - attrMap.put(apijson.JSONObject.KEY_METHOD, GET); - } + Map objAttrMap = new HashMap<>(); + objAttrMap.put(apijson.JSONObject.KEY_METHOD, GET); + keyObjectAttributesMap.put(key, objAttrMap); } else { _method = method; - if (attrMap == null) { - Map objAttrMap = new HashMap<>(); - objAttrMap.put(apijson.JSONObject.KEY_METHOD, method); - keyObjectAttributesMap.put(key, objAttrMap); - } else { - attrMap.put(apijson.JSONObject.KEY_METHOD, method); - } + Map objAttrMap = new HashMap<>(); + objAttrMap.put(apijson.JSONObject.KEY_METHOD, method); + keyObjectAttributesMap.put(key, objAttrMap); } } else { _method = (RequestMethod) attrMap.get(apijson.JSONObject.KEY_METHOD); @@ -2236,29 +2264,29 @@ public abstract class AbstractParser implements Parser, Par // get请求不校验 if (RequestMethod.isPublicMethod(_method)) { - jsonObject.put(key, obj); + correctRequest.put(key, obj); continue; } - if(tag != null && !tag.contains(":")) { + if (tag != null && ! tag.contains(":")) { JSONObject object = getRequestStructure(_method, tag, version); JSONObject ret = objectVerify(_method, tag, version, name, request, maxUpdateCount, creator, object); - jsonObject.putAll(ret); + correctRequest.putAll(ret); break; } String _tag = buildTag(request, key, method, tag); JSONObject object = getRequestStructure(_method, _tag, version); - if(method == RequestMethod.CRUD && StringUtil.isEmpty(tag, true)) { + if (method == RequestMethod.CRUD && StringUtil.isEmpty(tag, true)) { JSONObject requestItem = new JSONObject(); requestItem.put(key, obj); JSONObject ret = objectVerify(_method, _tag, version, name, requestItem, maxUpdateCount, creator, object); - jsonObject.put(key, ret.get(key)); + correctRequest.put(key, ret.get(key)); } else { return objectVerify(_method, _tag, version, name, request, maxUpdateCount, creator, object); } } else { - jsonObject.put(key, obj); + correctRequest.put(key, obj); } } catch (Exception e) { e.printStackTrace(); @@ -2266,12 +2294,12 @@ public abstract class AbstractParser implements Parser, Par } } - // 这里是requestObject ref request 的引用, 删除不需要的临时变量 + // 这里是 requestObject ref request 的引用, 删除不需要的临时变量 for (String removeKey : removeTmpKeys) { request.remove(removeKey); } - return jsonObject; + return correctRequest; } public static > E getEnum(final Class enumClass, final String enumName, final E defaultEnum) { @@ -2284,7 +2312,7 @@ public abstract class AbstractParser implements Parser, Par return defaultEnum; } } - + protected void setRequestAttribute(String key, boolean isArray, String attrKey, @NotNull JSONObject request) { Map attrMap = keyObjectAttributesMap.get(isArray ? key + apijson.JSONObject.KEY_ARRAY : key); Object attrVal = attrMap == null ? null : attrMap.get(attrKey); @@ -2308,7 +2336,7 @@ public abstract class AbstractParser implements Parser, Par } return tag; } - + protected JSONObject objectVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request , int maxUpdateCount, SQLCreator creator, JSONObject object) throws Exception { @@ -2317,7 +2345,7 @@ public abstract class AbstractParser implements Parser, Par // JSONObject clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {} return getVerifier().verifyRequest(method, name, target, request, maxUpdateCount, getGlobalDatabase(), getGlobalSchema(), creator); } - + /*** * 兼容url crud, 获取真实method * @param method = crud diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 9d601837..eaf3bbf8 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -4901,8 +4901,8 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - config.setExplain(explain); + config.setExplain(explain != null && explain); config.setCache(getCache(cache)); config.setDistinct(distinct); config.setColumn(column == null ? null : cs); //解决总是 config.column != null,总是不能得到 * @@ -5587,23 +5588,60 @@ public abstract class AbstractSQLConfig implements SQLConfig Date: Sun, 3 Sep 2023 03:53:56 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=8A=E6=AC=A1?= =?UTF-8?q?=E5=B0=91=E6=8F=90=E4=BA=A4=E7=9A=84=20import=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/orm/AbstractParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index c731b02c..5cbfe7c6 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -5,6 +5,7 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; +import apijson.orm.exception.ConflictException; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; From 83e878033544a6bb3d3729584de8ee35833607fa Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 3 Sep 2023 17:25:21 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E8=B5=8B=E5=80=BC=E5=8F=96=E4=B8=8D=E5=88=B0=E6=9C=89=E6=95=88?= =?UTF-8?q?=E5=80=BC=EF=BC=8C=E7=9B=B4=E6=8E=A5=E5=BF=BD=E7=95=A5=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E4=BB=8D=E7=84=B6=E6=89=A7=E8=A1=8C=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/apijson/orm/AbstractObjectParser.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 301914dc..6c010cde 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -423,7 +423,15 @@ public abstract class AbstractObjectParser implements ObjectParser { if (target == null) { // String#equals(null)会出错 Log.d(TAG, "onParse target == null >> return true;"); - return true; + // 非查询关键词 @key 不影响查询,直接跳过 + if (isTable && (key.startsWith("@") == false || JSONRequest.TABLE_KEY_LIST.contains(key))) { + Log.e(TAG, "onParse isTable && (key.startsWith(@) == false" + + " || JSONRequest.TABLE_KEY_LIST.contains(key)) >> return null;"); + return false; // 获取不到就不用再做无效的 query 了。不考虑 Table:{Table:{}} 嵌套 + } + + Log.d(TAG, "onParse isTable(table) == false >> return true;"); + return true; // 舍去,对Table无影响 } // if (target instanceof Map) { // target 可能是从 requestObject 里取出的 {} From 83eeaa28a5ec019fafc9d68d059b424acb2dc761 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 10 Sep 2023 02:30:03 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=E5=85=81?= =?UTF-8?q?=E8=AE=B8=E4=BD=86=E5=AE=B9=E6=98=93=E5=AF=BC=E8=87=B4=E6=BD=9C?= =?UTF-8?q?=E5=9C=A8=E9=97=AE=E9=A2=98=E7=9A=84=E6=83=85=E5=86=B5=E5=9C=A8?= =?UTF-8?q?=20DEBUG=20=E4=B8=8B=E8=BF=94=E5=9B=9E=E8=AD=A6=E5=91=8A?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apijson/orm/AbstractObjectParser.java | 27 +++ .../main/java/apijson/orm/AbstractParser.java | 213 ++++++++++++------ .../java/apijson/orm/AbstractSQLConfig.java | 45 +++- 3 files changed, 212 insertions(+), 73 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 6c010cde..7bfc9ff6 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -833,12 +833,39 @@ public abstract class AbstractObjectParser implements ObjectParser { if (parser.getSQLExecutor() == null) { parser.createSQLExecutor(); } + if (parser != null && config.getParser() == null) { + config.setParser(parser); + } return parser.getSQLExecutor().execute(config, isProcedure); } @Override public SQLConfig newSQLConfig(boolean isProcedure) throws Exception { + String raw = Log.DEBUG == false || sqlRequest == null ? null : sqlRequest.getString(apijson.JSONRequest.KEY_RAW); + String[] keys = raw == null ? null : StringUtil.split(raw); + if (keys != null && keys.length > 0) { + boolean allow = AbstractSQLConfig.ALLOW_MISSING_KEY_4_COMBINE; + + for (String key : keys) { + if (sqlRequest.get(key) != null) { + continue; + } + + String msg = "@raw:value 的 value 中 " + key + " 不合法!对应的 " + + key + ": value 在当前对象 " + name + " 不存在或 value = null,无法有效转为原始 SQL 片段!"; + + if (allow == false) { + throw new UnsupportedOperationException(msg); + } + + if (parser instanceof AbstractParser) { + ((AbstractParser) parser).putWarnIfNeed(JSONRequest.KEY_RAW, msg); + } + break; + } + } + return newSQLConfig(method, table, alias, sqlRequest, joinList, isProcedure) .setParser(parser) .setObjectParser(this); diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 5cbfe7c6..4a5ed4bc 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -121,10 +121,10 @@ public abstract class AbstractParser implements Parser, Par * @param method null ? requestMethod = GET */ public AbstractParser(RequestMethod method) { - super(); - setMethod(method); - setNeedVerifyRole(AbstractVerifier.ENABLE_VERIFY_ROLE); - setNeedVerifyContent(AbstractVerifier.ENABLE_VERIFY_CONTENT); + super(); + setMethod(method); + setNeedVerifyRole(AbstractVerifier.ENABLE_VERIFY_ROLE); + setNeedVerifyContent(AbstractVerifier.ENABLE_VERIFY_CONTENT); } /** * @param method null ? requestMethod = GET @@ -145,6 +145,57 @@ public abstract class AbstractParser implements Parser, Par return this; } + public static final String KEY_REF = "Reference"; + + /**警告信息 + * Map<"Reference", "引用赋值获取路径 /Comment/userId 对应的值为 null!"> + */ + protected Map warnMap = new LinkedHashMap<>(); + public String getWarn(String type) { + return warnMap == null ? null : warnMap.get(type); + } + public AbstractParser putWarnIfNeed(String type, String warn) { + if (Log.DEBUG) { + String w = getWarn(type); + if (StringUtil.isEmpty(w, true)) { + putWarn(type, warn); + } + } + return this; + } + public AbstractParser putWarn(String type, String warn) { + if (warnMap == null) { + warnMap = new LinkedHashMap<>(); + } + warnMap.put(type, warn); + return this; + } + /**获取警告信息 + * @return + */ + public String getWarnString() { + Set> set = warnMap == null ? null : warnMap.entrySet(); + if (set == null || set.isEmpty()) { + return null; + } + + StringBuilder sb = new StringBuilder(); + for (Entry e : set) { + String k = e == null ? null : e.getKey(); + String v = k == null ? null : e.getValue(); + if (StringUtil.isEmpty(v, true)) { + continue; + } + + if (StringUtil.isNotEmpty(k, true)) { + sb.append("[" + k + "]: "); + } + sb.append(v + "; "); + } + + return sb.toString(); + } + @NotNull protected Visitor visitor; @@ -334,9 +385,6 @@ public abstract class AbstractParser implements Parser, Par } - - - protected SQLExecutor sqlExecutor; protected Verifier verifier; protected Map queryResultMap;//path-result @@ -487,7 +535,9 @@ public abstract class AbstractParser implements Parser, Par onRollback(); } - requestObject = error == null ? extendSuccessResult(requestObject, isRoot) : extendErrorResult(requestObject, error, requestMethod, getRequestURL(), isRoot); + String warn = Log.DEBUG == false || error != null ? null : getWarnString(); + + requestObject = error == null ? extendSuccessResult(requestObject, warn, isRoot) : extendErrorResult(requestObject, error, requestMethod, getRequestURL(), isRoot); JSONObject res = (globalFormat != null && globalFormat) && JSONResponse.isSuccess(requestObject) ? new JSONResponse(requestObject) : requestObject; @@ -663,31 +713,49 @@ public abstract class AbstractParser implements Parser, Par * @return */ public static JSONObject newResult(int code, String msg) { - return newResult(code, msg, false); + return newResult(code, msg, null); } - /**新建带状态内容的JSONObject + + /** + * 添加JSONObject的状态内容,一般用于错误提示结果 + * * @param code * @param msg + * @param warn + * @return + */ + public static JSONObject newResult(int code, String msg, String warn) { + return newResult(code, msg, warn, false); + } + + /** + * 新建带状态内容的JSONObject + * + * @param code + * @param msg + * @param warn * @param isRoot * @return */ - public static JSONObject newResult(int code, String msg, boolean isRoot) { - return extendResult(null, code, msg, isRoot); + public static JSONObject newResult(int code, String msg, String warn, boolean isRoot) { + return extendResult(null, code, msg, warn, isRoot); } - /**添加JSONObject的状态内容,一般用于错误提示结果 + /** + * 添加JSONObject的状态内容,一般用于错误提示结果 + * * @param object * @param code * @param msg * @return */ - public static JSONObject extendResult(JSONObject object, int code, String msg, boolean isRoot) { + public static JSONObject extendResult(JSONObject object, int code, String msg, String warn, boolean isRoot) { int index = Log.DEBUG == false || isRoot == false || msg == null ? -1 : msg.lastIndexOf(Log.KEY_SYSTEM_INFO_DIVIDER); String debug = Log.DEBUG == false || isRoot == false ? null : (index >= 0 ? msg.substring(index + Log.KEY_SYSTEM_INFO_DIVIDER.length()).trim() : " \n提 bug 请发请求和响应的【完整截屏】,没图的自行解决!" - + " \n开发者有限的时间和精力主要放在【维护项目源码和文档】上!" - + " \n【描述不详细】 或 【文档/常见问题 已有答案】 的问题可能会被忽略!!" - + " \n【态度 不文明/不友善】的可能会被踢出群,问题也可能不予解答!!!" + + " \n开发者有限的时间和精力主要放在【维护项目源码和文档】上!" + + " \n【描述不详细】 或 【文档/常见问题 已有答案】 的问题可能会被忽略!!" + + " \n【态度 不文明/不友善】的可能会被踢出群,问题也可能不予解答!!!" + " \n\n **环境信息** " + " \n系统: " + Log.OS_NAME + " " + Log.OS_VERSION + " \n数据库: DEFAULT_DATABASE = " + AbstractSQLConfig.DEFAULT_DATABASE @@ -717,6 +785,9 @@ public abstract class AbstractParser implements Parser, Par object.put(JSONResponse.KEY_MSG, msg); if (debug != null) { + if (StringUtil.isNotEmpty(warn, true)) { + debug += "\n 【警告】:" + warn; + } object.put("debug:info|help", debug); } @@ -724,33 +795,51 @@ public abstract class AbstractParser implements Parser, Par } - /**添加请求成功的状态内容 + /** + * 添加请求成功的状态内容 + * * @param object * @return */ public static JSONObject extendSuccessResult(JSONObject object) { return extendSuccessResult(object, false); } + + public static JSONObject extendSuccessResult(JSONObject object, boolean isRoot) { + return extendSuccessResult(object, null, isRoot); + } + /**添加请求成功的状态内容 * @param object * @param isRoot * @return */ - public static JSONObject extendSuccessResult(JSONObject object, boolean isRoot) { - return extendResult(object, JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, isRoot); + public static JSONObject extendSuccessResult(JSONObject object, String warn, boolean isRoot) { + return extendResult(object, JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); } + /**获取请求成功的状态内容 * @return */ public static JSONObject newSuccessResult() { - return newSuccessResult(false); + return newSuccessResult(null); } + /**获取请求成功的状态内容 + * @param warn + * @return + */ + public static JSONObject newSuccessResult(String warn) { + return newSuccessResult(warn, false); + } + + /**获取请求成功的状态内容 + * @param warn * @param isRoot * @return */ - public static JSONObject newSuccessResult(boolean isRoot) { - return newResult(JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, isRoot); + public static JSONObject newSuccessResult(String warn, boolean isRoot) { + return newResult(JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); } /**添加请求成功的状态内容 @@ -848,7 +937,7 @@ public abstract class AbstractParser implements Parser, Par } int code = CommonException.getCode(e); - return extendResult(object, code, msg, isRoot); + return extendResult(object, code, msg, null, isRoot); } /**新建错误状态内容 @@ -872,16 +961,13 @@ public abstract class AbstractParser implements Parser, Par String msg = CommonException.getMsg(e); Integer code = CommonException.getCode(e); - return newResult(code, msg, isRoot); + return newResult(code, msg, null, isRoot); } - return newResult(JSONResponse.CODE_SERVER_ERROR, JSONResponse.MSG_SERVER_ERROR, isRoot); + return newResult(JSONResponse.CODE_SERVER_ERROR, JSONResponse.MSG_SERVER_ERROR, null, isRoot); } - - - //TODO 启动时一次性加载Request所有内容,作为初始化。 /**获取正确的请求,非GET请求必须是服务器指定的 * @return * @throws Exception @@ -902,7 +988,6 @@ public abstract class AbstractParser implements Parser, Par */ @Override public JSONObject getStructure(@NotNull String table, String method, String tag, int version) throws Exception { - // TODO 目前只使用 Request 而不使用 Response,所以这里写死用 REQUEST_MAP,以后可能 Response 表也会与 Request 表合并,用字段来区分 String cacheKey = AbstractVerifier.getCacheKeyForRequest(method, tag); SortedMap versionedMap = AbstractVerifier.REQUEST_MAP.get(cacheKey); @@ -1419,17 +1504,17 @@ public abstract class AbstractParser implements Parser, Par index = path.lastIndexOf("/"); String tableKey = index < 0 ? path : path.substring(0, index); // User:owner - int index2 = tableKey.lastIndexOf("/"); - String arrKey = index2 < 0 ? null : tableKey.substring(0, index2); - if (arrKey != null && JSONRequest.isArrayKey(arrKey) == false) { + int index2 = tableKey.lastIndexOf("/"); + String arrKey = index2 < 0 ? null : tableKey.substring(0, index2); + if (arrKey != null && JSONRequest.isArrayKey(arrKey) == false) { throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + " 不是合法的数组 key[] !" + - "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!"); - } + "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!"); + } - tableKey = index2 < 0 ? tableKey : tableKey.substring(index2+1); + tableKey = index2 < 0 ? tableKey : tableKey.substring(index2+1); - apijson.orm.Entry entry = Pair.parseEntry(tableKey, true); - String table = entry.getKey(); // User + apijson.orm.Entry entry = Pair.parseEntry(tableKey, true); + String table = entry.getKey(); // User if (StringUtil.isName(table) == false) { throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":value 中 value 的 Table 值 " + table + " 不合法!" + "必须为 &/Table0, implements Parser, Par "必须是 {} 这种 JSONObject 格式!" + e2.getMessage()); } - if (arrKey != null) { - if (parentPathObj.get(JSONRequest.KEY_JOIN) != null) { - throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ join: value } 中 value 不合法!" + - "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!"); + if (arrKey != null) { + if (parentPathObj.get(JSONRequest.KEY_JOIN) != null) { + throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ join: value } 中 value 不合法!" + + "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!"); + } + + Integer subPage = parentPathObj.getInteger(JSONRequest.KEY_PAGE); + if (subPage != null && subPage != 0) { + throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ page: value } 中 value 不合法!" + + "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中 page 值只能为 null 或 0 !"); + } } - Integer subPage = parentPathObj.getInteger(JSONRequest.KEY_PAGE); - if (subPage != null && subPage != 0) { - throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ page: value } 中 value 不合法!" + - "@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中 page 值只能为 null 或 0 !"); - } - } - - boolean isAppJoin = "@".equals(joinType); + boolean isAppJoin = "@".equals(joinType); JSONObject refObj = new JSONObject(tableObj.size(), true); @@ -1489,8 +1574,8 @@ public abstract class AbstractParser implements Parser, Par } if (isAppJoin && StringUtil.isName(key.substring(0, key.length() - 1)) == false) { - throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + key + " 不合法 !" + - "@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!"); + throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + key + " 不合法 !" + + "@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!"); } refObj.put(key, tableObj.getString(key)); @@ -1525,20 +1610,20 @@ public abstract class AbstractParser implements Parser, Par apijson.orm.Entry te = tk == null || p.substring(ind2 + 1).indexOf("/") >= 0 ? null : Pair.parseEntry(tk, true); if (te != null && JSONRequest.isTableKey(te.getKey()) && request.get(tk) instanceof JSONObject) { - if (isAppJoin) { - if (refObj.size() >= 1) { - throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":" + e.getKey() + " 中 " + k + " 不合法!" - + "@ APP JOIN 必须有且只有一个引用赋值键值对!"); + if (isAppJoin) { + if (refObj.size() >= 1) { + throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":" + e.getKey() + " 中 " + k + " 不合法!" + + "@ APP JOIN 必须有且只有一个引用赋值键值对!"); + } + + if (StringUtil.isName(k.substring(0, k.length() - 1)) == false) { + throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + k + " 不合法 !" + + "@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!"); + } } - if (StringUtil.isName(k.substring(0, k.length() - 1)) == false) { - throw new IllegalArgumentException(JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + k + " 不合法 !" + - "@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!"); - } - } - - refObj.put(k, v); - continue; + refObj.put(k, v); + continue; } } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index eaf3bbf8..d162f6a7 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -118,6 +118,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig parser; @Override public Parser getParser() { + if (parser == null && objectParser != null) { + parser = objectParser.getParser(); + } return parser; } @Override - public AbstractSQLConfig setParser(Parser parser) { + public AbstractSQLConfig setParser(Parser parser) { this.parser = parser; return this; } + public AbstractSQLConfig putWarnIfNeed(String type, String warn) { + if (Log.DEBUG && parser instanceof AbstractParser) { + ((AbstractParser) parser).putWarnIfNeed(type, warn); + } + return this; + } + public AbstractSQLConfig putWarn(String type, String warn) { + if (Log.DEBUG && parser instanceof AbstractParser) { + ((AbstractParser) parser).putWarn(type, warn); + } + return this; + } private ObjectParser objectParser; @Override @@ -799,7 +815,7 @@ public abstract class AbstractSQLConfig implements SQLConfig setObjectParser(ObjectParser objectParser) { this.objectParser = objectParser; return this; } @@ -1665,7 +1681,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig banKeyList = Arrays.asList(idKey, idInKey, userIdKey, userIdInKey); for (String key : banKeyList) { - if(keyInCombineExpr(combineExpr, key)) { + if (isKeyInCombineExpr(combineExpr, key)) { throw new UnsupportedOperationException(table + ":{} 里的 @combine:value 中的 value 里 " + key + " 不合法!" + "不允许传 [" + idKey + ", " + idInKey + ", " + userIdKey + ", " + userIdInKey + "] 其中任何一个!"); } @@ -5339,6 +5358,10 @@ public abstract class AbstractSQLConfig implements SQLConfig) config).putWarnIfNeed(KEY_COMBINE, table + ":{} 里的 @combine:value 中的 value 里 " + + ws[i] + " 对应的条件 " + w + ":value 中 value 必须存在且不能为 null!"); + } } } } @@ -5361,7 +5384,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig Date: Sun, 10 Sep 2023 02:31:29 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E5=BD=93=E6=89=BE=E4=B8=8D=E5=88=B0?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E8=B5=8B=E5=80=BC=E8=B7=AF=E5=BE=84=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84=E9=9D=9E=20null=20=E5=80=BC=E6=97=B6?= =?UTF-8?q?=E5=9C=A8=20DEBUG=20=E4=B8=8B=E8=BF=94=E5=9B=9E=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/orm/AbstractObjectParser.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 7bfc9ff6..bd4a6846 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -423,6 +423,11 @@ public abstract class AbstractObjectParser implements ObjectParser { if (target == null) { // String#equals(null)会出错 Log.d(TAG, "onParse target == null >> return true;"); + + if (Log.DEBUG) { + parser.putWarnIfNeed(AbstractParser.KEY_REF, path + "/" + key + ": " + targetPath + " 引用赋值获取路径对应的值为 null!请检查路径是否错误!"); + } + // 非查询关键词 @key 不影响查询,直接跳过 if (isTable && (key.startsWith("@") == false || JSONRequest.TABLE_KEY_LIST.contains(key))) { Log.e(TAG, "onParse isTable && (key.startsWith(@) == false" From 72524b29569b162a9d3fe9ba9e9b02abaf073254 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 10 Sep 2023 03:13:03 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E4=B8=BB=E9=94=AE=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E5=85=A8=E9=9D=A2=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=B3=9B=E5=9E=8B=EF=BC=9B=E5=88=A0=E9=99=A4=20@Depre?= =?UTF-8?q?cated=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/JSONObject.java | 12 ---- .../apijson/orm/AbstractFunctionParser.java | 42 ++++++------- .../apijson/orm/AbstractObjectParser.java | 25 +++++--- .../main/java/apijson/orm/AbstractParser.java | 30 ++++----- .../java/apijson/orm/AbstractSQLConfig.java | 23 +++---- .../java/apijson/orm/AbstractSQLExecutor.java | 61 +++++++++---------- .../main/java/apijson/orm/FunctionParser.java | 22 +++---- .../main/java/apijson/orm/ObjectParser.java | 32 +++++----- .../src/main/java/apijson/orm/Parser.java | 10 +-- .../main/java/apijson/orm/SQLExecutor.java | 28 ++++----- 10 files changed, 136 insertions(+), 149 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java index 571c0aed..5d507740 100755 --- a/APIJSONORM/src/main/java/apijson/JSONObject.java +++ b/APIJSONORM/src/main/java/apijson/JSONObject.java @@ -421,18 +421,6 @@ public class JSONObject extends com.alibaba.fastjson.JSONObject { return puts(KEY_JSON, keys); } - /**用 setJson 替代。 - * set keys to cast to json - * @param keys "key0,key1,key2..." - * @return - * @see #{@link #setJson(String)} - */ - @Deprecated - public JSONObject setJSON(String keys) { - return puts(KEY_JSON, keys); - } - - //JSONObject内关键词 key >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java index 75f0d261..25739bf1 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java @@ -25,7 +25,7 @@ import static apijson.orm.SQLConfig.TYPE_ITEM; /**可远程调用的函数类 * @author Lemon */ -public class AbstractFunctionParser implements FunctionParser { +public class AbstractFunctionParser implements FunctionParser { private static final String TAG = "AbstractFunctionParser"; /**是否解析参数 key 的对应的值,不用手动编码 curObj.getString(key) @@ -65,15 +65,15 @@ public class AbstractFunctionParser implements FunctionParser { setRequest(request); } - private Parser parser; + private Parser parser; @Override - public Parser getParser() { + public Parser getParser() { return parser; } @Override - public AbstractFunctionParser setParser(Parser parser) { + public AbstractFunctionParser setParser(Parser parser) { this.parser = parser; return this; } @@ -84,7 +84,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setMethod(RequestMethod method) { + public AbstractFunctionParser setMethod(RequestMethod method) { this.method = method; return this; } @@ -95,7 +95,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setTag(String tag) { + public AbstractFunctionParser setTag(String tag) { this.tag = tag; return this; } @@ -106,7 +106,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setVersion(int version) { + public AbstractFunctionParser setVersion(int version) { this.version = version; return this; } @@ -119,7 +119,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setKey(String key) { + public AbstractFunctionParser setKey(String key) { this.key = key; return this; } @@ -132,7 +132,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setParentPath(String parentPath) { + public AbstractFunctionParser setParentPath(String parentPath) { this.parentPath = parentPath; return this; } @@ -145,7 +145,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setCurrentName(String currentName) { + public AbstractFunctionParser setCurrentName(String currentName) { this.currentName = currentName; return this; } @@ -157,7 +157,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setRequest(@NotNull JSONObject request) { + public AbstractFunctionParser setRequest(@NotNull JSONObject request) { this.request = request; return this; } @@ -171,7 +171,7 @@ public class AbstractFunctionParser implements FunctionParser { } @Override - public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject) { + public AbstractFunctionParser setCurrentObject(@NotNull JSONObject currentObject) { this.currentObject = currentObject; return this; } @@ -294,7 +294,7 @@ public class AbstractFunctionParser implements FunctionParser { /**根据路径取值 * @param path * @param clazz - * @param tryAll false-仅当前对象,true-本次请求的全局对象以及 Parser 缓存值 + * @param tryAll false-仅当前对象,true-本次请求的全局对象以及 Parser 缓存值 * @return * @param */ @@ -342,14 +342,14 @@ public class AbstractFunctionParser implements FunctionParser { public Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception { return invoke(this, function, currentObject, containRaw); } - + /**反射调用 * @param parser * @param function 例如get(Map:map,key),参数只允许引用,不能直接传值 * @param currentObject * @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[])} */ - public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception { + public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception { if (ENABLE_REMOTE_FUNCTION == false) { throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" + " == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !"); @@ -369,9 +369,9 @@ public class AbstractFunctionParser implements FunctionParser { throw new UnsupportedOperationException("language = " + language + " 不合法!AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION" + " == false 时不支持远程函数中的脚本形式!如需支持则设置 AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION = true !"); } - + if (lang != null && SCRIPT_EXECUTOR_MAP.get(lang) == null) { - throw new ClassNotFoundException("找不到脚本语言 " + lang + " 对应的执行引擎!请先依赖相关库并在后端 APIJSONFunctionParser 中注册!"); + throw new ClassNotFoundException("找不到脚本语言 " + lang + " 对应的执行引擎!请先依赖相关库并在后端 APIJSONFunctionParser 中注册!"); } int version = row.getIntValue("version"); @@ -413,7 +413,7 @@ public class AbstractFunctionParser implements FunctionParser { } } - + /**反射调用 * @param parser * @param methodName @@ -422,7 +422,7 @@ public class AbstractFunctionParser implements FunctionParser { * @return {@link #invoke(AbstractFunctionParser, String, Class[], Object[], String, JSONObject, ScriptExecutor)} * @throws Exception */ - public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName + public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName , @NotNull Class[] parameterTypes, @NotNull Object[] args) throws Exception { return invoke(parser, methodName, parameterTypes, args, null, null, null); } @@ -437,7 +437,7 @@ public class AbstractFunctionParser implements FunctionParser { * @return * @throws Exception */ - public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName + public static Object invoke(@NotNull AbstractFunctionParser parser, @NotNull String methodName , @NotNull Class[] parameterTypes, @NotNull Object[] args, String returnType , JSONObject currentObject, ScriptExecutor scriptExecutor) throws Exception { if (scriptExecutor != null) { @@ -474,7 +474,7 @@ public class AbstractFunctionParser implements FunctionParser { * @return * @throws Exception */ - public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName + public static Object invokeScript(@NotNull AbstractFunctionParser parser, @NotNull String methodName , @NotNull Class[] parameterTypes, @NotNull Object[] args, String returnType, JSONObject currentObject, ScriptExecutor scriptExecutor) throws Exception { Object result = scriptExecutor.execute(parser, currentObject, methodName, args); if (Log.DEBUG && result != null) { diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index bd4a6846..e6442013 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -35,20 +35,24 @@ import static apijson.RequestMethod.GET; /**简化Parser,getObject和getArray(getArrayConfig)都能用 * @author Lemon */ -public abstract class AbstractObjectParser implements ObjectParser { +public abstract class AbstractObjectParser implements ObjectParser { private static final String TAG = "AbstractObjectParser"; @NotNull - protected AbstractParser parser; - public AbstractObjectParser setParser(AbstractParser parser) { - this.parser = parser; + protected AbstractParser parser; + @Override + public AbstractParser getParser() { + return parser; + } + @Override + public AbstractObjectParser setParser(Parser parser) { + this.parser = (AbstractParser) parser; return this; } - protected JSONObject request;//不用final是为了recycle protected String parentPath;//不用final是为了recycle - protected SQLConfig arrayConfig;//不用final是为了recycle + protected SQLConfig arrayConfig;//不用final是为了recycle protected boolean isSubquery; protected final int type; @@ -435,6 +439,7 @@ public abstract class AbstractObjectParser implements ObjectParser { return false; // 获取不到就不用再做无效的 query 了。不考虑 Table:{Table:{}} 嵌套 } + Log.d(TAG, "onParse isTable(table) == false >> return true;"); return true; // 舍去,对Table无影响 } @@ -828,13 +833,13 @@ public abstract class AbstractObjectParser implements ObjectParser { @Override public JSONObject parseResponse(RequestMethod method, String table, String alias , JSONObject request, List joinList, boolean isProcedure) throws Exception { - SQLConfig config = newSQLConfig(method, table, alias, request, joinList, isProcedure) + SQLConfig config = newSQLConfig(method, table, alias, request, joinList, isProcedure) .setParser(parser) .setObjectParser(this); return parseResponse(config, isProcedure); } @Override - public JSONObject parseResponse(SQLConfig config, boolean isProcedure) throws Exception { + public JSONObject parseResponse(SQLConfig config, boolean isProcedure) throws Exception { if (parser.getSQLExecutor() == null) { parser.createSQLExecutor(); } @@ -1217,13 +1222,13 @@ public abstract class AbstractObjectParser implements ObjectParser { return alias; } @Override - public SQLConfig getArrayConfig() { + public SQLConfig getArrayConfig() { return arrayConfig; } @Override - public SQLConfig getSQLConfig() { + public SQLConfig getSQLConfig() { return sqlConfig; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 4a5ed4bc..c552888b 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -39,7 +39,7 @@ import static apijson.JSONObject.KEY_EXPLAIN; import static apijson.RequestMethod.CRUD; import static apijson.RequestMethod.GET; -/**parser for parsing request to JSONObject +/**Parser for parsing request to JSONObject * @author Lemon */ public abstract class AbstractParser implements Parser, ParserCreator, VerifierCreator, SQLCreator { @@ -595,7 +595,7 @@ public abstract class AbstractParser implements Parser, Par * @throws Exception */ @Override - public void onVerifyRole(@NotNull SQLConfig config) throws Exception { + public void onVerifyRole(@NotNull SQLConfig config) throws Exception { if (Log.DEBUG) { Log.i(TAG, "onVerifyRole config = " + JSON.toJSONString(config)); } @@ -1036,7 +1036,7 @@ public abstract class AbstractParser implements Parser, Par } // 获取指定的JSON结构 <<<<<<<<<<<<<< - SQLConfig config = createSQLConfig().setMethod(GET).setTable(table); + SQLConfig config = createSQLConfig().setMethod(GET).setTable(table); config.setPrepared(false); config.setColumn(Arrays.asList("structure")); @@ -1066,7 +1066,7 @@ public abstract class AbstractParser implements Parser, Par protected Map arrayObjectParserCacheMap = new HashMap<>(); - // protected SQLConfig itemConfig; + // protected SQLConfig itemConfig; /**获取单个对象,该对象处于parentObject内 * @param request parentObject 的 value * @param parentPath parentObject 的路径 @@ -1078,7 +1078,7 @@ public abstract class AbstractParser implements Parser, Par */ @Override public JSONObject onObjectParse(final JSONObject request - , String parentPath, String name, final SQLConfig arrayConfig, boolean isSubquery) throws Exception { + , String parentPath, String name, final SQLConfig arrayConfig, boolean isSubquery) throws Exception { if (Log.DEBUG) { Log.i(TAG, "\ngetObject: parentPath = " + parentPath @@ -1111,7 +1111,7 @@ public abstract class AbstractParser implements Parser, Par boolean isArrayMainTable = isSubquery == false && isTable && type == SQLConfig.TYPE_ITEM_CHILD_0 && arrayConfig != null && RequestMethod.isGetMethod(arrayConfig.getMethod(), true); boolean isReuse = isArrayMainTable && position > 0; - ObjectParser op = null; + ObjectParser op = null; if (isReuse) { // 数组主表使用专门的缓存数据 op = arrayObjectParserCacheMap.get(parentPath.substring(0, parentPath.lastIndexOf("[]") + 2)); op.setParentPath(parentPath); @@ -1143,7 +1143,7 @@ public abstract class AbstractParser implements Parser, Par if (compat != null && compat) { // 解决对聚合函数字段通过 query:2 分页查总数返回值错误 // 这里可能改变了内部的一些数据,下方通过 arrayConfig 还原 - SQLConfig cfg = op.setSQLConfig(0, 0, 0).getSQLConfig(); + SQLConfig cfg = op.setSQLConfig(0, 0, 0).getSQLConfig(); boolean isExplain = cfg.isExplain(); cfg.setExplain(false); @@ -1151,7 +1151,7 @@ public abstract class AbstractParser implements Parser, Par subqy.setFrom(cfg.getTable()); subqy.setConfig(cfg); - SQLConfig countSQLCfg = createSQLConfig(); + SQLConfig countSQLCfg = createSQLConfig(); countSQLCfg.setColumn(Arrays.asList("count(*):count")); countSQLCfg.setFrom(subqy); @@ -1336,7 +1336,7 @@ public abstract class AbstractParser implements Parser, Par //Table<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< response = new JSONArray(); - SQLConfig config = createSQLConfig() + SQLConfig config = createSQLConfig() .setMethod(requestMethod) .setCount(size) .setPage(page2) @@ -1745,7 +1745,7 @@ public abstract class AbstractParser implements Parser, Par // onList.add(table + "." + key + " = " + targetTable + "." + targetKey); // ON User.id = Moment.userId // 保证和 SQLExcecutor 缓存的 Config 里 where 顺序一致,生成的 SQL 也就一致 <<<<<<<<< - // AbstractSQLConfig.newSQLConfig 中强制把 id, id{}, userId, userId{} 放到了最前面 tableObj.put(key, tableObj.remove(key)); + // AbstractSQLConfig.newSQLConfig 中强制把 id, id{}, userId, userId{} 放到了最前面 tableObj.put(key, tableObj.remove(key)); if (refObj.size() != tableObj.size()) { // 把 key 强制放最前,AbstractSQLExcecutor 中 config.putWhere 也是放尽可能最前 refObj.putAll(tableObj); @@ -1757,8 +1757,8 @@ public abstract class AbstractParser implements Parser, Par // 保证和 SQLExcecutor 缓存的 Config 里 where 顺序一致,生成的 SQL 也就一致 >>>>>>>>> } - //拼接多个 SQLConfig 的SQL语句,然后执行,再把结果分别缓存(Moment, User等)到 SQLExecutor 的 cacheMap - // AbstractSQLConfig config0 = null; + //拼接多个 SQLConfig 的SQL语句,然后执行,再把结果分别缓存(Moment, User等)到 SQLExecutor 的 cacheMap + // AbstractSQLConfig config0 = null; // String sql = "SELECT " + config0.getColumnString() + " FROM " + config0.getTable() + " INNER JOIN " + targetTable + " ON " // + onList.get(0) + config0.getGroupString() + config0.getHavingString() + config0.getOrderString(); @@ -1981,7 +1981,7 @@ public abstract class AbstractParser implements Parser, Par * @throws Exception */ @Override - public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception { + public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception { if (config == null) { Log.d(TAG, "executeSQL config == null >> return null;"); return null; @@ -2029,7 +2029,7 @@ public abstract class AbstractParser implements Parser, Par else { sqlExecutor = getSQLExecutor(); result = sqlExecutor.execute(config, false); - // FIXME 改为直接在 sqlExecutor 内加好,最后 Parser 取结果,可以解决并发执行导致内部计算出错 + // FIXME 改为直接在 sqlExecutor 内加好,最后 Parser 取结果,可以解决并发执行导致内部计算出错 // executedSQLDuration += sqlExecutor.getExecutedSQLDuration() + sqlExecutor.getSqlResultDuration(); } @@ -2150,7 +2150,7 @@ public abstract class AbstractParser implements Parser, Par queryResultMap = null; } - private void setOpMethod(JSONObject request, ObjectParser op, String key) { + private void setOpMethod(JSONObject request, ObjectParser op, String key) { String _method = key == null ? null : request.getString(apijson.JSONObject.KEY_METHOD); if (_method != null) { RequestMethod method = RequestMethod.valueOf(_method); // 必须精准匹配,避免缓存命中率低 diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index d162f6a7..887f721d 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -4704,7 +4704,7 @@ public abstract class AbstractSQLConfig implements SQLConfig=".equals(rt) || "<=".equals(rt) || ">".equals(rt) || "<".equals(rt)) { if (isNot) { @@ -4892,13 +4892,6 @@ public abstract class AbstractSQLConfig implements SQLConfig onList, On on) { - onJoinComplexRelation(sql, quote, join, table, onList, on); - } - protected void onGetJoinString(Join join) throws UnsupportedOperationException { } protected void onGetCrossJoinString(Join join) throws UnsupportedOperationException { @@ -4914,7 +4907,7 @@ public abstract class AbstractSQLConfig implements SQLConfig SQLConfig newSQLConfig(RequestMethod method, String table, String alias + public static SQLConfig newSQLConfig(RequestMethod method, String table, String alias , JSONObject request, List joinList, boolean isProcedure, Callback callback) throws Exception { if (request == null) { // User:{} 这种空内容在查询时也有效 throw new NullPointerException(TAG + ": newSQLConfig request == null!"); @@ -4934,7 +4927,7 @@ public abstract class AbstractSQLConfig implements SQLConfig config = callback.getSQLConfig(method, database, schema, datasource, table); config.setAlias(alias); config.setDatabase(database); // 不删,后面表对象还要用的,必须放在 parseJoin 前 @@ -5680,7 +5673,7 @@ public abstract class AbstractSQLConfig implements SQLConfig SQLConfig parseJoin(RequestMethod method, SQLConfig config + public static SQLConfig parseJoin(RequestMethod method, SQLConfig config , List joinList, Callback callback) throws Exception { boolean isQuery = RequestMethod.isQueryMethod(method); config.setKeyPrefix(isQuery && config.isMain() == false); @@ -5697,8 +5690,8 @@ public abstract class AbstractSQLConfig implements SQLConfig joinConfig = newSQLConfig(method, table, alias, j.getRequest(), null, false, callback); + SQLConfig cacheConfig = j.canCacheViceTable() == false ? null : newSQLConfig(method, table, alias , j.getRequest(), null, false, callback).setCount(j.getCount()); if (j.isAppJoin() == false) { //除了 @ APP JOIN,其它都是 SQL JOIN,则副表要这样配置 @@ -5725,7 +5718,7 @@ public abstract class AbstractSQLConfig implements SQLConfig outterConfig = newSQLConfig(method, table, alias, j.getOuter(), null, false, callback); outterConfig.setMain(false) .setKeyPrefix(true) .setDatabase(joinConfig.getDatabase()) @@ -5934,7 +5927,7 @@ public abstract class AbstractSQLConfig implements SQLConfig getSQLConfig(RequestMethod method, String database, String schema, String datasource, String table); /**combine 里的 key 在 request 中 value 为 null 或不存在,即 request 中缺少用来作为 combine 条件的 key: value * @param combine diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index d11638bd..e4b38d0b 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -50,7 +50,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut return parser; } @Override - public AbstractSQLExecutor setParser(Parser parser) { + public AbstractSQLExecutor setParser(Parser parser) { this.parser = parser; return this; } @@ -93,10 +93,10 @@ public abstract class AbstractSQLExecutor implements SQLExecut /**保存缓存 * @param sql key * @param list value - * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null + * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null */ @Override - public void putCache(String sql, List list, SQLConfig config) { + public void putCache(String sql, List list, SQLConfig config) { if (sql == null || list == null) { // 空 list 有效,说明查询过 sql 了 || list.isEmpty()) { Log.i(TAG, "saveList sql == null || list == null >> return;"); return; @@ -107,26 +107,26 @@ public abstract class AbstractSQLExecutor implements SQLExecut /**获取缓存 * @param sql key - * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null + * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null */ @Override - public List getCache(String sql, SQLConfig config) { + public List getCache(String sql, SQLConfig config) { return cacheMap.get(sql); } /**获取缓存 * @param sql key * @param position - * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null + * @param config 一般主表 SQLConfig 不为 null,JOIN 副表的为 null * @return */ @Override - public JSONObject getCacheItem(String sql, int position, SQLConfig config) { + public JSONObject getCacheItem(String sql, int position, SQLConfig config) { List list = getCache(sql, config); return getCacheItem(list, position, config); } - public JSONObject getCacheItem(List list, int position, SQLConfig config) { + public JSONObject getCacheItem(List list, int position, SQLConfig config) { // 只要 list 不为 null,则如果 list.get(position) == null,则返回 {} ,避免再次 SQL 查询 if (list == null) { return null; @@ -145,7 +145,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @param config */ @Override - public void removeCache(String sql, SQLConfig config) { + public void removeCache(String sql, SQLConfig config) { if (sql == null) { Log.i(TAG, "removeList sql == null >> return;"); return; @@ -177,9 +177,8 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @throws Exception */ @Override - public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception { + public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception { long executedSQLStartTime = System.currentTimeMillis(); - final String sql = config.getSQL(false); if (StringUtil.isEmpty(sql, true)) { @@ -433,7 +432,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut // 为什么 isExplain == false 不用判断?因为所有字段都在一张 Query Plan 表 if (index <= 0 && columnIndexAndJoinMap != null) { // && viceColumnStart > length) { - SQLConfig curConfig = curJoin == null || ! curJoin.isSQLJoin() ? null : curJoin.getCacheConfig(); + SQLConfig curConfig = curJoin == null || ! curJoin.isSQLJoin() ? null : curJoin.getCacheConfig(); List curColumn = curConfig == null ? null : curConfig.getColumn(); String sqlTable = curConfig == null ? null : curConfig.getSQLTable(); String sqlAlias = curConfig == null ? null : curConfig.getAlias(); @@ -462,7 +461,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut int nextViceColumnStart = lastViceColumnStart; // 主表没有 @column 时会偏小 lastViceColumnStart for (int j = lastViceTableStart; j < joinList.size(); j++) { // 查找副表 @column,定位字段所在表 Join join = joinList.get(j); - SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig(); + SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig(); List c = cfg == null ? null : cfg.getColumn(); nextViceColumnStart += (c != null && ! c.isEmpty() ? @@ -507,7 +506,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut if (toFindJoin) { // 找到对应的副表 JOIN 配置 for (int j = lastViceTableStart; j < joinList.size(); j++) { // 查找副表 @column,定位字段所在表 Join join = joinList.get(j); - SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig(); + SQLConfig cfg = join == null || ! join.isSQLJoin() ? null : join.getJoinConfig(); if (cfg != null && StringUtil.equalsIgnoreCase(sqlTable, cfg.getSQLTable()) ) { // FIXME 导致副表字段错放到主表 && StringUtil.equals(sqlAlias, cfg.getAlias())) { @@ -552,7 +551,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut // 如果是主表则直接用主表对应的 item,否则缓存副表数据到 childMap Join prevJoin = columnIndexAndJoinMap == null || i < 2 ? null : columnIndexAndJoinMap[i - 2]; if (curJoin != prevJoin) { // 前后字段不在同一个表对象,即便后面出现 null,也不该是主表数据,而是逻辑 bug 导致 - SQLConfig viceConfig = curJoin != null && curJoin.isSQLJoin() ? curJoin.getCacheConfig() : null; + SQLConfig viceConfig = curJoin != null && curJoin.isSQLJoin() ? curJoin.getCacheConfig() : null; if (viceConfig != null) { //FIXME 只有和主表关联才能用 item,否则应该从 childMap 查其它副表数据 List onList = curJoin.getOnList(); int size = onList == null ? 0 : onList.size(); @@ -568,7 +567,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut } } } - String viceSql = viceConfig == null ? null : viceConfig.getSQL(false); //TODO 在 SQLConfig 缓存 SQL,减少大量的重复生成 + String viceSql = viceConfig == null ? null : viceConfig.getSQL(false); //TODO 在 SQLConfig 缓存 SQL,减少大量的重复生成 if (StringUtil.isEmpty(viceSql, true)) { Log.i(TAG, "execute StringUtil.isEmpty(viceSql, true) >> item = null; >> "); @@ -676,7 +675,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @param childMap * @throws Exception */ - protected void executeAppJoin(SQLConfig config, List resultList, Map> childMap) throws Exception { + protected void executeAppJoin(SQLConfig config, List resultList, Map> childMap) throws Exception { List joinList = config.getJoinList(); if (joinList != null) { @@ -686,7 +685,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut continue; } - SQLConfig cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好 + SQLConfig cc = join.getCacheConfig(); //这里用config改了getSQL后再还原很麻烦,所以提前给一个config2更好 if (cc == null) { if (Log.DEBUG) { throw new NullPointerException("服务器内部错误, executeAppJoin cc == null ! 导致不能缓存 @ APP JOIN 的副表数据!"); @@ -694,7 +693,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut continue; } - SQLConfig jc = join.getJoinConfig(); + SQLConfig jc = join.getJoinConfig(); List onList = join.getOnList(); On on = onList == null || onList.isEmpty() ? null : onList.get(0); // APP JOIN 应该有且只有一个 ON 条件 @@ -901,7 +900,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @return result * @throws Exception */ - protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd + protected JSONObject onPutColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Join join, Map childMap) throws Exception { if (table == null) { // 对应副表 viceSql 不能生成正常 SQL, 或者是 ! - Outer, ( - ANTI JOIN 的副表这种不需要缓存及返回的数据 Log.i(TAG, "onPutColumn table == null >> return table;"); @@ -935,7 +934,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @return * @throws SQLException */ - protected boolean isHideColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd + protected boolean isHideColumn(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map childMap) throws SQLException { return rsmd.getColumnName(columnIndex).startsWith("_"); } @@ -949,7 +948,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @param table * @return resultList */ - protected List onPutTable(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd + protected List onPutTable(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd , @NotNull List resultList, int position, @NotNull JSONObject table) { resultList.add(table); @@ -958,7 +957,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut - protected String getKey(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd + protected String getKey(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd , final int tablePosition, @NotNull JSONObject table, final int columnIndex, Map childMap) throws Exception { long startTime = System.currentTimeMillis(); String key = rsmd.getColumnLabel(columnIndex); // dotIndex < 0 ? lable : lable.substring(dotIndex + 1); @@ -978,7 +977,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut return key; } - protected Object getValue(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd + protected Object getValue(@NotNull SQLConfig config, @NotNull ResultSet rs, @NotNull ResultSetMetaData rsmd , final int tablePosition, @NotNull JSONObject table, final int columnIndex, String lable, Map childMap) throws Exception { long startTime = System.currentTimeMillis(); @@ -1068,7 +1067,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut * @return */ @Override - public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable) { + public boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable) { try { long startTime = System.currentTimeMillis(); String column = rsmd.getColumnTypeName(position); @@ -1094,11 +1093,11 @@ public abstract class AbstractSQLExecutor implements SQLExecut @Override // 重写是为了返回类型从 Statement 改为 PreparedStatement,避免其它方法出错 - public PreparedStatement getStatement(@NotNull SQLConfig config) throws Exception { + public PreparedStatement getStatement(@NotNull SQLConfig config) throws Exception { return getStatement(config, null); } @Override - public PreparedStatement getStatement(@NotNull SQLConfig config, String sql) throws Exception { + public PreparedStatement getStatement(@NotNull SQLConfig config, String sql) throws Exception { if (StringUtil.isEmpty(sql)) { sql = config.getSQL(config.isPrepared()); } @@ -1150,7 +1149,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut return statement; } - public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNull PreparedStatement statement, int index, Object value) throws SQLException { + public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNull PreparedStatement statement, int index, Object value) throws SQLException { //JSON.isBooleanOrNumberOrString(v) 解决 PostgreSQL: Can't infer the SQL type to use for an instance of com.alibaba.fastjson.JSONArray if (apijson.JSON.isBooleanOrNumberOrString(value)) { statement.setObject(index + 1, value); //PostgreSQL JDBC 不支持隐式类型转换 tinyint = varchar 报错 @@ -1165,7 +1164,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut protected Connection connection; @NotNull @Override - public Connection getConnection(@NotNull SQLConfig config) throws Exception { + public Connection getConnection(@NotNull SQLConfig config) throws Exception { String connectionKey = config.getDatasource() + "-" + config.getDatabase(); connection = connectionMap.get(connectionKey); if (connection == null || connection.isClosed()) { @@ -1346,7 +1345,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut } @Override - public ResultSet executeQuery(@NotNull SQLConfig config, String sql) throws Exception { + public ResultSet executeQuery(@NotNull SQLConfig config, String sql) throws Exception { if (config.isPrepared() == false || config.isTDengine() // TDengine JDBC 不支持 PreparedStatement || (config.isExplain() && (config.isPresto() || config.isTrino()))) { // Presto JDBC 0.277 在 EXPLAIN 模式下预编译值不会替代 ? 占位导致报错 @@ -1371,7 +1370,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut @Override - public int executeUpdate(@NotNull SQLConfig config, String sql) throws Exception { + public int executeUpdate(@NotNull SQLConfig config, String sql) throws Exception { Statement stt; int count; if (config.isTDengine()) { diff --git a/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java b/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java index 189d9d44..ec5aefbd 100644 --- a/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/FunctionParser.java @@ -14,41 +14,41 @@ import apijson.RequestMethod; /**远程函数解析器 * @author Lemon */ -public interface FunctionParser { +public interface FunctionParser { Object invoke(@NotNull String function, @NotNull JSONObject currentObject) throws Exception; Object invoke(@NotNull String function, @NotNull JSONObject currentObject, boolean containRaw) throws Exception; - Parser getParser(); + Parser getParser(); - AbstractFunctionParser setParser(Parser parser); + FunctionParser setParser(Parser parser); RequestMethod getMethod(); - FunctionParser setMethod(RequestMethod method); + FunctionParser setMethod(RequestMethod method); String getTag(); - FunctionParser setTag(String tag); + FunctionParser setTag(String tag); int getVersion(); - AbstractFunctionParser setVersion(int version); + FunctionParser setVersion(int version); @NotNull JSONObject getRequest(); - FunctionParser setRequest(@NotNull JSONObject request); + FunctionParser setRequest(@NotNull JSONObject request); String getKey(); - FunctionParser setKey(String key); + FunctionParser setKey(String key); String getParentPath(); - FunctionParser setParentPath(String parentPath); + FunctionParser setParentPath(String parentPath); String getCurrentName(); - FunctionParser setCurrentName(String currentName); + FunctionParser setCurrentName(String currentName); @NotNull JSONObject getCurrentObject(); - FunctionParser setCurrentObject(@NotNull JSONObject currentObject); + FunctionParser setCurrentObject(@NotNull JSONObject currentObject); diff --git a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java index 2f0b3a3c..6df050e0 100755 --- a/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/ObjectParser.java @@ -18,20 +18,22 @@ import apijson.RequestMethod; /**简化Parser,getObject和getArray(getArrayConfig)都能用 * @author Lemon */ -public interface ObjectParser { +public interface ObjectParser { + + Parser getParser(); + ObjectParser setParser(Parser parser); String getParentPath(); - ObjectParser setParentPath(String parentPath); + ObjectParser setParentPath(String parentPath); /**解析成员 * response重新赋值 - * @param parentPath - * @param name + * @param name * @param isReuse * @return null or this * @throws Exception */ - ObjectParser parse(String name, boolean isReuse) throws Exception; + ObjectParser parse(String name, boolean isReuse) throws Exception; /**调用 parser 的 sqlExecutor 来解析结果 * @param method @@ -43,14 +45,14 @@ public interface ObjectParser { * @return * @throws Exception */ - public JSONObject parseResponse(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception; + JSONObject parseResponse(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception; /**调用 parser 的 sqlExecutor 来解析结果 * @param config * @param isProcedure * @return * @throws Exception */ - public JSONObject parseResponse(SQLConfig config, boolean isProcedure) throws Exception; + JSONObject parseResponse(SQLConfig config, boolean isProcedure) throws Exception; @@ -95,20 +97,20 @@ public interface ObjectParser { * @return {@link #setSQLConfig(int, int, int)} * @throws Exception */ - ObjectParser setSQLConfig() throws Exception; + ObjectParser setSQLConfig() throws Exception; /**SQL 配置 * @return * @throws Exception */ - ObjectParser setSQLConfig(int count, int page, int position) throws Exception; + ObjectParser setSQLConfig(int count, int page, int position) throws Exception; /**执行 SQL * @return * @throws Exception */ - ObjectParser executeSQL() throws Exception; + ObjectParser executeSQL() throws Exception; /** @@ -129,8 +131,8 @@ public interface ObjectParser { void onChildResponse() throws Exception; - SQLConfig newSQLConfig(boolean isProcedure) throws Exception; - SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception; + SQLConfig newSQLConfig(boolean isProcedure) throws Exception; + SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception; /** * response has the final value after parse (and query if isTableKey) @@ -143,7 +145,7 @@ public interface ObjectParser { void recycle(); - ObjectParser setMethod(RequestMethod method); + ObjectParser setMethod(RequestMethod method); RequestMethod getMethod(); @@ -151,9 +153,9 @@ public interface ObjectParser { String getPath(); String getTable(); String getAlias(); - SQLConfig getArrayConfig(); + SQLConfig getArrayConfig(); - SQLConfig getSQLConfig(); + SQLConfig getSQLConfig(); JSONObject getResponse(); JSONObject getSqlRequest(); JSONObject getSqlResponse(); diff --git a/APIJSONORM/src/main/java/apijson/orm/Parser.java b/APIJSONORM/src/main/java/apijson/orm/Parser.java index 65613e8c..969dff95 100755 --- a/APIJSONORM/src/main/java/apijson/orm/Parser.java +++ b/APIJSONORM/src/main/java/apijson/orm/Parser.java @@ -66,7 +66,7 @@ public interface Parser { JSONObject getStructure(String table, String method, String tag, int version) throws Exception; - JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery) throws Exception; + JSONObject onObjectParse(JSONObject request, String parentPath, String name, SQLConfig arrayConfig, boolean isSubquery) throws Exception; JSONArray onArrayParse(JSONObject request, String parentPath, String name, boolean isSubquery) throws Exception; @@ -81,7 +81,7 @@ public interface Parser { */ Object onFunctionParse(String key, String function, String parentPath, String currentName, JSONObject currentObject, boolean containRaw) throws Exception; - ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception; + ObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig, boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception; int getDefaultQueryCount(); int getMaxQueryPage(); @@ -100,11 +100,11 @@ public interface Parser { void onVerifyLogin() throws Exception; void onVerifyContent() throws Exception; - void onVerifyRole(SQLConfig config) throws Exception; + void onVerifyRole(SQLConfig config) throws Exception; - JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception; + JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception; - SQLExecutor getSQLExecutor(); + SQLExecutor getSQLExecutor(); Verifier getVerifier(); diff --git a/APIJSONORM/src/main/java/apijson/orm/SQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/SQLExecutor.java index 0c11b075..2805682e 100755 --- a/APIJSONORM/src/main/java/apijson/orm/SQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/SQLExecutor.java @@ -22,21 +22,21 @@ import apijson.NotNull; */ public interface SQLExecutor { Parser getParser(); - SQLExecutor setParser(Parser parser); + SQLExecutor setParser(Parser parser); /**保存缓存 * @param sql * @param list * @param config */ - void putCache(String sql, List list, SQLConfig config); + void putCache(String sql, List list, SQLConfig config); /**获取缓存 * @param sql * @param config * @return */ - List getCache(String sql, SQLConfig config); + List getCache(String sql, SQLConfig config); /**获取缓存 * @param sql @@ -44,13 +44,13 @@ public interface SQLExecutor { * @param config * @return */ - JSONObject getCacheItem(String sql, int position, SQLConfig config); + JSONObject getCacheItem(String sql, int position, SQLConfig config); /**移除缓存 * @param sql * @param config */ - void removeCache(String sql, SQLConfig config); + void removeCache(String sql, SQLConfig config); /**执行SQL * @param config @@ -58,7 +58,7 @@ public interface SQLExecutor { * @return * @throws Exception */ - JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception; + JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception; //executeQuery和executeUpdate这两个函数因为返回类型不同,所以不好合并 /**执行查询 @@ -66,20 +66,20 @@ public interface SQLExecutor { * @return * @throws SQLException */ - default ResultSet executeQuery(@NotNull SQLConfig config) throws Exception { + default ResultSet executeQuery(@NotNull SQLConfig config) throws Exception { return executeQuery(config, null); } - ResultSet executeQuery(@NotNull SQLConfig config, String sql) throws Exception; + ResultSet executeQuery(@NotNull SQLConfig config, String sql) throws Exception; /**执行增、删、改 * @param config * @return * @throws SQLException */ - default int executeUpdate(@NotNull SQLConfig config) throws Exception { + default int executeUpdate(@NotNull SQLConfig config) throws Exception { return executeUpdate(config, null); } - int executeUpdate(@NotNull SQLConfig config, String sql) throws Exception; + int executeUpdate(@NotNull SQLConfig config, String sql) throws Exception; /**判断是否为JSON类型 @@ -89,14 +89,14 @@ public interface SQLExecutor { * @param lable * @return */ - boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable); + boolean isJSONType(@NotNull SQLConfig config, ResultSetMetaData rsmd, int position, String lable); - Connection getConnection(@NotNull SQLConfig config) throws Exception; - default Statement getStatement(@NotNull SQLConfig config) throws Exception { + Connection getConnection(@NotNull SQLConfig config) throws Exception; + default Statement getStatement(@NotNull SQLConfig config) throws Exception { return getStatement(config, null); } - Statement getStatement(@NotNull SQLConfig config, String sql) throws Exception; + Statement getStatement(@NotNull SQLConfig config, String sql) throws Exception; int getTransactionIsolation(); void setTransactionIsolation(int transactionIsolation); From 2b0d612770d95a218aebe113e4f9aaa54aac63be Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 10 Sep 2023 05:17:40 +0800 Subject: [PATCH 14/15] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A9=BC=E5=B3=B0?= =?UTF-8?q?=E4=B8=8E=E8=9B=87=E5=BD=A2=E5=91=BD=E5=90=8D=E4=BA=92=E8=BD=AC?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=BB=A5=E5=8F=8A=20JSONResponse.IS=5FFORMAT?= =?UTF-8?q?=5FUNDERLINE=20=E7=AD=89=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/JSONRequest.java | 67 ++++++++++ .../src/main/java/apijson/JSONResponse.java | 123 +++++++++++++----- 2 files changed, 160 insertions(+), 30 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/JSONRequest.java b/APIJSONORM/src/main/java/apijson/JSONRequest.java index 8707cc2c..cf64f187 100755 --- a/APIJSONORM/src/main/java/apijson/JSONRequest.java +++ b/APIJSONORM/src/main/java/apijson/JSONRequest.java @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import static apijson.StringUtil.PATTERN_ALPHA_BIG; + /**wrapper for request * @author Lemon * @see #puts @@ -196,4 +198,69 @@ public class JSONRequest extends JSONObject { return this; } + + /**ABCdEfg => upper ? A-B-CD-EFG : a-b-cd-efg + * @param key + * @return + */ + public static String recoverHyphen(@NotNull String key, Boolean upper) { + return recoverDivider(key, "-", upper); + } + + /**ABCdEfg => upper ? A_B_CD_EFG : a_b_cd_efg + * @param key + * @return + */ + public static String recoverUnderline(@NotNull String key, Boolean upper) { + return recoverDivider(key, "_", upper); + } + + /**ABCdEfg => upper ? A$B$CD$EFG : a$b$cd$efg + * @param key + * @return + */ + public static String recoverDollar(@NotNull String key, Boolean upper) { + return recoverDivider(key, "$", upper); + } + + /**ABCdEfg => upper ? A.B.CD.EFG : a.b.cd.efg + * @param key + * @return + */ + public static String recoverDot(@NotNull String key, Boolean upper) { + return recoverDivider(key, ".", upper); + } + + /**ABCdEfg => upper ? A_B_CD_EFG : a/b/cd/efg + * @param key + * @return + */ + public static String recoverDivider(@NotNull String key, Boolean upper) { + return recoverDivider(key, "/", upper); + } + + /**驼峰格式转为带分隔符的全大写或全小写格式 + * @param key + * @param divider + * @param upper + * @return + */ + public static String recoverDivider(@NotNull String key, @NotNull String divider, Boolean upper) { + StringBuilder name = new StringBuilder(); + char[] cs = key.toCharArray(); + int len = key.length(); + for (int i = 0; i < len; i++) { + String s = key.substring(i, i + 1); + if (i > 0 && PATTERN_ALPHA_BIG.matcher(s).matches()) { + name.append(divider); + } + if (upper != null) { + s = upper ? s.toUpperCase() : s.toLowerCase(); + } + name.append(s); + } + return name.toString(); + } + + } diff --git a/APIJSONORM/src/main/java/apijson/JSONResponse.java b/APIJSONORM/src/main/java/apijson/JSONResponse.java index c69955c3..9f61edad 100755 --- a/APIJSONORM/src/main/java/apijson/JSONResponse.java +++ b/APIJSONORM/src/main/java/apijson/JSONResponse.java @@ -5,13 +5,12 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson; -import java.util.List; -import java.util.Set; -import java.util.StringTokenizer; - import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import java.util.List; +import java.util.Set; + /**parser for response * @author Lemon * @see #getObject @@ -23,6 +22,17 @@ import com.alibaba.fastjson.JSONObject; public class JSONResponse extends apijson.JSONObject { private static final long serialVersionUID = 1L; + // 节约性能和减少 bug,除了关键词 @key ,一般都符合变量命名规范,不符合也原样返回便于调试 + /**格式化带 - 中横线的单词 + */ + public static boolean IS_FORMAT_HYPHEN = false; + /**格式化带 _ 下划线的单词 + */ + public static boolean IS_FORMAT_UNDERLINE = false; + /**格式化带 $ 美元符的单词 + */ + public static boolean IS_FORMAT_DOLLAR = false; + private static final String TAG = "JSONResponse"; public JSONResponse() { @@ -206,10 +216,6 @@ public class JSONResponse extends apijson.JSONObject { //状态信息,非GET请求获得的信息>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - - /** * key = clazz.getSimpleName() * @param clazz @@ -408,18 +414,18 @@ public class JSONResponse extends apijson.JSONObject { /**获取变量名 * @param fullName - * @return {@link #formatKey(String, boolean, boolean, boolean, boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true + * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true */ public static String getVariableName(String fullName) { if (isArrayKey(fullName)) { fullName = StringUtil.addSuffix(fullName.substring(0, fullName.length() - 2), "list"); } - return formatKey(fullName, true, true, true, true); + return formatKey(fullName, true, true, true, true, false, true); } /**格式化数组的名称 key[] => keyList; key:alias[] => aliasList; Table-column[] => tableColumnList * @param key empty ? "list" : key + "List" 且首字母小写 - * @return {@link #formatKey(String, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = true, firstCase = true + * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = true, firstCase = true */ public static String formatArrayKey(String key) { if (isArrayKey(key)) { @@ -430,28 +436,29 @@ public class JSONResponse extends apijson.JSONObject { return key.substring(index + 1); //不处理自定义的 } - return formatKey(key, false, true, true, true); //节约性能,除了数组对象 Table-column:alias[] ,一般都符合变量命名规范 + return formatKey(key, false, true, true, IS_FORMAT_UNDERLINE, IS_FORMAT_DOLLAR, false); //节约性能,除了数组对象 Table-column:alias[] ,一般都符合变量命名规范 } /**格式化对象的名称 name => name; name:alias => alias * @param key name 或 name:alias - * @return {@link #formatKey(String, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = true + * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = true */ public static String formatObjectKey(String key) { int index = key == null ? -1 : key.indexOf(":"); if (index >= 0) { - return key.substring(index + 1); //不处理自定义的 + return key.substring(index + 1); // 不处理自定义的 } - return formatKey(key, false, true, false, true); //节约性能,除了表对象 Table:alias ,一般都符合变量命名规范 + return formatKey(key, false, true, IS_FORMAT_HYPHEN, IS_FORMAT_UNDERLINE, IS_FORMAT_DOLLAR, false); //节约性能,除了表对象 Table:alias ,一般都符合变量命名规范 } /**格式化普通值的名称 name => name; name:alias => alias * @param fullName name 或 name:alias - * @return {@link #formatKey(String, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = false + * @return {@link #formatKey(String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = false */ public static String formatOtherKey(String fullName) { - return formatKey(fullName, false, true, false, false); //节约性能,除了关键词 @key ,一般都符合变量命名规范,不符合也原样返回便于调试 + return formatKey(fullName, false, true, IS_FORMAT_HYPHEN, IS_FORMAT_UNDERLINE, IS_FORMAT_DOLLAR + , IS_FORMAT_HYPHEN || IS_FORMAT_UNDERLINE || IS_FORMAT_DOLLAR ? false : null); } @@ -460,10 +467,13 @@ public class JSONResponse extends apijson.JSONObject { * @param formatAt 去除前缀 @ , @a => a * @param formatColon 去除分隔符 : , A:b => b * @param formatHyphen 去除分隔符 - , A-b-cd-Efg => aBCdEfg + * @param formatUnderline 去除分隔符 _ , A_b_cd_Efg => aBCdEfg + * @param formatDollar 去除分隔符 $ , A$b$cd$Efg => aBCdEfg * @param firstCase 第一个单词首字母小写,后面的首字母大写, Ab => ab ; A-b-Cd => aBCd * @return name => name; name:alias => alias */ - public static String formatKey(String fullName, boolean formatColon, boolean formatAt, boolean formatHyphen, boolean firstCase) { + public static String formatKey(String fullName, boolean formatColon, boolean formatAt, boolean formatHyphen + , boolean formatUnderline, boolean formatDollar, Boolean firstCase) { if (fullName == null) { Log.w(TAG, "formatKey fullName == null >> return null;"); return null; @@ -476,10 +486,17 @@ public class JSONResponse extends apijson.JSONObject { fullName = formatAt(fullName); } if (formatHyphen) { - fullName = formatHyphen(fullName, firstCase); + fullName = formatHyphen(fullName, firstCase != null); + } + if (formatUnderline) { + fullName = formatUnderline(fullName, firstCase != null); + } + if (formatDollar) { + fullName = formatDollar(fullName, firstCase != null); } - return firstCase ? StringUtil.firstCase(fullName) : fullName; //不格式化普通 key:value (value 不为 [], {}) 的 key + // 默认不格式化普通 key:value (value 不为 [], {}) 的 key + return firstCase == null ? fullName : StringUtil.firstCase(fullName, firstCase); } /**"@key" => "key" @@ -489,6 +506,7 @@ public class JSONResponse extends apijson.JSONObject { public static String formatAt(@NotNull String key) { return key.startsWith("@") ? key.substring(1) : key; } + /**key:alias => alias * @param key * @return @@ -502,15 +520,60 @@ public class JSONResponse extends apijson.JSONObject { * @param key * @return */ - public static String formatHyphen(@NotNull String key, boolean firstCase) { - String name = ""; - - StringTokenizer parts = new StringTokenizer(key, "-"); - name += parts.nextToken(); - while(parts.hasMoreTokens()) { - String part = parts.nextToken(); - name += firstCase ? StringUtil.firstCase(part, true) : part; - } - return name; + public static String formatHyphen(@NotNull String key, Boolean firstCase) { + return formatDivider(key, "-", firstCase); } + + /**A_b_cd_Efg => ABCdEfg + * @param key + * @return + */ + public static String formatUnderline(@NotNull String key, Boolean firstCase) { + return formatDivider(key, "_", firstCase); + } + + /**A$b$cd$Efg => ABCdEfg + * @param key + * @return + */ + public static String formatDollar(@NotNull String key, Boolean firstCase) { + return formatDivider(key, "$", firstCase); + } + + /**A.b.cd.Efg => ABCdEfg + * @param key + * @return + */ + public static String formatDot(@NotNull String key, Boolean firstCase) { + return formatDivider(key, ".", firstCase); + } + + /**A/b/cd/Efg => ABCdEfg + * @param key + * @return + */ + public static String formatDivider(@NotNull String key, Boolean firstCase) { + return formatDivider(key, "/", firstCase); + } + + /**去除分割符,返回驼峰格式 + * @param key + * @param divider + * @param firstCase + * @return + */ + public static String formatDivider(@NotNull String key, @NotNull String divider, Boolean firstCase) { + String[] parts = StringUtil.split(key, divider); + StringBuilder name = new StringBuilder(); + for (String part : parts) { + part = part.toLowerCase(); // 始终小写,也方便反过来 ABCdEfg -> A_b_cd_Efg + if (firstCase != null) { + // 始终小写, A_b_cd_Efg -> ABCdEfg, firstCase ? part.toLowerCase() : part.toUpperCase(); + part = StringUtil.firstCase(part, firstCase); + } + name.append(part); + } + return name.toString(); + } + } From 371cd0bcf0b8cf5f19f26d1034e527143843fef9 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 17 Sep 2023 23:22:54 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=86=E4=BA=AB?= =?UTF-8?q?=E6=96=87=E7=AB=A0=E6=96=B0=E5=A2=9E=20MassCMS=20With=20APIJSON?= =?UTF-8?q?=E6=9C=80=E4=BD=B3=E5=AE=9E=E8=B7=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 感谢博主的热心分享,点赞支持下吧~ https://zhuanlan.zhihu.com/p/655826966 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9a53bc6f..6fe127e4 100644 --- a/README.md +++ b/README.md @@ -584,6 +584,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson 初探](https://www.cnblogs.com/x3d/p/apijson-lowcode.html) [APIJSON使用介绍](http://api.flyrise.cn:9099/docs/open-docs//1459) + +[MassCMS With APIJSON最佳实践](https://zhuanlan.zhihu.com/p/655826966) ### 生态项目 [APIJSON-Demo](https://github.com/APIJSON/APIJSON-Demo) APIJSON 各种语言、各种框架 的 使用示例项目、上手文档、测试数据 SQL 文件 等