From c03d0d31eca5470c86b74462411691627d6cd928 Mon Sep 17 00:00:00 2001 From: guanlinc <437663002@qq.com> Date: Thu, 14 Mar 2024 21:16:51 +0800 Subject: [PATCH 01/47] =?UTF-8?q?RN=E5=88=97=E6=95=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E5=8F=8C=E5=BC=95=E5=8F=B7=EF=BC=8C=E9=81=B5?= =?UTF-8?q?=E5=BE=AA=E6=95=B0=E6=8D=AE=E5=BA=93=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 278b5e15..c39fd9d4 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -4592,9 +4592,9 @@ public abstract class AbstractSQLConfig implements SQLConfig " + offset; + String quote = getQuote(); + return "SELECT * FROM (SELECT " + alias + ".*, ROWNUM "+ quote + "RN" + quote +" FROM (" + sql + ") " + alias + + " WHERE ROWNUM <= " + (offset + count) + ") WHERE "+ quote + "RN" + quote +" > " + offset; } /**获取条件SQL字符串 -- Gitee From ac186678dc1bc4a4a2f399034aebebd641d188b8 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 18 Mar 2024 22:20:20 +0800 Subject: [PATCH 02/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20Mi?= =?UTF-8?q?lvus-AI=20=E5=90=91=E9=87=8F=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E3=80=81InfluxDB-=E7=89=A9=E8=81=94=E7=BD=91=E6=97=B6=E5=BA=8F?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E3=80=81MongoDB&Cassandra-NoSQL=20?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=20=E7=9A=84=204=20=E4=B8=AA=20APIJS?= =?UTF-8?q?ON=20=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON#%E7%94%9F%E6%80%81%E9%A1%B9%E7%9B%AE --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 0f70ad51..e64f3c66 100644 --- a/README.md +++ b/README.md @@ -602,6 +602,14 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-column](https://github.com/APIJSON/apijson-column) APIJSON 的字段插件,支持 字段名映射 和 !key 反选字段 +[apijson-milvus](https://github.com/APIJSON/apijson-milvus) APIJSON 的 Milvus AI 向量数据库插件 + +[apijson-influxdb](https://github.com/APIJSON/apijson-influxdb) APIJSON 的 InfluxDB 物联网时序数据库插件 + +[apijson-mongodb](https://github.com/APIJSON/apijson-mongodb) APIJSON 的 MongoDB NoSQL 数据库插件 + +[apijson-cassandra](https://github.com/APIJSON/apijson-cassandra) APIJSON 的 Cassandra NoSQL 数据库插件 + [APIAuto](https://github.com/TommyLemon/APIAuto) 敏捷开发最强大易用的接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 [UnitAuto](https://github.com/TommyLemon/UnitAuto) 机器学习零代码单元测试平台,零代码、全方位、自动化 测试 方法/函数 的正确性、可用性和性能 -- Gitee From a763bf6afa6c3a56dac60bd55bc2848f5ef3ce2e Mon Sep 17 00:00:00 2001 From: jia199807 <44639807+jia199807@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:04:57 +0800 Subject: [PATCH 03/47] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 企业登记 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e64f3c66..da55a1d5 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ https://github.com/Tencent/APIJSON/issues/187 * [邻盛科技(武汉)有限公司](http://www.linksame.com) * [上海麦市信息科技有限公司](https://www.masscms.com) * [上海翊丞互联网科技有限公司](http://www.renrencjl.com/home) + * [上海直真君智科技有限公司](http://www.zzjunzhi.com) ### 贡献者们 主项目 APIJSON 的贡献者们(6 个腾讯工程师、1 个微软工程师、1 个阿里云工程师、1 个字节跳动工程师、1 个网易工程师、1 个 Zoom 工程师、1 个圆通工程师、1 个知乎基础研发架构师、1 个智联招聘工程师、1 个美国加州大学学生、3 个 SUSTech 学生等):
-- Gitee From 7403f0a7471819ae8897c2fa56ea7eea4ab9c4c7 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 21 Apr 2024 11:36:21 +0800 Subject: [PATCH 04/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8C=85=E6=8B=AC?= =?UTF-8?q?=E8=80=81=E5=A4=96=E5=9C=A8=E5=86=85=E7=9A=84=2011=20=E4=B8=AA?= =?UTF-8?q?=E8=B4=A1=E7=8C=AE=E8=80=85=EF=BC=8C=E6=84=9F=E8=B0=A2=E5=A4=A7?= =?UTF-8?q?=E5=AE=B6=E7=9A=84=E8=B4=A1=E7=8C=AE~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E8%B4%A1%E7%8C%AE%E8%80%85%E4%BB%AC --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index da55a1d5..86399e40 100644 --- a/README.md +++ b/README.md @@ -407,6 +407,17 @@ https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md
+ + + + + + + + + + +
-- Gitee From 9f6272478ac5db11d7389225fc47eae91aa72974 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 19 May 2024 17:27:56 +0800 Subject: [PATCH 05/47] =?UTF-8?q?=E5=A4=A7=E6=95=B0=E8=BD=AC=20String=20?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=EF=BC=8C=E9=81=BF=E5=85=8D=E5=89=8D=E7=AB=AF?= =?UTF-8?q?/=E5=AE=A2=E6=88=B7=E7=AB=AF=E6=8B=BF=E5=88=B0=E7=B2=BE?= =?UTF-8?q?=E5=BA=A6=E4=B8=A2=E5=A4=B1=E7=94=9A=E8=87=B3=E4=B8=A5=E9=87=8D?= =?UTF-8?q?=E5=A4=B1=E7=9C=9F=E7=9A=84=E5=80=BC=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=87=8D=E5=86=99=20getNumVal=20=E6=9D=A5=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractSQLExecutor.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index e4b38d0b..bb476783 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -6,6 +6,8 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; import java.io.BufferedReader; +import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; @@ -995,9 +997,12 @@ public abstract class AbstractSQLExecutor implements SQLExecut boolean castToJson = false; //数据库查出来的null和empty值都有意义,去掉会导致 Moment:{ @column:"content" } 部分无结果及中断数组查询! - if (value instanceof Boolean || value instanceof Number) { + if (value instanceof Boolean) { //加快判断速度 } + else if (value instanceof Number) { + value = getNumVal((Number) value); + } else if (value instanceof Timestamp) { value = ((Timestamp) value).toString(); } @@ -1058,6 +1063,27 @@ public abstract class AbstractSQLExecutor implements SQLExecut return value; } + public Object getNumVal(Number value) { + if (value == null) { + return null; + } + + if (value instanceof BigInteger) { + return ((BigInteger) value).toString(); + } + + if (value instanceof BigDecimal) { + return ((BigDecimal) value).toString(); + } + + double v = value.doubleValue(); + if (v > Integer.MAX_VALUE || v < Integer.MIN_VALUE) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 + return value.toString(); + } + + return value; + } + /**判断是否为JSON类型 * @param config -- Gitee From 4a2e7f590de7db7c3133736edbe584a229bfc1e6 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 19 May 2024 17:38:44 +0800 Subject: [PATCH 06/47] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=B8=BA=207.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/pom.xml | 4 ++-- APIJSONORM/src/main/java/apijson/Log.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index a3ecc333..45f4522c 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -4,8 +4,8 @@ 4.0.0 com.github.Tencent - APIJSON-spring-boot3 - 6.4.3 + APIJSON + 7.0.0 jar APIJSONORM diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java index a0201331..3bdad052 100755 --- a/APIJSONORM/src/main/java/apijson/Log.java +++ b/APIJSONORM/src/main/java/apijson/Log.java @@ -14,7 +14,7 @@ public class Log { public static boolean DEBUG = true; - public static final String VERSION = "6.4.3"; + public static final String VERSION = "7.0.0"; public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n"; public static final String OS_NAME; -- Gitee From aab39ff28dc65982ae5a5bec35af86cc40270b78 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 19 May 2024 23:28:06 +0800 Subject: [PATCH 07/47] =?UTF-8?q?=E6=95=B0=E5=AD=97=E8=BD=AC=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E8=8C=83=E5=9B=B4=E4=BC=98=E5=8C=96=E4=B8=BA?= =?UTF-8?q?=20JavaScript=20=E7=9A=84=20Number.MAX=5FSAFE=5FINTEGER=20~=20N?= =?UTF-8?q?umber.MIN=5FSAFE=5FINTEGER?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/orm/AbstractSQLExecutor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index bb476783..03cd3506 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -1077,10 +1077,14 @@ public abstract class AbstractSQLExecutor implements SQLExecut } double v = value.doubleValue(); - if (v > Integer.MAX_VALUE || v < Integer.MIN_VALUE) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 + // if (v > Integer.MAX_VALUE || v < Integer.MIN_VALUE) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 + // return value.toString(); + // } + // JavaScript: Number.MAX_SAFE_INTEGER ~ Number.MIN_SAFE_INTEGER + if (v > 9007199254740991L || v < -9007199254740991) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 return value.toString(); } - + return value; } -- Gitee From 75902360ef1ba27661259a91d2eccb99817e1bbb Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 19 May 2024 23:29:02 +0800 Subject: [PATCH 08/47] JavaScript: Number.MAX_SAFE_INTEGER ~ Number.MIN_SAFE_INTEGER --- APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index 03cd3506..426a53ee 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -1081,7 +1081,7 @@ public abstract class AbstractSQLExecutor implements SQLExecut // return value.toString(); // } // JavaScript: Number.MAX_SAFE_INTEGER ~ Number.MIN_SAFE_INTEGER - if (v > 9007199254740991L || v < -9007199254740991) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 + if (v > 9007199254740991L || v < -9007199254740991L) { // 避免前端/客户端拿到精度丢失甚至严重失真的值 return value.toString(); } -- Gitee From 482368c6ef8b20cb5363477f5d754a3deeff2692 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 19 May 2024 23:30:03 +0800 Subject: [PATCH 09/47] Update README-English.md --- README-English.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-English.md b/README-English.md index 3cd37214..4d4aacb1 100644 --- a/README-English.md +++ b/README-English.md @@ -7,7 +7,7 @@ This source code is licensed under the Apache License Version 2.0
-

🏆 Tencent Top 8 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀
A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.

+

🏆 Tencent Top 7 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀
A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.

 中文版  -- Gitee From b70ee9074e3e6ff30b17f52340408f9f829f4067 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 19 May 2024 23:32:54 +0800 Subject: [PATCH 10/47] =?UTF-8?q?=E8=85=BE=E8=AE=AF=E5=86=85=E5=A4=96=205?= =?UTF-8?q?=20=E4=B8=AA=E5=A5=96=E9=A1=B9=E3=80=81=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E5=BC=80=E6=BA=90=E5=89=8D=E4=B8=83=E3=80=81GitHub=20Java=20To?= =?UTF-8?q?p=20100=E3=80=81Trending=20=E6=97=A5=E5=91=A8=E6=9C=88=E6=A6=9C?= =?UTF-8?q?=E5=A4=A7=E6=BB=A1=E8=B4=AF=20=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON/tree/master?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86399e40..9f7dd24a 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ https://github.com/Tencent/APIJSON/wiki * **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) * **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) * **社区影响力大** (GitHub 16K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) -* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前八、腾讯后端 Star 第一、GitHub Java 日周月榜大满贯 等) +* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、GitHub Java Top 100、Trending 日周月榜大满贯 等) * **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等) * **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目) * **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等) -- Gitee From 4d199a1591aec3ce6e2901b64720cd21fcf959dc Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 25 May 2024 22:52:03 +0800 Subject: [PATCH 11/47] =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E3=80=8AAPIJSON=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=EF=BC=8C=E8=B6=85=E8=AF=A6=E7=BB=86=E3=80=8B?= =?UTF-8?q?=EF=BC=8C=E6=84=9F=E8=B0=A2=E4=BD=9C=E8=80=85=E7=9A=84=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 点赞、收藏、转发支持热心的作者吧 ^_^ https://juejin.cn/post/7370950331599306806 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9f7dd24a..0f2290e2 100644 --- a/README.md +++ b/README.md @@ -602,6 +602,9 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [APIJSON使用介绍](http://api.flyrise.cn:9099/docs/open-docs//1459) [MassCMS With APIJSON最佳实践](https://zhuanlan.zhihu.com/p/655826966) + +[APIJSON语法使用,超详细](https://juejin.cn/post/7370950331599306806) + ### 生态项目 [APIJSON-Demo](https://github.com/APIJSON/APIJSON-Demo) APIJSON 各种语言、各种框架 的 使用示例项目、上手文档、测试数据 SQL 文件 等 -- Gitee From 72996e95507e0de4201294e34d01bbbdc97136f0 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 27 May 2024 00:45:20 +0800 Subject: [PATCH 12/47] =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E3=80=8AAPIJSON=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=EF=BC=8C=E8=B6=85=E8=AF=A6=E7=BB=86=E3=80=8B?= =?UTF-8?q?=EF=BC=8C=E6=84=9F=E8=B0=A2=E4=BD=9C=E8=80=85=E7=9A=84=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 点赞、收藏、转发支持热心的作者吧 ^_^ https://blog.csdn.net/qq_36565607/article/details/139167040 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f2290e2..ad60c57f 100644 --- a/README.md +++ b/README.md @@ -603,7 +603,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [MassCMS With APIJSON最佳实践](https://zhuanlan.zhihu.com/p/655826966) -[APIJSON语法使用,超详细](https://juejin.cn/post/7370950331599306806) +[APIJSON语法使用,超详细](https://blog.csdn.net/qq_36565607/article/details/139167040) ### 生态项目 -- Gitee From 5e4e848dde5984cd89fff27955a15862e4ae4d21 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Jun 2024 15:49:25 +0800 Subject: [PATCH 13/47] =?UTF-8?q?Java=20=E7=89=88=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E6=98=AF=E5=9B=BD=E5=86=85=E9=A1=B6=E7=BA=A7=E3=80=81=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E4=B8=80=E6=B5=81=E7=9A=84=20Java=20=E5=BC=80?= =?UTF-8?q?=E6=BA=90=E9=A1=B9=E7=9B=AE=E4=BA=86=20-=20=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E5=BC=80=E6=BA=90=E6=8C=87=E5=8D=97=E9=92=88=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON#%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ad60c57f..28ac0178 100644 --- a/README.md +++ b/README.md @@ -488,6 +488,8 @@ https://search.gitee.com/?skin=rec&type=repository&q=apijson&sort=stars_count image +根据开源指南针报告,APIJSON Java 版已经是国内顶级、国际一流的 Java 开源项目了 [#518](https://github.com/Tencent/APIJSON/issues/518)
+image ### 规划及路线图 新增功能、强化安全、提高性能、增强稳定、完善文档、丰富周边、推广使用
-- Gitee From 201c078083a4c8aa59e0aa93f24af6ab18728ec8 Mon Sep 17 00:00:00 2001 From: Bill <1594805355@qq.com> Date: Sun, 2 Jun 2024 17:02:21 +0800 Subject: [PATCH 14/47] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=92=8C?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=20TABLE=5FSCHEMA=5FMAP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractSQLConfig.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index c39fd9d4..8c2339dc 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -130,6 +130,11 @@ public abstract class AbstractSQLConfig implements SQLConfig TABLE_SCHEMA_MAP; + /** * 表名映射,隐藏真实表名,对安全要求很高的表可以这么做 */ @@ -157,6 +162,19 @@ public abstract class AbstractSQLConfig implements SQLConfig\\|\\[\\]\\{\\} /\\.\\+\\-\\*\\^\\?\\(\\)\\$]+$"); + TABLE_SCHEMA_MAP = new HashMap<>(); + TABLE_SCHEMA_MAP.put(Table.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(Column.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(PgClass.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(PgAttribute.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(SysTable.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(SysColumn.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(ExtendedProperty.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(AllTable.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(AllColumn.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(AllTableComment.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_SCHEMA_MAP.put(AllColumnComment.class.getSimpleName(), DEFAULT_SCHEMA); + TABLE_KEY_MAP = new HashMap<>(); TABLE_KEY_MAP.put(Table.class.getSimpleName(), Table.TABLE_NAME); TABLE_KEY_MAP.put(Column.class.getSimpleName(), Column.TABLE_NAME); @@ -1320,7 +1338,8 @@ public abstract class AbstractSQLConfig implements SQLConfig Date: Sun, 2 Jun 2024 17:13:13 +0800 Subject: [PATCH 15/47] =?UTF-8?q?getSQLSchema=20=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E4=BC=98=E5=85=88=E7=BA=A7=E5=A4=84=E7=90=86=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/orm/AbstractSQLConfig.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 8c2339dc..6b714e58 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -1323,7 +1323,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig Date: Sun, 16 Jun 2024 19:22:15 +0800 Subject: [PATCH 16/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20ke?= =?UTF-8?q?y[]:{=20query:2=20=E6=88=96=20query:"All"=20}=20=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E8=BF=94=E5=9B=9E=E5=88=97=E8=A1=A8=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractObjectParser.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index e6442013..6b169235 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -27,6 +27,7 @@ import java.util.Map.Entry; import static apijson.JSONObject.KEY_COMBINE; import static apijson.JSONObject.KEY_DROP; import static apijson.JSONObject.KEY_TRY; +import static apijson.JSONRequest.KEY_QUERY; import static apijson.RequestMethod.POST; import static apijson.RequestMethod.PUT; import static apijson.orm.SQLConfig.TYPE_ITEM; @@ -555,8 +556,22 @@ public abstract class AbstractObjectParser implements ObjectPa } } + String query = value.getString(KEY_QUERY); child = parser.onArrayParse(value, path, key, isSubquery); isEmpty = child == null || ((JSONArray) child).isEmpty(); + + if (isEmpty == false && ("2".equals(query) || "ALL".equals(query))) { + String infoKey = JSONResponse.formatArrayKey(key) + "Info"; + if (request.containsKey("total@") == false && request.containsKey(infoKey + "@") == false) { + // onParse("total@", "/" + key + "/total"); + // onParse(infoKey + "@", "/" + key + "/info"); + // 替换为以下性能更好、对流程干扰最小的方式: + String totalPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/total"); + String infoPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/info"); + response.put("total", onReferenceParse(totalPath)); + response.put(infoKey, onReferenceParse(infoPath)); + } + } } else { //APIJSON Object boolean isTableKey = JSONRequest.isTableKey(Pair.parseEntry(key, true).getKey()); -- Gitee From 8715e1298d1303b6ead6abd2f5d87cf91c529959 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 16 Jun 2024 19:24:00 +0800 Subject: [PATCH 17/47] =?UTF-8?q?key[]:{=20query:2=20=E6=88=96=20query:"Al?= =?UTF-8?q?l"=20}=20=E5=9C=A8=E5=B7=B2=E6=9C=89=20total=20=E5=92=8C=20keyL?= =?UTF-8?q?istInfo=20=E5=AD=97=E6=AE=B5=E6=97=B6=E4=B8=8D=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E9=BB=98=E8=AE=A4=E7=9A=84=E5=88=97=E8=A1=A8=E5=88=86?= =?UTF-8?q?=E9=A1=B5=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 6b169235..23b9b271 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -562,7 +562,8 @@ public abstract class AbstractObjectParser implements ObjectPa if (isEmpty == false && ("2".equals(query) || "ALL".equals(query))) { String infoKey = JSONResponse.formatArrayKey(key) + "Info"; - if (request.containsKey("total@") == false && request.containsKey(infoKey + "@") == false) { + if (request.containsKey("total") == false && request.containsKey(infoKey) == false + && request.containsKey("total@") == false && request.containsKey(infoKey + "@") == false) { // onParse("total@", "/" + key + "/total"); // onParse(infoKey + "@", "/" + key + "/info"); // 替换为以下性能更好、对流程干扰最小的方式: -- Gitee From 09a60dc89191c5ab2c6fa6ff21c663e7a69cfced Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 16 Jun 2024 19:31:27 +0800 Subject: [PATCH 18/47] =?UTF-8?q?key[]:{=20query:2=20=E6=88=96=20query:"Al?= =?UTF-8?q?l"=20}=20=E9=BB=98=E8=AE=A4=E8=BF=94=E5=9B=9E=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E4=BF=A1=E6=81=AF=20=E8=B0=83=E6=95=B4=20tot?= =?UTF-8?q?al=20=E7=9A=84=20key=20=E5=90=8D=EF=BC=8C=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E5=90=8C=E7=BA=A7=E5=A4=9A=E5=88=97=E8=A1=A8=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E9=87=8D=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/orm/AbstractObjectParser.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 23b9b271..03b41997 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -561,15 +561,16 @@ public abstract class AbstractObjectParser implements ObjectPa isEmpty = child == null || ((JSONArray) child).isEmpty(); if (isEmpty == false && ("2".equals(query) || "ALL".equals(query))) { + String totalKey = JSONResponse.formatArrayKey(key) + "Total"; String infoKey = JSONResponse.formatArrayKey(key) + "Info"; - if (request.containsKey("total") == false && request.containsKey(infoKey) == false - && request.containsKey("total@") == false && request.containsKey(infoKey + "@") == false) { + if ((request.containsKey(totalKey) || request.containsKey(infoKey) + || request.containsKey(totalKey + "@") || request.containsKey(infoKey + "@")) == false) { // onParse("total@", "/" + key + "/total"); // onParse(infoKey + "@", "/" + key + "/info"); // 替换为以下性能更好、对流程干扰最小的方式: String totalPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/total"); String infoPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/info"); - response.put("total", onReferenceParse(totalPath)); + response.put(totalKey, onReferenceParse(totalPath)); response.put(infoKey, onReferenceParse(infoPath)); } } -- Gitee From 0093589068d7962719798e665c4bc49c7074a3cb Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 16 Jun 2024 23:02:39 +0800 Subject: [PATCH 19/47] =?UTF-8?q?key[]:{=20query:2=20=E6=88=96=20query:"Al?= =?UTF-8?q?l"=20}=20=E8=A7=A3=E5=86=B3=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA=E4=B8=8D=E8=BF=94=E5=9B=9E=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=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 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java index 03b41997..94e2020d 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java @@ -560,7 +560,7 @@ public abstract class AbstractObjectParser implements ObjectPa child = parser.onArrayParse(value, path, key, isSubquery); isEmpty = child == null || ((JSONArray) child).isEmpty(); - if (isEmpty == false && ("2".equals(query) || "ALL".equals(query))) { + if ("2".equals(query) || "ALL".equals(query)) { // 不判断 isEmpty,因为分页数据可能只是某页没有 String totalKey = JSONResponse.formatArrayKey(key) + "Total"; String infoKey = JSONResponse.formatArrayKey(key) + "Info"; if ((request.containsKey(totalKey) || request.containsKey(infoKey) @@ -568,8 +568,10 @@ public abstract class AbstractObjectParser implements ObjectPa // onParse("total@", "/" + key + "/total"); // onParse(infoKey + "@", "/" + key + "/info"); // 替换为以下性能更好、对流程干扰最小的方式: - String totalPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/total"); - String infoPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key + "/info"); + + String keyPath = AbstractParser.getValuePath(type == TYPE_ITEM ? path : parentPath, "/" + key); + String totalPath = keyPath + "/total"; + String infoPath = keyPath + "/info"; response.put(totalKey, onReferenceParse(totalPath)); response.put(infoKey, onReferenceParse(infoPath)); } -- Gitee From abe10a270ac7f4b19d8a46bf739cbfc9211e3d90 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 16 Jun 2024 23:04:33 +0800 Subject: [PATCH 20/47] =?UTF-8?q?=E8=85=BE=E8=AE=AF=E5=86=85=E5=A4=96=205?= =?UTF-8?q?=20=E4=B8=AA=E5=A5=96=E9=A1=B9=E3=80=81=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E5=BC=80=E6=BA=90=E5=89=8D=E4=B8=83=E3=80=81=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=20Star=20=E7=AC=AC=E4=B8=80=E3=80=81Trending?= =?UTF-8?q?=20=E6=97=A5=E5=91=A8=E6=9C=88=E6=A6=9C=E5=A4=A7=E6=BB=A1?= =?UTF-8?q?=E8=B4=AF=20=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28ac0178..8d6afdad 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ https://github.com/Tencent/APIJSON/wiki * **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) * **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) * **社区影响力大** (GitHub 16K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) -* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、GitHub Java Top 100、Trending 日周月榜大满贯 等) +* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) * **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等) * **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目) * **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等) -- Gitee From 35012589cfe57991523eab7c0d4f886cbdb0ad85 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 30 Jun 2024 18:02:00 +0800 Subject: [PATCH 21/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8A=8A=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E8=B5=8B=E5=80=BC=E8=B7=AF=E5=BE=84=20URL=20encode=20?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E5=80=BC=20decode=20=E5=9B=9E=E5=8E=9F?= =?UTF-8?q?=E5=A7=8B=E5=80=BC=EF=BC=8C=E4=BE=8B=E5=A6=82=20%2Fuser%2Flist?= =?UTF-8?q?=20->=20/user/list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/apijson/orm/AbstractParser.java | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 1a744108..44b19661 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -12,7 +12,9 @@ import com.alibaba.fastjson.JSONObject; import java.io.UnsupportedEncodingException; import java.lang.management.ManagementFactory; import java.net.InetAddress; +import java.net.URLDecoder; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.SQLException; import java.sql.Savepoint; @@ -1778,15 +1780,17 @@ public abstract class AbstractParser implements Parser, Par } //逐层到达child的直接容器JSONObject parent - final int last = pathKeys.length - 1; + int last = pathKeys.length - 1; for (int i = 0; i < last; i++) {//一步一步到达指定位置 if (parent == null) {//不存在或路径错误(中间的key对应value不是JSONObject) break; } - parent = getJSONObject(parent, pathKeys[i]); + + String k = getDecodedKey(pathKeys[i]); + parent = getJSONObject(parent, k); } - return parent == null ? null : (V) parent.get(pathKeys[last]); + return parent == null ? null : (V) parent.get(getDecodedKey(pathKeys[last])); } @@ -1912,18 +1916,21 @@ public abstract class AbstractParser implements Parser, Par } //逐层到达targetKey的直接容器JSONObject parent - if (keys != null && keys.length > 1) { - for (int i = 0; i < keys.length - 1; i++) {//一步一步到达指定位置parentPath + int last = keys == null ? -1 : keys.length - 1; + if (last >= 1) { + for (int i = 0; i < last; i++) {//一步一步到达指定位置parentPath if (parent == null) {//不存在或路径错误(中间的key对应value不是JSONObject) break; } - parent = getJSONObject(parent, keys[i]); + + String k = getDecodedKey(keys[i]); + parent = getJSONObject(parent, k); } } if (parent != null) { Log.i(TAG, "getValueByPath >> get from queryResultMap >> return parent.get(keys[keys.length - 1]);"); - target = keys == null || keys.length <= 0 ? parent : parent.get(keys[keys.length - 1]); //值为null应该报错NotExistExeption,一般都是id关联,不可为null,否则可能绕过安全机制 + target = last < 0 ? parent : parent.get(getDecodedKey(keys[last])); //值为null应该报错NotExistExeption,一般都是id关联,不可为null,否则可能绕过安全机制 if (target != null) { Log.i(TAG, "getValueByPath >> getValue >> return target = " + target); return target; @@ -1942,6 +1949,18 @@ public abstract class AbstractParser implements Parser, Par return null; } + /**解码 引用赋值 路径中的 key,支持把 URL encode 后的值,转为 decode 后的原始值,例如 %2Fuser%2Flist -> /user/list ; %7B%7D -> [] + * @param key + * @return + */ + public static String getDecodedKey(String key) { + try { + return URLDecoder.decode(key, StandardCharsets.UTF_8); + } catch (Throwable e) { + return key; + } + } + //依赖引用关系 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- Gitee From 8dbaa2dea9e063eac2bbf76f5f5155390eba512f Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 30 Jun 2024 18:43:15 +0800 Subject: [PATCH 22/47] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20format:=20true=20?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=20key=20=E8=BF=94=E5=9B=9E=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E5=B0=8F=E9=A9=BC=E5=B3=B0=EF=BC=8C=E8=80=8C=E6=98=AF=E5=BC=BA?= =?UTF-8?q?=E5=88=B6=E5=B0=8F=E5=86=99=EF=BC=8C=E4=BE=8B=E5=A6=82=20User[]?= =?UTF-8?q?=20=20=E8=BF=94=E5=9B=9E=E4=B8=8D=E6=98=AF=20userList=20?= =?UTF-8?q?=E8=80=8C=E6=98=AF=20userlist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/JSONResponse.java | 114 ++++++++++++++++-- 1 file changed, 101 insertions(+), 13 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/JSONResponse.java b/APIJSONORM/src/main/java/apijson/JSONResponse.java index 9f61edad..21f3fe8f 100755 --- a/APIJSONORM/src/main/java/apijson/JSONResponse.java +++ b/APIJSONORM/src/main/java/apijson/JSONResponse.java @@ -485,14 +485,14 @@ public class JSONResponse extends apijson.JSONObject { if (formatAt) { //关键词只去掉前缀,不格式化单词,例如 @a-b 返回 a-b ,最后不会调用 setter fullName = formatAt(fullName); } - if (formatHyphen) { - fullName = formatHyphen(fullName, firstCase != null); + if (formatHyphen && fullName.contains("-")) { + fullName = formatHyphen(fullName, true); } - if (formatUnderline) { - fullName = formatUnderline(fullName, firstCase != null); + if (formatUnderline && fullName.contains("_")) { + fullName = formatUnderline(fullName, true); } - if (formatDollar) { - fullName = formatDollar(fullName, firstCase != null); + if (formatDollar && fullName.contains("$")) { + fullName = formatDollar(fullName, true); } // 默认不格式化普通 key:value (value 不为 [], {}) 的 key @@ -520,32 +520,100 @@ public class JSONResponse extends apijson.JSONObject { * @param key * @return */ + public static String formatHyphen(@NotNull String key) { + return StringUtil.firstCase(formatHyphen(key, true), false); + } + /**A-b-cd-Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ public static String formatHyphen(@NotNull String key, Boolean firstCase) { - return formatDivider(key, "-", firstCase); + return formatHyphen(key, firstCase, false); + } + /**A-b-cd-Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @param otherCase 非首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ + public static String formatHyphen(@NotNull String key, Boolean firstCase, Boolean otherCase) { + return formatDivider(key, "-", firstCase, otherCase); } /**A_b_cd_Efg => ABCdEfg * @param key * @return */ + public static String formatUnderline(@NotNull String key) { + return StringUtil.firstCase(formatUnderline(key, true), false); + } + /**A_b_cd_Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ public static String formatUnderline(@NotNull String key, Boolean firstCase) { - return formatDivider(key, "_", firstCase); + return formatUnderline(key, firstCase, false); + } + /**A_b_cd_Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @param otherCase 非首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ + public static String formatUnderline(@NotNull String key, Boolean firstCase, Boolean otherCase) { + return formatDivider(key, "_", firstCase, otherCase); } /**A$b$cd$Efg => ABCdEfg * @param key * @return */ + public static String formatDollar(@NotNull String key) { + return StringUtil.firstCase(formatDollar(key, true), false); + } + /**A$b$cd$Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ public static String formatDollar(@NotNull String key, Boolean firstCase) { - return formatDivider(key, "$", firstCase); + return formatDollar(key, firstCase, false); + } + /**A$b$cd$Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @param otherCase 非首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ + public static String formatDollar(@NotNull String key, Boolean firstCase, Boolean otherCase) { + return formatDivider(key, "$", firstCase, otherCase); } /**A.b.cd.Efg => ABCdEfg * @param key * @return */ + public static String formatDot(@NotNull String key) { + return StringUtil.firstCase(formatDot(key, true), false); + } + /**A.b.cd.Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ public static String formatDot(@NotNull String key, Boolean firstCase) { - return formatDivider(key, ".", firstCase); + return formatDot(key, firstCase, false); + } + /**A.b.cd.Efg => ABCdEfg + * @param key + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @param otherCase 非首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ + public static String formatDot(@NotNull String key, Boolean firstCase, Boolean otherCase) { + return formatDivider(key, ".", firstCase, otherCase); } /**A/b/cd/Efg => ABCdEfg @@ -559,16 +627,36 @@ public class JSONResponse extends apijson.JSONObject { /**去除分割符,返回驼峰格式 * @param key * @param divider - * @param firstCase + * @return + */ + public static String formatDivider(@NotNull String key, @NotNull String divider) { + return StringUtil.firstCase(formatDivider(key, divider, true), false); + } + /**去除分割符,返回驼峰格式 + * @param key + * @param divider + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 * @return */ public static String formatDivider(@NotNull String key, @NotNull String divider, Boolean firstCase) { + return formatDivider(key, divider, firstCase, false); + } + + /**去除分割符,返回驼峰格式 + * @param key + * @param divider + * @param firstCase 首字符的大小写,true-大写,false-小写,null-不处理 + * @param otherCase 非首字符的大小写,true-大写,false-小写,null-不处理 + * @return + */ + public static String formatDivider(@NotNull String key, @NotNull String divider, Boolean firstCase, Boolean otherCase) { String[] parts = StringUtil.split(key, divider); StringBuilder name = new StringBuilder(); for (String part : parts) { - part = part.toLowerCase(); // 始终小写,也方便反过来 ABCdEfg -> A_b_cd_Efg + if (otherCase != null) { + part = otherCase ? part.toUpperCase() : part.toLowerCase(); + } if (firstCase != null) { - // 始终小写, A_b_cd_Efg -> ABCdEfg, firstCase ? part.toLowerCase() : part.toUpperCase(); part = StringUtil.firstCase(part, firstCase); } name.append(part); -- Gitee From 53adfabf14842b50e62151c94603a0d1821dca11 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 30 Jun 2024 19:10:54 +0800 Subject: [PATCH 23/47] Update Document.md --- Document.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Document.md b/Document.md index 38adef50..90148bed 100644 --- a/Document.md +++ b/Document.md @@ -403,24 +403,24 @@ DELETE:
删除数据 | base_url/delete/ | {
   TableName:{< 功能 | 键值对格式 | 使用示例 ------------ | ------------ | ------------ - 查询数组 | "key[]":{},后面是JSONObject,key可省略。当key和里面的Table名相同时,Table会被提取出来,即 {Table:{Content}} 会被转化为 {Content} | [{"User[]":{"User":{}}}](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{}}}),查询一个User数组。这里key和Table名都是User,User会被提取出来,即 {"User":{"id", ...}} 会被转化为 {"id", ...},如果要进一步提取User中的id,可以把User[]改为User-id[] - 匹配选项范围 | "key{}":[],后面是JSONArray,作为key可取的值的选项 | ["id{}":[38710,82001,70793]](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":[38710,82001,70793]}}}),对应SQL是`id IN(38710,82001,70793)`,查询id符合38710,82001,70793中任意一个的一个User数组 - 匹配条件范围 | "key{}":"条件0,条件1...",条件为SQL表达式字符串,可进行数字比较运算等 | ["id{}":"<=80000,\>90000"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":"<=80000,\>90000"}}}),对应SQL是`id<=80000 OR id>90000`,查询id符合id\<=80000 \| id>90000的一个User数组 - 包含选项范围 | "key<\>":Object => "key<\>":[Object],key对应值的类型必须为JSONArray,Object类型不能为JSON | ["contactIdList<\>":38710](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"contactIdList<\>":38710}}}),对应SQL是`json_contains(contactIdList,38710)`,查询contactIdList包含38710的一个User数组 + 查询数组 | "key[]":{},后面是 JSONObject,key 可省略。当 key 和里面的 Table 名相同时,Table 会被提取出来,即 {Table:{Content}} 会被转化为 {Content} | [{"User[]":{"User":{}}}](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{}}}),查询一个 User 数组。这里 key 和 Table 名都是 User,User 会被提取出来,即 {"User":{"id", ...}} 会被转化为 {"id", ...},如果要进一步提取 User 中的 id,可以把 User[] 改为 User-id[],其中 - 用来分隔路径中涉及的 key + 匹配选项范围 | "key{}":[],后面是 JSONArray,作为 key 可取的值的选项 | ["id{}":[38710,82001,70793]](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":[38710,82001,70793]}}}),对应 SQL 是`id IN(38710,82001,70793)`,查询 id 符合 38710,82001,70793 中任意一个的一个 User 数组 + 匹配条件范围 | "key{}":"条件0,条件1...",条件为 SQL 表达式字符串,可进行数字比较运算等 | ["id{}":"<=80000,\>90000"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":"<=80000,\>90000"}}}),对应 SQL 是`id<=80000 OR id>90000`,查询 id 符合 id\<=80000 \| id>90000 的一个 User 数组 + 包含选项范围 | "key<\>":Object => "key<\>":[value],key 对应值的类型必须为 JSONArray,value 类型不能为 JSON | ["contactIdList<\>":38710](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"contactIdList<\>":38710}}}),对应SQL是`json_contains(contactIdList,38710)`,查询 contactIdList 包含 38710 的一个 User 数组 判断是否存在 | "key}{@":{
   "from":"Table",
   "Table":{ ... }
}
其中:
}{ 表示 EXISTS;
key 用来标识是哪个判断;
@ 后面是 子查询 对象,具体见下方 子查询 的说明。 | ["id}{@":{
   "from":"Comment",
   "Comment":{
      "momentId":15
   }
}](http://apijson.cn:8080/get/{"User":{"id}{@":{"from":"Comment","Comment":{"momentId":15}}}})
WHERE EXISTS(SELECT * FROM Comment WHERE momentId=15) - 远程调用函数 | "key()":"函数表达式",函数表达式为 function(key0,key1...),会调用后端对应的函数 function(JSONObject request, String key0, String key1...),实现 参数校验、数值计算、数据同步、消息推送、字段拼接、结构变换 等特定的业务逻辑处理,
可使用 - 和 + 表示优先级,解析 key-() > 解析当前对象 > 解析 key() > 解析子对象 > 解析 key+() | ["isPraised()":"isContain(praiseUserIdList,userId)"](http://apijson.cn:8080/get/{"Moment":{"id":301,"isPraised()":"isContain(praiseUserIdList,userId)"}}),会调用远程函数 [boolean isContain(JSONObject request, String array, String value)](https://github.com/APIJSON/apijson-framework/blob/master/src/main/java/apijson/framework/APIJSONFunctionParser.java#L361-L374) ,然后变为 "isPraised":true 这种(假设点赞用户id列表包含了userId,即这个User点了赞) - 存储过程 | "@key()":"SQL函数表达式",函数表达式为
function(key0,key1...)
会调用后端数据库对应的存储过程 SQL函数
function(String key0, String key1...)
除了参数会提前赋值,其它和 远程函数 一致 | ["@limit":10,
"@offset":0,
"@procedure()":"getCommentByUserId(id,@limit,@offset)"](http://apijson.cn:8080/get/{"User":{"@limit":10,"@offset":0,"@procedure()":"getCommentByUserId(id,@limit,@offset)"}})
会转为
`getCommentByUserId(38710,10,0)`
来调用存储过程 SQL 函数
`getCommentByUserId(IN id bigint, IN limit int, IN offset int)`
然后变为
"procedure":{
   "count":-1,
   "update":false,
   "list":[]
}
其中 count 是指写操作影响记录行数,-1 表示不是写操作;update 是指是否为写操作(增删改);list 为返回结果集 - 引用赋值 | "key@":"key0/key1/.../refKey",引用路径为用/分隔的字符串。以/开头的是缺省引用路径,从声明key所处容器的父容器路径开始;其它是完整引用路径,从最外层开始。
被引用的refKey必须在声明key的上面。如果对refKey的容器指定了返回字段,则被引用的refKey必须写在@column对应的值内,例如 "@column":"refKey,key1,..." | ["Moment":{
   "userId":38710
},
"User":{
   "id@":"/Moment/userId"
}](http://apijson.cn:8080/get/{"Moment":{"userId":38710},"User":{"id@":"%252FMoment%252FuserId"}})
User内的id引用了与User同级的Moment内的userId,
即User.id = Moment.userId,请求完成后
"id@":"/Moment/userId" 会变成 "id":38710 - 子查询 | "key@":{
   "range":"ALL",
   "from":"Table",
   "Table":{ ... }
}
其中:
range 可为 ALL,ANY;
from 为目标表 Table 的名称;
@ 后面的对象类似数组对象,可使用 count 和 join 等功能。 | ["id@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id=(SELECT min(userId) FROM Comment) - 模糊搜索 | `"key$":"SQL搜索表达式"` => `"key$":["SQL搜索表达式"]`,任意SQL搜索表达式字符串,如 %key%(包含key), key%(以key开始), %k%e%y%(包含字母k,e,y) 等,%表示任意字符 | ["name$":"%m%"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name$":"%2525m%2525"}}}),对应SQL是`name LIKE '%m%'`,查询name包含"m"的一个User数组 - 正则匹配 | "key~":"正则表达式" => "key~":["正则表达式"],任意正则表达式字符串,如 ^[0-9]+$ ,*~ 忽略大小写,可用于高级搜索 | ["name~":"^[0-9]+$"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name~":"^[0-9]%252B$"}}}),对应SQL是`name REGEXP '^[0-9]+$'`,查询name中字符全为数字的一个User数组 - 连续范围 | "key%":"start,end" => "key%":["start,end"],其中 start 和 end 都只能为 Boolean, Number, String 中的一种,如 "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"] ,可用于连续范围内的筛选 | ["date%":"2017-10-01,2018-10-01"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"date%2525":"2017-10-01,2018-10-01"}}}),对应SQL是`date BETWEEN '2017-10-01' AND '2018-10-01'`,查询在2017-10-01和2018-10-01期间注册的用户的一个User数组 - 新建别名 | "name:alias",name映射为alias,用alias替代name。可用于 column,Table,SQL函数 等。只用于GET类型、HEAD类型的请求 | ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}}),对应SQL是`toId AS parentId`,将查询的字段toId变为parentId返回 - 增加 或 扩展 | "key+":Object,Object的类型由key指定,且类型为Number,String,JSONArray中的一种。如 82001,"apijson",["url0","url1"] 等。只用于PUT请求 | "praiseUserIdList+":[82001],对应SQL是`json_insert(praiseUserIdList,82001)`,添加一个点赞用户id,即这个用户点了赞 + 远程调用函数 | "key()":"函数表达式",函数表达式为 function(key0,key1...),会调用后端对应的函数 function(JSONObject request, String key0, String key1...),实现 参数校验、数值计算、数据同步、消息推送、字段拼接、结构变换 等特定的业务逻辑处理,
可使用 - 和 + 表示优先级,解析 key-() > 解析当前对象 > 解析 key() > 解析子对象 > 解析 key+() | ["isPraised()":"isContain(praiseUserIdList,userId)"](http://apijson.cn:8080/get/{"Moment":{"id":301,"isPraised()":"isContain(praiseUserIdList,userId)"}}),会调用远程函数 [boolean isContain(JSONObject request, String array, String value)](https://github.com/APIJSON/apijson-framework/blob/master/src/main/java/apijson/framework/APIJSONFunctionParser.java#L361-L374) ,然后变为 "isPraised":true 这种(假设点赞用户 id 列表包含了 userId,即这个 User 点了赞) + 存储过程 | "@key()":"SQL函数表达式",函数表达式为
function(key0,key1...)
会调用后端数据库对应的存储过程 SQL 函数
function(String key0, String key1...)
除了参数会提前赋值,其它和 远程函数 一致 | ["@limit":10,
"@offset":0,
"@procedure()":"getCommentByUserId(id,@limit,@offset)"](http://apijson.cn:8080/get/{"User":{"@limit":10,"@offset":0,"@procedure()":"getCommentByUserId(id,@limit,@offset)"}})
会转为
`getCommentByUserId(38710,10,0)`
来调用存储过程 SQL 函数
`getCommentByUserId(IN id bigint, IN limit int, IN offset int)`
然后变为
"procedure":{
   "count":-1,
   "update":false,
   "list":[]
}
其中 count 是指写操作影响记录行数,-1 表示不是写操作;update 是指是否为写操作(增删改);list 为返回结果集 + 引用赋值 | "key@":"key0/key1/.../refKey",引用路径为用 / 分隔的字符串。以 / 开头的是缺省引用路径,从声明 key 所处容器的父容器路径开始;其它是完整引用路径,从最外层开始。
被引用的 refKey 必须在声明 key 的上面。如果对 refKey 的容器指定了返回字段,则被引用的 refKey 必须写在 @column 对应的值内,例如 "@column":"refKey,key1,..." | ["Moment":{
   "userId":38710
},
"User":{
   "id@":"/Moment/userId"
}](http://apijson.cn:8080/get/{"Moment":{"userId":38710},"User":{"id@":"%252FMoment%252FuserId"}})
User 内的 id 引用了与 User 同级的 Moment 内的 userId,
即 User.id = Moment.userId,请求完成后
"id@":"/Moment/userId" 会变成 "id":38710 + 子查询 | "key@":{
   "range":"ALL",
   "from":"Table", // 可省略,默认为首个表对象 key 名
   "Table":{ ... }
}
其中:
range 可为 ALL,ANY;
from 为目标表 Table 的名称;
@ 后面的对象类似数组对象,可使用 count 和 join 等功能。 | ["id@":{
   "from":"Comment", // 可省略
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id=(SELECT min(userId) FROM Comment) + 模糊搜索 | `"key$":"SQL搜索表达式"` => `"key$":["SQL搜索表达式"]`,任意 SQL 搜索表达式字符串,如 %key%(包含 key), key%(以 key 开始), %k%e%y%(包含字母 k,e,y) 等,% 表示任意字符 | ["name$":"%m%"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name$":"%2525m%2525"}}}),对应 SQL 是`name LIKE '%m%'`,查询 name 包含 "m" 的一个 User 数组 + 正则匹配 | "key~":"正则表达式" => "key~":["正则表达式"],任意正则表达式字符串,如 ^[0-9]+$ ,*~ 忽略大小写,可用于高级搜索 | ["name~":"^[0-9]+$"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"name~":"^[0-9]%252B$"}}}),对应 SQL 是`name REGEXP '^[0-9]+$'`,查询 name 中字符全为数字的一个 User 数组 + 连续范围 | "key%":"start,end" => "key%":["start,end"],其中 start 和 end 都只能为 Number, String 中的一种,如 "2017-01-01,2019-01-01" ,["1,90000", "82001,100000"] ,可用于连续范围内的筛选 | ["date%":"2017-10-01,2018-10-01"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"date%2525":"2017-10-01,2018-10-01"}}}),对应SQL是`date BETWEEN '2017-10-01' AND '2018-10-01'`,查询在2017-10-01和2018-10-01期间注册的用户的一个User数组 + 新建别名 | "name:alias",name 映射为 alias,用 alias 替代 name。可用于 column,Table,SQL 函数 等。只用于 GET 类型、HEAD 类型的请求 | ["@column":"toId:parentId"](http://apijson.cn:8080/get/{"Comment":{"@column":"id,toId:parentId","id":51}}),对应 SQL 是`toId AS parentId`,将查询的字段 toId 变为 parentId 返回 + 增加 或 扩展 | "key+":Object,Object的类型由key指定,且类型为 Number,String,JSONArray 中的一种。如 82001,"apijson",["url0","url1"] 等。只用于 PUT 请求 | "praiseUserIdList+":[82001],对应 SQL 是`json_insert(praiseUserIdList,82001)`,添加一个点赞用户 id,即这个用户点了赞 减少 或 去除 | "key-":Object,与"key+"相反 | "balance-":100.00,对应SQL是`balance = balance - 100.00`,余额减少100.00,即花费了100元 - 比较运算 | >, <, >=, <= 比较运算符,用于
① 提供 "id{}":"<=90000" 这种条件范围的简化写法

② 实现子查询相关比较运算

不支持 "key=":Object 和 "key!=":Object 这两种写法,直接用更简单的 "key":Object 和 "key!":Object 替代。 | ① ["id<=":90000](http://apijson.cn:8080/get/{"[]":{"User":{"id<=":90000}}}),对应SQL是`id<=90000`,查询符合id<=90000的一个User数组

② ["id>@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id>@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id>(SELECT min(userId) FROM Comment) - 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于"key&{}":"条件"等

② \| 可用于"key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如"key!":Object,也可像&,\|一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同"id{}":">90000,<=80000",对应SQL是`id>90000 OR id<=80000`,即id满足id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应SQL是`id NOT IN(82001,38710)`,即id满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 - 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中{}内的关键词,Object的类型由key指定

① "count":Integer,查询数量,0 表示最大值,默认最大值为100

② "page":Integer,查询页码,从0开始,默认最大值为100,一般和count一起用

③ "query":Integer,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应SQL是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应SQL是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total",
"info@":"/[]/info"](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, //总数
"info":{ //分页详情
   "total":139, //总数
   "count":5, //每页数量
   "page":0, //当前页码
   "max":27, //最大页码
   "more":true, //是否还有更多
   "first":true, //是否为首页
   "last":false //是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" //主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", //自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) - 对象关键词,可自定义 | "@key":Object,@key为 Table:{} 中{}内的关键词,Object的类型由@key指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果@column里声明了Table的id,则id也必须在@group中声明;其它情况下必须满足至少一个条件:
1.分组的key在@column里声明
2.Table主键在@group中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL函数条件,一般和@group一起用,函数一般在@column里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防SQL注入

⑬ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索name或tag任何一个字段包含字符a的User列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询id,sex,name这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应SQL是`SELECT id,sex,name`

③ 查询按 name降序、id默认顺序 排序的User数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应SQL是`ORDER BY name DESC,id`

④ 查询按userId分组的Moment数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应SQL是`GROUP BY userId,id`

⑤ 查询 按userId分组、id最大值>=100 的Moment数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应SQL是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应SQL是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应SQL是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应SQL是`EXPLAIN`

⑫ 统计最近一周偶数userId的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应SQL是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 从pictureList获取第0张图片:
["@position":0, //自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) - 全局关键词 | 为最外层对象 {} 内的关键词。其中 @database,@schema, @datasource, @role, @explain 基本同对象关键词,见上方说明,区别是全局关键词会每个表对象中没有时自动放入,作为默认值。

① "tag":String,后面的 tag 是非 GET、HEAD 请求中匹配请求的 JSON 结构的标识,一般是要查询的 Table 的名称或该名称对应的数组 Table[] 或 Table:[],由后端 Request 表中指定。

② "version":Integer,接口版本,version 不传、为 null 或 <=0 都会使用最高版本,传了其它有效值则会使用最接近它的最低版本,由后端 Request 表中指定。

③ "format":Boolean,格式化返回 Response JSON 的 key,一般是将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias, TableName-key[] 转为 tableNameKeyList 等小驼峰格式。 | ① 查隐私信息:
[{"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

② 使用第 1 版接口查隐私信息:
[{"version":1,"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22version%22:1,%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

③ 格式化朋友圈接口返回 JSON 中的 key:
[{
   "format":true,
   "[]":{
     "page":0,
     "count":3,
     "Moment":{},
     "User":{
       "id@":"/Moment/userId"
     },
     "Comment[]":{
       "count":3,
       "Comment":{
         "momentId@":"[]/Moment/id"
       }
     }
   }
}](http://apijson.cn:8080/get/{"format":true,"[]":{"page":0,"count":3,"Moment":{},"User":{"id@":"%252FMoment%252FuserId"},"Comment[]":{"count":3,"Comment":{"momentId@":"[]%252FMoment%252Fid"}}}}) + 比较运算 | >, <, >=, <= 比较运算符,用于
① 提供 "id{}":"<=90000" 这种条件范围的简化写法

② 实现子查询相关比较运算

不支持 "key=":Object 和 "key!=":Object 这两种写法,直接用更简单的 "key":Object 和 "key!":Object 替代。 | ① ["id<=":90000](http://apijson.cn:8080/get/{"[]":{"User":{"id<=":90000}}}),对应 SQL 是`id<=90000`,查询符合id<=90000的一个User数组

② ["id>@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id>@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id>(SELECT min(userId) FROM Comment) + 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于 "key&{}":"条件"等

② \| 可用于 "key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如 "key!":Object,也可像 &,\| 一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同"id{}":">90000,<=80000",对应 SQL 是`id>90000 OR id<=80000`,即 id 满足 id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应 SQL 是`id NOT IN(82001,38710)`,即 id 满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 + 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中{}内的关键词,Object的类型由key指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) + 对象关键词,可自定义 | "@key":Object,@key 为 Table:{} 中 {} 内的关键词,Object 的类型由 @key 指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果 @column 里声明了 Table 的 id,则 id 也必须在 @group 中声明;其它情况下必须满足至少一个条件:
1.分组的 key 在 @column 里声明
2.Table 主键在 @group 中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL 函数条件,一般和 @group 一起用,函数一般在 @column 里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防 SQL 注入

⑬ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索 name 或 tag 任何一个字段包含字符 a 的 User 列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询 id,sex,name 这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应 SQL 是`SELECT id,sex,name`

③ 查询按 name 降序、id 默认顺序 排序的 User 数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应 SQL 是`ORDER BY name DESC,id`

④ 查询按 userId 分组的 Moment 数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应 SQL 是`GROUP BY userId,id`

⑤ 查询 按 userId 分组、id 最大值>=100 的 Moment 数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应 SQL 是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应 SQL 是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应 SQL 是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应 SQL 是`EXPLAIN`

⑫ 统计最近一周偶数 userId 的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应 SQL 是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 从pictureList 获取第 0 张图片:
["@position":0, // 自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) + 全局关键词 | 为最外层对象 {} 内的关键词。其中 @database,@schema, @datasource, @role, @explain 基本同对象关键词,见上方说明,区别是全局关键词会每个表对象中没有时自动放入,作为默认值。

① "tag":"Table",后面的 tag 是非 GET、HEAD 请求中匹配请求的 JSON 结构的标识,一般是要查询的 Table 的名称或该名称对应的数组 Table[] 或 Table:[],由后端 Request 表中指定。

② "version":1,接口版本,version 不传、为 null 或 <=0 都会使用最高版本,传了其它有效值则会使用最接近它的最低版本,由后端 Request 表中指定。

③ "format":true,格式化返回 Response JSON 的 key,一般是将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias, TableName-key[] 转为 tableNameKeyList 等小驼峰格式。 | ① 查隐私信息:
[{"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

② 使用第 1 版接口查隐私信息:
[{"version":1,"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22version%22:1,%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

③ 格式化朋友圈接口返回 JSON 中的 key:
[{
   "format":true,
   "[]":{
     "page":0,
     "count":3,
     "Moment":{},
     "User":{
       "id@":"/Moment/userId"
     },
     "Comment[]":{
       "count":3,
       "Comment":{
         "momentId@":"[]/Moment/id"
       }
     }
   }
}](http://apijson.cn:8080/get/{"format":true,"[]":{"page":0,"count":3,"Moment":{},"User":{"id@":"%252FMoment%252FuserId"},"Comment[]":{"count":3,"Comment":{"momentId@":"[]%252FMoment%252Fid"}}}})
-- Gitee From 9e1187cfae3d6d44f41e4f5d1b9522568427a8c2 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 30 Jun 2024 19:16:37 +0800 Subject: [PATCH 24/47] Update Document.md --- Document.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Document.md b/Document.md index 90148bed..42c70036 100644 --- a/Document.md +++ b/Document.md @@ -406,7 +406,7 @@ DELETE:
删除数据 | base_url/delete/ | {
   TableName:{< 查询数组 | "key[]":{},后面是 JSONObject,key 可省略。当 key 和里面的 Table 名相同时,Table 会被提取出来,即 {Table:{Content}} 会被转化为 {Content} | [{"User[]":{"User":{}}}](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{}}}),查询一个 User 数组。这里 key 和 Table 名都是 User,User 会被提取出来,即 {"User":{"id", ...}} 会被转化为 {"id", ...},如果要进一步提取 User 中的 id,可以把 User[] 改为 User-id[],其中 - 用来分隔路径中涉及的 key 匹配选项范围 | "key{}":[],后面是 JSONArray,作为 key 可取的值的选项 | ["id{}":[38710,82001,70793]](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":[38710,82001,70793]}}}),对应 SQL 是`id IN(38710,82001,70793)`,查询 id 符合 38710,82001,70793 中任意一个的一个 User 数组 匹配条件范围 | "key{}":"条件0,条件1...",条件为 SQL 表达式字符串,可进行数字比较运算等 | ["id{}":"<=80000,\>90000"](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"id{}":"<=80000,\>90000"}}}),对应 SQL 是`id<=80000 OR id>90000`,查询 id 符合 id\<=80000 \| id>90000 的一个 User 数组 - 包含选项范围 | "key<\>":Object => "key<\>":[value],key 对应值的类型必须为 JSONArray,value 类型不能为 JSON | ["contactIdList<\>":38710](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"contactIdList<\>":38710}}}),对应SQL是`json_contains(contactIdList,38710)`,查询 contactIdList 包含 38710 的一个 User 数组 + 包含选项范围 | "key<\>":value => "key<\>":[value],key 对应值的类型必须为 JSONArray,value 值类型只能为 Boolean, Number, String 中的一种 | ["contactIdList<\>":38710](http://apijson.cn:8080/get/{"User[]":{"count":3,"User":{"contactIdList<\>":38710}}}),对应SQL是`json_contains(contactIdList,38710)`,查询 contactIdList 包含 38710 的一个 User 数组 判断是否存在 | "key}{@":{
   "from":"Table",
   "Table":{ ... }
}
其中:
}{ 表示 EXISTS;
key 用来标识是哪个判断;
@ 后面是 子查询 对象,具体见下方 子查询 的说明。 | ["id}{@":{
   "from":"Comment",
   "Comment":{
      "momentId":15
   }
}](http://apijson.cn:8080/get/{"User":{"id}{@":{"from":"Comment","Comment":{"momentId":15}}}})
WHERE EXISTS(SELECT * FROM Comment WHERE momentId=15) 远程调用函数 | "key()":"函数表达式",函数表达式为 function(key0,key1...),会调用后端对应的函数 function(JSONObject request, String key0, String key1...),实现 参数校验、数值计算、数据同步、消息推送、字段拼接、结构变换 等特定的业务逻辑处理,
可使用 - 和 + 表示优先级,解析 key-() > 解析当前对象 > 解析 key() > 解析子对象 > 解析 key+() | ["isPraised()":"isContain(praiseUserIdList,userId)"](http://apijson.cn:8080/get/{"Moment":{"id":301,"isPraised()":"isContain(praiseUserIdList,userId)"}}),会调用远程函数 [boolean isContain(JSONObject request, String array, String value)](https://github.com/APIJSON/apijson-framework/blob/master/src/main/java/apijson/framework/APIJSONFunctionParser.java#L361-L374) ,然后变为 "isPraised":true 这种(假设点赞用户 id 列表包含了 userId,即这个 User 点了赞) 存储过程 | "@key()":"SQL函数表达式",函数表达式为
function(key0,key1...)
会调用后端数据库对应的存储过程 SQL 函数
function(String key0, String key1...)
除了参数会提前赋值,其它和 远程函数 一致 | ["@limit":10,
"@offset":0,
"@procedure()":"getCommentByUserId(id,@limit,@offset)"](http://apijson.cn:8080/get/{"User":{"@limit":10,"@offset":0,"@procedure()":"getCommentByUserId(id,@limit,@offset)"}})
会转为
`getCommentByUserId(38710,10,0)`
来调用存储过程 SQL 函数
`getCommentByUserId(IN id bigint, IN limit int, IN offset int)`
然后变为
"procedure":{
   "count":-1,
   "update":false,
   "list":[]
}
其中 count 是指写操作影响记录行数,-1 表示不是写操作;update 是指是否为写操作(增删改);list 为返回结果集 -- Gitee From e267b68241061c89720e05c59a1e33f84bf0887d Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 30 Jun 2024 19:28:55 +0800 Subject: [PATCH 25/47] Update Document.md --- Document.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Document.md b/Document.md index 42c70036..72355006 100644 --- a/Document.md +++ b/Document.md @@ -419,8 +419,8 @@ DELETE:
删除数据 | base_url/delete/ | {
   TableName:{< 增加 或 扩展 | "key+":Object,Object的类型由key指定,且类型为 Number,String,JSONArray 中的一种。如 82001,"apijson",["url0","url1"] 等。只用于 PUT 请求 | "praiseUserIdList+":[82001],对应 SQL 是`json_insert(praiseUserIdList,82001)`,添加一个点赞用户 id,即这个用户点了赞 减少 或 去除 | "key-":Object,与"key+"相反 | "balance-":100.00,对应SQL是`balance = balance - 100.00`,余额减少100.00,即花费了100元 比较运算 | >, <, >=, <= 比较运算符,用于
① 提供 "id{}":"<=90000" 这种条件范围的简化写法

② 实现子查询相关比较运算

不支持 "key=":Object 和 "key!=":Object 这两种写法,直接用更简单的 "key":Object 和 "key!":Object 替代。 | ① ["id<=":90000](http://apijson.cn:8080/get/{"[]":{"User":{"id<=":90000}}}),对应 SQL 是`id<=90000`,查询符合id<=90000的一个User数组

② ["id>@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id>@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id>(SELECT min(userId) FROM Comment) - 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于 "key&{}":"条件"等

② \| 可用于 "key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如 "key!":Object,也可像 &,\| 一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同"id{}":">90000,<=80000",对应 SQL 是`id>90000 OR id<=80000`,即 id 满足 id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应 SQL 是`id NOT IN(82001,38710)`,即 id 满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 - 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中{}内的关键词,Object的类型由key指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) + 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于 "key&{}":"条件"等

② \| 可用于 "key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如 "key!":Object,也可像 &,\| 一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同 "id{}":">90000,<=80000",对应 SQL 是`id>90000 OR id<=80000`,即 id 满足 id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应 SQL 是`id NOT IN(82001,38710)`,即 id 满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 + 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中 {} 内的关键词,Object 的类型由 key 指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) 对象关键词,可自定义 | "@key":Object,@key 为 Table:{} 中 {} 内的关键词,Object 的类型由 @key 指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果 @column 里声明了 Table 的 id,则 id 也必须在 @group 中声明;其它情况下必须满足至少一个条件:
1.分组的 key 在 @column 里声明
2.Table 主键在 @group 中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL 函数条件,一般和 @group 一起用,函数一般在 @column 里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防 SQL 注入

⑬ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索 name 或 tag 任何一个字段包含字符 a 的 User 列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询 id,sex,name 这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应 SQL 是`SELECT id,sex,name`

③ 查询按 name 降序、id 默认顺序 排序的 User 数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应 SQL 是`ORDER BY name DESC,id`

④ 查询按 userId 分组的 Moment 数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应 SQL 是`GROUP BY userId,id`

⑤ 查询 按 userId 分组、id 最大值>=100 的 Moment 数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应 SQL 是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应 SQL 是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应 SQL 是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应 SQL 是`EXPLAIN`

⑫ 统计最近一周偶数 userId 的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应 SQL 是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 从pictureList 获取第 0 张图片:
["@position":0, // 自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) 全局关键词 | 为最外层对象 {} 内的关键词。其中 @database,@schema, @datasource, @role, @explain 基本同对象关键词,见上方说明,区别是全局关键词会每个表对象中没有时自动放入,作为默认值。

① "tag":"Table",后面的 tag 是非 GET、HEAD 请求中匹配请求的 JSON 结构的标识,一般是要查询的 Table 的名称或该名称对应的数组 Table[] 或 Table:[],由后端 Request 表中指定。

② "version":1,接口版本,version 不传、为 null 或 <=0 都会使用最高版本,传了其它有效值则会使用最接近它的最低版本,由后端 Request 表中指定。

③ "format":true,格式化返回 Response JSON 的 key,一般是将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias, TableName-key[] 转为 tableNameKeyList 等小驼峰格式。 | ① 查隐私信息:
[{"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

② 使用第 1 版接口查隐私信息:
[{"version":1,"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22version%22:1,%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

③ 格式化朋友圈接口返回 JSON 中的 key:
[{
   "format":true,
   "[]":{
     "page":0,
     "count":3,
     "Moment":{},
     "User":{
       "id@":"/Moment/userId"
     },
     "Comment[]":{
       "count":3,
       "Comment":{
         "momentId@":"[]/Moment/id"
       }
     }
   }
}](http://apijson.cn:8080/get/{"format":true,"[]":{"page":0,"count":3,"Moment":{},"User":{"id@":"%252FMoment%252FuserId"},"Comment[]":{"count":3,"Comment":{"momentId@":"[]%252FMoment%252Fid"}}}})
-- Gitee From 02865ec955fef8838d1b8dee5cdc95021d010639 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 30 Jun 2024 23:13:53 +0800 Subject: [PATCH 26/47] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E5=88=B0=207.0.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/pom.xml | 2 +- APIJSONORM/src/main/java/apijson/Log.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index 45f4522c..d466682c 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -5,7 +5,7 @@ com.github.Tencent APIJSON - 7.0.0 + 7.0.3 jar APIJSONORM diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java index 3bdad052..662dc912 100755 --- a/APIJSONORM/src/main/java/apijson/Log.java +++ b/APIJSONORM/src/main/java/apijson/Log.java @@ -14,7 +14,7 @@ public class Log { public static boolean DEBUG = true; - public static final String VERSION = "7.0.0"; + public static final String VERSION = "7.0.3"; public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n"; public static final String OS_NAME; -- Gitee From 225abd5b67666e9eb93242904a08b126c56a9654 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 15 Jul 2024 23:57:55 +0800 Subject: [PATCH 27/47] =?UTF-8?q?=E7=94=9F=E6=80=81=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20lanmuc-=E5=90=8E=E7=AB=AF=E4=BD=8E?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E4=BA=A7=E6=8E=A5=E5=8F=A3=E7=9A=84?= =?UTF-8?q?=E5=B9=B3=E5=8F=B0=EF=BC=8C=E5=85=BC=E5=AE=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=BC=8F=E6=8E=A5=E5=8F=A3=E5=92=8C=E7=BC=96=E5=86=99=E5=BC=8F?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=8F=AF=E5=81=9A=E5=88=B0=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E7=94=9F=E4=BA=A7=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=B8=8A?= =?UTF-8?q?=E7=BA=BF=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 感谢作者的热心贡献,右上角点亮 ⭐️Star 支持下 TA 吧~ https://gitee.com/element-admin/lanmuc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8d6afdad..bb9c01ed 100644 --- a/README.md +++ b/README.md @@ -712,6 +712,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-query-spring-boot-starter](https://gitee.com/mingbaobaba/apijson-query-spring-boot-starter) 一个快速构建 APIJSON 查询条件的插件 [apijson-builder](https://github.com/yeli19950109/apijson-builder) 简单包装 APIJSON,相比直接构造查询 JSON 更好记,ts 编写,调整了一些参数和使用方式 + +[lanmuc](https://gitee.com/element-admin/lanmuc) 后端低代码生产接口的平台,兼容配置式接口和编写式接口,可做到快速生产接口,上线项目 感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~ -- Gitee From e6cf73e202df6d907162d12fc55a66d6e43bf8a2 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 28 Jul 2024 23:30:12 +0800 Subject: [PATCH 28/47] Update jitpack.yml --- jitpack.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jitpack.yml b/jitpack.yml index 9e42c425..f1e4ecdd 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,6 +1,6 @@ jdk: - - openjdk17 + - openjdk8 before_install: - - sdk install java 17.0.6-open - - sdk use java 17.0.6-open + - sdk install java 1.8.0-open + - sdk use java 1.8.0-open -- Gitee From f787f8e6038dedd9e55a238fbcb7bc7757871f11 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 28 Jul 2024 23:31:30 +0800 Subject: [PATCH 29/47] Update jitpack.yml --- jitpack.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jitpack.yml b/jitpack.yml index f1e4ecdd..9e42c425 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,6 +1,6 @@ jdk: - - openjdk8 + - openjdk17 before_install: - - sdk install java 1.8.0-open - - sdk use java 1.8.0-open + - sdk install java 17.0.6-open + - sdk use java 17.0.6-open -- Gitee From e16718fc7aabfefeeb22e03a9bd9613aadff3301 Mon Sep 17 00:00:00 2001 From: zxcwindy Date: Tue, 30 Jul 2024 15:56:51 +0800 Subject: [PATCH 30/47] =?UTF-8?q?=E5=8C=97=E6=98=8E=E8=BD=AF=E4=BB=B6?= =?UTF-8?q?=E7=99=BB=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bb9c01ed..277743c5 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,7 @@ https://github.com/Tencent/APIJSON/issues/187 * [上海麦市信息科技有限公司](https://www.masscms.com) * [上海翊丞互联网科技有限公司](http://www.renrencjl.com/home) * [上海直真君智科技有限公司](http://www.zzjunzhi.com) + * [北明软件有限公司](https://www.bmsoft.com.cn/) ### 贡献者们 主项目 APIJSON 的贡献者们(6 个腾讯工程师、1 个微软工程师、1 个阿里云工程师、1 个字节跳动工程师、1 个网易工程师、1 个 Zoom 工程师、1 个圆通工程师、1 个知乎基础研发架构师、1 个智联招聘工程师、1 个美国加州大学学生、3 个 SUSTech 学生等):
-- Gitee From 746f291a619c4a792907c0dfa4a74eea5dae34f9 Mon Sep 17 00:00:00 2001 From: LY Date: Wed, 7 Aug 2024 15:05:22 +0800 Subject: [PATCH 31/47] =?UTF-8?q?fix:=20=E5=A4=84=E7=90=86=E8=87=AA?= =?UTF-8?q?=E5=85=B3=E8=81=94=E6=9F=A5=E8=AF=A2=E6=97=B6=EF=BC=8C=E5=AF=B9?= =?UTF-8?q?Table:alias=E7=9A=84=E5=86=99=E6=B3=95sql=E8=A1=A8=E5=90=8D?= =?UTF-8?q?=E6=8B=BC=E5=86=99=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractSQLConfig.java | 106 +++++++++--------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 6b714e58..6131e3be 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -188,7 +188,7 @@ public abstract class AbstractSQLConfig implements SQLConfig(); + ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP = new HashMap<>(); CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet()); CONFIG_TABLE_LIST.add(Function.class.getSimpleName()); @@ -492,8 +492,8 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig raw = getRaw(); - // 提前把 @having& 转为 @having,或者干脆不允许 @raw:"@having&" boolean containRaw = raw != null && (raw.contains(KEY_HAVING) || raw.contains(KEY_HAVING_AND)); + // 提前把 @having& 转为 @having,或者干脆不允许 @raw:"@having&" boolean containRaw = raw != null && (raw.contains(KEY_HAVING) || raw.contains(KEY_HAVING_AND)); boolean containRaw = raw != null && raw.contains(KEY_HAVING); // 直接把 having 类型从 Map 定改为 Map,避免额外拷贝 @@ -2657,12 +2663,12 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig= 8)) { return "regexp_like(" + getKey(column) + ", " + getValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")"; } - if (isPresto() || isTrino()) { - return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") - + ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")"; - } + if (isPresto() || isTrino()) { + return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + + ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")"; + } if (isClickHouse()) { return "match(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")"; } - if (isElasticsearch()) { - return getKey(column) + " RLIKE " + getValue(key, column, value); - } + if (isElasticsearch()) { + return getKey(column) + " RLIKE " + getValue(key, column, value); + } if (isHive()) { return (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + " REGEXP " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : ""); @@ -4135,7 +4141,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig " + offset; } @@ -4816,7 +4822,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig".equals(rt)) { @@ -4950,12 +4956,12 @@ public abstract class AbstractSQLConfig implements SQLConfig character varying "[" + c + "]"); -- Gitee From 6bfb21840d8b9152dc1131d1cd8ba7c0a9137de6 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 11 Aug 2024 17:08:25 +0800 Subject: [PATCH 32/47] =?UTF-8?q?getSQLTableWithAlias=20=E5=B8=A6=E4=B8=8A?= =?UTF-8?q?=E5=8E=9F=E8=A1=A8=E5=90=8D=EF=BC=8C=E9=81=BF=E5=85=8D=20alias?= =?UTF-8?q?=20=E4=B8=8E=E5=85=B6=E5=AE=83=E8=A1=A8=E5=90=8D/=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20=E5=86=B2=E7=AA=81=EF=BC=9B=E4=BC=98=E5=8C=96=20Git?= =?UTF-8?q?Hub=20=E5=AF=B9=20tab=20=E5=92=8C=20IDE=20=E5=A4=84=E7=90=86?= =?UTF-8?q?=E4=B8=8D=E4=B8=80=E8=87=B4=E5=AF=BC=E8=87=B4=E7=BC=A9=E8=BF=9B?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractSQLConfig.java | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 6131e3be..5014f0eb 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -143,9 +143,9 @@ public abstract class AbstractSQLConfig implements SQLConfig COLUMN_KEY_MAP; - /** - * 允许批量增删改部分记录失败的表 - */ + /** + * 允许批量增删改部分记录失败的表 + */ public static Map ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP; public static List CONFIG_TABLE_LIST; public static List DATABASE_LIST; @@ -188,7 +188,7 @@ public abstract class AbstractSQLConfig implements SQLConfig(); + ALLOW_PARTIAL_UPDATE_FAIL_TABLE_MAP = new HashMap<>(); CONFIG_TABLE_LIST = new ArrayList<>(); // Table, Column 等是系统表 AbstractVerifier.SYSTEM_ACCESS_MAP.keySet()); CONFIG_TABLE_LIST.add(Function.class.getSimpleName()); @@ -492,8 +492,8 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig= 8)) { return "regexp_like(" + getKey(column) + ", " + getValue(key, column, value) + (ignoreCase ? ", 'i'" : ", 'c'") + ")"; } - if (isPresto() || isTrino()) { - return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + if (isPresto() || isTrino()) { + return "regexp_like(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")"; - } + } if (isClickHouse()) { return "match(" + (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + ", " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : "") + ")"; } - if (isElasticsearch()) { - return getKey(column) + " RLIKE " + getValue(key, column, value); - } + if (isElasticsearch()) { + return getKey(column) + " RLIKE " + getValue(key, column, value); + } if (isHive()) { return (ignoreCase ? "lower(" : "") + getKey(column) + (ignoreCase ? ")" : "") + " REGEXP " + (ignoreCase ? "lower(" : "") + getValue(key, column, value) + (ignoreCase ? ")" : ""); @@ -4202,11 +4202,11 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig " + offset; } @@ -4796,10 +4796,10 @@ public abstract class AbstractSQLConfig implements SQLConfig opvl = getPreparedValueList(); - // if (opvl != null && opvl.isEmpty() == false) { - // pvl.addAll(opvl); - // } + // List opvl = getPreparedValueList(); + // if (opvl != null && opvl.isEmpty() == false) { + // pvl.addAll(opvl); + // } setPreparedValueList(pvl); //} @@ -4822,7 +4822,7 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig implements SQLConfig".equals(rt)) { -- Gitee From 8dbdc4f6e2a7470c1b2bb523addf1d37f657b0fa Mon Sep 17 00:00:00 2001 From: afumu Date: Thu, 29 Aug 2024 16:11:09 +0800 Subject: [PATCH 33/47] =?UTF-8?q?=E5=A2=9E=E5=8A=A0SQLite=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/apijson/orm/AbstractSQLConfig.java | 8 ++++++++ APIJSONORM/src/main/java/apijson/orm/SQLConfig.java | 2 ++ 2 files changed, 10 insertions(+) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 5014f0eb..bcb1af59 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -1301,6 +1301,14 @@ public abstract class AbstractSQLConfig implements SQLConfig { String DATABASE_MONGODB = "MONGODB"; // https://www.mongodb.com/docs/atlas/data-federation/query/query-with-sql String DATABASE_KAFKA = "KAFKA"; // https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONDemo-MultiDataSource-Kafka String DATABASE_MQ = "MQ"; // + String DATABASE_SQLITE = "SQLITE"; // https://www.sqlite.org String SCHEMA_INFORMATION = "information_schema"; //MySQL, PostgreSQL, SQL Server 都有的系统模式 String SCHEMA_SYS = "sys"; //SQL Server 系统模式 @@ -91,6 +92,7 @@ public interface SQLConfig { boolean isMongoDB(); boolean isKafka(); boolean isMQ(); + boolean isSQLite(); // 暂时只兼容以上几种 -- Gitee From 44e596ff2718412235967b54b11c51369c3ecf0f Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 8 Sep 2024 23:07:44 +0800 Subject: [PATCH 34/47] =?UTF-8?q?17K+=20Star=20=E5=9C=A8=20400W=C2=A0Java?= =?UTF-8?q?=20=E9=A1=B9=E7=9B=AE=E6=8E=92=E5=90=8D=E5=89=8D=20100=EF=BC=8C?= =?UTF-8?q?=E8=BF=9C=E8=B6=85=20FLAG,=20BAT=20=E7=AD=89=E5=9B=BD=E5=86=85?= =?UTF-8?q?=E5=A4=96=E7=BB=9D=E5=A4=A7=E9=83=A8=E5=88=86=E5=BC=80=E6=BA=90?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON/edit/master/README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 277743c5..403be4cf 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ https://github.com/Tencent/APIJSON/wiki * **解决十大痛点** (可帮前后端开发大幅提振开发效率、强力杜绝联调扯皮、巧妙规避文档缺陷、非常节省流量带宽) * **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) * **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) -* **社区影响力大** (GitHub 16K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) +* **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) * **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) * **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等) * **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目) -- Gitee From 886344adb6c1cfae650402ec06cdd4b0433c275a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 19 Sep 2024 00:52:43 +0800 Subject: [PATCH 35/47] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20UnitAuto=20=E7=AE=80?= =?UTF-8?q?=E4=BB=8B:=20=E6=9C=80=E5=85=88=E8=BF=9B=E3=80=81=E6=9C=80?= =?UTF-8?q?=E7=9C=81=E4=BA=8B=E3=80=81ROI=20=E6=9C=80=E9=AB=98=E7=9A=84?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=EF=BC=8C=E6=9C=BA=E5=99=A8?= =?UTF-8?q?=E5=AD=A6=E4=B9=A0=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E3=80=81?= =?UTF-8?q?=E5=85=A8=E6=96=B9=E4=BD=8D=E3=80=81=E8=87=AA=E5=8A=A8=E5=8C=96?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=20=E6=96=B9=E6=B3=95/=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E6=88=B7=E5=8C=85=E5=90=AB=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E3=80=81=E5=BF=AB=E6=89=8B=E3=80=81=E6=9F=90=20500=20=E5=BC=BA?= =?UTF-8?q?=E5=B7=A8=E5=A4=B4=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持 Java, Go, C++, Python, Kotlin, Android 等。 创作不易、坚持更难,右上角点亮 ⭐ Star 支持下本项目吧,谢谢 ^_^ https://github.com/TommyLemon/UnitAuto --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 403be4cf..b2aa8221 100644 --- a/README.md +++ b/README.md @@ -630,7 +630,7 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [APIAuto](https://github.com/TommyLemon/APIAuto) 敏捷开发最强大易用的接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 -[UnitAuto](https://github.com/TommyLemon/UnitAuto) 机器学习零代码单元测试平台,零代码、全方位、自动化 测试 方法/函数 的正确性、可用性和性能 +[UnitAuto](https://github.com/TommyLemon/UnitAuto) 最先进、最省事、ROI 最高的单元测试,机器学习 零代码、全方位、自动化 测试 方法/函数,用户包含腾讯、快手、某 500 强巨头等 [SQLAuto](https://github.com/TommyLemon/SQLAuto) 智能零代码自动化测试 SQL 语句执行结果的数据库工具,一键批量生成参数组合、快速构造大量测试数据 -- Gitee From b749e538a109495ccaa60663c6b9b48c54c540f5 Mon Sep 17 00:00:00 2001 From: alittle-yu <131329000+alittle-yu@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:30:44 +0800 Subject: [PATCH 36/47] =?UTF-8?q?fix=EF=BC=9A=E8=B0=83=E6=95=B4parseRespon?= =?UTF-8?q?se=E8=8E=B7=E5=8F=96SQLExecutor=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/orm/AbstractParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java index 44b19661..4da6aa24 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java @@ -520,7 +520,7 @@ public abstract class AbstractParser implements Parser, Par queryResultMap = new HashMap(); Exception error = null; - sqlExecutor = createSQLExecutor(); + sqlExecutor = getSQLExecutor(); onBegin(); try { queryDepth = 0; -- Gitee From 016f31a63eee52ac7350482a25e39eb2a7e47c54 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 28 Sep 2024 11:25:52 +0800 Subject: [PATCH 37/47] =?UTF-8?q?=E9=80=9A=E7=94=A8=E6=96=87=E6=A1=A3?= =?UTF-8?q?=EF=BC=9A=E5=8A=9F=E8=83=BD=E7=AC=A6=E6=96=B0=E5=A2=9E=E7=A9=BA?= =?UTF-8?q?=E5=80=BC=E9=94=AE=E5=80=BC=E5=AF=B9=20"@null":"key1,key2..."?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON/blob/master/Document.md#32-%E5%8A%9F%E8%83%BD%E7%AC%A6 --- Document.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Document.md b/Document.md index 72355006..e20bfbb2 100644 --- a/Document.md +++ b/Document.md @@ -421,6 +421,6 @@ DELETE:
删除数据 | base_url/delete/ | {
   TableName:{< 比较运算 | >, <, >=, <= 比较运算符,用于
① 提供 "id{}":"<=90000" 这种条件范围的简化写法

② 实现子查询相关比较运算

不支持 "key=":Object 和 "key!=":Object 这两种写法,直接用更简单的 "key":Object 和 "key!":Object 替代。 | ① ["id<=":90000](http://apijson.cn:8080/get/{"[]":{"User":{"id<=":90000}}}),对应 SQL 是`id<=90000`,查询符合id<=90000的一个User数组

② ["id>@":{
   "from":"Comment",
   "Comment":{
      "@column":"min(userId)"
   }
}](http://apijson.cn:8080/get/{"User":{"id>@":{"from":"Comment","Comment":{"@column":"min(userId)"}}}})
WHERE id>(SELECT min(userId) FROM Comment) 逻辑运算 | &, \|, ! 逻辑运算符,对应数据库 SQL 中的 AND, OR, NOT。
横或纵与:同一键值对的值内条件默认 \| 或连接,可以在 key 后加逻辑运算符来具体指定;不同键值对的条件默认 & 与连接,可以用下面说明的对象关键词 @combine 来具体指定。

① & 可用于 "key&{}":"条件"等

② \| 可用于 "key\|{}":"条件", "key\|{}":[]等,一般可省略

③ ! 可单独使用,如 "key!":Object,也可像 &,\| 一样配合其他功能符使用
"key!":null 无效,null 值会导致整个键值对被忽略解析,可以用 "key{}":"!=null" 替代,
"key":null 同理,用 "key{}":"=null" 替代。 | ① ["id&{}":">80000,<=90000"](http://apijson.cn:8080/head/{"User":{"id&{}":">80000,<=90000"}}),对应SQL是`id>80000 AND id<=90000`,即id满足id>80000 & id<=90000

② ["id\|{}":">90000,<=80000"](http://apijson.cn:8080/head/{"User":{"id\|{}":">90000,<=80000"}}),同 "id{}":">90000,<=80000",对应 SQL 是`id>90000 OR id<=80000`,即 id 满足 id>90000 \| id<=80000

③ ["id!{}":[82001,38710]](http://apijson.cn:8080/head/{"User":{"id!{}":[82001,38710]}}),对应 SQL 是`id NOT IN(82001,38710)`,即 id 满足 ! (id=82001 \| id=38710),可过滤黑名单的消息 数组关键词,可自定义 | "key":Object,key为 "[]":{} 中 {} 内的关键词,Object 的类型由 key 指定

① "count":5,查询数量,0 表示最大值,默认值为 10,默认最大值为 100

② "page":1,查询页码,从 0 开始,默认值为 0,默认最大值为 100,一般和 count 一起用

③ "query":2,查询内容
0-对象,1-总数和分页详情,2-数据、总数和分页详情
总数关键词为 total,分页详情关键词为 info,
它们都和 query 同级,通过引用赋值得到自定义 key:value 键值对,不传则返回默认键值对,例如
"total@":"/[]/total", "info@":"/[]/info"
这里query及total仅为GET类型的请求提供方便,
一般可直接用HEAD类型的请求获取总数

④ "join":"&/Table0,\"join":{
   "&/Table0":{}, // 支持 ON 多个字段关联,
   "\      "key0":value0, // 其它ON条件
     "key2":value2,
     ...
     "@combine":"...", // 其它ON条件的组合方式
     "@column":"...", // 外层 SELECT
     "@group":"...", // 外层 GROUP BY
     "@having":"..." // 外层 HAVING
   }
}
多表连接方式:
"@" - APP JOIN
"\<" - LEFT JOIN
">" - RIGHT JOIN
"&" - INNER JOIN
"\|" - FULL JOIN
"!" - OUTER JOIN
"*" - CROSS JOIN
"^" - SIDE JOIN
"(" - ANTI JOIN
")" - FOREIGN JOIN
其中 @ APP JOIN 为应用层连表,会从已查出的主表里取得所有副表 key@ 关联的主表内的 refKey 作为一个数组 refKeys: [value0, value1...],然后把原来副表 count 次查询 key=$refKey 的 SQL 用 key IN($refKeys) 的方式合并为一条 SQL 来优化性能;
其它 JOIN 都是 SQL JOIN,具体功能和 MySQL,PostgreSQL 等数据库的 JOIN 一一对应
`"join":"`"MainTable":{},`
`"ViceTable":{"key@":"/MainTable/refKey"}`
会对应生成
`MainTable LEFT JOIN ViceTable`
`ON ViceTable.key=MainTable.refKey` AND 其它ON条件
除了 = 等价关联,也支持 ! 不等关联、\> \< \>= \<= 等比较关联和 $ ~ {} <> 等其它复杂关联方式

⑤ "otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 查询User数组,最多5个:
["count":5](http://apijson.cn:8080/get/{"[]":{"count":5,"User":{}}})
对应 SQL 是`LIMIT 5`

② 查询第3页的User数组,每页5个:
["count":5,
"page":3](http://apijson.cn:8080/get/{"[]":{"count":5,"page":3,"User":{}}})
对应 SQL 是`LIMIT 5 OFFSET 15`

③ 查询User数组和对应的User总数:
["[]":{
   "query":2,
   "User":{}
},
"total@":"/[]/total", // 可省略
"info@":"/[]/info" // 可省略](http://apijson.cn:8080/get/{"[]":{"query":2,"count":5,"User":{}},"total@":"%252F[]%252Ftotal","info@":"%252F[]%252Finfo"})
返回的数据中,总数及分页详情结构为:
"total":139, // 总数
"info":{ // 分页详情
   "total":139, // 总数
   "count":5, // 每页数量
   "page":0, // 当前页码
   "max":27, // 最大页码
   "more":true, // 是否还有更多
   "first":true, // 是否为首页
   "last":false // 是否为尾页
}

④ Moment INNER JOIN User LEFT JOIN Comment:
["[]":{
   "join":"&/User/id@,\    "Moment":{
     "@group":"id" // 主副表不是一对一,要去除重复数据
   },
   "User":{
     "name~":"t",
     "id@":"/Moment/userId"
   },
   "Comment":{
     "momentId@":"/Moment/id"
   }
}](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/get&json=%7B%22%5B%5D%22:%7B%22count%22:5,%22join%22:%22%26%2FUser%2Fid@,%3C%2FComment%22,%22Moment%22:%7B%22@column%22:%22id,userId,content%22,%22@group%22:%22id%22%7D,%22User%22:%7B%22name~%22:%22t%22,%22id@%22:%22%2FMoment%2FuserId%22,%22@column%22:%22id,name,head%22%7D,%22Comment%22:%7B%22momentId@%22:%22%2FMoment%2Fid%22,%22@column%22:%22id,momentId,content%22%7D%7D%7D)

⑤ 每一层都加当前用户名:
["User":{},
"[]":{
   "name@":"User/name", // 自定义关键词
   "Moment":{}
}](http://apijson.cn:8080/get/{"User":{},"[]":{"name@":"User%252Fname","Moment":{}}}) - 对象关键词,可自定义 | "@key":Object,@key 为 Table:{} 中 {} 内的关键词,Object 的类型由 @key 指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果 @column 里声明了 Table 的 id,则 id 也必须在 @group 中声明;其它情况下必须满足至少一个条件:
1.分组的 key 在 @column 里声明
2.Table 主键在 @group 中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL 函数条件,一般和 @group 一起用,函数一般在 @column 里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防 SQL 注入

⑬ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索 name 或 tag 任何一个字段包含字符 a 的 User 列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询 id,sex,name 这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应 SQL 是`SELECT id,sex,name`

③ 查询按 name 降序、id 默认顺序 排序的 User 数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应 SQL 是`ORDER BY name DESC,id`

④ 查询按 userId 分组的 Moment 数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应 SQL 是`GROUP BY userId,id`

⑤ 查询 按 userId 分组、id 最大值>=100 的 Moment 数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应 SQL 是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应 SQL 是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应 SQL 是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应 SQL 是`EXPLAIN`

⑫ 统计最近一周偶数 userId 的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应 SQL 是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 从pictureList 获取第 0 张图片:
["@position":0, // 自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) + 对象关键词,可自定义 | "@key":Object,@key 为 Table:{} 中 {} 内的关键词,Object 的类型由 @key 指定

① "@combine":"key0 \| (key1 & (key2 \| !key3))...",条件组合方式,最终按
(其它key条件 AND 连接) AND (key0条件 OR (key1条件 AND (key2条件 OR (NOT key3条件))))
这种方式连接,其中 "其它key" 是指与 @combine 在同一对象,且未被它声明的条件 key,默认都是 & 连接。注意不要缺少或多余任何一个空格。

② "@column":"column;function(arg)...",返回字段

③ "@order":"column0+,column1-...",排序方式

④ "@group":"column0,column1...",分组方式。如果 @column 里声明了 Table 的 id,则 id 也必须在 @group 中声明;其它情况下必须满足至少一个条件:
1.分组的 key 在 @column 里声明
2.Table 主键在 @group 中声明

⑤ "@having":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // OR 连接,或
"@having&":"function0(...)?value0;function1(...)?value1;function2(...)?value2..." // AND 连接,或
"@having":{
   "h0":"function0(...)?value0",
   "h1":function1(...)?value1",
   "h2":function2(...)?value2...",
   "@combine":"h0 & (h1 \| !h2)" // 任意组合,非必传
}
SQL 函数条件,一般和 @group 一起用,函数一般在 @column 里声明

⑥ "@schema":"sys",集合空间(数据库名/模式),非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑦ "@database":"POSTGRESQL",数据库类型,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑧ "@datasource":"DRUID",跨数据源,非默认的值可通过它来指定,可以在最外层作为全局默认配置

⑨ "@json":"key0,key1...",转为 JSON 格式返回,符合 JSONObject 则转为 {...},符合 JSONArray 则转为 \[...]

⑩ "@role":"OWNER",来访角色,包括
UNKNOWN,LOGIN,CONTACT,CIRCLE,OWNER,ADMIN,
可以在最外层作为全局默认配置,
可自定义其它角色并重写 Verifier.verify 等相关方法来自定义校验

⑪ "@explain":true,性能分析,可以在最外层作为全局默认配置

⑫ "@raw":"key0,key1...",其中 key0, key1 都对应有键值对
"key0":"SQL片段或SQL片段的别名",
"key1":"SQL片段或SQL片段的别名"
自定义原始SQL片段,可扩展嵌套SQL函数等复杂语句,必须是后端已配置的,只有其它功能符都做不到才考虑,谨慎使用,注意防 SQL 注入

⑬ "@null":"key1,key2...",空值键值对,自动插入 key1:null, key2:null ... 并作为有效键值对执行,作为条件时对应 SQL 是 `WHERE tag IS NULL`,作为值时对应 SQL 是 `SET tag = NULL`

⑭ "@otherKey":Object,自定义关键词,名称和以上系统关键词不一样,且原样返回上传的值 | ① 搜索 name 或 tag 任何一个字段包含字符 a 的 User 列表:
["name~":"a",
"tag~":"a",
"@combine":"name~ \| tag~"](http://apijson.cn:8080/get/{"User[]":{"count":10,"User":{"@column":"id,name,tag","name~":"a","tag~":"a","@combine":"name~%20%7C%20tag~"}}})
对应SQL是`name REGEXP 'a' OR tag REGEXP 'a'`

② 只查询 id,sex,name 这几列并且请求结果也按照这个顺序:
["@column":"id,sex,name"](http://apijson.cn:8080/get/{"User":{"@column":"id,sex,name","id":38710}})
对应 SQL 是`SELECT id,sex,name`

③ 查询按 name 降序、id 默认顺序 排序的 User 数组:
["@order":"name-,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"User":{"@column":"name,id","@order":"name-,id"}}})
对应 SQL 是`ORDER BY name DESC,id`

④ 查询按 userId 分组的 Moment 数组:
["@group":"userId,id"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":%7B"@column":"userId,id","@group":"userId,id"}}})
对应 SQL 是`GROUP BY userId,id`

⑤ 查询 按 userId 分组、id 最大值>=100 的 Moment 数组:
["@column":"userId;max(id)",
"@group":"userId",
"@having":"max(id)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id)","@group":"userId","@having":"max(id)>=100"}}})
对应 SQL 是`SELECT userId,max(id) ... GROUP BY userId HAVING max(id)>=100`
还可以指定函数返回名:
["@column":"userId;max(id):maxId",
"@group":"userId",
"@having":"(maxId)>=100"](http://apijson.cn:8080/get/{"[]":{"count":10,"Moment":{"@column":"userId%253Bmax(id):maxId","@group":"userId","@having":"(maxId)>=100"}}})
对应 SQL 是`SELECT userId,max(id) AS maxId ... GROUP BY userId HAVING (maxId)>=100`

⑥ 查询 sys 内的 User 表:
["@schema":"sys"](http://apijson.cn:8080/get/{"User":{"@schema":"sys"}})
对应 SQL 是`FROM sys.User`

⑦ 查询 PostgreSQL 数据库的 User 表:
["@database":"POSTGRESQL"](http://apijson.cn:8080/get/{"User":{"@database":"POSTGRESQL","@explain":true}})

⑧ 使用 Druid 连接池查询 User 表:
["@datasource":"DRUID"](http://apijson.cn:8080/get/{"User":{"@datasource":"DRUID"}})

⑨ 将 VARCHAR 字符串字段 get 转为 JSONArray 返回:
["@json":"get"](http://apijson.cn:8080/get/{"Access":{"@json":"get"}})

⑩ 查询当前用户的动态:
["@role":"OWNER"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@role":"OWNER"}}})

⑪ 开启性能分析:
["@explain":true](http://apijson.cn:8080/get/{"[]":{"Moment":{"@explain":true}}})
对应 SQL 是`EXPLAIN`

⑫ 统计最近一周偶数 userId 的数量
["@column":"date;left(date,10):day;sum(if(userId%2=0,1,0))",
"@group":"day",
"@having":"to_days(now())-to_days(\`date\`)<=7",
"@raw":"@column,@having"](http://apijson.cn:8080/get/{"[]":{"Moment":{"@column":"date%3bleft(date,10):day%3bsum(if(userId%252=0,1,0))","@group":"day","@having":"to_days(now())-to_days(\`date\`)<=7","@raw":"@column,@having"}}})
对应 SQL 是``SELECT date, left(date,10) AS day, sum(if(userId%2=0,1,0)) ... GROUP BY day HAVING to_days(now())-to_days(`date`)<=7``

⑬ 把用户的标签设置为空
["@null":"tag"](http://apijson.cn/api/?type=JSON&url=http://apijson.cn:8080/put/User&json={%22id%22:82001,%22@null%22:%22tag%22,%22@explain%22:true})

⑭ 从pictureList 获取第 0 张图片:
["@position":0, // 自定义关键词
"firstPicture()":"getFromArray(pictureList,@position)"](http://apijson.cn:8080/get/{"User":{"id":38710,"@position":0,"firstPicture()":"getFromArray(pictureList,@position)"}}) 全局关键词 | 为最外层对象 {} 内的关键词。其中 @database,@schema, @datasource, @role, @explain 基本同对象关键词,见上方说明,区别是全局关键词会每个表对象中没有时自动放入,作为默认值。

① "tag":"Table",后面的 tag 是非 GET、HEAD 请求中匹配请求的 JSON 结构的标识,一般是要查询的 Table 的名称或该名称对应的数组 Table[] 或 Table:[],由后端 Request 表中指定。

② "version":1,接口版本,version 不传、为 null 或 <=0 都会使用最高版本,传了其它有效值则会使用最接近它的最低版本,由后端 Request 表中指定。

③ "format":true,格式化返回 Response JSON 的 key,一般是将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias, TableName-key[] 转为 tableNameKeyList 等小驼峰格式。 | ① 查隐私信息:
[{"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

② 使用第 1 版接口查隐私信息:
[{"version":1,"tag":"Privacy","Privacy":{"id":82001}}](http://apijson.cn/api?url=http%3A%2F%2Fapijson.cn%3A8080%2Fgets&type=JSON&json={%22version%22:1,%22tag%22:%22Privacy%22,%22Privacy%22:{%22id%22:82001}})

③ 格式化朋友圈接口返回 JSON 中的 key:
[{
   "format":true,
   "[]":{
     "page":0,
     "count":3,
     "Moment":{},
     "User":{
       "id@":"/Moment/userId"
     },
     "Comment[]":{
       "count":3,
       "Comment":{
         "momentId@":"[]/Moment/id"
       }
     }
   }
}](http://apijson.cn:8080/get/{"format":true,"[]":{"page":0,"count":3,"Moment":{},"User":{"id@":"%252FMoment%252FuserId"},"Comment[]":{"count":3,"Comment":{"momentId@":"[]%252FMoment%252Fid"}}}})
-- Gitee From 041735362050f0e1764ef2793a7a24f3946b4744 Mon Sep 17 00:00:00 2001 From: Damon Nicola <69659973+Reynold3D@users.noreply.github.com> Date: Sun, 29 Sep 2024 17:22:43 +0800 Subject: [PATCH 38/47] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=99=BB=E8=AE=B0?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E4=B8=8A=E6=B5=B7=E9=92=B0=E4=BA=BF?= =?UTF-8?q?=E7=8E=AF=E4=BF=9D=E7=A7=91=E6=8A=80=E6=9C=89=E9=99=90=E5=85=AC?= =?UTF-8?q?=E5=8F=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b2aa8221..4acdba48 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,7 @@ https://github.com/Tencent/APIJSON/issues/187 * [上海翊丞互联网科技有限公司](http://www.renrencjl.com/home) * [上海直真君智科技有限公司](http://www.zzjunzhi.com) * [北明软件有限公司](https://www.bmsoft.com.cn/) + * [上海钰亿环保科技有限公司](#) ### 贡献者们 主项目 APIJSON 的贡献者们(6 个腾讯工程师、1 个微软工程师、1 个阿里云工程师、1 个字节跳动工程师、1 个网易工程师、1 个 Zoom 工程师、1 个圆通工程师、1 个知乎基础研发架构师、1 个智联招聘工程师、1 个美国加州大学学生、3 个 SUSTech 学生等):
-- Gitee From 6ea0b9b60bbe49e7793a06c22c9cd22ad96e3d1a Mon Sep 17 00:00:00 2001 From: calmcc Date: Thu, 17 Oct 2024 16:09:21 +0800 Subject: [PATCH 39/47] =?UTF-8?q?1.=E5=AF=B9=E6=9F=90=E4=BA=9B=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E8=BE=93=E5=87=BAnull=E5=80=BC=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E9=9C=80=E6=B1=82=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=BE=93?= =?UTF-8?q?=E5=87=BAnull=E5=80=BC=E7=9A=84=E5=BC=80=E5=85=B3=20=E5=9C=A8?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E5=87=BD=E6=95=B0=E5=A2=9E=E5=8A=A0=E8=BF=99?= =?UTF-8?q?=E4=B8=A4=E5=8F=A5=20JSON.DEFAULT=5FGENERATE=5FFEATURE=20|=3D?= =?UTF-8?q?=20SerializerFeature.WriteMapNullValue.getMask();=20AbstractSQL?= =?UTF-8?q?Executor.ENABLE=5FOUTPUT=5FNULL=5FCOLUMN=20=3D=20true;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/src/main/java/apijson/JSON.java | 3 +- .../java/apijson/orm/AbstractSQLExecutor.java | 43 ++++++++----------- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/JSON.java b/APIJSONORM/src/main/java/apijson/JSON.java index 48b80aac..d7854aae 100755 --- a/APIJSONORM/src/main/java/apijson/JSON.java +++ b/APIJSONORM/src/main/java/apijson/JSON.java @@ -8,7 +8,6 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import com.alibaba.fastjson.serializer.SerializerFeature; -import com.alibaba.fastjson.JSONReader; import java.util.List; @@ -203,7 +202,7 @@ public class JSON { try { return com.alibaba.fastjson.JSON.toJSONString(obj, features); } catch (Exception e) { - Log.e(TAG, "parseArray catch \n" + e.getMessage()); + Log.e(TAG, "toJSONString catch \n" + e.getMessage()); } return null; } diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java index 426a53ee..36ef71ca 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java @@ -5,45 +5,32 @@ This source code is licensed under the Apache License Version 2.0.*/ package apijson.orm; +import apijson.*; +import apijson.orm.Join.On; +import apijson.orm.exception.NotExistException; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; + import java.io.BufferedReader; import java.math.BigDecimal; import java.math.BigInteger; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Connection; -import java.util.*; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Savepoint; -import java.sql.Statement; -import java.sql.Timestamp; +import java.sql.*; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.Month; import java.time.Year; +import java.util.Date; +import java.util.*; import java.util.Map.Entry; import java.util.regex.Pattern; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; - -import apijson.JSONResponse; -import apijson.Log; -import apijson.NotNull; -import apijson.RequestMethod; -import apijson.StringUtil; -import apijson.orm.Join.On; -import apijson.orm.exception.NotExistException; - /**executor for query(read) or update(write) MySQL database * @author Lemon */ public abstract class AbstractSQLExecutor implements SQLExecutor { private static final String TAG = "AbstractSQLExecutor"; - + //是否返回 值为null的字段 + public static boolean ENABLE_OUTPUT_NULL_COLUMN = false; public static String KEY_RAW_LIST = "@RAW@LIST"; // 避免和字段命名冲突,不用 $RAW@LIST$ 是因为 $ 会在 fastjson 内部转义,浪费性能 private Parser parser; @@ -918,8 +905,14 @@ public abstract class AbstractSQLExecutor implements SQLExecut Object value = getValue(config, rs, rsmd, tablePosition, table, columnIndex, label, childMap); // 主表必须 put 至少一个 null 进去,否则全部字段为 null 都不 put 会导致中断后续正常返回值 - if (value != null || (join == null && table.isEmpty())) { + if (value != null) { table.put(label, value); + } else{ + if (join == null && table.isEmpty()) { + table.put(label, null); + } else if (ENABLE_OUTPUT_NULL_COLUMN) { + table.put(label, null); + } } return table; -- Gitee From 90b896c9d59cb6883b2e4469d3806e1c3ed815b9 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Oct 2024 21:50:51 +0800 Subject: [PATCH 40/47] =?UTF-8?q?=E5=A4=9A=E5=B9=B4=E6=8C=81=E7=BB=AD?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3:=20=E8=87=AA=202016=20=E5=B9=B4=E8=B5=B7?= =?UTF-8?q?=E5=B7=B2=E8=BF=9E=E7=BB=AD=E7=BB=B4=E6=8A=A4=207=20=E5=B9=B4?= =?UTF-8?q?=E5=A4=9A=EF=BC=8C70+=20=E8=B4=A1=E7=8C=AE=E8=80=85=E3=80=8190+?= =?UTF-8?q?=20=E5=8F=91=E7=89=88=E3=80=813000+=20=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E6=96=AD=E6=9B=B4=E6=96=B0=E8=BF=AD=E4=BB=A3?= =?UTF-8?q?=E4=B8=AD...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4acdba48..0f69856a 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ https://github.com/Tencent/APIJSON/wiki * **高质可靠代码** (代码严谨规范,商业分析软件源伞 Pinpoint 代码扫描报告平均每行代码 Bug 率低至 0.15%) * **兼容各种项目** (协议不限 HTTP,与其它库无冲突,对各类 Web 框架集成友好且提供 SpringBoot, JFinal 的示例) * **工程轻量小巧** (仅依赖 fastjson,Jar 仅 280KB,Java 文件仅 59 个共 13719 行代码,例如 APIJSONORM 4.3.1) -* **多年持续迭代** (自 2016 年起已连续维护 7 年多,60+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...) +* **多年持续迭代** (自 2016 年起已连续维护 7 年多,70+ 贡献者、90+ 发版、3000+ 提交,不断更新迭代中...) **按照一般互联网中小型项目情况可得出以下对比表格:** -- Gitee From 64042e59bd80146c1b589b95242e234a06fd5efb Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 3 Nov 2024 20:25:18 +0800 Subject: [PATCH 41/47] =?UTF-8?q?=E5=AE=9E=E6=97=B6=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E3=80=81=E5=85=A8=E5=8A=9F=E8=83=BD=E3=80=81=E5=BC=BA?= =?UTF-8?q?=E5=AE=89=E5=85=A8=20ORM=20=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f69856a..c1d70c7f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This source code is licensed under the Apache License Version 2.0
APIJSON -

🏆 零代码、全功能、强安全 ORM 库 🚀
后端接口和文档零代码,前端(客户端) 定制返回 JSON 的数据和结构

+

🏆 实时 零代码、全功能、强安全 ORM 库 🚀
后端接口和文档零代码,前端(客户端) 定制返回 JSON 的数据和结构

English -- Gitee From 4f6066cffaf1d06a41a7b4f6a127f22ae56c80c0 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 3 Nov 2024 20:27:54 +0800 Subject: [PATCH 42/47] =?UTF-8?q?=E7=94=9F=E6=80=81=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20review=5Fplan-=E5=A4=8D=E4=B9=A0=E6=8F=90?= =?UTF-8?q?=E9=86=92Web=E7=89=88=EF=BC=88Java=E6=8A=80=E6=9C=AF=E7=BB=83?= =?UTF-8?q?=E4=B9=A0=E9=A1=B9=E7=9B=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 创作不易,右上角点亮 ⭐️ Star 支持热心的作者吧 ^_^ https://gitee.com/TommyLemon/review_plan --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c1d70c7f..f668756d 100644 --- a/README.md +++ b/README.md @@ -716,6 +716,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [apijson-builder](https://github.com/yeli19950109/apijson-builder) 简单包装 APIJSON,相比直接构造查询 JSON 更好记,ts 编写,调整了一些参数和使用方式 [lanmuc](https://gitee.com/element-admin/lanmuc) 后端低代码生产接口的平台,兼容配置式接口和编写式接口,可做到快速生产接口,上线项目 + +[review_plan](https://gitee.com/PPXcodeTry/review_plan) 复习提醒Web版(Java技术练习项目) 感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~ -- Gitee From 8f55a3cef023a155e4bbadabdcea85df9175a059 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 11 Nov 2024 00:45:01 +0800 Subject: [PATCH 43/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20APIJSON=20+=20Nutz?= =?UTF-8?q?=20=E6=A1=86=E6=9E=B6=20+=20NutzBoot=20=E7=9A=84=20Demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 创作不易,右上角点亮 ⭐️ Star 支持下热心的作者吧 ^_^ https://github.com/vincent109/apijson-nutz --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f668756d..0d43b030 100644 --- a/README.md +++ b/README.md @@ -718,6 +718,8 @@ Issue/问卷 一般解答顺序:贡献者 > 帮助他人的用户 > 提供任 [lanmuc](https://gitee.com/element-admin/lanmuc) 后端低代码生产接口的平台,兼容配置式接口和编写式接口,可做到快速生产接口,上线项目 [review_plan](https://gitee.com/PPXcodeTry/review_plan) 复习提醒Web版(Java技术练习项目) + +[apijson-nutz](https://github.com/vincent109/apijson-nutz) APIJSON + Nutz 框架 + NutzBoot 的 Demo 感谢热心的作者们的贡献,点 ⭐Star 支持下他们吧~ -- Gitee From d9b5405290f0b745d98e57c02eb54a00ca3803a1 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 18 Nov 2024 00:41:57 +0800 Subject: [PATCH 44/47] =?UTF-8?q?=F0=9F=8F=86=20Tencent=20Top=206=20Open?= =?UTF-8?q?=20Source=20Project,=20Achieved=205=20Awards=20Inside=20&=20Out?= =?UTF-8?q?side=20Tencent=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON/blob/master/README-English.md --- README-English.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-English.md b/README-English.md index 4d4aacb1..9329faf0 100644 --- a/README-English.md +++ b/README-English.md @@ -7,7 +7,7 @@ This source code is licensed under the Apache License Version 2.0
-

🏆 Tencent Top 7 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀
A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.

+

🏆 Tencent Top 6 Open Source Project, Achieved 5 Awards Inside & Outside Tencent 🚀
A JSON Transmission Protocol and an ORM Library for providing APIs and Documents without writing any code.

 中文版  -- Gitee From 1f3b59b5583eb2d0a7739dabfc2ef841525ff2ce Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Sun, 24 Nov 2024 23:57:06 +0800 Subject: [PATCH 45/47] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20ke?= =?UTF-8?q?y[=20=E8=A1=A8=E7=A4=BA=20length(key)=20=E5=92=8C=20key{=20?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=20json=5Flength(key)=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E4=B8=8E=20=E4=B8=8E=E6=88=96=E9=9D=9E=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E7=AC=A6=E3=80=81=E5=85=B6=E5=AE=83=E5=90=84=E7=A7=8D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E7=AC=A6=20=E7=BB=84=E5=90=88=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- APIJSONORM/pom.xml | 2 +- .../src/main/java/apijson/JSONObject.java | 25 +++++++++ APIJSONORM/src/main/java/apijson/Log.java | 2 +- APIJSONORM/src/main/java/apijson/SQL.java | 7 +++ .../java/apijson/orm/AbstractSQLConfig.java | 51 ++++++++++++++----- 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/APIJSONORM/pom.xml b/APIJSONORM/pom.xml index d466682c..f668c0d4 100644 --- a/APIJSONORM/pom.xml +++ b/APIJSONORM/pom.xml @@ -5,7 +5,7 @@ com.github.Tencent APIJSON - 7.0.3 + 7.0.5 jar APIJSONORM diff --git a/APIJSONORM/src/main/java/apijson/JSONObject.java b/APIJSONORM/src/main/java/apijson/JSONObject.java index 8aa8eac3..32c5caab 100755 --- a/APIJSONORM/src/main/java/apijson/JSONObject.java +++ b/APIJSONORM/src/main/java/apijson/JSONObject.java @@ -480,6 +480,31 @@ public class JSONObject extends com.alibaba.fastjson.JSONObject { public JSONObject putsLength(String key, String compare) { return puts(key+"{}", SQL.length(key) + compare); } + /** + * @param key + * @param compare <=, > ... + * @param value 1, 5, 3.14, -99 ... + * @return {@link #puts(String, Object)} + */ + public JSONObject putsLength(String key, String compare, Object value) { + return puts(key+"["+(StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); + } + /** + * @param key + * @param compare <=0, >5 ... + * @return {@link #puts(String, Object)} + */ + public JSONObject putsJSONLength(String key, String compare) { + return puts(key+"{}", SQL.json_length(key) + compare); + } + /** + * @param key + * @param compare <=0, >5 ... + * @return {@link #puts(String, Object)} + */ + public JSONObject putsJSONLength(String key, String compare, Object value) { + return puts(key + "{" + (StringUtil.isEmpty(compare) || "=".equals(compare) ? "" : ("!=".equals(compare) ? "!" : compare)), value); + } /**设置搜索 * type = SEARCH_TYPE_CONTAIN_FULL diff --git a/APIJSONORM/src/main/java/apijson/Log.java b/APIJSONORM/src/main/java/apijson/Log.java index 662dc912..7252eb5a 100755 --- a/APIJSONORM/src/main/java/apijson/Log.java +++ b/APIJSONORM/src/main/java/apijson/Log.java @@ -14,7 +14,7 @@ public class Log { public static boolean DEBUG = true; - public static final String VERSION = "7.0.3"; + public static final String VERSION = "7.0.5"; public static final String KEY_SYSTEM_INFO_DIVIDER = "\n---|-----APIJSON SYSTEM INFO-----|---\n"; public static final String OS_NAME; diff --git a/APIJSONORM/src/main/java/apijson/SQL.java b/APIJSONORM/src/main/java/apijson/SQL.java index 391d5db4..6cec79bd 100755 --- a/APIJSONORM/src/main/java/apijson/SQL.java +++ b/APIJSONORM/src/main/java/apijson/SQL.java @@ -116,6 +116,13 @@ public class SQL { public static String length(String s) { return "length(" + s + ")"; } + /** + * @param s 因为POWER(x,y)等函数含有不只一个key,所以需要客户端添加进去,服务端检测到条件中有'('和')'时就不转换,直接当SQL语句查询 + * @return "json_length(" + s + ")" + */ + public static String json_length(String s) { + return "json_length(" + s + ")"; + } /** * @param s 因为POWER(x,y)等函数含有不只一个key,所以需要客户端添加进去,服务端检测到条件中有'('和')'时就不转换,直接当SQL语句查询 * @return "char_length(" + s + ")" diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index bcb1af59..4c82ea30 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -3585,7 +3585,9 @@ public abstract class AbstractSQLConfig implements SQLConfig, <, >=, <=] 只支持 [Boolean, Number, String] 内的类型 !"); } - if (StringUtil.isName(column) == false) { + + String rc = column.endsWith("[") || column.endsWith("{") ? column.substring(0, column.length() - 1) : column; + if ( ! StringUtil.isName(rc)) { throw new IllegalArgumentException(key + ":value 中 key 不合法!比较运算 [>, <, >=, <=] 不支持 [&, !, |] 中任何逻辑运算符 !"); } @@ -3594,7 +3596,16 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig raw = getRaw(); + sqlKey = parseSQLExpression(KEY_KEY, expression, raw != null && raw.contains(KEY_KEY), false); } - // (name,tag) left(date,4) 等 - List raw = getRaw(); - return parseSQLExpression(KEY_KEY, expression, raw != null && raw.contains(KEY_KEY), false); + return lenFun.isEmpty() ? sqlKey : lenFun + "(" + sqlKey + ")"; } public String getSQLKey(String key) { String q = getQuote(); @@ -6016,9 +6032,15 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig Date: Sun, 24 Nov 2024 23:59:58 +0800 Subject: [PATCH 46/47] =?UTF-8?q?=E5=90=84=E9=A1=B9=E8=8D=A3=E8=AA=89?= =?UTF-8?q?=E6=88=90=E5=B0=B1=20(=E8=85=BE=E8=AE=AF=E5=86=85=E5=A4=96=205?= =?UTF-8?q?=20=E4=B8=AA=E5=A5=96=E9=A1=B9=E3=80=81=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E5=BC=80=E6=BA=90=E5=89=8D=E5=85=AD=E3=80=81=E8=85=BE=E8=AE=AF?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=20Star=20=E7=AC=AC=E4=B8=80=E3=80=81Trending?= =?UTF-8?q?=20=E6=97=A5=E5=91=A8=E6=9C=88=E6=A6=9C=E5=A4=A7=E6=BB=A1?= =?UTF-8?q?=E8=B4=AF=20=E7=AD=89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/Tencent/APIJSON?tab=readme-ov-file#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-apijson --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d43b030..ea6ffa17 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,7 @@ https://github.com/Tencent/APIJSON/wiki * **开发提速很大** (CRUD 零代码热更新全自动,APIJSONBoot 对比 SSM、SSH 等保守估计可提速 20 倍以上) * **腾讯官方开源** (使用 GitHub、Gitee、工蜂 等平台的官方账号开源,微信公众号、腾讯云+社区 等官方公告) * **社区影响力大** (GitHub 17K+ Star 在 400W Java 项目排名前 100,远超 FLAG, BAT 等国内外绝大部分开源项目) -* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前七、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) +* **各项荣誉成就** (腾讯内外 5 个奖项、腾讯开源前六、腾讯后端 Star 第一、Trending 日周月榜大满贯 等) * **多样用户案例** (腾讯内有互娱、音乐、微信、云与智慧,外部有华为、华能、百度、快手、中兴、圆通、传音等) * **适用场景广泛** (社交聊天、阅读资讯、影音娱乐、办公学习 等各种 App、网站、小程序、公众号 等非金融类项目) * **周边生态丰富** (Android, iOS, Web 等各种 Demo、继承 JSON 的海量生态、零代码 接口测试 和 单元测试 工具等) -- Gitee From 067e7b9f5bb1d5bc0794741c0ffb31ca75dfff92 Mon Sep 17 00:00:00 2001 From: TommyLemon Date: Mon, 25 Nov 2024 00:05:11 +0800 Subject: [PATCH 47/47] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20key[=20=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=20length(key)=20=E5=92=8C=20key{=20=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=20json=5Flength(key)=20=E4=B8=8D=E6=94=AF=E6=8C=81=20=3D=20?= =?UTF-8?q?=E5=92=8C=20!=3D=20=E6=AF=94=E8=BE=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/apijson/orm/AbstractSQLConfig.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java index 4c82ea30..4bbd6f57 100755 --- a/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java +++ b/APIJSONORM/src/main/java/apijson/orm/AbstractSQLConfig.java @@ -3571,7 +3571,9 @@ public abstract class AbstractSQLConfig implements SQLConfig implements SQLConfig implements SQLConfig