├── .gitignore ├── LICENSE ├── README.md ├── libs ├── APIJSON-7.0.0.jar ├── apijson-column-2.0.0.jar ├── unitauto-jar-3.0.5.jar └── unitauto-java-3.0.5.jar ├── pom.xml └── src └── main ├── java └── apijson │ └── framework │ ├── APIJSONApplication.java │ ├── APIJSONConstant.java │ ├── APIJSONController.java │ ├── APIJSONCreator.java │ ├── APIJSONFunctionParser.java │ ├── APIJSONObjectParser.java │ ├── APIJSONParser.java │ ├── APIJSONSQLConfig.java │ ├── APIJSONSQLExecutor.java │ ├── APIJSONVerifier.java │ ├── AssertUtil.java │ ├── BaseModel.java │ ├── ColumnUtil.java │ ├── javax │ ├── APIJSONApplication.java │ ├── APIJSONConstant.java │ ├── APIJSONController.java │ ├── APIJSONCreator.java │ ├── APIJSONFunctionParser.java │ ├── APIJSONObjectParser.java │ ├── APIJSONParser.java │ ├── APIJSONSQLConfig.java │ ├── APIJSONSQLExecutor.java │ ├── APIJSONVerifier.java │ ├── AssertUtil.java │ ├── BaseModel.java │ ├── ColumnUtil.java │ └── package-info.java │ └── package-info.java └── resources └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | target/ 5 | 6 | !gradle/wrapper/gradle-wrapper.jar 7 | !**/src/main/**/build/ 8 | !**/src/test/**/build/ 9 | 10 | ### STS ### 11 | .apt_generated 12 | .classpath 13 | .factorypath 14 | .project 15 | .settings 16 | .springBeans 17 | .sts4-cache 18 | bin/ 19 | !**/src/main/**/bin/ 20 | !**/src/test/**/bin/ 21 | 22 | ### IntelliJ IDEA ### 23 | .idea 24 | *.iws 25 | *.iml 26 | *.ipr 27 | out/ 28 | !**/src/main/**/out/ 29 | !**/src/test/**/out/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright ©2020 APIJSON(https://github.com/APIJSON) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # apijson-framework [![](https://jitpack.io/v/APIJSON/apijson-framework.svg)](https://jitpack.io/#APIJSON/apijson-framework) 2 | 腾讯 [APIJSON](https://github.com/Tencent/APIJSON) 服务端框架,通过数据库表配置角色权限、参数校验等,简化使用。
3 | Tencent [APIJSON](https://github.com/Tencent/APIJSON) Server Framework for configuring access of roles and validation of arguments in database tables, then using APIJSON easier. 4 | 5 | #### Access: https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/MethodAccess.java 6 | ![image](https://user-images.githubusercontent.com/5738175/167259883-e5fff2f4-b3e8-4b2f-a597-d851004c3393.png) 7 | 8 | #### Request: https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/Operation.java 9 | ![image](https://user-images.githubusercontent.com/5738175/167259922-f343683f-6335-4778-aaeb-d1b9aed999dc.png) 10 | 11 |
12 | 13 | ## 添加依赖 14 | ## Add Dependency 15 | 16 | ### Maven 17 | #### 1. 在 pom.xml 中添加 JitPack 仓库 18 | #### 1. Add the JitPack repository to pom.xml 19 | ```xml 20 | 21 | 22 | jitpack.io 23 | https://jitpack.io 24 | 25 | 26 | ``` 27 | 28 | ![image](https://user-images.githubusercontent.com/5738175/167261102-12f7f4d6-7895-4d79-a50e-076f93fca6d7.png) 29 | 30 |
31 | 32 | #### 2. 在 pom.xml 中添加 apijson-framework 依赖 33 | #### 2. Add the apijson-framework dependency to pom.xml 34 | ```xml 35 | 36 | com.github.APIJSON 37 | apijson-framework 38 | LATEST 39 | 40 | ``` 41 | 42 | ![image](https://user-images.githubusercontent.com/5738175/167261052-263ee9b4-aae5-4c51-b4d2-6a0446fc4152.png) 43 | 44 |
45 | 46 | https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONDemo/pom.xml 47 | 48 |
49 |
50 | 51 | ### Gradle 52 | #### 1. 在项目根目录 build.gradle 中最后添加 JitPack 仓库 53 | #### 1. Add the JitPack repository in your root build.gradle at the end of repositories 54 | ```gradle 55 | allprojects { 56 | repositories { 57 | maven { url 'https://jitpack.io' } 58 | } 59 | } 60 | ``` 61 |
62 | 63 | #### 2. 在项目某个 module 目录(例如 `app`) build.gradle 中添加 apijson-orm 依赖 64 | #### 2. Add the apijson-orm dependency in one of your modules(such as `app`) 65 | ```gradle 66 | dependencies { 67 | implementation 'com.github.APIJSON:apijson-framework:latest' 68 | } 69 | ``` 70 | 71 |
72 |
73 |
74 | 75 | ## 初始化 76 | ## Initialization 77 | #### 1.在你项目的主程序启动类 Application 的 static {} 代码块配置 APIJSONApplication.DEFAULT_APIJSON_CREATOR,至少重写 createSQLConfig 方法返回你自己继承 APIJSONSQLConfig 的子类 78 | #### 1.Configure APIJSONApplication.DEFAULT_APIJSON_CREATOR in static {} of your Application, at least override createSQLConfig method and return your APIJSONSQLConfig extends APIJSONSQLConfig. 79 | 80 | ```java 81 | static { 82 | APIJSONApplication.DEFAULT_APIJSON_CREATOR = new APIJSONCreator() { 83 | @Override 84 | public DemoSQLConfig createSQLConfig() { 85 | return new DemoSQLConfig(); 86 | } 87 | }; 88 | } 89 | ``` 90 | 91 |
92 | 93 | #### 2.在你项目的主程序启动类 Application 的 main 方法里 SpringApplication.run 后调用 APIJSONApplication.init 94 | #### 2.Call APIJSONApplication.init after SpringApplication.run in main method of your Application 95 | 96 | ```java 97 | public static void main(String[] args) throws Exception { 98 | SpringApplication.run(DemoApplication.class, args); 99 | APIJSONApplication.init(); 100 | } 101 | ``` 102 | 103 |
104 | 105 | #### 见 [apijson.framework](/src/main/java/apijson/framework) 里各个类的注释及 [APIJSONDemo](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONDemo) 里的 [DemoApplication](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONDemo/src/main/java/apijson/demo/DemoApplication.java)
106 | 107 | #### See document in [apijson.framework](/src/main/java/apijson/framework) classes and [DemoApplication](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONDemo/src/main/java/apijson/demo/DemoApplication.java) in [APIJSONDemo](https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONDemo) 108 | 109 | ![image](https://user-images.githubusercontent.com/5738175/167260539-27d7e13b-27b9-43ad-925e-3f79c99e8ac9.png) 110 | 111 |
112 |
113 |
114 | 115 | ## 使用 116 | ## Usage 117 | 118 | #### Access: https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/MethodAccess.java 119 | ![image](https://user-images.githubusercontent.com/5738175/167259883-e5fff2f4-b3e8-4b2f-a597-d851004c3393.png) 120 | 121 | ![image](https://user-images.githubusercontent.com/5738175/167261523-59abf4ba-e211-49f9-92bd-a79384bb757f.png) 122 | 123 | #### Request: https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/Operation.java 124 | ![image](https://user-images.githubusercontent.com/5738175/167259922-f343683f-6335-4778-aaeb-d1b9aed999dc.png) 125 | 126 | ![image](https://user-images.githubusercontent.com/5738175/167262762-2c2a1c58-e7bf-4352-a7b9-fcbb0fa67f7f.png) 127 | 128 |
129 | 有问题可以去 Tencent/APIJSON 提 issue
130 | https://github.com/Tencent/APIJSON/issues/36 131 | 132 |
133 |
134 | 135 | ### 贡献者 136 | ### Contributors 137 | 1 个腾讯工程师、1 京东工程师 等,感谢大家的贡献~
138 | 1 Tencent engineer, 1 JD engineer, etc. Thank you all~
139 | https://github.com/APIJSON/apijson-framework/graphs/contributors 140 | 141 |
142 | 143 | #### 创作不易、坚持更难,点右上角 ⭐Star 支持一下,谢谢 ^_^ 144 | #### Please ⭐Star this project ^_^ 145 | https://github.com/APIJSON/apijson-framework 146 | -------------------------------------------------------------------------------- /libs/APIJSON-7.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APIJSON/apijson-framework/8f88df2504b147791e0d7c59bf093705b7d6d90e/libs/APIJSON-7.0.0.jar -------------------------------------------------------------------------------- /libs/apijson-column-2.0.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APIJSON/apijson-framework/8f88df2504b147791e0d7c59bf093705b7d6d90e/libs/apijson-column-2.0.0.jar -------------------------------------------------------------------------------- /libs/unitauto-jar-3.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APIJSON/apijson-framework/8f88df2504b147791e0d7c59bf093705b7d6d90e/libs/unitauto-jar-3.0.5.jar -------------------------------------------------------------------------------- /libs/unitauto-java-3.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APIJSON/apijson-framework/8f88df2504b147791e0d7c59bf093705b7d6d90e/libs/unitauto-java-3.0.5.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | apijson.framework 7 | apijson-framework 8 | 7.2.1 9 | jar 10 | 11 | APIJSONFramework 12 | APIJSON Server Framework, simplify use for APIJSON 13 | 14 | 15 | UTF-8 16 | UTF-8 17 | 1.8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | 24 | jakarta.servlet 25 | jakarta.servlet-api 26 | 5.0.0 27 | provided 28 | 29 | 30 | 31 | 32 | javax.servlet 33 | javax.servlet-api 34 | 4.0.1 35 | provided 36 | 37 | 38 | 39 | 40 | com.github.Tencent 41 | APIJSON 42 | 8.0.0 43 | 44 | 45 | 46 | 47 | com.mysql 48 | mysql-connector-j 49 | 9.2.0 50 | 51 | 52 | org.postgresql 53 | postgresql 54 | 42.7.3 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-compiler-plugin 65 | 3.12.1 66 | 67 | 1.8 68 | 1.8 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | jitpack.io 78 | https://jitpack.io 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONApplication.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.rmi.ServerException; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import apijson.Log; 22 | import apijson.NotNull; 23 | import apijson.orm.AbstractFunctionParser; 24 | import apijson.orm.script.ScriptExecutor; 25 | 26 | 27 | /**启动入口 Application 28 | * 右键这个类 > Run As > Java Application 29 | * @author Lemon 30 | */ 31 | public class APIJSONApplication { 32 | public static final String TAG = "APIJSONApplication"; 33 | 34 | @NotNull 35 | public static APIJSONCreator, ? extends List> DEFAULT_APIJSON_CREATOR; 36 | static { 37 | DEFAULT_APIJSON_CREATOR = new APIJSONCreator<>(); 38 | } 39 | 40 | @SuppressWarnings("unchecked") 41 | public static , L extends List> APIJSONParser createParser() { 42 | return (APIJSONParser) DEFAULT_APIJSON_CREATOR.createParser(); 43 | } 44 | @SuppressWarnings("unchecked") 45 | public static , L extends List> APIJSONFunctionParser createFunctionParser() { 46 | return (APIJSONFunctionParser) DEFAULT_APIJSON_CREATOR.createFunctionParser(); 47 | } 48 | 49 | @SuppressWarnings("unchecked") 50 | public static , L extends List> APIJSONVerifier createVerifier() { 51 | return (APIJSONVerifier) DEFAULT_APIJSON_CREATOR.createVerifier(); 52 | } 53 | 54 | @SuppressWarnings("unchecked") 55 | public static , L extends List> APIJSONSQLConfig createSQLConfig() { 56 | return (APIJSONSQLConfig) DEFAULT_APIJSON_CREATOR.createSQLConfig(); 57 | } 58 | 59 | @SuppressWarnings("unchecked") 60 | public static , L extends List> APIJSONSQLExecutor createSQLExecutor() { 61 | return (APIJSONSQLExecutor) DEFAULT_APIJSON_CREATOR.createSQLExecutor(); 62 | } 63 | 64 | 65 | /**初始化,加载所有配置并校验 66 | * @return 67 | * @throws Exception 68 | */ 69 | public static void init() throws Exception { 70 | init(true, DEFAULT_APIJSON_CREATOR); 71 | } 72 | /**初始化,加载所有配置并校验 73 | * @param shutdownWhenServerError 74 | * @return 75 | * @throws Exception 76 | */ 77 | public static void init(boolean shutdownWhenServerError) throws Exception { 78 | init(shutdownWhenServerError, DEFAULT_APIJSON_CREATOR); 79 | } 80 | /**初始化,加载所有配置并校验 81 | * @param creator 82 | * @return 83 | * @throws Exception 84 | */ 85 | public static , L extends List> void init( 86 | @NotNull APIJSONCreator creator) throws Exception { 87 | init(true, creator); 88 | } 89 | /**初始化,加载所有配置并校验 90 | * @param shutdownWhenServerError 91 | * @param creator 92 | * @return 93 | * @throws Exception 94 | */ 95 | public static , L extends List> void init( 96 | boolean shutdownWhenServerError, @NotNull APIJSONCreator creator) throws Exception { 97 | System.out.println("\n\n\n\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON 开始启动 >>>>>>>>>>>>>>>>>>>>>>>>\n"); 98 | DEFAULT_APIJSON_CREATOR = creator; 99 | 100 | if (APIJSONVerifier.ENABLE_VERIFY_ROLE) { 101 | System.out.println("\n\n\n开始初始化: Access 权限校验配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 102 | try { 103 | APIJSONVerifier.initAccess(shutdownWhenServerError, creator); 104 | } catch (Throwable e) { 105 | e.printStackTrace(); 106 | if (shutdownWhenServerError) { 107 | onServerError("Access 权限校验配置 初始化失败!", shutdownWhenServerError); 108 | } 109 | } 110 | System.out.println("\n完成初始化: Access 权限校验配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 111 | } 112 | 113 | 114 | if (APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION) { 115 | System.out.println("\n\n\n开始初始化: Function 远程函数配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 116 | try { 117 | APIJSONFunctionParser.init(shutdownWhenServerError, creator); 118 | } catch (Throwable e) { 119 | e.printStackTrace(); 120 | if (shutdownWhenServerError) { 121 | onServerError("Function 远程函数配置 初始化失败!", shutdownWhenServerError); 122 | } 123 | } 124 | System.out.println("\n完成初始化: Function 远程函数配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 125 | 126 | System.out.println("开始测试: Function 远程函数 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 127 | try { 128 | APIJSONFunctionParser.test(); 129 | } catch (Throwable e) { 130 | e.printStackTrace(); 131 | if (shutdownWhenServerError) { 132 | onServerError("Function 远程函数配置 测试失败!", shutdownWhenServerError); 133 | } 134 | } 135 | System.out.println("\n完成测试: Function 远程函数 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 136 | } 137 | 138 | 139 | if (APIJSONVerifier.ENABLE_VERIFY_CONTENT) { 140 | System.out.println("\n\n\n开始初始化: Request 请求参数校验配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 141 | try { 142 | APIJSONVerifier.initRequest(shutdownWhenServerError, creator); 143 | } catch (Throwable e) { 144 | e.printStackTrace(); 145 | if (shutdownWhenServerError) { 146 | onServerError("Request 请求参数校验配置 初始化失败!", shutdownWhenServerError); 147 | } 148 | } 149 | System.out.println("\n完成初始化: Request 请求参数校验校验配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 150 | 151 | System.out.println("\n\n\n开始测试: Request 请求参数校验 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 152 | try { 153 | APIJSONVerifier.testStructure(); 154 | } catch (Throwable e) { 155 | e.printStackTrace(); 156 | if (shutdownWhenServerError) { 157 | onServerError("Request 请求参数校验 测试失败!", shutdownWhenServerError); 158 | } 159 | } 160 | System.out.println("\n完成测试: Request 请求参数校验 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 161 | } 162 | 163 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER) { 164 | System.out.println("\n\n\n开始初始化: Document 请求映射配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 165 | try { 166 | APIJSONVerifier.initDocument(shutdownWhenServerError, creator); 167 | } catch (Throwable e) { 168 | e.printStackTrace(); 169 | if (shutdownWhenServerError) { 170 | onServerError("Document 请求映射配置 初始化失败!", shutdownWhenServerError); 171 | } 172 | } 173 | System.out.println("\n完成初始化: Document 请求映射配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 174 | } 175 | 176 | 177 | System.out.println("官方网站: http://apijson.cn"); 178 | System.out.println("设计规范: https://github.com/Tencent/APIJSON/blob/master/Document.md#3"); 179 | System.out.println("测试链接: http://apijson.cn/api?type=JSON&url=http://localhost:8080/get"); 180 | System.out.println("\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON 启动完成,试试调用零代码万能通用 API 吧 ^_^ >>>>>>>>>>>>>>>>>>>>>>>>\n"); 181 | } 182 | 183 | protected static void onServerError(String msg, boolean shutdown) throws ServerException { 184 | Log.e(TAG, "\n启动时自检测试未通过!原因:\n" + msg); 185 | 186 | if (shutdown) { 187 | System.exit(1); 188 | } else { 189 | throw new ServerException(msg); 190 | } 191 | } 192 | 193 | public static , L extends List> void addScriptExecutor(String language, ScriptExecutor scriptExecutor) { 194 | scriptExecutor.init(); 195 | AbstractFunctionParser.SCRIPT_EXECUTOR_MAP.put(language, scriptExecutor); 196 | } 197 | 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONConstant.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.util.Arrays; 18 | import java.util.List; 19 | 20 | import apijson.JSONResponse; 21 | import apijson.orm.JSONRequest; 22 | import apijson.orm.Visitor; 23 | import apijson.orm.model.Access; 24 | import apijson.orm.model.Column; 25 | import apijson.orm.model.Document; 26 | import apijson.orm.model.ExtendedProperty; 27 | import apijson.orm.model.Function; 28 | import apijson.orm.model.PgAttribute; 29 | import apijson.orm.model.PgClass; 30 | import apijson.orm.model.Request; 31 | import apijson.orm.model.Script; 32 | import apijson.orm.model.SysColumn; 33 | import apijson.orm.model.SysTable; 34 | import apijson.orm.model.Table; 35 | import apijson.orm.model.TestRecord; 36 | 37 | 38 | /**APIJSON 常量类 39 | * @author Lemon 40 | */ 41 | public class APIJSONConstant { 42 | public static String KEY_DEBUG = "debug"; 43 | 44 | public static final String DEFAULTS = "defaults"; 45 | public static final String USER_ = "User"; 46 | public static final String PRIVACY_ = "Privacy"; 47 | public static final String VISITOR_ID = "visitorId"; 48 | 49 | public static final String ID = JSONRequest.KEY_ID; 50 | public static final String USER_ID = JSONRequest.KEY_USER_ID; 51 | public static final String TAG = JSONRequest.KEY_TAG; 52 | public static final String VERSION = JSONRequest.KEY_VERSION; 53 | public static final String FORMAT = JSONRequest.KEY_FORMAT; 54 | 55 | public static final String CODE = JSONResponse.KEY_CODE; 56 | public static final String MSG = JSONResponse.KEY_MSG; 57 | public static final String COUNT = JSONResponse.KEY_COUNT; 58 | public static final String TOTAL = JSONResponse.KEY_TOTAL; 59 | 60 | public static final String ACCESS_; 61 | public static final String COLUMN_; 62 | public static final String DOCUMENT_; 63 | public static final String EXTENDED_PROPERTY_; 64 | public static final String FUNCTION_; 65 | public static final String SCRIPT_; 66 | public static final String PG_ATTRIBUTE_; 67 | public static final String PG_CLASS_; 68 | public static final String REQUEST_; 69 | public static final String SYS_COLUMN_; 70 | public static final String SYS_TABLE_; 71 | public static final String TABLE_; 72 | public static final String TEST_RECORD_; 73 | 74 | public static final String VISITOR_; 75 | 76 | public static final List METHODS; 77 | 78 | static { 79 | ACCESS_ = Access.class.getSimpleName(); 80 | COLUMN_ = Column.class.getSimpleName(); 81 | DOCUMENT_ = Document.class.getSimpleName(); 82 | EXTENDED_PROPERTY_ = ExtendedProperty.class.getSimpleName(); 83 | FUNCTION_ = Function.class.getSimpleName(); 84 | SCRIPT_ = Script.class.getSimpleName(); 85 | PG_ATTRIBUTE_ = PgAttribute.class.getSimpleName(); 86 | PG_CLASS_ = PgClass.class.getSimpleName(); 87 | REQUEST_ = Request.class.getSimpleName(); 88 | SYS_COLUMN_ = SysColumn.class.getSimpleName(); 89 | SYS_TABLE_ = SysTable.class.getSimpleName(); 90 | TABLE_ = Table.class.getSimpleName(); 91 | TEST_RECORD_ = TestRecord.class.getSimpleName(); 92 | 93 | VISITOR_ = Visitor.class.getSimpleName(); 94 | 95 | METHODS = Arrays.asList("get", "head", "gets", "heads", "post", "put", "delete"); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONController.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import apijson.*; 18 | import apijson.JSONRequest; 19 | import apijson.orm.*; 20 | 21 | import jakarta.servlet.http.HttpSession; 22 | 23 | import java.rmi.ServerException; 24 | import java.util.*; 25 | 26 | import static apijson.JSON.*; 27 | import static apijson.RequestMethod.*; 28 | import static apijson.framework.APIJSONConstant.*; 29 | 30 | 31 | /**APIJSON base controller,建议在子项目被 @RestController 注解的类继承它或通过它的实例调用相关方法 32 | *
全通过 HTTP POST 来请求: 33 | *
1.减少代码 - 客户端无需写 HTTP GET, HTTP PUT 等各种方式的请求代码 34 | *
2.提高性能 - 无需 URL encode 和 decode 35 | *
3.调试方便 - 建议使用 APIAuto-机器学习自动化接口管理工具(https://github.com/TommyLemon/APIAuto) 36 | * @author Lemon 37 | */ 38 | public class APIJSONController, L extends List> { 39 | public static final String TAG = "APIJSONController"; 40 | 41 | public String getRequestURL() { 42 | return null; 43 | } 44 | 45 | public APIJSONParser newParser(HttpSession session, RequestMethod method) { 46 | APIJSONParser parser = APIJSONApplication.createParser(); 47 | parser.setMethod(method); 48 | parser.setSession(session); 49 | parser.setRequestURL(getRequestURL()); 50 | return parser; 51 | } 52 | 53 | public static APIJSONParser, ? extends List> COMMON_PARSER = APIJSONApplication.createParser(); 54 | 55 | /**新建带状态内容的JSONObject 56 | * @param code 57 | * @param msg 58 | * @return 59 | */ 60 | public static > M newResult(int code, String msg) { 61 | return newResult(code, msg, null); 62 | } 63 | 64 | /** 65 | * 添加JSONObject的状态内容,一般用于错误提示结果 66 | * 67 | * @param code 68 | * @param msg 69 | * @param warn 70 | * @return 71 | */ 72 | public static > M newResult(int code, String msg, String warn) { 73 | return newResult(code, msg, warn, false); 74 | } 75 | 76 | /** 77 | * 新建带状态内容的JSONObject 78 | * 79 | * @param code 80 | * @param msg 81 | * @param warn 82 | * @param isRoot 83 | * @return 84 | */ 85 | public static > M newResult(int code, String msg, String warn, boolean isRoot) { 86 | return extendResult(null, code, msg, warn, isRoot); 87 | } 88 | 89 | /** 90 | * 添加JSONObject的状态内容,一般用于错误提示结果 91 | * 92 | * @param object 93 | * @param code 94 | * @param msg 95 | * @return 96 | */ 97 | public static > M extendResult(M object, int code, String msg, String warn, boolean isRoot) { 98 | return (M) COMMON_PARSER.extendResult(JSON.createJSONObject(object), code, msg, warn, isRoot); 99 | } 100 | 101 | 102 | /** 103 | * 添加请求成功的状态内容 104 | * 105 | * @param object 106 | * @return 107 | */ 108 | public M extendSuccessResult(M object) { 109 | return extendSuccessResult(object, false); 110 | } 111 | 112 | public M extendSuccessResult(M object, boolean isRoot) { 113 | return extendSuccessResult(object, null, isRoot); 114 | } 115 | 116 | /**添加请求成功的状态内容 117 | * @param object 118 | * @param isRoot 119 | * @return 120 | */ 121 | public static > M extendSuccessResult(M object, String warn, boolean isRoot) { 122 | return extendResult(object, JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); 123 | } 124 | 125 | /**获取请求成功的状态内容 126 | * @return 127 | */ 128 | public static > M newSuccessResult() { 129 | return newSuccessResult(null); 130 | } 131 | 132 | /**获取请求成功的状态内容 133 | * @param warn 134 | * @return 135 | */ 136 | public static > M newSuccessResult(String warn) { 137 | return newSuccessResult(warn, false); 138 | } 139 | 140 | /**获取请求成功的状态内容 141 | * @param warn 142 | * @param isRoot 143 | * @return 144 | */ 145 | public static > M newSuccessResult(String warn, boolean isRoot) { 146 | return newResult(JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); 147 | } 148 | 149 | /**添加请求成功的状态内容 150 | * @param object 151 | * @param e 152 | * @return 153 | */ 154 | public static > M extendErrorResult(M object, Throwable e) { 155 | return extendErrorResult(object, e, false); 156 | } 157 | /**添加请求成功的状态内容 158 | * @param object 159 | * @param e 160 | * @param isRoot 161 | * @return 162 | */ 163 | public static > M extendErrorResult(M object, Throwable e, boolean isRoot) { 164 | return extendErrorResult(object, e, null, null, isRoot); 165 | } 166 | /**添加请求成功的状态内容 167 | * @param object 168 | * @return 169 | */ 170 | public static > M extendErrorResult(M object, Throwable e, RequestMethod requestMethod, String url, boolean isRoot) { 171 | return (M) COMMON_PARSER.extendErrorResult(JSON.createJSONObject(object), e, requestMethod, url, isRoot); 172 | } 173 | 174 | public static > M newErrorResult(Exception e) { 175 | return newErrorResult(e, false); 176 | } 177 | public static > M newErrorResult(Exception e, boolean isRoot) { 178 | return (M) COMMON_PARSER.newErrorResult(e, isRoot); 179 | } 180 | 181 | 182 | public String parse(RequestMethod method, String request, HttpSession session) { 183 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER && ! Log.DEBUG) { 184 | return JSON.toJSONString( 185 | newErrorResult( 186 | new IllegalArgumentException("APIJSONVerifier.ENABLE_APIJSON_ROUTER = true 已启用 router," + 187 | "Log.DEBUG = false 时不允许调用 /router/{method}/{tag} 外的万能通用接口!" 188 | ) 189 | ) 190 | ); 191 | } 192 | 193 | return newParser(session, method).parse(request); 194 | } 195 | 196 | public String parseByTag(RequestMethod method, String tag, Map params, String request, HttpSession session) { 197 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER && ! Log.DEBUG) { 198 | return JSON.toJSONString( 199 | newErrorResult( 200 | new IllegalArgumentException("APIJSONVerifier.ENABLE_APIJSON_ROUTER = true 已启用 router," + 201 | "Log.DEBUG = false 时不允许调用 /router/{method}/{tag} 外的万能通用接口!" 202 | ) 203 | ) 204 | ); 205 | } 206 | 207 | APIJSONParser parser = newParser(session, method); 208 | M req = parser.wrapRequest(method, tag, JSON.parseObject(request), false); 209 | if (req == null) { 210 | req = JSON.createJSONObject(); 211 | } 212 | if (params != null && params.isEmpty() == false) { 213 | req.putAll(params); 214 | } 215 | 216 | return parser.parse(req); 217 | } 218 | 219 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 220 | 221 | /**全能增删改查统一入口,这个一个方法可替代以下所有万能通用方法,一个接口通用增删改查 222 | * @param request 223 | * @param session 224 | * @return 225 | */ 226 | public String crudAll(String request, HttpSession session) { 227 | return parse(CRUD, request, session); 228 | } 229 | 230 | /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一点路由解析性能来提升一些开发效率 231 | * @param method 232 | * @param request 233 | * @param session 234 | * @return 235 | */ 236 | public String crud(String method, String request, HttpSession session) { 237 | if (METHODS.contains(method)) { 238 | return parse(RequestMethod.valueOf(method.toUpperCase()), request, session); 239 | } 240 | 241 | return toJSONString(newErrorResult( 242 | new IllegalArgumentException("URL 路径 /{method} 中 method 值 " 243 | + method + " 错误!只允许 " + METHODS + " 中的一个!") 244 | )); 245 | } 246 | 247 | /**获取 248 | * @param request 只用String,避免encode后未decode 249 | * @param session 250 | * @return 251 | * @see {@link RequestMethod#GET} 252 | */ 253 | public String get(String request, HttpSession session) { 254 | return parse(GET, request, session); 255 | } 256 | 257 | /**计数 258 | * @param request 只用String,避免encode后未decode 259 | * @param session 260 | * @return 261 | * @see {@link RequestMethod#HEAD} 262 | */ 263 | public String head(String request, HttpSession session) { 264 | return parse(HEAD, request, session); 265 | } 266 | 267 | /**限制性GET,request和response都非明文,浏览器看不到,用于对安全性要求高的GET请求 268 | * @param request 只用String,避免encode后未decode 269 | * @param session 270 | * @return 271 | * @see {@link RequestMethod#GETS} 272 | */ 273 | public String gets(String request, HttpSession session) { 274 | return parse(GETS, request, session); 275 | } 276 | 277 | /**限制性HEAD,request和response都非明文,浏览器看不到,用于对安全性要求高的HEAD请求 278 | * @param request 只用String,避免encode后未decode 279 | * @param session 280 | * @return 281 | * @see {@link RequestMethod#HEADS} 282 | */ 283 | public String heads(String request, HttpSession session) { 284 | return parse(HEADS, request, session); 285 | } 286 | 287 | /**新增 288 | * @param request 只用String,避免encode后未decode 289 | * @param session 290 | * @return 291 | * @see {@link RequestMethod#POST} 292 | */ 293 | public String post(String request, HttpSession session) { 294 | return parse(POST, request, session); 295 | } 296 | 297 | /**修改 298 | * @param request 只用String,避免encode后未decode 299 | * @param session 300 | * @return 301 | * @see {@link RequestMethod#PUT} 302 | */ 303 | public String put(String request, HttpSession session) { 304 | return parse(PUT, request, session); 305 | } 306 | 307 | /**删除 308 | * @param request 只用String,避免encode后未decode 309 | * @param session 310 | * @return 311 | * @see {@link RequestMethod#DELETE} 312 | */ 313 | public String delete(String request, HttpSession session) { 314 | return parse(DELETE, request, session); 315 | } 316 | 317 | /**支持全局事物、批量执行多条语句 318 | * @param request 只用String,避免encode后未decode 319 | * @param session 320 | * @return 321 | * @see {@link RequestMethod#GET} 322 | */ 323 | public String crud(String request, HttpSession session) { 324 | return parse(CRUD, request, session); 325 | } 326 | 327 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 328 | 329 | 330 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 331 | 332 | 333 | /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一些路由解析性能来提升一点开发效率 334 | * @param method 335 | * @param tag 336 | * @param params 337 | * @param request 338 | * @param session 339 | * @return 340 | */ 341 | public String crudByTag(String method, String tag, Map params, String request, HttpSession session) { 342 | if (METHODS.contains(method)) { 343 | return parseByTag(RequestMethod.valueOf(method.toUpperCase()), tag, params, request, session); 344 | } 345 | 346 | return toJSONString(newErrorResult( 347 | new IllegalArgumentException("URL 路径 /{method}/{tag} 中 method 值 " 348 | + method + " 错误!只允许 " + METHODS + " 中的一个!") 349 | )); 350 | } 351 | 352 | 353 | // /**获取列表 354 | // * @param request 只用String,避免encode后未decode 355 | // * @param session 356 | // * @return 357 | // * @see {@link RequestMethod#GET} 358 | // */ 359 | // public String listByTag(String tag, String request, HttpSession session) { 360 | // return parseByTag(GET, tag + apijson.JSONMap.KEY_ARRAY, request, session); 361 | // } 362 | 363 | /**获取 364 | * @param request 只用String,避免encode后未decode 365 | * @param session 366 | * @return 367 | * @see {@link RequestMethod#GET} 368 | */ 369 | public String getByTag(String tag, Map params, String request, HttpSession session) { 370 | return parseByTag(GET, tag, params, request, session); 371 | } 372 | 373 | 374 | /**计数 375 | * @param request 只用String,避免encode后未decode 376 | * @param session 377 | * @return 378 | * @see {@link RequestMethod#HEAD} 379 | */ 380 | public String headByTag(String tag, Map params, String request, HttpSession session) { 381 | return parseByTag(HEAD, tag, params, request, session); 382 | } 383 | 384 | /**限制性GET,request和response都非明文,浏览器看不到,用于对安全性要求高的GET请求 385 | * @param request 只用String,避免encode后未decode 386 | * @param session 387 | * @return 388 | * @see {@link RequestMethod#GETS} 389 | */ 390 | public String getsByTag(String tag, Map params, String request, HttpSession session) { 391 | return parseByTag(GETS, tag, params, request, session); 392 | } 393 | 394 | /**限制性HEAD,request和response都非明文,浏览器看不到,用于对安全性要求高的HEAD请求 395 | * @param request 只用String,避免encode后未decode 396 | * @param session 397 | * @return 398 | * @see {@link RequestMethod#HEADS} 399 | */ 400 | public String headsByTag(String tag, Map params, String request, HttpSession session) { 401 | return parseByTag(HEADS, tag, params, request, session); 402 | } 403 | 404 | /**新增 405 | * @param request 只用String,避免encode后未decode 406 | * @param session 407 | * @return 408 | * @see {@link RequestMethod#POST} 409 | */ 410 | public String postByTag(String tag, Map params, String request, HttpSession session) { 411 | return parseByTag(POST, tag, params, request, session); 412 | } 413 | 414 | /**修改 415 | * @param request 只用String,避免encode后未decode 416 | * @param session 417 | * @return 418 | * @see {@link RequestMethod#PUT} 419 | */ 420 | public String putByTag(String tag, Map params, String request, HttpSession session) { 421 | return parseByTag(PUT, tag, params, request, session); 422 | } 423 | 424 | /**删除 425 | * @param request 只用String,避免encode后未decode 426 | * @param session 427 | * @return 428 | * @see {@link RequestMethod#DELETE} 429 | */ 430 | public String deleteByTag(String tag, Map params, String request, HttpSession session) { 431 | return parseByTag(DELETE, tag, params, request, session); 432 | } 433 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 434 | 435 | /**增删改查统一的类 RESTful API 入口,牺牲一些路由解析性能来提升一点开发效率 436 | * compatCommonAPI = Log.DEBUG 437 | * @param method 438 | * @param tag 439 | * @param params 440 | * @param request 441 | * @param session 442 | * @return 443 | */ 444 | public String router(String method, String tag, Map params, String request, HttpSession session) { 445 | return router(method, tag, params, request, session, Log.DEBUG); 446 | } 447 | /**增删改查统一的类 RESTful API 入口,牺牲一些路由解析性能来提升一点开发效率 448 | * @param method 449 | * @param tag 450 | * @param params 451 | * @param request 452 | * @param session 453 | * @param compatCommonAPI 兼容万能通用 API,当没有映射 APIJSON 格式请求时,自动转到万能通用 API 454 | * @return 455 | */ 456 | public String router(String method, String tag, Map params, String request, HttpSession session, boolean compatCommonAPI) { 457 | if (! APIJSONVerifier.ENABLE_APIJSON_ROUTER) { 458 | return JSON.toJSONString( 459 | newErrorResult( 460 | new IllegalArgumentException("未启用 router!请配置 APIJSONVerifier.ENABLE_APIJSON_ROUTER = true !" 461 | ) 462 | ) 463 | ); 464 | } 465 | 466 | RequestMethod requestMethod = null; 467 | try { 468 | requestMethod = RequestMethod.valueOf(method.toUpperCase()); 469 | } catch (Throwable e) { 470 | // 下方 METHODS.contains(method) 会抛异常 471 | } 472 | Parser parser = newParser(session, requestMethod); 473 | 474 | if (METHODS.contains(method) == false) { 475 | return JSON.toJSONString( 476 | newErrorResult( 477 | new IllegalArgumentException("URL 路径 /{method}/{tag} 中 method 值 " 478 | + method + " 错误!只允许 " + METHODS + " 中的一个!" 479 | ) 480 | ) 481 | ); 482 | } 483 | 484 | String t = compatCommonAPI && tag != null && tag.endsWith("[]") ? tag.substring(0, tag.length() - 2) : tag; 485 | if (StringUtil.isName(t) == false) { 486 | return JSON.toJSONString( 487 | newErrorResult( 488 | new IllegalArgumentException("URL 路径 /" + method + "/{tag} 的 tag 中 " 489 | + t + " 错误!tag 不能为空,且只允许变量命名格式!" 490 | ) 491 | ) 492 | ); 493 | } 494 | 495 | String versionStr = params == null ? null : params.remove(APIJSONConstant.VERSION); 496 | Integer version; 497 | try { 498 | version = StringUtil.isEmpty(versionStr, false) ? null : Integer.valueOf(versionStr); 499 | } 500 | catch (Exception e) { 501 | return JSON.toJSONString( 502 | newErrorResult(new IllegalArgumentException("URL 路径 /" + method + "/" 503 | + tag + "?version=value 中 value 值 " + versionStr + " 错误!必须符合整数格式!") 504 | ) 505 | ); 506 | } 507 | 508 | if (version == null) { 509 | version = 0; 510 | } 511 | 512 | try { 513 | // 从 Document 查这样的接口 514 | String cacheKey = AbstractVerifier.getCacheKeyForRequest(method, tag); 515 | SortedMap> versionedMap = APIJSONVerifier.DOCUMENT_MAP.get(cacheKey); 516 | 517 | Map result = versionedMap == null ? null : versionedMap.get(version); 518 | if (result == null) { // version <= 0 时使用最新,version > 0 时使用 > version 的最接近版本(最小版本) 519 | Set>> set = versionedMap == null ? null : versionedMap.entrySet(); 520 | 521 | if (set != null && set.isEmpty() == false) { 522 | Map.Entry> maxEntry = null; 523 | 524 | for (Map.Entry> entry : set) { 525 | if (entry == null || entry.getKey() == null || entry.getValue() == null) { 526 | continue; 527 | } 528 | 529 | if (version == null || version <= 0 || version == entry.getKey()) { // 这里应该不会出现相等,因为上面 versionedMap.get(Integer.valueOf(version)) 530 | maxEntry = entry; 531 | break; 532 | } 533 | 534 | if (entry.getKey() < version) { 535 | break; 536 | } 537 | 538 | maxEntry = entry; 539 | } 540 | 541 | result = maxEntry == null ? null : maxEntry.getValue(); 542 | } 543 | 544 | if (result != null) { // 加快下次查询,查到值的话组合情况其实是有限的,不属于恶意请求 545 | if (versionedMap == null) { 546 | versionedMap = new TreeMap<>((o1, o2) -> { 547 | return o2 == null ? -1 : o2.compareTo(o1); // 降序 548 | }); 549 | } 550 | 551 | versionedMap.put(version, result); 552 | APIJSONVerifier.DOCUMENT_MAP.put(cacheKey, versionedMap); 553 | } 554 | } 555 | 556 | @SuppressWarnings("unchecked") 557 | APIJSONCreator creator = (APIJSONCreator) APIJSONApplication.DEFAULT_APIJSON_CREATOR; 558 | if (result == null && Log.DEBUG && APIJSONVerifier.DOCUMENT_MAP.isEmpty()) { 559 | 560 | //获取指定的JSON结构 <<<<<<<<<<<<<< 561 | SQLConfig config = creator.createSQLConfig().setMethod(GET).setTable(APIJSONConstant.DOCUMENT_); 562 | config.setPrepared(false); 563 | config.setColumn(Arrays.asList("request,apijson")); 564 | 565 | Map where = new HashMap(); 566 | where.put("url", "/" + method + "/" + tag); 567 | where.put("apijson{}", "length(apijson)>0"); 568 | 569 | if (version > 0) { 570 | where.put(JSONRequest.KEY_VERSION + ">=", version); 571 | } 572 | config.setWhere(where); 573 | config.setOrder(JSONRequest.KEY_VERSION + (version > 0 ? "+" : "-")); 574 | config.setCount(1); 575 | 576 | //too many connections error: 不try-catch,可以让客户端看到是服务器内部异常 577 | result = creator.createSQLExecutor().execute(config, false); 578 | 579 | // version, method, tag 组合情况太多了,JDK 里又没有 LRUCache,所以要么启动时一次性缓存全部后面只用缓存,要么每次都查数据库 580 | // versionedMap.put(Integer.valueOf(version), result); 581 | // DOCUMENT_MAP.put(cacheKey, versionedMap); 582 | } 583 | 584 | String apijson = result == null ? null : getString(result, "apijson"); 585 | if (StringUtil.isEmpty(apijson, true)) { // 586 | if (compatCommonAPI) { 587 | return crudByTag(method, tag, params, request, session); 588 | } 589 | 590 | throw new IllegalArgumentException("URL 路径 /" + method 591 | + "/" + tag + (versionStr == null ? "" : "?version=" + versionStr) + " 对应的接口不存在!"); 592 | } 593 | 594 | M rawReq = JSON.parseObject(request); 595 | if (rawReq == null) { 596 | rawReq = JSON.createJSONObject(); 597 | } 598 | if (params != null && params.isEmpty() == false) { 599 | rawReq.putAll(params); 600 | } 601 | 602 | if (parser.isNeedVerifyContent()) { 603 | Verifier verifier = parser.getVerifier(); 604 | 605 | //获取指定的JSON结构 <<<<<<<<<<<< 606 | Map target = parser.getStructure("Request", method.toUpperCase(), tag, version); 607 | if (target == null) { //empty表示随意操作 || object.isEmpty()) { 608 | throw new UnsupportedOperationException("找不到 version: " + version + ", method: " + method.toUpperCase() + ", tag: " + tag + " 对应的 structure !" 609 | + "非开放请求必须是后端 Request 表中校验规则允许的操作!如果需要则在 Request 表中新增配置!"); 610 | } 611 | 612 | //M clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {} 613 | verifier.verifyRequest(requestMethod, "", JSON.createJSONObject(target), rawReq, 0, null, null); 614 | } 615 | 616 | M apijsonReq = JSON.parseObject(apijson); 617 | if (apijsonReq == null) { 618 | apijsonReq = JSON.createJSONObject(); 619 | } 620 | 621 | Set> rawSet = rawReq.entrySet(); 622 | if (rawSet != null && rawSet.isEmpty() == false) { 623 | for (Map.Entry entry : rawSet) { 624 | String key = entry == null ? null : entry.getKey(); 625 | if (key == null) { // value 为 null 有效 626 | continue; 627 | } 628 | 629 | String[] pathKeys = key.split("\\."); 630 | //逐层到达child的直接容器JSONObject parent 631 | int last = pathKeys.length - 1; 632 | M parent = apijsonReq; 633 | for (int i = 0; i < last; i++) {//一步一步到达指定位置 634 | M p = getJSONObject(parent, pathKeys[i]); 635 | if (p == null) { 636 | p = JSON.createJSONObject(); 637 | parent.put(key, p); 638 | } 639 | parent = p; 640 | } 641 | 642 | parent.put(pathKeys[last], entry.getValue()); 643 | } 644 | } 645 | 646 | // 没必要,已经是预设好的实际参数了,如果要 tag 就在 apijson 字段配置 apijsonReq.put(JSONRequest.KEY_TAG, tag); 647 | 648 | return parser.setNeedVerifyContent(false).parse(apijsonReq); 649 | } 650 | catch (Exception e) { 651 | return JSON.toJSONString(newErrorResult(e)); 652 | } 653 | } 654 | 655 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 656 | 657 | 658 | 659 | 660 | /**重新加载配置 661 | * @return 662 | * @see 663 | *
664 | 	{
665 | 	"type": "ALL",  //重载对象,ALL, FUNCTION, REQUEST, ACCESS,非必须
666 | 	"phone": "13000082001",
667 | 	"verify": "1234567" //验证码,对应类型为 Verify.TYPE_RELOAD
668 | 	}
669 | 	 * 
670 | */ 671 | public M reload(String type) { 672 | M result = newSuccessResult(); 673 | 674 | boolean reloadAll = StringUtil.isEmpty(type, true) || "ALL".equals(type); 675 | 676 | if (reloadAll || "ACCESS".equals(type)) { 677 | try { 678 | if (reloadAll == false && APIJSONVerifier.ENABLE_VERIFY_ROLE == false) { 679 | throw new UnsupportedOperationException("AbstractVerifier.ENABLE_VERIFY_ROLE == false 时不支持校验角色权限!" + 680 | "如需支持则设置 AbstractVerifier.ENABLE_VERIFY_ROLE = true !"); 681 | } 682 | 683 | if (APIJSONVerifier.ENABLE_VERIFY_ROLE) { 684 | result.put(ACCESS_, APIJSONVerifier.initAccess()); 685 | } 686 | } catch (ServerException e) { 687 | e.printStackTrace(); 688 | result.put(ACCESS_, newErrorResult(e)); 689 | } 690 | } 691 | 692 | if (reloadAll || "FUNCTION".equals(type)) { 693 | try { 694 | if (reloadAll == false && APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION == false) { 695 | throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" + 696 | " == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !"); 697 | } 698 | 699 | if (APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION) { 700 | result.put(FUNCTION_, APIJSONFunctionParser.init()); 701 | } 702 | } catch (ServerException e) { 703 | e.printStackTrace(); 704 | result.put(FUNCTION_, newErrorResult(e)); 705 | } 706 | } 707 | 708 | if (reloadAll || "REQUEST".equals(type)) { 709 | try { 710 | if (reloadAll == false && APIJSONVerifier.ENABLE_VERIFY_CONTENT == false) { 711 | throw new UnsupportedOperationException("AbstractVerifier.ENABLE_VERIFY_CONTENT == false 时不支持校验请求传参内容!" + 712 | "如需支持则设置 AbstractVerifier.ENABLE_VERIFY_CONTENT = true !"); 713 | } 714 | 715 | if (APIJSONVerifier.ENABLE_VERIFY_CONTENT) { 716 | result.put(REQUEST_, APIJSONVerifier.initRequest()); 717 | } 718 | } catch (ServerException e) { 719 | e.printStackTrace(); 720 | result.put(REQUEST_, newErrorResult(e)); 721 | } 722 | } 723 | 724 | return result; 725 | } 726 | 727 | 728 | /**用户登录 729 | * @param session 730 | * @param visitor 731 | * @param version 732 | * @param format 733 | * @param defaults 734 | * @return 返回类型设置为 Object 是为了子类重写时可以有返回值,避免因为冲突而另写一个有返回值的登录方法 735 | */ 736 | public Object login(@NotNull HttpSession session, @NotNull Visitor visitor, Integer version, Boolean format, M defaults) { 737 | //登录状态保存至session 738 | session.setAttribute(VISITOR_ID, visitor.getId()); //用户id 739 | session.setAttribute(VISITOR_, visitor); //用户 740 | session.setAttribute(VERSION, version); //全局默认版本号 741 | session.setAttribute(FORMAT, format); //全局默认格式化配置 742 | session.setAttribute(DEFAULTS, defaults); //给每个请求JSON最外层加的字段 743 | return null; 744 | } 745 | 746 | /**退出登录,清空session 747 | * @param session 748 | * @return 返回类型设置为 Object 是为了子类重写时可以有返回值,避免因为冲突而另写一个有返回值的登录方法 749 | */ 750 | public Object logout(@NotNull HttpSession session) { 751 | Object userId = APIJSONVerifier.getVisitorId(session);//必须在session.invalidate();前! 752 | Log.d(TAG, "logout userId = " + userId + "; session.getId() = " + (session == null ? null : session.getId())); 753 | session.invalidate(); 754 | return null; 755 | } 756 | 757 | 758 | 759 | // public JSONMap listMethod(String request) { 760 | // if (Log.DEBUG == false) { 761 | // return APIJSONParser.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用 UnitAuto 单元测试!")); 762 | // } 763 | // return MethodUtil.listMethod(request); 764 | // } 765 | // 766 | // public void invokeMethod(String request, HttpServletRequest servletRequest) { 767 | // AsyncContext asyncContext = servletRequest.startAsync(); 768 | // 769 | // final boolean[] called = new boolean[] { false }; 770 | // MethodUtil.Listener listener = new MethodUtil.Listener() { 771 | // 772 | // @Override 773 | // public void complete(JSONMap data, Method method, InterfaceProxy proxy, Object... extras) throws Exception { 774 | // 775 | // ServletResponse servletResponse = called[0] ? null : asyncContext.getResponse(); 776 | // if (servletResponse == null) { // || servletResponse.isCommitted()) { // isCommitted 在高并发时可能不准,导致写入多次 777 | // Log.w(TAG, "invokeMethod listener.complete servletResponse == null || servletResponse.isCommitted() >> return;"); 778 | // return; 779 | // } 780 | // called[0] = true; 781 | // 782 | // servletResponse.setCharacterEncoding(servletRequest.getCharacterEncoding()); 783 | // servletResponse.setContentType(servletRequest.getContentType()); 784 | // servletResponse.getWriter().println(data); 785 | // asyncContext.complete(); 786 | // } 787 | // }; 788 | // 789 | // if (Log.DEBUG == false) { 790 | // try { 791 | // listener.complete(MethodUtil.JSON_CALLBACK.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用 UnitAuto 单元测试!"))); 792 | // } 793 | // catch (Exception e1) { 794 | // e1.printStackTrace(); 795 | // asyncContext.complete(); 796 | // } 797 | // 798 | // return; 799 | // } 800 | // 801 | // 802 | // try { 803 | // MethodUtil.invokeMethod(request, null, listener); 804 | // } 805 | // catch (Exception e) { 806 | // Log.e(TAG, "invokeMethod try { JSONMap req = JSON.parseObject(request); ... } catch (Exception e) { \n" + e.getMessage()); 807 | // try { 808 | // listener.complete(MethodUtil.JSON_CALLBACK.newErrorResult(e)); 809 | // } 810 | // catch (Exception e1) { 811 | // e1.printStackTrace(); 812 | // asyncContext.complete(); 813 | // } 814 | // } 815 | // } 816 | 817 | } 818 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONCreator.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import apijson.orm.ParserCreator; 18 | import apijson.orm.SQLCreator; 19 | import apijson.orm.VerifierCreator; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | 25 | /**APIJSON相关创建器 26 | * @author Lemon 27 | */ 28 | public class APIJSONCreator, L extends List> 29 | implements ParserCreator, VerifierCreator, SQLCreator { 30 | 31 | @Override 32 | public APIJSONParser createParser() { 33 | return new APIJSONParser<>(); 34 | } 35 | 36 | @Override 37 | public APIJSONFunctionParser createFunctionParser() { 38 | return new APIJSONFunctionParser<>(); 39 | } 40 | 41 | @Override 42 | public APIJSONVerifier createVerifier() { 43 | return new APIJSONVerifier<>(); 44 | } 45 | 46 | @Override 47 | public APIJSONSQLConfig createSQLConfig() { 48 | return new APIJSONSQLConfig<>(); 49 | } 50 | 51 | @Override 52 | public APIJSONSQLExecutor createSQLExecutor() { 53 | return new APIJSONSQLExecutor<>(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONFunctionParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import apijson.*; 18 | import apijson.orm.AbstractFunctionParser; 19 | import apijson.orm.script.JavaScriptExecutor; 20 | import apijson.orm.script.ScriptExecutor; 21 | import jakarta.servlet.http.HttpSession; 22 | //import unitauto.MethodUtil; 23 | //import unitauto.MethodUtil.Argument; 24 | 25 | import java.rmi.ServerException; 26 | import java.util.*; 27 | 28 | import static apijson.JSON.*; 29 | import static apijson.JSONRequest.KEY_COUNT; 30 | import static apijson.RequestMethod.*; 31 | import static apijson.framework.APIJSONConstant.FUNCTION_; 32 | import static apijson.framework.APIJSONConstant.SCRIPT_; 33 | 34 | 35 | /**可远程调用的函数类 36 | * @author Lemon 37 | */ 38 | public class APIJSONFunctionParser, L extends List> extends AbstractFunctionParser { 39 | public static final String TAG = "APIJSONFunctionParser"; 40 | 41 | @NotNull 42 | public static final String[] ALL_METHODS; 43 | static { 44 | ALL_METHODS = new String[]{ GET.name(), HEAD.name(), GETS.name(), HEADS.name(), POST.name(), PUT.name(), DELETE.name() }; 45 | } 46 | 47 | private HttpSession session; 48 | public APIJSONFunctionParser() { 49 | this(null); 50 | } 51 | public APIJSONFunctionParser(HttpSession session) { 52 | this(null, null, 0, null, session); 53 | } 54 | public APIJSONFunctionParser(RequestMethod method, String tag, int version, M curObj, HttpSession session) { 55 | super(method, tag, version, curObj); 56 | setSession(session); 57 | } 58 | 59 | public HttpSession getSession() { 60 | return session; 61 | } 62 | public APIJSONFunctionParser setSession(HttpSession session) { 63 | this.session = session; 64 | return this; 65 | } 66 | 67 | @Override 68 | public APIJSONFunctionParser setMethod(RequestMethod method) { 69 | super.setMethod(method); 70 | return this; 71 | } 72 | @Override 73 | public APIJSONFunctionParser setTag(String tag) { 74 | super.setTag(tag); 75 | return this; 76 | } 77 | @Override 78 | public APIJSONFunctionParser setVersion(int version) { 79 | super.setVersion(version); 80 | return this; 81 | } 82 | 83 | /**初始化,加载所有远程函数配置,并校验是否已在应用层代码实现 84 | * @return 85 | * @throws ServerException 86 | */ 87 | public static > M init() throws ServerException { 88 | return init(false); 89 | } 90 | /**初始化,加载所有远程函数配置,并校验是否已在应用层代码实现 91 | * @param shutdownWhenServerError 92 | * @return 93 | * @throws ServerException 94 | */ 95 | public static > M init(boolean shutdownWhenServerError) throws ServerException { 96 | return init(shutdownWhenServerError, null); 97 | } 98 | /**初始化,加载所有远程函数配置,并校验是否已在应用层代码实现 99 | * @param creator 100 | * @return 101 | * @throws ServerException 102 | */ 103 | public static , L extends List> M init(APIJSONCreator creator) throws ServerException { 104 | return init(false, creator); 105 | } 106 | /**初始化,加载所有远程函数配置,并校验是否已在应用层代码实现 107 | * @param shutdownWhenServerError 108 | * @param creator 109 | * @return 110 | * @throws ServerException 111 | */ 112 | public static , L extends List> M init(boolean shutdownWhenServerError, APIJSONCreator creator) throws ServerException { 113 | return init(shutdownWhenServerError, creator, null); 114 | } 115 | /**初始化,加载所有远程函数配置,并校验是否已在应用层代码实现 116 | * @param shutdownWhenServerError 117 | * @param creator 118 | * @param table 表内自定义数据过滤条件 119 | * @return 120 | * @throws ServerException 121 | */ 122 | @SuppressWarnings("unchecked") 123 | public static , L extends List> M init(boolean shutdownWhenServerError 124 | , APIJSONCreator creator, M table) throws ServerException { 125 | if (creator == null) { 126 | creator = (APIJSONCreator) APIJSONApplication.DEFAULT_APIJSON_CREATOR; 127 | } 128 | 129 | boolean isAll = table == null || table.isEmpty(); 130 | 131 | //JSONRequest function = isAll ? JSON.createJSONObject() : table; 132 | //if (Log.DEBUG == false) { 133 | // function.put(APIJSONConstant.KEY_DEBUG, 0); 134 | //} 135 | // 136 | //JSONRequest functionItem = JSON.createJSONObject(); 137 | //functionItem.put(FUNCTION_, function); 138 | // 139 | //JSONRequest script = JSON.createJSONObject(); // isAll ? JSON.createJSONObject() : table; 140 | //script.put("simple", 0); 141 | //if (Log.DEBUG == false) { 142 | // script.put(APIJSONConstant.KEY_DEBUG, 0); 143 | //} 144 | // 不能用这个来优化,因为可能配置了不校验远程函数是否存在 145 | //{ // name{}@ <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 146 | //JSONRequest nameInAt = JSON.createJSONObject(); 147 | //nameInAt.put("from", "Function"); 148 | //{ // Function <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 149 | // JSONRequest fun = JSON.createJSONObject(); 150 | // fun.setColumn("name"); 151 | // nameInAt.put("Function", fun); 152 | //} // Function >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 153 | 154 | //script.put("name{}@", nameInAt); 155 | //} // name{}@ >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 156 | 157 | //JSONRequest scriptItem = JSON.createJSONObject(); 158 | //scriptItem.put(SCRIPT_, script); 159 | 160 | M request = JSON.createJSONObject(); 161 | //request.putAll(functionItem.toArray(0, 0, FUNCTION_)); 162 | //request.putAll(scriptItem.toArray(0, 0, SCRIPT_)); 163 | 164 | // 可以用它,因为 Function 表必须存在,没有绕过校验的配置 // 不能用这个来优化,因为可能配置了不校验远程函数是否存在 165 | { // [] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 166 | M item = JSON.createJSONObject(); 167 | 168 | { // Function <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 169 | M function = isAll ? JSON.createJSONObject() : table; 170 | if (! Log.DEBUG) { 171 | function.put(APIJSONConstant.KEY_DEBUG, 0); 172 | } 173 | item.put(FUNCTION_, function); 174 | } // Function >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 175 | 176 | if (ENABLE_SCRIPT_FUNCTION) { // Script <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 177 | M script = JSON.createJSONObject(); 178 | script.put("name@", "/Function/name"); 179 | script.put("simple", 0); 180 | item.put(SCRIPT_, script); 181 | } // Script >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 182 | 183 | item.put(KEY_COUNT, 0); 184 | request.put("[]", item); 185 | } // [] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 186 | 187 | 188 | M response = creator.createParser().setMethod(GET).setNeedVerify(true).parseResponse(request); 189 | if (! JSONResponse.isSuccess(response)) { 190 | onServerError("\n\n\n\n\n !!!! 查询远程函数异常 !!!\n" + response.get(JSONResponse.KEY_MSG) + "\n\n\n\n\n", shutdownWhenServerError); 191 | } 192 | 193 | //初始化默认脚本引擎,避免增量 194 | if (isAll || SCRIPT_EXECUTOR_MAP.get("js") == null) { 195 | ScriptExecutor javaScriptExecutor = new JavaScriptExecutor<>(); 196 | javaScriptExecutor.init(); 197 | SCRIPT_EXECUTOR_MAP.put("js", javaScriptExecutor); 198 | SCRIPT_EXECUTOR_MAP.put("JavaScript", javaScriptExecutor); 199 | SCRIPT_EXECUTOR_MAP.put("javascript", javaScriptExecutor); 200 | } 201 | 202 | Map scriptMap = new HashMap<>(); 203 | L scriptList = JSON.get(response, "[]"); // response.getJSONArray(SCRIPT_ + "[]"); 204 | if (scriptList != null && ! scriptList.isEmpty()) { 205 | //if (isAll) { 206 | // SCRIPT_MAP = new LinkedHashMap<>(); 207 | //} 208 | Map newMap = new LinkedHashMap<>(); 209 | 210 | for (int i = 0; i < scriptList.size(); i++) { 211 | M item = JSON.get(scriptList, i); 212 | item = item == null ? null : JSON.get(item, SCRIPT_); 213 | if (item == null) { // 关联查不到很正常 214 | continue; 215 | } 216 | 217 | String n = getString(item, "name"); 218 | if (! StringUtil.isName(n)) { 219 | onServerError("Script 表字段 name 的值 " + n + " 不合法!必须为合法的方法名字符串!", shutdownWhenServerError); 220 | } 221 | 222 | String s = getString(item, "script"); 223 | if (StringUtil.isEmpty(s, true)) { 224 | onServerError("Script 表字段 script 的值 " + s + " 不合法!不能为空!", shutdownWhenServerError); 225 | } 226 | newMap.put(n, item); 227 | } 228 | 229 | scriptMap = newMap; 230 | } 231 | 232 | L list = scriptList; // response.getJSONArray(FUNCTION_ + "[]"); 233 | int size = list == null ? 0 : list.size(); 234 | if (isAll && size <= 0) { 235 | Log.w(TAG, "init isAll && size <= 0,,没有可用的远程函数"); 236 | return response; 237 | } 238 | 239 | 240 | if (isAll) { // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP! 如果要做成完全校验通过才更新 FUNCTION_MAP,但又不提供 忽略校验 参数,似乎无解 241 | FUNCTION_MAP = new LinkedHashMap<>(); 242 | } 243 | Map> newMap = FUNCTION_MAP; // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP! new LinkedHashMap<>(); 244 | 245 | for (int i = 0; i < size; i++) { 246 | M item = JSON.get(list, i); 247 | item = item == null ? null : JSON.get(item, FUNCTION_); 248 | if (item == null) { 249 | continue; 250 | } 251 | 252 | M demo = JSON.parseObject(getString(item, "demo")); 253 | if (demo == null) { 254 | try { 255 | onServerError("字段 demo 的值必须为合法且非 null 的 JSONObejct 字符串!", shutdownWhenServerError); 256 | } catch (Exception e) { 257 | throw new RuntimeException(e); 258 | } 259 | } 260 | String name = getString(item, "name"); 261 | // demo.put(apijson.JSONRequest.KEY_TAG, getString(item, apijson.JSONRequest.KEY_TAG)); 262 | // demo.put(apijson.JSONRequest.KEY_VERSION, item.getInteger(apijson.JSONRequest.KEY_VERSION)); 263 | //加载脚本 264 | if (item.get("language") != null) { 265 | String language = getString(item, "language"); 266 | // if (SCRIPT_EXECUTOR_MAP.get(language) == null) { 267 | // onServerError("找不到脚本语言 " + language + " 对应的执行引擎!请先依赖相关库并在后端 APIJSONFunctionParser 中注册!", shutdownWhenServerError); 268 | // } 269 | //脚本语言执行 270 | if (SCRIPT_EXECUTOR_MAP.containsKey(language)){ 271 | ScriptExecutor scriptExecutor = (ScriptExecutor) SCRIPT_EXECUTOR_MAP.get(language); 272 | M script = scriptMap.get(name); 273 | scriptExecutor.load(name, getString(script, "script")); 274 | } 275 | } 276 | newMap.put(name, item); // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP! 277 | 278 | String[] methods = StringUtil.split(getString(item, "methods")); 279 | 280 | if (methods == null || methods.length <= 0) { 281 | methods = ALL_METHODS; 282 | } 283 | 284 | if (demo != null){ 285 | if (! demo.containsKey("result()")) { 286 | demo.put("result()", getFunctionCall(name, getString(item, "arguments"))); 287 | } 288 | demo.put(apijson.JSONRequest.KEY_TAG, item.get(apijson.JSONRequest.KEY_TAG)); 289 | demo.put(apijson.JSONRequest.KEY_VERSION, item.get(apijson.JSONRequest.KEY_VERSION)); 290 | } 291 | 292 | for (String method : methods) { 293 | APIJSONParser parser = APIJSONApplication.createParser(); 294 | M r = parser.setMethod(RequestMethod.valueOf(method)) 295 | .setNeedVerify(false) 296 | .parseResponse(demo); 297 | 298 | if (! JSONResponse.isSuccess(r)) { 299 | try { 300 | onServerError(JSONResponse.getMsg(r), shutdownWhenServerError); 301 | } catch (Exception e) { 302 | throw new RuntimeException(e); 303 | } 304 | } 305 | } 306 | } 307 | 308 | // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP! 309 | // if (isAll) { 310 | // FUNCTION_MAP = newMap; 311 | // } 312 | // else { 313 | // FUNCTION_MAP.putAll(newMap); 314 | // } 315 | 316 | return response; 317 | } 318 | 319 | 320 | protected static void onServerError(String msg, boolean shutdown) throws ServerException { 321 | Log.e(TAG, "\n远程函数文档测试未通过!\n请新增 demo 里的函数,或修改 Function 表里的 demo 为已有的函数示例!\n保证前端看到的远程函数文档是正确的!!!\n\n原因:\n" + msg); 322 | 323 | if (shutdown) { 324 | System.exit(1); 325 | } else { 326 | throw new ServerException(msg); 327 | } 328 | } 329 | 330 | 331 | public static void test() throws Exception { 332 | test(null); 333 | } 334 | public static , L extends List> void test( 335 | APIJSONFunctionParser functionParser) throws Exception { 336 | int i0 = 1, i1 = -2; 337 | M request = JSON.createJSONObject(); 338 | request.put("id", 10); 339 | request.put("i0", i0); 340 | request.put("i1", i1); 341 | L arr = JSON.createJSONArray(); 342 | arr.add(JSON.createJSONObject()); 343 | request.put("arr", arr); 344 | 345 | L array = JSON.createJSONArray(); 346 | array.add(1);//JSON.createJSONObject()); 347 | array.add(2);//JSON.createJSONObject()); 348 | array.add(4);//JSON.createJSONObject()); 349 | array.add(10);//JSON.createJSONObject()); 350 | request.put("array", array); 351 | 352 | request.put("position", 1); 353 | request.put("@position", 0); 354 | 355 | request.put("key", "key"); 356 | M object = JSON.createJSONObject(); 357 | object.put("key", "success"); 358 | request.put("object", object); 359 | 360 | APIJSONParser parser = APIJSONApplication.createParser(); 361 | parser.setRequest(request); 362 | if (functionParser == null) { 363 | functionParser = APIJSONApplication.createFunctionParser(); 364 | functionParser.setParser(parser); 365 | functionParser.setMethod(parser.getMethod()); 366 | functionParser.setTag(parser.getTag()); 367 | functionParser.setVersion(parser.getVersion()); 368 | functionParser.setRequest(parser.getRequest()); 369 | 370 | //if (functionParser instanceof APIJSONFunctionParser) { 371 | ((APIJSONFunctionParser) functionParser).setSession(parser.getSession()); 372 | //} 373 | } 374 | 375 | // functionParser.setKey(null); 376 | // functionParser.setParentPath(null); 377 | // functionParser.setCurrentName(null); 378 | functionParser.setCurrentObject(request); 379 | 380 | // 等数据库 Function 表加上 plus 配置再过两个以上迭代(应该是到 5.0)后再取消注释 381 | // Log.i(TAG, "plus(1,-2) = " + function.invoke("plus(i0,i1)", request)); 382 | // AssertUtil.assertEqual(-1, function.invoke("plus(i0,i1)", request)); 383 | 384 | Log.i(TAG, "count([1,2,4,10]) = " + functionParser.invoke("countArray(array)", request)); 385 | AssertUtil.assertEqual(4, functionParser.invoke("countArray(array)", request)); 386 | 387 | Log.i(TAG, "isContain([1,2,4,10], 10) = " + functionParser.invoke("isContain(array,id)", request)); 388 | AssertUtil.assertEqual(true, functionParser.invoke("isContain(array,id)", request)); 389 | 390 | Log.i(TAG, "getFromArray([1,2,4,10], 0) = " + functionParser.invoke("getFromArray(array,@position)", request)); 391 | AssertUtil.assertEqual(1, functionParser.invoke("getFromArray(array,@position)", request)); 392 | 393 | Log.i(TAG, "getFromObject({key:\"success\"}, key) = " + functionParser.invoke("getFromObject(object,key)", request)); 394 | AssertUtil.assertEqual("success", functionParser.invoke("getFromObject(object,key)", request)); 395 | 396 | } 397 | 398 | 399 | /**获取远程函数的demo,如果没有就自动补全 400 | * @param curObj 401 | * @return 402 | * @throws ServerException 403 | */ 404 | public M getFunctionDemo(@NotNull M curObj) { 405 | M demo = JSON.parseObject(getString(curObj, "demo")); 406 | if (demo == null) { 407 | demo = JSON.createJSONObject(); 408 | } 409 | if (! demo.containsKey("result()")) { 410 | demo.put("result()", getFunctionCall(getString(curObj, "name"), getString(curObj, "arguments"))); 411 | } 412 | return demo; 413 | } 414 | 415 | /**获取远程函数的demo,如果没有就自动补全 416 | * @param curObj 417 | * @return 418 | */ 419 | public String getFunctionDetail(@NotNull M curObj) { 420 | return getFunctionCall(getString(curObj, "name"), getString(curObj, "arguments")) 421 | + ": " + StringUtil.trim(getString(curObj, "detail")); 422 | } 423 | /**获取函数调用代码 424 | * @param name 425 | * @param arguments 426 | * @return 427 | */ 428 | private static String getFunctionCall(String name, String arguments) { 429 | return name + "(" + StringUtil.trim(arguments) + ")"; 430 | } 431 | 432 | 433 | public double plus(@NotNull M curObj, String i0, String i1) { 434 | return getDoubleValue(curObj, i0) + getDoubleValue(curObj, i1); 435 | } 436 | public double minus(@NotNull M curObj, String i0, String i1) { 437 | return getDoubleValue(curObj, i0) - getDoubleValue(curObj, i1); 438 | } 439 | public double multiply(@NotNull M curObj, String i0, String i1) { 440 | return getDoubleValue(curObj, i0) * getDoubleValue(curObj, i1); 441 | } 442 | public double divide(@NotNull M curObj, String i0, String i1) { 443 | return getDoubleValue(curObj, i0) / getDoubleValue(curObj, i1); 444 | } 445 | 446 | public double plus(@NotNull M curObj, Number n0, Number n1) { 447 | return n0.doubleValue() + n1.doubleValue(); 448 | } 449 | public double minus(@NotNull M curObj, Number n0, Number n1) { 450 | return n0.doubleValue() - n1.doubleValue(); 451 | } 452 | public double multiply(@NotNull M curObj, Number n0, Number n1) { 453 | return n0.doubleValue() * n1.doubleValue(); 454 | } 455 | public double divide(@NotNull M curObj, Number n0, Number n1) { 456 | return n0.doubleValue() / n1.doubleValue(); 457 | } 458 | 459 | //判断是否为空 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 460 | /**判断array是否为空 461 | * @param curObj 462 | * @param array 463 | * @return 464 | */ 465 | public boolean isArrayEmpty(@NotNull M curObj, String array) { 466 | return BaseModel.isEmpty((Collection) getJSONArray(curObj, array)); 467 | } 468 | /**判断object是否为空 469 | * @param curObj 470 | * @param object 471 | * @return 472 | */ 473 | public boolean isObjectEmpty(@NotNull M curObj, String object) { 474 | return BaseModel.isEmpty((Map) getJSONObject(curObj, object)); 475 | } 476 | //判断是否为空 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 477 | 478 | //判断是否为包含 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 479 | /**判断array是否包含value 480 | * @param curObj 481 | * @param array 482 | * @param value 483 | * @return 484 | */ 485 | public boolean isContain(@NotNull M curObj, String array, String value) { 486 | //解决isContain((List) [82001,...], (Integer) 82001) == false及类似问题, list元素可能是从数据库查到的bigint类型的值 487 | // return BaseModel.isContain(getJSONArray(curObj, array), curObj.get(value)); 488 | 489 | //不用准确的的 getString(curObj, value).getClass() ,因为Long值转Integer崩溃,而且转成一种类型本身就和字符串对比效果一样了。 490 | List list = JSON.parseArray(getString(curObj, array), String.class); 491 | return list != null && list.contains(getString(curObj, value)); 492 | } 493 | /**判断object是否包含key 494 | * @param curObj 495 | * @param object 496 | * @param key 497 | * @return 498 | */ 499 | public boolean isContainKey(@NotNull M curObj, String object, String key) { 500 | return BaseModel.isContainKey(getJSONObject(curObj, object), getString(curObj, key)); 501 | } 502 | /**判断object是否包含value 503 | * @param curObj 504 | * @param object 505 | * @param value 506 | * @return 507 | */ 508 | public boolean isContainValue(@NotNull M curObj, String object, String value) { 509 | return BaseModel.isContainValue(getJSONObject(curObj, object), curObj.get(value)); 510 | } 511 | //判断是否为包含 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 512 | 513 | 514 | //获取集合长度 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 515 | /**获取数量 516 | * @param curObj 517 | * @param array 518 | * @return 519 | */ 520 | public int countArray(@NotNull M curObj, String array) { 521 | return BaseModel.count((Collection) getJSONArray(curObj, array)); 522 | } 523 | /**获取数量 524 | * @param curObj 525 | * @param object 526 | * @return 527 | */ 528 | public int countObject(@NotNull M curObj, String object) { 529 | return BaseModel.count((Map) getJSONObject(curObj, object)); 530 | } 531 | //获取集合长度 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 532 | 533 | 534 | //根据键获取值 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 535 | /**获取 536 | ** @param curObj 537 | * @param array 538 | * @param position 支持直接传数字,例如 getFromArray(array,0) ;或者引用当前对象的值,例如 "@position": 0, "result()": "getFromArray(array,@position)" 539 | * @return 540 | */ 541 | public Object getFromArray(@NotNull M curObj, String array, String position) { 542 | int p; 543 | try { 544 | p = Integer.parseInt(position); 545 | } catch (Exception e) { 546 | p = getIntValue(curObj, position); 547 | } 548 | return BaseModel.get(getJSONArray(curObj, array), p); 549 | } 550 | /**获取 551 | * @param curObj 552 | * @param object 553 | * @param key 554 | * @return 555 | */ 556 | public Object getFromObject(@NotNull M curObj, String object, String key) { 557 | return BaseModel.get(getJSONObject(curObj, object), getString(curObj, key)); 558 | } 559 | //根据键获取值 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 560 | 561 | //根据键移除值 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 562 | /**移除 563 | ** @param curObj 564 | * @param position 支持直接传数字,例如 getFromArray(array,0) ;或者引用当前对象的值,例如 "@position": 0, "result()": "getFromArray(array,@position)" 565 | * @return 566 | */ 567 | public Object removeIndex(@NotNull M curObj, String position) { 568 | int p; 569 | try { 570 | p = Integer.parseInt(position); 571 | } catch (Exception e) { 572 | p = getIntValue(curObj, position); 573 | } 574 | curObj.remove(p); 575 | return null; 576 | } 577 | /**移除 578 | * @param curObj 579 | * @param key 580 | * @return 581 | */ 582 | public Object removeKey(@NotNull M curObj, String key) { 583 | curObj.remove(key); 584 | return null; 585 | } 586 | //根据键获取值 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 587 | 588 | 589 | 590 | //获取非基本类型对应基本类型的非空值 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 591 | /**获取非空值 592 | * @param curObj 593 | * @param value 594 | * @return 595 | */ 596 | public boolean booleanValue(@NotNull M curObj, String value) { 597 | return getBooleanValue(curObj, value); 598 | } 599 | /**获取非空值 600 | * @param curObj 601 | * @param value 602 | * @return 603 | */ 604 | public int intValue(@NotNull M curObj, String value) { 605 | return getIntValue(curObj, value); 606 | } 607 | /**获取非空值 608 | * @param curObj 609 | * @param value 610 | * @return 611 | */ 612 | public long longValue(@NotNull M curObj, String value) { 613 | return getLongValue(curObj, value); 614 | } 615 | /**获取非空值 616 | * @param curObj 617 | * @param value 618 | * @return 619 | */ 620 | public float floatValue(@NotNull M curObj, String value) { 621 | return getFloatValue(curObj, value); 622 | } 623 | /**获取非空值 624 | * @param curObj 625 | * @param value 626 | * @return 627 | */ 628 | public double doubleValue(@NotNull M curObj, String value) { 629 | return getDoubleValue(curObj, value); 630 | } 631 | //获取非基本类型对应基本类型的非空值 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 632 | 633 | /**获取value,当value为null时获取defaultValue 634 | * @param curObj 635 | * @param value 636 | * @param defaultValue 637 | * @return v == null ? curObj.get(defaultValue) : v 638 | */ 639 | public Object getWithDefault(@NotNull M curObj, String value, String defaultValue) { 640 | Object v = curObj.get(value); 641 | return v == null ? curObj.get(defaultValue) : v; 642 | } 643 | 644 | // FIXME UnitAuto 去除 fastjson 后恢复 645 | ///**获取方法参数的定义 646 | // * @param curObj 647 | // * @return 648 | // * @throws IOException 649 | // * @throws ClassNotFoundException 650 | // * @throws IllegalArgumentException 651 | // */ 652 | //public String getMethodArguments(@NotNull M curObj) throws IllegalArgumentException, ClassNotFoundException, IOException { 653 | // return getMethodArguments(curObj, "methodArgs"); 654 | //} 655 | ///**获取方法参数的定义 656 | // * @param curObj 657 | // * @param methodArgsKey 658 | // * @return 659 | // * @throws IllegalArgumentException 660 | // * @throws ClassNotFoundException 661 | // * @throws IOException 662 | // */ 663 | //public String getMethodArguments(@NotNull M curObj, String methodArgsKey) throws IllegalArgumentException, ClassNotFoundException, IOException { 664 | // M obj = getJSONObject(curObj, "request"); 665 | // String argsStr = obj == null ? null : getString(obj, methodArgsKey); 666 | // if (StringUtil.isEmpty(argsStr, true)) { 667 | // argsStr = getString(curObj, methodArgsKey); 668 | // } 669 | // List methodArgs = JSON.parseArray(removeComment(argsStr), Argument.class); 670 | // if (methodArgs == null || methodArgs.isEmpty()) { 671 | // return ""; 672 | // } 673 | // 674 | // // Class[] types = new Class[methodArgs.size()]; 675 | // // Object[] args = new Object[methodArgs.size()]; 676 | // // MethodUtil.initTypesAndValues(methodArgs, types, args, true); 677 | // 678 | // String s = ""; 679 | // // if (types != null) { 680 | // // String sn; 681 | // // for (int i = 0; i < types.length; i++) { 682 | // // sn = types[i] == null ? null : types[i].getSimpleName(); 683 | // // if (sn == null) { 684 | // // sn = Object.class.getSimpleName(); 685 | // // } 686 | // // 687 | // // if (i > 0) { 688 | // // s += ","; 689 | // // } 690 | // // 691 | // // if (MethodUtil.CLASS_MAP.containsKey(sn)) { 692 | // // s += sn; 693 | // // } 694 | // // else { 695 | // // s += types[i].getName(); 696 | // // } 697 | // // } 698 | // // } 699 | // 700 | // for (int i = 0; i < methodArgs.size(); i++) { 701 | // Argument arg = methodArgs.get(i); 702 | // 703 | // String sn = arg == null ? null : arg.getType(); 704 | // if (sn == null) { 705 | // sn = arg.getValue() == null ? Object.class.getSimpleName() : MethodUtil.trimType(arg.getValue().getClass()); 706 | // } 707 | // 708 | // if (i > 0) { 709 | // s += ","; 710 | // } 711 | // s += sn; 712 | // } 713 | // 714 | // return s; 715 | //} 716 | // 717 | // 718 | ///**获取方法的定义 719 | // * @param curObj 720 | // * @return 721 | // * @throws IOException 722 | // * @throws ClassNotFoundException 723 | // * @throws IllegalArgumentException 724 | // */ 725 | //public String getMethodDefinition(@NotNull M curObj) throws IllegalArgumentException { 726 | // // curObj.put("arguments", removeComment(getString(curObj, "methodArgs"))); 727 | // return getMethodDefinition(curObj, "method", "arguments", "genericType", "genericExceptions", "Java"); 728 | //} 729 | ///**获取方法的定义 730 | // * @param curObj 731 | // * @param method 732 | // * @param arguments 733 | // * @param type 734 | // * @return method(argType0,argType1...): returnType 735 | // * @throws IOException 736 | // * @throws ClassNotFoundException 737 | // * @throws IllegalArgumentException 738 | // */ 739 | //public String getMethodDefinition(@NotNull M curObj, String method, String arguments 740 | // , String type, String exceptions, String language) throws IllegalArgumentException { 741 | // String n = getString(curObj, method); 742 | // if (StringUtil.isEmpty(n, true)) { 743 | // throw new NullPointerException("getMethodDefination StringUtil.isEmpty(methodArgs, true) !"); 744 | // } 745 | // String a = getString(curObj, arguments); 746 | // String t = getString(curObj, type); 747 | // String e = getString(curObj, exceptions); 748 | // 749 | // if (language == null) { 750 | // language = ""; 751 | // } 752 | // switch (language) { 753 | // case "TypeScript": 754 | // return n + "(" + (StringUtil.isEmpty(a, true) ? "" : a) + ")" + (StringUtil.isEmpty(t, true) ? "" : ": " + t) + (StringUtil.isEmpty(e, true) ? "" : " throws " + e); 755 | // case "Go": 756 | // return n + "(" + (StringUtil.isEmpty(a, true) ? "" : a ) + ")" + (StringUtil.isEmpty(t, true) ? "" : " " + t) + (StringUtil.isEmpty(e, true) ? "" : " throws " + e); 757 | // default: 758 | // //类型可能很长,Eclipse, Idea 代码提示都是类型放后面 return (StringUtil.isEmpty(t, true) ? "" : t + " ") + n + "(" + (StringUtil.isEmpty(a, true) ? "" : a) + ")"; 759 | // return n + "(" + (StringUtil.isEmpty(a, true) ? "" : a) + ")" + (StringUtil.isEmpty(t, true) ? "" : ": " + t) + (StringUtil.isEmpty(e, true) ? "" : " throws " + e); 760 | // } 761 | //} 762 | // 763 | ///** 764 | // * methodArgs 和 classArgs 都可以带注释 765 | // */ 766 | //public String getMethodRequest(@NotNull M curObj) { 767 | // String req = getString(curObj, "request"); 768 | // if (StringUtil.isEmpty(req, true) == false) { 769 | // return req; 770 | // } 771 | // 772 | // req = "{"; 773 | // Boolean isStatic = getBoolean(curObj, "static"); 774 | // String methodArgs = getString(curObj, "methodArgs"); 775 | // String classArgs = getString(curObj, "classArgs"); 776 | // 777 | // boolean comma = false; 778 | // if (isStatic != null && isStatic) { 779 | // req += "\n \"static\": " + true; 780 | // comma = true; 781 | // } 782 | // if (! StringUtil.isEmpty(methodArgs, true)) { 783 | // req += (comma ? "," : "") + "\n \"methodArgs\": " + methodArgs; 784 | // comma = true; 785 | // } 786 | // if (! StringUtil.isEmpty(classArgs, true)) { 787 | // req += (comma ? "," : "") + "\n \"classArgs\": " + classArgs; 788 | // } 789 | // req += "\n}"; 790 | // return req; 791 | //} 792 | // 793 | //// public static JSONRequest removeComment(String json) { 794 | //// return JSON.parseObject(removeComment(json)); 795 | //// } 796 | //public static String removeComment(String json) { 797 | // return json == null ? null: json.replaceAll("(//.*)|(/\\*[\\s\\S]*?\\*/)", ""); 798 | //} 799 | 800 | } 801 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONObjectParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | import jakarta.servlet.http.HttpSession; 21 | 22 | import apijson.orm.*; 23 | 24 | import apijson.NotNull; 25 | import apijson.RequestMethod; 26 | 27 | 28 | /**简化Parser,getObject和getArray(getArrayConfig)都能用 29 | * @author Lemon 30 | */ 31 | public class APIJSONObjectParser, L extends List> extends AbstractObjectParser { 32 | public static final String TAG = "APIJSONObjectParser"; 33 | 34 | /**for single object 35 | * @param session 36 | * @param request 37 | * @param parentPath 38 | * @param arrayConfig 39 | * @param isSubquery 40 | * @param isTable 41 | * @param isArrayMainTable 42 | * @throws Exception 43 | */ 44 | public APIJSONObjectParser(HttpSession session, @NotNull M request, String parentPath, SQLConfig arrayConfig 45 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 46 | super(request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable); 47 | } 48 | 49 | @Override 50 | public APIJSONObjectParser setMethod(RequestMethod method) { 51 | super.setMethod(method); 52 | return this; 53 | } 54 | 55 | @Override 56 | public APIJSONObjectParser setParser(Parser parser) { 57 | super.setParser(parser); 58 | return this; 59 | } 60 | 61 | 62 | @Override 63 | public SQLConfig newSQLConfig(RequestMethod method, String table, String alias, M request 64 | , List> joinList, boolean isProcedure) throws Exception { 65 | return APIJSONSQLConfig.newSQLConfig(method, table, alias, request, joinList, isProcedure); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import static apijson.framework.APIJSONConstant.DEFAULTS; 18 | import static apijson.framework.APIJSONConstant.FORMAT; 19 | import static apijson.framework.APIJSONConstant.VERSION; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | import jakarta.servlet.http.HttpSession; 26 | 27 | import apijson.NotNull; 28 | import apijson.RequestMethod; 29 | import apijson.orm.AbstractParser; 30 | import apijson.orm.FunctionParser; 31 | import apijson.orm.SQLConfig; 32 | 33 | 34 | /**请求解析器 35 | * @author Lemon 36 | */ 37 | public class APIJSONParser, L extends List> extends AbstractParser { 38 | public static final String TAG = "APIJSONParser"; 39 | 40 | 41 | public APIJSONParser() { 42 | super(); 43 | } 44 | public APIJSONParser(RequestMethod method) { 45 | super(method); 46 | } 47 | public APIJSONParser(RequestMethod method, boolean needVerify) { 48 | super(method, needVerify); 49 | } 50 | 51 | private HttpSession session; 52 | public HttpSession getSession() { 53 | return session; 54 | } 55 | public APIJSONParser setSession(HttpSession session) { 56 | this.session = session; 57 | setVisitor(APIJSONVerifier.getVisitor(session)); 58 | return this; 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | @Override 63 | public APIJSONParser createParser() { 64 | return APIJSONApplication.createParser(); 65 | } 66 | @Override 67 | public APIJSONFunctionParser createFunctionParser() { 68 | return APIJSONApplication.createFunctionParser(); 69 | } 70 | 71 | @SuppressWarnings("unchecked") 72 | @Override 73 | public APIJSONVerifier createVerifier() { 74 | return APIJSONApplication.createVerifier(); 75 | } 76 | 77 | @Override 78 | public APIJSONSQLConfig createSQLConfig() { 79 | return APIJSONApplication.createSQLConfig(); 80 | } 81 | @Override 82 | public APIJSONSQLExecutor createSQLExecutor() { 83 | return APIJSONApplication.createSQLExecutor(); 84 | } 85 | 86 | @Override 87 | public APIJSONParser setNeedVerify(boolean needVerify) { 88 | super.setNeedVerify(needVerify); 89 | return this; 90 | } 91 | 92 | @Override 93 | public APIJSONParser setNeedVerifyLogin(boolean needVerifyLogin) { 94 | super.setNeedVerifyLogin(needVerifyLogin); 95 | return this; 96 | } 97 | 98 | @Override 99 | public APIJSONParser setNeedVerifyRole(boolean needVerifyRole) { 100 | super.setNeedVerifyRole(needVerifyRole); 101 | return this; 102 | } 103 | 104 | @Override 105 | public APIJSONParser setNeedVerifyContent(boolean needVerifyContent) { 106 | super.setNeedVerifyContent(needVerifyContent); 107 | return this; 108 | } 109 | 110 | @Override 111 | public M parseResponse(M request) { 112 | //补充format 113 | if (session != null && request != null) { 114 | if (request.get(FORMAT) == null) { 115 | request.put(FORMAT, session.getAttribute(FORMAT)); 116 | } 117 | if (request.get(VERSION) == null) { 118 | request.put(VERSION, session.getAttribute(VERSION)); 119 | } 120 | 121 | if (request.get(DEFAULTS) == null) { 122 | M defaults = (M) session.getAttribute(DEFAULTS); 123 | Set> set = defaults == null ? null : defaults.entrySet(); 124 | 125 | if (set != null) { 126 | for (Map.Entry e : set) { 127 | if (e != null && request.get(e.getKey()) == null) { 128 | request.put(e.getKey(), e.getValue()); 129 | } 130 | } 131 | } 132 | } 133 | } 134 | 135 | return super.parseResponse(request); 136 | } 137 | 138 | private FunctionParser functionParser; 139 | public FunctionParser getFunctionParser() { 140 | return functionParser; 141 | } 142 | @Override 143 | public Object onFunctionParse(String key, String function, String parentPath, String currentName, M currentObject, boolean containRaw) throws Exception { 144 | if (functionParser == null) { 145 | functionParser = createFunctionParser(); 146 | functionParser.setParser(this); 147 | functionParser.setMethod(getMethod()); 148 | functionParser.setTag(getTag()); 149 | functionParser.setVersion(getVersion()); 150 | functionParser.setRequest(requestObject); 151 | 152 | if (functionParser instanceof APIJSONFunctionParser) { 153 | ((APIJSONFunctionParser) functionParser).setSession(getSession()); 154 | } 155 | } 156 | functionParser.setKey(key); 157 | functionParser.setParentPath(parentPath); 158 | functionParser.setCurrentName(currentName); 159 | functionParser.setCurrentObject(currentObject); 160 | 161 | return functionParser.invoke(function, currentObject, containRaw); 162 | } 163 | 164 | 165 | @Override 166 | public APIJSONObjectParser createObjectParser(@NotNull M request, String parentPath, SQLConfig arrayConfig 167 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 168 | 169 | return new APIJSONObjectParser(getSession(), request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable) { 170 | 171 | // @Override 172 | // protected APIJSONSQLConfig newQueryConfig() { 173 | // if (itemConfig != null) { 174 | // return itemConfig; 175 | // } 176 | // return super.newQueryConfig(); 177 | // } 178 | 179 | // 导致最多评论的(Strong 30个)的那个动态详情界面Android(82001)无姓名和头像,即User=null 180 | // @Override 181 | // protected void onComplete() { 182 | // if (response != null) { 183 | // putQueryResult(path, response); // 解决获取关联数据时requestObject里不存在需要的关联数据 184 | // } 185 | // } 186 | 187 | }.setMethod(getMethod()).setParser(this); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONSQLConfig.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import static apijson.framework.APIJSONConstant.ID; 18 | import static apijson.framework.APIJSONConstant.PRIVACY_; 19 | import static apijson.framework.APIJSONConstant.USER_; 20 | import static apijson.framework.APIJSONConstant.USER_ID; 21 | 22 | import java.util.LinkedHashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | import apijson.JSONList; 27 | import apijson.JSONMap; 28 | //import apijson.column.ColumnUtil; 29 | 30 | import apijson.RequestMethod; 31 | import apijson.orm.AbstractSQLConfig; 32 | import apijson.orm.Join; 33 | import apijson.orm.SQLConfig; 34 | 35 | 36 | /**SQL配置 37 | * TiDB 用法和 MySQL 一致 38 | * @author Lemon 39 | */ 40 | public class APIJSONSQLConfig, L extends List> extends AbstractSQLConfig { 41 | public static final String TAG = "APIJSONSQLConfig"; 42 | 43 | public static boolean ENABLE_COLUMN_CONFIG = false; 44 | 45 | public static Callback, ? extends List> SIMPLE_CALLBACK; 46 | 47 | static { 48 | DEFAULT_DATABASE = DATABASE_MYSQL; //TODO 默认数据库类型,改成你自己的 49 | DEFAULT_SCHEMA = "sys"; //TODO 默认模式名,改成你自己的,默认情况是 MySQL: sys, PostgreSQL: public, SQL Server: dbo, Oracle: 50 | // TABLE_KEY_MAP.put(Access.class.getSimpleName(), "apijson_access"); 51 | 52 | // 由 APIJSONVerifier.init 方法读取数据库 Access 表来替代手动输入配置 53 | // //表名映射,隐藏真实表名,对安全要求很高的表可以这么做 54 | // TABLE_KEY_MAP.put(User.class.getSimpleName(), "apijson_user"); 55 | // TABLE_KEY_MAP.put(Privacy.class.getSimpleName(), "apijson_privacy"); 56 | 57 | SIMPLE_CALLBACK = new SimpleCallback, List>() { 58 | 59 | @Override 60 | public SQLConfig, List> getSQLConfig( 61 | RequestMethod method, String database, String schema, String datasource, String table) { 62 | SQLConfig, List> config = APIJSONApplication.createSQLConfig(); 63 | config.setMethod(method); 64 | config.setDatabase(database); 65 | config.setDatasource(datasource); 66 | config.setSchema(schema); 67 | config.setTable(table); 68 | return config; 69 | } 70 | 71 | //取消注释来实现自定义各个表的主键名 72 | // @Override 73 | // public String getIdKey(String database, String schema, String datasource, String table) { 74 | // return StringUtil.firstCase(table + "Id"); // userId, comemntId ... 75 | // // return StringUtil.toLowerCase(t) + "_id"; // user_id, comemnt_id ... 76 | // // return StringUtil.toUpperCase(t) + "_ID"; // USER_ID, COMMENT_ID ... 77 | // } 78 | 79 | @Override 80 | public String getUserIdKey(String database, String schema, String datasource, String table) { 81 | return USER_.equals(table) || PRIVACY_.equals(table) ? ID : USER_ID; // id / userId 82 | } 83 | 84 | //取消注释来实现数据库自增 id 85 | // @Override 86 | // public Object newId(RequestMethod method, String database, String schema, String datasource, String table) { 87 | // return null; // return null 则不生成 id,一般用于数据库自增 id 88 | // } 89 | }; 90 | 91 | } 92 | 93 | /**获取SQL配置 94 | * @param table 95 | * @param alias 96 | * @param request 97 | * @param isProcedure 98 | * @return 99 | * @throws Exception 100 | */ 101 | public static , L extends List> SQLConfig newSQLConfig( 102 | RequestMethod method, String table, String alias, M request, List> joinList, boolean isProcedure) throws Exception { 103 | return newSQLConfig(method, table, alias, request, joinList, isProcedure, (SimpleCallback) SIMPLE_CALLBACK); 104 | } 105 | 106 | public APIJSONSQLConfig() { 107 | this(RequestMethod.GET); 108 | } 109 | public APIJSONSQLConfig(RequestMethod method) { 110 | super(method); 111 | } 112 | public APIJSONSQLConfig(RequestMethod method, String table) { 113 | super(method, table); 114 | } 115 | public APIJSONSQLConfig(RequestMethod method, int count, int page) { 116 | super(method, count, page); 117 | } 118 | 119 | 120 | public String gainDBVersion() { 121 | if (isMySQL()) { 122 | return "5.7.22"; //"8.0.11"; //TODO 改成你自己的 MySQL 或 PostgreSQL 数据库版本号 //MYSQL 8 和 7 使用的 JDBC 配置不一样 123 | } 124 | if (isPostgreSQL()) { 125 | return "9.6.15"; //TODO 改成你自己的 126 | } 127 | if (isSQLServer()) { 128 | return "2016"; //TODO 改成你自己的 129 | } 130 | if (isOracle()) { 131 | return "18c"; //TODO 改成你自己的 132 | } 133 | return null; 134 | } 135 | 136 | public String gainDBUri() { 137 | if (isMySQL()) { 138 | return "jdbc:mysql://localhost:3306"; 139 | } 140 | if (isTiDB()) { 141 | return "jdbc:mysql://localhost:4000"; 142 | } 143 | if (isPostgreSQL()) { // PG JDBC 必须在 URI 传 catalog 144 | return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 145 | } 146 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 147 | // return "jdbc:postgresql://localhost:26257/movr?sslmode=require"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach && cockroach demo 148 | // // return "jdbc:postgresql://localhost:26258/postgres?sslmode=disable"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach # && start 3 nodes and init cluster 149 | //} 150 | if (isSQLServer()) { 151 | return "jdbc:jtds:sqlserver://localhost:1433/pubs;instance=SQLEXPRESS"; //TODO 改成你自己的 152 | } 153 | if (isOracle()) { 154 | return "jdbc:oracle:thin:@localhost:1521:orcl"; //TODO 改成你自己的 155 | } 156 | if (isDb2()) { 157 | return "jdbc:db2://localhost:50000/BLUDB"; //TODO 改成你自己的 158 | } 159 | if (isSQLite()) { 160 | return "jdbc:sqlite:sample.db"; //TODO 改成你自己的 161 | } 162 | if (isDameng()) { 163 | return "jdbc:dm://localhost:5236"; //TODO 改成你自己的 164 | } 165 | if (isTDengine()) { 166 | // return "jdbc:TAOS://localhost:6030"; //TODO 改成你自己的 167 | return "jdbc:TAOS-RS://localhost:6041"; //TODO 改成你自己的 168 | } 169 | if (isTimescaleDB()) { // PG JDBC 必须在 URI 传 catalog 170 | return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 171 | } 172 | if (isQuestDB()) { // PG JDBC 必须在 URI 传 catalog 173 | return "jdbc:postgresql://localhost:8812/qdb"; //TODO 改成你自己的 174 | } 175 | if (isInfluxDB()) { 176 | return "http://203.189.6.3:8086"; //TODO 改成你自己的 177 | } 178 | if (isMilvus()) { 179 | return "http://localhost:19530"; //TODO 改成你自己的 180 | } 181 | if (isManticore()) { 182 | return "jdbc:mysql://localhost:9306?characterEncoding=utf8&maxAllowedPacket=512000"; 183 | } 184 | if (isIoTDB()) { 185 | return "jdbc:iotdb://localhost:6667"; // ?charset=GB18030 加参数会报错 URI 格式错误 186 | } 187 | if (isMongoDB()) { 188 | return "jdbc:mongodb://atlas-sql-6593c65c296c5865121e6ebe-xxskv.a.query.mongodb.net/myVirtualDatabase?ssl=true&authSource=admin"; 189 | } 190 | if (isCassandra()) { 191 | return "http://localhost:7001"; 192 | } 193 | if (isDuckDB()) { 194 | return "jdbc:duckdb:/Users/root/my_database.duckdb"; 195 | } 196 | if (isSurrealDB()) { 197 | // return "memory"; 198 | // return "surrealkv://localhost:8000"; 199 | return "ws://localhost:8000"; 200 | } 201 | if (isOpenGauss()) { 202 | return "jdbc:opengauss://127.0.0.1:5432/postgres?currentSchema=" + DEFAULT_SCHEMA; 203 | } 204 | if (isDoris()) { 205 | return "jdbc:mysql://localhost:9030"; 206 | } 207 | return null; 208 | } 209 | 210 | public String gainDBAccount() { 211 | if (isMySQL()) { 212 | return "root"; //TODO 改成你自己的 213 | } 214 | if (isPostgreSQL()) { 215 | return "postgres"; //TODO 改成你自己的 216 | } 217 | if (isSQLServer()) { 218 | return "sa"; //TODO 改成你自己的 219 | } 220 | if (isOracle()) { 221 | return "scott"; //TODO 改成你自己的 222 | } 223 | if (isMySQL()) { 224 | return "root"; // ""apijson"; //TODO 改成你自己的 225 | } 226 | if (isPostgreSQL()) { 227 | return "postgres"; //TODO 改成你自己的 228 | } 229 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 230 | // return "demo"; //TODO 改成你自己的 231 | // //return "postgres"; //TODO 改成你自己的 232 | //} 233 | if (isSQLServer()) { 234 | return "sa"; //TODO 改成你自己的 235 | } 236 | if (isOracle()) { 237 | return "scott"; //TODO 改成你自己的 238 | } 239 | if (isDb2()) { 240 | return "db2admin"; //TODO 改成你自己的 241 | } 242 | // if (isSQLite()) { 243 | // return "root"; //TODO 改成你自己的 244 | // } 245 | if (isDameng()) { 246 | return "SYSDBA"; 247 | } 248 | if (isTDengine()) { 249 | return "root"; //TODO 改成你自己的 250 | } 251 | //if (isTimescaleDB()) { 252 | // return "postgres"; //TODO 改成你自己的 253 | //} 254 | if (isQuestDB()) { 255 | return "admin"; //TODO 改成你自己的 256 | } 257 | if (isInfluxDB()) { 258 | return "iotos"; 259 | } 260 | if (isMilvus()) { 261 | return "root"; 262 | } 263 | if (isManticore()) { 264 | return null; // "root"; 265 | } 266 | if (isIoTDB()) { 267 | return "root"; 268 | } 269 | if (isMongoDB()) { 270 | return "root"; //TODO 改成你自己的 271 | } 272 | if (isCassandra()) { 273 | return "root"; //TODO 改成你自己的 274 | } 275 | if (isDuckDB()) { 276 | return "root"; //TODO 改成你自己的 277 | } 278 | if (isSurrealDB()) { 279 | return "root"; //TODO 改成你自己的 280 | } 281 | if (isOpenGauss()) { 282 | return "postgres"; //TODO 改成你自己的 283 | // 不允许用初始账号,需要 CREATE USER 创建新账号并 GRANT 授权 return "opengauss"; //TODO 改成你自己的 284 | } 285 | if (isDoris()) { 286 | return "root"; //TODO 改成你自己的 287 | } 288 | 289 | return null; 290 | } 291 | 292 | public String gainDBPassword() { 293 | if (isMySQL()) { 294 | return "yourPassword@123"; 295 | } 296 | if (isTiDB()) { 297 | return ""; 298 | } 299 | if (isPostgreSQL()) { 300 | return null; 301 | } 302 | if (isSQLServer()) { 303 | return "yourPassword@123"; 304 | } 305 | if (isOracle()) { 306 | return "tiger"; 307 | } 308 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 309 | // return "demo39865"; 310 | // // return null 311 | //} 312 | if (isSQLServer()) { 313 | return "yourPassword@123"; 314 | } 315 | if (isOracle()) { 316 | return "tiger"; 317 | } 318 | if (isDb2()) { 319 | return "123"; 320 | } 321 | if (isSQLite()) { 322 | return "yourPassword@123"; 323 | } 324 | if (isDameng()) { 325 | return "SYSDBA"; 326 | } 327 | if (isTDengine()) { 328 | return "taosdata"; 329 | } 330 | if (isTimescaleDB()) { 331 | return "password"; 332 | } 333 | if (isQuestDB()) { 334 | return "quest"; 335 | } 336 | if (isInfluxDB()) { 337 | return "yourPassword@123"; 338 | } 339 | if (isMilvus()) { 340 | return "yourPassword@123"; 341 | } 342 | //if (isManticore()) { 343 | // return null; 344 | //} 345 | //if (isIoTDB()) { 346 | // return "root"; 347 | //} 348 | if (isMongoDB()) { 349 | return "yourPassword@123"; 350 | } 351 | if (isCassandra()) { 352 | return "yourPassword@123"; 353 | } 354 | if (isDuckDB()) { 355 | return ""; 356 | } 357 | if (isSurrealDB()) { 358 | return "root"; 359 | } 360 | if (isOpenGauss()) { 361 | return "yourPassword@123"; 362 | } 363 | if (isDoris()) { 364 | return ""; 365 | } 366 | 367 | return null; 368 | } 369 | 370 | /**获取 APIJSON 配置表所在数据库模式 database,默认与业务表一块 371 | * @return 372 | */ 373 | public String getConfigDatabase() { 374 | return getDatabase(); 375 | } 376 | /**获取 APIJSON 配置表所在数据库模式 schema,默认与业务表一块 377 | * @return 378 | */ 379 | public String getConfigSchema() { 380 | return getSchema(); 381 | } 382 | /**是否为 APIJSON 配置表,如果和业务表一块,可以重写这个方法,固定 return false 来提高性能 383 | * @return 384 | */ 385 | public boolean isConfigTable() { 386 | return CONFIG_TABLE_LIST.contains(getTable()); 387 | } 388 | @Override 389 | public String gainSQLDatabase() { 390 | String db = isConfigTable() ? getConfigDatabase() : super.gainSQLDatabase(); 391 | return db == null ? DEFAULT_DATABASE : db; 392 | } 393 | @Override 394 | public String gainSQLSchema() { 395 | String sch = isConfigTable() ? getConfigSchema() : super.gainSQLSchema(); 396 | return sch == null ? DEFAULT_SCHEMA : sch; 397 | } 398 | 399 | 400 | @Override 401 | public String getIdKey() { 402 | return SIMPLE_CALLBACK.getIdKey(getDatabase(), getSchema(), getDatasource(), getTable()); 403 | } 404 | 405 | @Override 406 | public String getUserIdKey() { 407 | return SIMPLE_CALLBACK.getUserIdKey(getDatabase(), getSchema(), getDatasource(), getTable()); 408 | } 409 | 410 | 411 | // 支持 !key 反选字段 和 字段名映射,依赖插件 https://github.com/APIJSON/apijson-column 412 | @Override 413 | public APIJSONSQLConfig setColumn(List column) { 414 | if (ENABLE_COLUMN_CONFIG) { 415 | column = ColumnUtil.compatInputColumn(column, getTable(), getMethod(), getVersion(), ! isConfigTable()); 416 | } 417 | super.setColumn(column); 418 | return this; 419 | } 420 | 421 | @Override 422 | public String gainKey(String key) { 423 | if (ENABLE_COLUMN_CONFIG) { 424 | key = ColumnUtil.compatInputKey(key, getTable(), getMethod()); 425 | } 426 | return super.gainKey(key); 427 | } 428 | 429 | } 430 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/APIJSONSQLExecutor.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.sql.PreparedStatement; 18 | import java.sql.ResultSet; 19 | import java.sql.ResultSetMetaData; 20 | import java.sql.SQLException; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | import org.postgresql.util.PGobject; 25 | 26 | import apijson.JSON; 27 | import apijson.Log; 28 | import apijson.NotNull; 29 | import apijson.orm.AbstractSQLExecutor; 30 | import apijson.orm.SQLConfig; 31 | 32 | 33 | /**executor for query(read) or update(write) MySQL database 34 | * @author Lemon 35 | */ 36 | public class APIJSONSQLExecutor, L extends List> extends AbstractSQLExecutor { 37 | public static final String TAG = "APIJSONSQLExecutor"; 38 | 39 | static { 40 | try { //加载驱动程序 41 | Log.d(TAG, "尝试加载 MySQL 8 驱动 <<<<<<<<<<<<<<<<<<<<< "); 42 | Class.forName("com.mysql.cj.jdbc.Driver"); 43 | Log.d(TAG, "成功加载 MySQL 8 驱动!>>>>>>>>>>>>>>>>>>>>>"); 44 | } 45 | catch (ClassNotFoundException e) { 46 | Log.e(TAG, "加载 MySQL 8 驱动失败,请检查 pom.xml 中 mysql-connector-java 版本是否存在以及可用 !!!"); 47 | e.printStackTrace(); 48 | 49 | try { //加载驱动程序 50 | Log.d(TAG, "尝试加载 MySQL 7 及以下版本的 驱动 <<<<<<<<<<<<<<<<<<<<< "); 51 | Class.forName("com.mysql.jdbc.Driver"); 52 | Log.d(TAG, "成功加载 MySQL 7 及以下版本的 驱动!>>>>>>>>>>>>>>>>>>>>> "); 53 | } 54 | catch (ClassNotFoundException e2) { 55 | Log.e(TAG, "加载 MySQL 7 及以下版本的 驱动失败,请检查 pom.xml 中 mysql-connector-java 版本是否存在以及可用 !!!"); 56 | e2.printStackTrace(); 57 | } 58 | } 59 | 60 | try { //加载驱动程序 61 | Log.d(TAG, "尝试加载 PostgresSQL 驱动 <<<<<<<<<<<<<<<<<<<<< "); 62 | Class.forName("org.postgresql.Driver"); 63 | Log.d(TAG, "成功加载 PostgresSQL 驱动!>>>>>>>>>>>>>>>>>>>>> "); 64 | } 65 | catch (ClassNotFoundException e) { 66 | e.printStackTrace(); 67 | Log.e(TAG, "加载 PostgresSQL 驱动失败,请检查 libs 目录中 postgresql.jar 版本是否存在以及可用 !!!"); 68 | } 69 | 70 | } 71 | 72 | 73 | @Override 74 | public PreparedStatement setArgument(@NotNull SQLConfig config, @NotNull PreparedStatement statement, int index, Object value) throws SQLException { 75 | if (config.isPostgreSQL() && JSON.isBoolOrNumOrStr(value) == false) { 76 | PGobject o = new PGobject(); 77 | o.setType("jsonb"); 78 | o.setValue(value == null ? null : value.toString()); 79 | statement.setObject(index + 1, o); //PostgreSQL 除了基本类型,其它的必须通过 PGobject 设置进去,否则 jsonb = varchar 等报错 80 | return statement; 81 | } 82 | 83 | return super.setArgument(config, statement, index, value); 84 | } 85 | 86 | 87 | @Override 88 | protected Object getValue( 89 | SQLConfig config, ResultSet rs, ResultSetMetaData rsmd, int row 90 | , M table, int columnIndex, String label, Map childMap, Map keyMap 91 | ) throws Exception { 92 | 93 | Object value = super.getValue(config, rs, rsmd, row, table, columnIndex, label, childMap, keyMap); 94 | 95 | return value instanceof PGobject ? JSON.parse(((PGobject) value).getValue()) : value; 96 | } 97 | 98 | // 支持 !key 反选字段 和 字段名映射,依赖插件 https://github.com/APIJSON/apijson-column 99 | @Override 100 | protected String getKey( 101 | SQLConfig config, ResultSet rs, ResultSetMetaData rsmd, int row 102 | , M table, int columnIndex, Map childMap, Map keyMap 103 | ) throws Exception { 104 | 105 | String key = super.getKey(config, rs, rsmd, row, table, columnIndex, childMap, keyMap); 106 | if (APIJSONSQLConfig.ENABLE_COLUMN_CONFIG) { 107 | return ColumnUtil.compatOutputKey(key, config.getTable(), config.getMethod()); 108 | } 109 | 110 | return key; 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/AssertUtil.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | 18 | /**简单断言工具类,不用额外引入 JUnit 等库 19 | * @author Lemon 20 | */ 21 | public class AssertUtil { 22 | 23 | public static void assertEqual(Object a, Object b) { 24 | assertEqual(a, b, null); 25 | } 26 | 27 | public static void assertEqual(Object a, Object b, String errorMessage) { 28 | if (a == b) { 29 | return; 30 | } 31 | 32 | if (a == null || !a.equals(b)) { 33 | throw new AssertionError(errorMessage == null ? "assert fail: a != b" : errorMessage); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/BaseModel.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.io.Serializable; 18 | import java.sql.Timestamp; 19 | import java.util.Arrays; 20 | import java.util.Collection; 21 | import java.util.Date; 22 | import java.util.Map; 23 | 24 | import apijson.JSON; 25 | import apijson.StringUtil; 26 | 27 | /**base model for reduce model codes 28 | * @author Lemon 29 | * @use extends BaseModel 30 | */ 31 | public abstract class BaseModel implements Serializable { 32 | private static final long serialVersionUID = 1L; 33 | 34 | private Long id; //主键,唯一标识 35 | private Long userId; //对应User表中的id,外键 36 | private String date; //创建时间,JSON没有Date,TimeStamp类型,都会被转成Long,不能用! 37 | 38 | public Long getId() { 39 | return id; 40 | } 41 | public BaseModel setId(Long id) { 42 | this.id = id; 43 | return this; 44 | } 45 | public Long getUserId() { 46 | return userId; 47 | } 48 | public BaseModel setUserId(Long userId) { 49 | this.userId = userId; 50 | return this; 51 | } 52 | public String getDate() { 53 | return date; 54 | } 55 | public BaseModel setDate(String date) { 56 | this.date = date; 57 | return this; 58 | } 59 | 60 | 61 | @Override 62 | public String toString() { 63 | return JSON.toJSONString(this); 64 | } 65 | 66 | 67 | /**获取当前时间戳 68 | * @return 69 | */ 70 | public static Timestamp currentTimeStamp() { 71 | return new Timestamp(new Date().getTime()); 72 | } 73 | /**获取时间戳 TODO 判空? 还是要报错? 74 | * @param time 75 | * @return 76 | */ 77 | public static Timestamp getTimeStamp(String time) { 78 | return Timestamp.valueOf(time); 79 | } 80 | /**获取时间毫秒值 TODO 判空? 还是要报错? 81 | * @param time 82 | * @return 83 | */ 84 | public static long getTimeMillis(String time) { 85 | return StringUtil.isEmpty(time, true) ? 0 : getTimeStamp(time).getTime(); 86 | } 87 | 88 | 89 | //判断是否为空 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 90 | /**判断array是否为空 91 | * @param array 92 | * @return 93 | */ 94 | public static boolean isEmpty(T[] array) { 95 | return array == null || array.length <= 0; 96 | } 97 | /**判断collection是否为空 98 | * @param collection 99 | * @return 100 | */ 101 | public static boolean isEmpty(Collection collection) { 102 | return collection == null || collection.isEmpty(); 103 | } 104 | /**判断map是否为空 105 | * @param map 106 | * @return 107 | */ 108 | public static boolean isEmpty(Map map) { 109 | return map == null || map.isEmpty(); 110 | } 111 | //判断是否为空 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 112 | 113 | //判断是否包含 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 114 | /**判断array是否包含a 115 | * @param array 116 | * @param a 117 | * @return 118 | */ 119 | public static boolean isContain(T[] array, T a) { 120 | return array == null ? false : Arrays.asList(array).contains(a); 121 | } 122 | /**判断collection是否包含object 123 | * @param collection 124 | * @param object 125 | * @return 126 | */ 127 | public static boolean isContain(Collection collection, T object) { 128 | return collection != null && collection.contains(object); 129 | } 130 | /**判断map是否包含key 131 | * @param 132 | * @param 133 | * @param map 134 | * @param key 135 | * @return 136 | */ 137 | public static boolean isContainKey(Map map, K key) { 138 | return map != null && map.containsKey(key); 139 | } 140 | /**判断map是否包含value 141 | * @param 142 | * @param 143 | * @param map 144 | * @param value 145 | * @return 146 | */ 147 | public static boolean isContainValue(Map map, V value) { 148 | return map != null && map.containsValue(value); 149 | } 150 | //判断是否为包含 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 151 | 152 | 153 | //获取集合长度 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 154 | /**获取数量 155 | * @param 156 | * @param array 157 | * @return 158 | */ 159 | public static int count(T[] array) { 160 | return array == null ? 0 : array.length; 161 | } 162 | /**获取数量 163 | * @param collection List, Vector, Set等都是Collection的子类 164 | * @return 165 | */ 166 | public static int count(Collection collection) { 167 | return collection == null ? 0 : collection.size(); 168 | } 169 | /**获取数量 170 | * @param map 171 | * @return 172 | */ 173 | public static int count(Map map) { 174 | return map == null ? 0 : map.size(); 175 | } 176 | //获取集合长度 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 177 | 178 | 179 | //获取集合长度 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 180 | /**获取 181 | * @param 182 | * @param array 183 | * @return 184 | */ 185 | public static T get(T[] array, int position) { 186 | return position < 0 || position >= count(array) ? null : array[position]; 187 | } 188 | /**获取 189 | * @param 190 | * @param collection List, Vector, Set等都是Collection的子类 191 | * @return 192 | */ 193 | @SuppressWarnings("unchecked") 194 | public static T get(Collection collection, int position) { 195 | return collection == null ? null : (T) get(collection.toArray(), position); 196 | } 197 | /**获取 198 | * @param 199 | * @param 200 | * @param map null ? null 201 | * @param key null ? null : map.get(key); 202 | * @return 203 | */ 204 | public static V get(Map map, K key) { 205 | return key == null || map == null ? null : map.get(key); 206 | } 207 | //获取集合长度 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 208 | 209 | 210 | 211 | //获取非基本类型对应基本类型的非空值 <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 212 | /**获取非空值 213 | * @param value 214 | * @return 215 | */ 216 | public static boolean value(Boolean value) { 217 | return value == null ? false : value; 218 | } 219 | /**获取非空值 220 | * @param value 221 | * @return 222 | */ 223 | public static int value(Integer value) { 224 | return value == null ? 0 : value; 225 | } 226 | /**获取非空值 227 | * @param value 228 | * @return 229 | */ 230 | public static long value(Long value) { 231 | return value == null ? 0 : value; 232 | } 233 | /**获取非空值 234 | * @param value 235 | * @return 236 | */ 237 | public static float value(Float value) { 238 | return value == null ? 0 : value; 239 | } 240 | /**获取非空值 241 | * @param value 242 | * @return 243 | */ 244 | public static double value(Double value) { 245 | return value == null ? 0 : value; 246 | } 247 | //获取非基本类型对应基本类型的非空值 >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 248 | 249 | /**index是否在arr长度范围内 250 | * @param index 251 | * @param array 252 | * @return 253 | */ 254 | public static boolean isIndexInRange(Integer index, Object[] array) { 255 | return index != null && index >= 0 && index < count(array); 256 | } 257 | 258 | /**获取在arr长度范围内的index 259 | * defaultIndex = 0 260 | * @param index 261 | * @param array 262 | * @return 263 | */ 264 | public static int getIndexInRange(Integer index, Object[] array) { 265 | return getIndexInRange(index, array, 0); 266 | } 267 | /**获取在arr长度范围内的index 268 | * @param index 269 | * @param array 270 | * @param defaultIndex 271 | * @return 272 | */ 273 | public static int getIndexInRange(Integer index, Object[] array, int defaultIndex) { 274 | return isIndexInRange(index, array) ? index : defaultIndex; 275 | } 276 | 277 | /**获取在arr长度范围内的index 278 | * defaultIndex = 0 279 | * @param 280 | * @param index 281 | * @param array 282 | * @return 283 | */ 284 | public static T getInRange(Integer index, T[] array) { 285 | return getInRange(index, array, 0); 286 | } 287 | /**获取在arr长度范围内的index 288 | * @param 289 | * @param index 290 | * @param array 291 | * @param defaultIndex 292 | * @return 293 | */ 294 | public static T getInRange(Integer index, T[] array, int defaultIndex) { 295 | return get(array, getIndexInRange(index, array, defaultIndex)); 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/ColumnUtil.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework; 16 | 17 | import java.util.*; 18 | import java.util.Map.Entry; 19 | 20 | import apijson.RequestMethod; 21 | import apijson.StringUtil; 22 | import apijson.orm.AbstractSQLConfig; 23 | import apijson.orm.AbstractSQLExecutor; 24 | 25 | 26 | /**表字段相关工具类 27 | * @author Lemon 28 | * @see 先提前配置 {@link #VERSIONED_TABLE_COLUMN_MAP}, {@link #VERSIONED_KEY_COLUMN_MAP} 等,然后调用相关方法。 29 | * 不支持直接关联 database, schema, datasource,可以把这些与 table 拼接为一个字符串传给参数 table,格式可以是 database-schema-datasource-table 30 | */ 31 | public class ColumnUtil { 32 | 33 | /**带版本的表和字段一对多对应关系,用来做 反选字段 34 | * Map> 35 | */ 36 | public static SortedMap>> VERSIONED_TABLE_COLUMN_MAP; 37 | 38 | /**带版本的 JSON key 和表字段一对一对应关系,用来做字段名映射 39 | * Map>> 40 | */ 41 | public static SortedMap>> VERSIONED_KEY_COLUMN_MAP; 42 | 43 | /**带版本的 JSON key 和表字段一对一对应关系,用来做字段名映射,与 VERSIONED_KEY_COLUMN_MAP 相反 44 | * Map>> 45 | */ 46 | private static SortedMap>> VERSIONED_COLUMN_KEY_MAP; 47 | 48 | public static final Comparator DESC_COMPARATOR = new Comparator() { 49 | @Override 50 | public int compare(Integer o1, Integer o2) { 51 | if (o2 == null) { 52 | return o1 == null ? 0 : -1; 53 | } 54 | return o2.compareTo(o1); 55 | } 56 | }; 57 | 58 | static { 59 | VERSIONED_TABLE_COLUMN_MAP = new TreeMap<>(DESC_COMPARATOR); 60 | VERSIONED_KEY_COLUMN_MAP = new TreeMap<>(DESC_COMPARATOR); 61 | VERSIONED_COLUMN_KEY_MAP = new TreeMap<>(DESC_COMPARATOR); 62 | } 63 | 64 | /**初始化 65 | */ 66 | public static void init() { 67 | VERSIONED_COLUMN_KEY_MAP.clear(); 68 | 69 | // 反过来补全 column -> key 的配置,以空间换时间 70 | Set>>> set = VERSIONED_KEY_COLUMN_MAP.entrySet(); 71 | if (set != null && set.isEmpty() == false) { 72 | 73 | SortedMap>> map = new TreeMap<>(DESC_COMPARATOR); 74 | 75 | for (Entry>> entry : set) { 76 | 77 | Map> tableKeyColumnMap = entry == null ? null : entry.getValue(); 78 | Set>> tableKeyColumnSet = tableKeyColumnMap == null ? null : tableKeyColumnMap.entrySet(); 79 | 80 | if (tableKeyColumnSet != null && tableKeyColumnSet.isEmpty() == false) { 81 | 82 | Map> tableColumnKeyMap = new HashMap<>(); 83 | 84 | for (Entry> tableKeyColumnEntry : tableKeyColumnSet) { 85 | 86 | Map keyColumnMap = tableKeyColumnEntry == null ? null : tableKeyColumnEntry.getValue(); 87 | Set> keyColumnSet = keyColumnMap == null ? null : keyColumnMap.entrySet(); 88 | 89 | if (keyColumnSet != null && keyColumnSet.isEmpty() == false) { 90 | Map columnKeyMap = new HashMap<>(); 91 | for (Entry keyColumnEntry : keyColumnSet) { 92 | if (keyColumnEntry == null) { 93 | continue; 94 | } 95 | 96 | columnKeyMap.put(keyColumnEntry.getValue(), keyColumnEntry.getKey()); 97 | } 98 | 99 | tableColumnKeyMap.put(tableKeyColumnEntry.getKey(), columnKeyMap); 100 | } 101 | } 102 | 103 | map.put(entry.getKey(), tableColumnKeyMap); 104 | } 105 | } 106 | 107 | VERSIONED_COLUMN_KEY_MAP = map; 108 | } 109 | 110 | 111 | // 补全剩下未定义别名的 key,以空间换时间 112 | Set>>> allSet = VERSIONED_TABLE_COLUMN_MAP.entrySet(); 113 | if (allSet != null && allSet.isEmpty() == false) { 114 | 115 | for (Entry>> entry : allSet) { 116 | Map> keyColumnMap = VERSIONED_KEY_COLUMN_MAP.get(entry.getKey()); 117 | // 没必要,没特殊配置的就原样返回,没有安全隐患,还能减少性能浪费 Map> columnKeyMap = VERSIONED_COLUMN_KEY_MAP.get(entry.getKey()); 118 | if (keyColumnMap == null) { 119 | keyColumnMap = new LinkedHashMap<>(); 120 | VERSIONED_KEY_COLUMN_MAP.put(entry.getKey(), keyColumnMap); 121 | } 122 | // if (columnKeyMap == null) { 123 | // columnKeyMap = new LinkedHashMap<>(); 124 | // VERSIONED_COLUMN_KEY_MAP.put(entry.getKey(), columnKeyMap); 125 | // } 126 | 127 | Map> tableKeyColumnMap = entry == null ? null : entry.getValue(); 128 | Set>> tableKeyColumnSet = tableKeyColumnMap == null ? null : tableKeyColumnMap.entrySet(); 129 | 130 | if (tableKeyColumnSet != null && tableKeyColumnSet.isEmpty() == false) { 131 | 132 | for (Entry> tableKeyColumnEntry : tableKeyColumnSet) { 133 | 134 | List list = tableKeyColumnEntry == null ? null : tableKeyColumnEntry.getValue(); 135 | 136 | if (list != null && list.isEmpty() == false) { 137 | 138 | Map kcm = keyColumnMap.get(tableKeyColumnEntry.getKey()); 139 | // Map ckm = columnKeyMap.get(tableKeyColumnEntry.getKey()); 140 | if (kcm == null) { 141 | kcm = new LinkedHashMap<>(); 142 | keyColumnMap.put(tableKeyColumnEntry.getKey(), kcm); 143 | } 144 | // if (ckm == null) { 145 | // ckm = new LinkedHashMap<>(); 146 | // columnKeyMap.put(tableKeyColumnEntry.getKey(), ckm); 147 | // } 148 | 149 | for (String column : list) { 150 | if (column == null) { 151 | continue; 152 | } 153 | 154 | // ckm.putIfAbsent(column, column); 155 | //FIXME 对 Comment.toId (多版本) 居然不起作用 156 | // if (kcm.containsValue(column) == false) { 157 | kcm.putIfAbsent(column, column); 158 | // } 159 | } 160 | 161 | // for (String column : list) { 162 | // if (column == null || ckm.get(column) != null) { 163 | // continue; 164 | // } 165 | // 166 | // kcm.putIfAbsent(column, column); 167 | // } 168 | 169 | } 170 | } 171 | 172 | } 173 | } 174 | 175 | } 176 | 177 | } 178 | 179 | /**适配请求参数 JSON 中 @column:value 的 value 中的 key。支持 !key 反选字段 和 字段名映射 180 | * @param columns 181 | * @param table 182 | * @param method 183 | * @return 184 | */ 185 | public static List compatInputColumn(List columns, String table, RequestMethod method) { 186 | return compatInputColumn(columns, table, method, null, false); 187 | } 188 | 189 | /**适配请求参数 JSON 中 @column:value 的 value 中的 key。支持 !key 反选字段 和 字段名映射 190 | * @param columns 191 | * @param table 192 | * @param method 193 | * @param version 194 | * @return 195 | * @see 先提前配置 {@link #VERSIONED_TABLE_COLUMN_MAP},然后在 {@link AbstractSQLConfig} 的子类重写 {@link AbstractSQLConfig#setColumn } 并调用这个方法,例如 196 | *
197 | 	public AbstractSQLConfig setColumn(List column) { 
198 | return super.setColumn(ColumnUtil.compatInputColumn(column, getTable(), version));
199 | } 200 | *
201 | */ 202 | public static List compatInputColumn(List columns, String table, RequestMethod method, Integer version, boolean throwWhenNoKey) { 203 | String[] keys = columns == null ? null : columns.toArray(new String[]{}); // StringUtil.split(c, ";"); 204 | if (keys == null || keys.length <= 0) { // JOIN 副表可以设置 @column:"" 来指定不返回字段 205 | return columns != null ? columns : getClosestValue(VERSIONED_TABLE_COLUMN_MAP, version, table); 206 | } 207 | 208 | // boolean isQueryMethod = RequestMethod.isQueryMethod(method); 209 | 210 | List exceptColumns = new ArrayList<>(); // Map exceptColumnMap = new HashMap<>(); 211 | List newColumns = new ArrayList<>(); 212 | 213 | Map keyColumnMap = getClosestValue(VERSIONED_KEY_COLUMN_MAP, version, table); 214 | boolean isEmpty = keyColumnMap == null || keyColumnMap.isEmpty(); 215 | 216 | String q = "`"; 217 | 218 | String expression; 219 | //...;fun0(arg0,arg1,...):fun0;fun1(arg0,arg1,...):fun1;... 220 | for (int i = 0; i < keys.length; i++) { 221 | 222 | //!column,column2,!column3,column4:alias4;fun(arg0,arg1,...) 223 | expression = keys[i]; 224 | int start = expression.indexOf("("); 225 | int end = expression.lastIndexOf(")"); 226 | if (start >= 0 && start < end) { 227 | String[] ks = StringUtil.split(expression.substring(start + 1, end)); 228 | 229 | String expr = expression.substring(0, start + 1); 230 | for (int j = 0; j < ks.length; j++) { 231 | String ck = ks[j]; 232 | boolean hasQuote = false; 233 | if (ck.endsWith("`")) { 234 | String nck = ck.substring(0, ck.length() - 1); 235 | if (nck.lastIndexOf("`") == 0) { 236 | ck = nck.substring(1); 237 | hasQuote = true; 238 | } 239 | } 240 | 241 | String rc = null; 242 | if (hasQuote || StringUtil.isName(ck)) { 243 | rc = isEmpty ? null : keyColumnMap.get(ck); 244 | if (rc == null && isEmpty == false && throwWhenNoKey) { 245 | throw new NullPointerException(table + ":{ @column: value } 的 value 中 " + ck + " 不合法!不允许传后端未授权访问的字段名!"); 246 | } 247 | } 248 | 249 | expr += (j <= 0 ? "" : ",") + (hasQuote ? q : "") + (rc == null ? ck : rc) + (hasQuote ? q : ""); 250 | } 251 | 252 | newColumns.add(expr + expression.substring(end)); 253 | 254 | // newColumns.add(expression); 255 | continue; 256 | } 257 | 258 | String[] ckeys = StringUtil.split(expression); 259 | if (ckeys != null && ckeys.length > 0) { 260 | for (int j = 0; j < ckeys.length; j++) { 261 | String ck = ckeys[j]; 262 | 263 | if (ck.startsWith("!")) { 264 | if (ck.length() <= 1) { 265 | throw new IllegalArgumentException("@column:value 的 value 中 " + ck 266 | + " 不合法! !column 不允许 column 为空字符串!column,!column2,!column3,column4:alias4 中所有 column 必须符合变量名格式!"); 267 | } 268 | String c = ck.substring(1); 269 | if (StringUtil.isName(c) == false) { 270 | throw new IllegalArgumentException("@column:value 的 value 中 " + c 271 | + " 不合法! column,!column2,!column3,column4:alias4 中所有 column 必须符合变量名格式!"); 272 | } 273 | 274 | String rc = isEmpty ? null : keyColumnMap.get(c); 275 | exceptColumns.add(rc == null ? c : rc); // 不使用数据库别名,以免 JOIN 等复杂查询情况下报错字段不存在 exceptColumnMap.put(nc == null ? c : nc, c); // column:alias 276 | } else { 277 | boolean hasQuote = false; 278 | if (ck.endsWith("`")) { 279 | String nck = ck.substring(0, ck.length() - 1); 280 | if (nck.lastIndexOf("`") == 0) { 281 | ck = nck.substring(1); 282 | hasQuote = true; 283 | } 284 | } 285 | 286 | String rc = null; 287 | if (hasQuote || StringUtil.isName(ck)) { 288 | rc = isEmpty ? null : keyColumnMap.get(ck); 289 | if (rc == null && isEmpty == false && throwWhenNoKey) { 290 | throw new NullPointerException(table + ":{ @column: value } 的 value 中 " + ck + " 不合法!不允许传后端未授权访问的字段名!"); 291 | } 292 | } 293 | 294 | newColumns.add(rc == null ? ck : rc); // 不使用数据库别名,以免 JOIN 等复杂查询情况下报错字段不存在 newColumns.add(rc == null ? ck : (isQueryMethod ? (rc + ":" + ck) : rc)); 295 | } 296 | } 297 | } 298 | } 299 | 300 | List allColumns = exceptColumns == null || exceptColumns.isEmpty() ? null : getClosestValue(VERSIONED_TABLE_COLUMN_MAP, version, table); 301 | 302 | if (allColumns != null && allColumns.isEmpty() == false) { 303 | 304 | // 不使用数据库别名,以免 JOIN 等复杂查询情况下报错字段不存在 305 | // Map> tableColumnKeyMap = VERSIONED_COLUMN_KEY_MAP == null || VERSIONED_COLUMN_KEY_MAP.isEmpty() ? null : VERSIONED_COLUMN_KEY_MAP.get(version); 306 | // Map columnKeyMap = tableColumnKeyMap == null || tableColumnKeyMap.isEmpty() ? null : tableColumnKeyMap.get(table); 307 | 308 | for (String c : allColumns) { 309 | if (c != null && exceptColumns.contains(c) == false) { // column:alias 310 | // 不使用数据库别名,以免 JOIN 等复杂查询情况下报错字段不存在 String alias = isQueryMethod == false || columnKeyMap == null || columnKeyMap.isEmpty() ? null : columnKeyMap.get(c); 311 | newColumns.add(c); // newColumns.add(alias == null ? c : (c + ":" + alias)); 312 | } 313 | } 314 | } 315 | 316 | return newColumns; 317 | } 318 | 319 | 320 | /**适配请求参数 JSON 中 条件/赋值 键值对的 key 321 | * @param key 322 | * @param table 323 | * @param method 324 | * @return 325 | */ 326 | public static String compatInputKey(String key, String table, RequestMethod method) { 327 | return compatInputKey(key, table, method, null, false); 328 | } 329 | 330 | /**适配请求参数 JSON 中 条件/赋值 键值对的 key 331 | * @param key 332 | * @param table 333 | * @param method 334 | * @param version 335 | * @return 336 | * @see 先提前配置 {@link #VERSIONED_KEY_COLUMN_MAP},然后在 {@link AbstractSQLConfig} 的子类重写 {@link AbstractSQLConfig#getKey } 并调用这个方法,例如 337 | *
338 | 	public String getKey(String key) { 
339 | return super.getKey(ColumnUtil.compatInputKey(key, getTable(), version));
340 | } 341 | *
342 | */ 343 | public static String compatInputKey(String key, String table, RequestMethod method, Integer version, boolean throwWhenNoKey) { 344 | Map keyColumnMap = getClosestValue(VERSIONED_KEY_COLUMN_MAP, version, table); 345 | boolean isEmpty = keyColumnMap == null || keyColumnMap.isEmpty(); 346 | String alias = isEmpty ? null : keyColumnMap.get(key); 347 | if (alias == null) { 348 | if (isEmpty == false && throwWhenNoKey) { 349 | throw new NullPointerException(table + ":{} 中不允许传 " + key + " !"); 350 | } 351 | return key; 352 | } 353 | 354 | return alias; 355 | } 356 | 357 | /**适配返回结果 JSON 中键值对的 key。可能通过不传 @column 等方式来返回原始字段名,这样就达不到隐藏真实字段名的需求了,所以只有最终这个兜底方式靠谱。 358 | * @param key 359 | * @param table 360 | * @param method 361 | * @return 362 | */ 363 | public static String compatOutputKey(String key, String table, RequestMethod method) { 364 | return compatOutputKey(key, table, method, null); 365 | } 366 | 367 | /**适配返回结果 JSON 中键值对的 key。可能通过不传 @column 等方式来返回原始字段名,这样就达不到隐藏真实字段名的需求了,所以只有最终这个兜底方式靠谱。 368 | * @param key 369 | * @param table 370 | * @param method 371 | * @param version 372 | * @return 373 | * @see 先提前配置 {@link #VERSIONED_COLUMN_KEY_MAP},然后在 {@link AbstractSQLExecutor} 的子类重写 {@link AbstractSQLExecutor#getKey } 并调用这个方法,例如 374 | *
375 | 	protected String getKey(SQLConfig config, ResultSet rs, ResultSetMetaData rsmd, int tablePosition, JSONMap table,
376 | 	int columnIndex, Map childMap) throws Exception { 
377 | return ColumnUtil.compatOutputKey(super.getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap), config.getTable(), config.getMethod(), version);
378 | } 379 | *
380 | */ 381 | public static String compatOutputKey(String key, String table, RequestMethod method, Integer version) { 382 | Map columnKeyMap = getClosestValue(VERSIONED_COLUMN_KEY_MAP, version, table); 383 | String alias = columnKeyMap == null || columnKeyMap.isEmpty() ? null : columnKeyMap.get(key); 384 | return alias == null ? key : alias; 385 | } 386 | 387 | public static T getClosestValue(SortedMap> versionedMap, Integer version, String table) { 388 | boolean isEmpty = versionedMap == null || versionedMap.isEmpty(); 389 | 390 | Map map = isEmpty || version == null ? null : versionedMap.get(version); 391 | T m = map == null ? null : map.get(table); 392 | if (isEmpty == false && m == null) { 393 | Set>> set = versionedMap.entrySet(); 394 | 395 | T lm = null; 396 | for (Entry> entry : set) { 397 | Map val = entry.getValue(); 398 | m = val == null ? null : val.get(table); 399 | if (m == null) { 400 | continue; 401 | } 402 | 403 | if (version == null || version == 0) { 404 | // versionedMap.put(null, val); 405 | return m; 406 | } 407 | 408 | Integer key = entry.getKey(); 409 | if (key == null) { 410 | lm = m; 411 | map = val; 412 | continue; 413 | } 414 | 415 | if (version >= key) { 416 | versionedMap.put(version, val); 417 | return m; 418 | } 419 | 420 | break; 421 | } 422 | 423 | if (lm != null) { 424 | m = lm; 425 | } 426 | 427 | if (map != null) { 428 | versionedMap.put(version, map); 429 | } 430 | } 431 | 432 | return m; 433 | } 434 | 435 | 436 | /**把多个表名相关属性拼接成一个表名 437 | * @param database 438 | * @param schema 439 | * @param datasource 440 | * @param table 441 | * @return 442 | */ 443 | public static String concat(String database, String schema, String datasource, String table) { 444 | return database + "-" + schema + "-" + datasource + "-" + table; 445 | } 446 | 447 | 448 | } 449 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONApplication.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.Log; 18 | import apijson.NotNull; 19 | import apijson.orm.AbstractFunctionParser; 20 | import apijson.orm.script.ScriptExecutor; 21 | 22 | import java.rmi.ServerException; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | 27 | /**启动入口 Application 28 | * 右键这个类 > Run As > Java Application 29 | * @author Lemon 30 | */ 31 | public class APIJSONApplication { 32 | public static final String TAG = "APIJSONApplication"; 33 | 34 | @NotNull 35 | public static APIJSONCreator, ? extends List> DEFAULT_APIJSON_CREATOR; 36 | static { 37 | DEFAULT_APIJSON_CREATOR = new APIJSONCreator<>(); 38 | } 39 | 40 | @SuppressWarnings("unchecked") 41 | public static , L extends List> APIJSONParser createParser() { 42 | return (APIJSONParser) DEFAULT_APIJSON_CREATOR.createParser(); 43 | } 44 | @SuppressWarnings("unchecked") 45 | public static , L extends List> APIJSONFunctionParser createFunctionParser() { 46 | return (APIJSONFunctionParser) DEFAULT_APIJSON_CREATOR.createFunctionParser(); 47 | } 48 | 49 | @SuppressWarnings("unchecked") 50 | public static , L extends List> APIJSONVerifier createVerifier() { 51 | return (APIJSONVerifier) DEFAULT_APIJSON_CREATOR.createVerifier(); 52 | } 53 | 54 | @SuppressWarnings("unchecked") 55 | public static , L extends List> APIJSONSQLConfig createSQLConfig() { 56 | return (APIJSONSQLConfig) DEFAULT_APIJSON_CREATOR.createSQLConfig(); 57 | } 58 | 59 | @SuppressWarnings("unchecked") 60 | public static , L extends List> APIJSONSQLExecutor createSQLExecutor() { 61 | return (APIJSONSQLExecutor) DEFAULT_APIJSON_CREATOR.createSQLExecutor(); 62 | } 63 | 64 | 65 | /**初始化,加载所有配置并校验 66 | * @return 67 | * @throws Exception 68 | */ 69 | public static void init() throws Exception { 70 | init(true, DEFAULT_APIJSON_CREATOR); 71 | } 72 | /**初始化,加载所有配置并校验 73 | * @param shutdownWhenServerError 74 | * @return 75 | * @throws Exception 76 | */ 77 | public static void init(boolean shutdownWhenServerError) throws Exception { 78 | init(shutdownWhenServerError, DEFAULT_APIJSON_CREATOR); 79 | } 80 | /**初始化,加载所有配置并校验 81 | * @param creator 82 | * @return 83 | * @throws Exception 84 | */ 85 | public static , L extends List> void init( 86 | @NotNull APIJSONCreator creator) throws Exception { 87 | init(true, creator); 88 | } 89 | /**初始化,加载所有配置并校验 90 | * @param shutdownWhenServerError 91 | * @param creator 92 | * @return 93 | * @throws Exception 94 | */ 95 | public static , L extends List> void init( 96 | boolean shutdownWhenServerError, @NotNull APIJSONCreator creator) throws Exception { 97 | System.out.println("\n\n\n\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON 开始启动 >>>>>>>>>>>>>>>>>>>>>>>>\n"); 98 | DEFAULT_APIJSON_CREATOR = creator; 99 | 100 | if (APIJSONVerifier.ENABLE_VERIFY_ROLE) { 101 | System.out.println("\n\n\n开始初始化: Access 权限校验配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 102 | try { 103 | APIJSONVerifier.initAccess(shutdownWhenServerError, creator); 104 | } catch (Throwable e) { 105 | e.printStackTrace(); 106 | if (shutdownWhenServerError) { 107 | onServerError("Access 权限校验配置 初始化失败!", shutdownWhenServerError); 108 | } 109 | } 110 | System.out.println("\n完成初始化: Access 权限校验配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 111 | } 112 | 113 | 114 | if (APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION) { 115 | System.out.println("\n\n\n开始初始化: Function 远程函数配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 116 | try { 117 | APIJSONFunctionParser.init(shutdownWhenServerError, creator); 118 | } catch (Throwable e) { 119 | e.printStackTrace(); 120 | if (shutdownWhenServerError) { 121 | onServerError("Function 远程函数配置 初始化失败!", shutdownWhenServerError); 122 | } 123 | } 124 | System.out.println("\n完成初始化: Function 远程函数配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 125 | 126 | System.out.println("开始测试: Function 远程函数 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 127 | try { 128 | APIJSONFunctionParser.test(); 129 | } catch (Throwable e) { 130 | e.printStackTrace(); 131 | if (shutdownWhenServerError) { 132 | onServerError("Function 远程函数配置 测试失败!", shutdownWhenServerError); 133 | } 134 | } 135 | System.out.println("\n完成测试: Function 远程函数 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 136 | } 137 | 138 | 139 | if (APIJSONVerifier.ENABLE_VERIFY_CONTENT) { 140 | System.out.println("\n\n\n开始初始化: Request 请求参数校验配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 141 | try { 142 | APIJSONVerifier.initRequest(shutdownWhenServerError, creator); 143 | } catch (Throwable e) { 144 | e.printStackTrace(); 145 | if (shutdownWhenServerError) { 146 | onServerError("Request 请求参数校验配置 初始化失败!", shutdownWhenServerError); 147 | } 148 | } 149 | System.out.println("\n完成初始化: Request 请求参数校验校验配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 150 | 151 | System.out.println("\n\n\n开始测试: Request 请求参数校验 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 152 | try { 153 | APIJSONVerifier.testStructure(); 154 | } catch (Throwable e) { 155 | e.printStackTrace(); 156 | if (shutdownWhenServerError) { 157 | onServerError("Request 请求参数校验 测试失败!", shutdownWhenServerError); 158 | } 159 | } 160 | System.out.println("\n完成测试: Request 请求参数校验 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 161 | } 162 | 163 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER) { 164 | System.out.println("\n\n\n开始初始化: Document 请求映射配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); 165 | try { 166 | APIJSONVerifier.initDocument(shutdownWhenServerError, creator); 167 | } catch (Throwable e) { 168 | e.printStackTrace(); 169 | if (shutdownWhenServerError) { 170 | onServerError("Document 请求映射配置 初始化失败!", shutdownWhenServerError); 171 | } 172 | } 173 | System.out.println("\n完成初始化: Document 请求映射配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); 174 | } 175 | 176 | 177 | System.out.println("官方网站: http://apijson.cn"); 178 | System.out.println("设计规范: https://github.com/Tencent/APIJSON/blob/master/Document.md#3"); 179 | System.out.println("测试链接: http://apijson.cn/api?type=JSON&url=http://localhost:8080/get"); 180 | System.out.println("\n\n<<<<<<<<<<<<<<<<<<<<<<<<< APIJSON 启动完成,试试调用零代码万能通用 API 吧 ^_^ >>>>>>>>>>>>>>>>>>>>>>>>\n"); 181 | } 182 | 183 | protected static void onServerError(String msg, boolean shutdown) throws ServerException { 184 | Log.e(TAG, "\n启动时自检测试未通过!原因:\n" + msg); 185 | 186 | if (shutdown) { 187 | System.exit(1); 188 | } else { 189 | throw new ServerException(msg); 190 | } 191 | } 192 | 193 | public static void addScriptExecutor(String language, ScriptExecutor scriptExecutor) { 194 | scriptExecutor.init(); 195 | AbstractFunctionParser.SCRIPT_EXECUTOR_MAP.put(language, scriptExecutor); 196 | } 197 | 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONConstant.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | /**APIJSON 常量类 18 | * @author Lemon 19 | */ 20 | public class APIJSONConstant extends apijson.framework.APIJSONConstant {} 21 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONController.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.*; 18 | import apijson.JSONRequest; 19 | import apijson.orm.*; 20 | 21 | import javax.servlet.http.HttpSession; 22 | 23 | import java.rmi.ServerException; 24 | import java.util.*; 25 | 26 | import static apijson.JSON.*; 27 | import static apijson.RequestMethod.*; 28 | import static apijson.framework.javax.APIJSONConstant.*; 29 | 30 | 31 | /**APIJSON base controller,建议在子项目被 @RestController 注解的类继承它或通过它的实例调用相关方法 32 | *
全通过 HTTP POST 来请求: 33 | *
1.减少代码 - 客户端无需写 HTTP GET, HTTP PUT 等各种方式的请求代码 34 | *
2.提高性能 - 无需 URL encode 和 decode 35 | *
3.调试方便 - 建议使用 APIAuto-机器学习自动化接口管理工具(https://github.com/TommyLemon/APIAuto) 36 | * @author Lemon 37 | */ 38 | public class APIJSONController, L extends List> { 39 | public static final String TAG = "APIJSONController"; 40 | 41 | public String getRequestURL() { 42 | return null; 43 | } 44 | 45 | public APIJSONParser newParser(HttpSession session, RequestMethod method) { 46 | APIJSONParser parser = APIJSONApplication.createParser(); 47 | parser.setMethod(method); 48 | parser.setSession(session); 49 | parser.setRequestURL(getRequestURL()); 50 | return parser; 51 | } 52 | 53 | public static APIJSONParser, ? extends List> COMMON_PARSER = APIJSONApplication.createParser(); 54 | 55 | /**新建带状态内容的JSONObject 56 | * @param code 57 | * @param msg 58 | * @return 59 | */ 60 | public static > M newResult(int code, String msg) { 61 | return newResult(code, msg, null); 62 | } 63 | 64 | /** 65 | * 添加JSONObject的状态内容,一般用于错误提示结果 66 | * 67 | * @param code 68 | * @param msg 69 | * @param warn 70 | * @return 71 | */ 72 | public static > M newResult(int code, String msg, String warn) { 73 | return newResult(code, msg, warn, false); 74 | } 75 | 76 | /** 77 | * 新建带状态内容的JSONObject 78 | * 79 | * @param code 80 | * @param msg 81 | * @param warn 82 | * @param isRoot 83 | * @return 84 | */ 85 | public static > M newResult(int code, String msg, String warn, boolean isRoot) { 86 | return extendResult(null, code, msg, warn, isRoot); 87 | } 88 | 89 | /** 90 | * 添加JSONObject的状态内容,一般用于错误提示结果 91 | * 92 | * @param object 93 | * @param code 94 | * @param msg 95 | * @return 96 | */ 97 | public static > M extendResult(M object, int code, String msg, String warn, boolean isRoot) { 98 | return (M) COMMON_PARSER.extendResult(JSON.createJSONObject(object), code, msg, warn, isRoot); 99 | } 100 | 101 | 102 | /** 103 | * 添加请求成功的状态内容 104 | * 105 | * @param object 106 | * @return 107 | */ 108 | public M extendSuccessResult(M object) { 109 | return extendSuccessResult(object, false); 110 | } 111 | 112 | public M extendSuccessResult(M object, boolean isRoot) { 113 | return extendSuccessResult(object, null, isRoot); 114 | } 115 | 116 | /**添加请求成功的状态内容 117 | * @param object 118 | * @param isRoot 119 | * @return 120 | */ 121 | public static > M extendSuccessResult(M object, String warn, boolean isRoot) { 122 | return extendResult(object, JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); 123 | } 124 | 125 | /**获取请求成功的状态内容 126 | * @return 127 | */ 128 | public static > M newSuccessResult() { 129 | return newSuccessResult(null); 130 | } 131 | 132 | /**获取请求成功的状态内容 133 | * @param warn 134 | * @return 135 | */ 136 | public static > M newSuccessResult(String warn) { 137 | return newSuccessResult(warn, false); 138 | } 139 | 140 | /**获取请求成功的状态内容 141 | * @param warn 142 | * @param isRoot 143 | * @return 144 | */ 145 | public static > M newSuccessResult(String warn, boolean isRoot) { 146 | return newResult(JSONResponse.CODE_SUCCESS, JSONResponse.MSG_SUCCEED, warn, isRoot); 147 | } 148 | 149 | /**添加请求成功的状态内容 150 | * @param object 151 | * @param e 152 | * @return 153 | */ 154 | public static > M extendErrorResult(M object, Throwable e) { 155 | return extendErrorResult(object, e, false); 156 | } 157 | /**添加请求成功的状态内容 158 | * @param object 159 | * @param e 160 | * @param isRoot 161 | * @return 162 | */ 163 | public static > M extendErrorResult(M object, Throwable e, boolean isRoot) { 164 | return extendErrorResult(object, e, null, null, isRoot); 165 | } 166 | /**添加请求成功的状态内容 167 | * @param object 168 | * @return 169 | */ 170 | public static > M extendErrorResult(M object, Throwable e, RequestMethod requestMethod, String url, boolean isRoot) { 171 | return (M) COMMON_PARSER.extendErrorResult(JSON.createJSONObject(object), e, requestMethod, url, isRoot); 172 | } 173 | 174 | public static > M newErrorResult(Exception e) { 175 | return newErrorResult(e, false); 176 | } 177 | public static > M newErrorResult(Exception e, boolean isRoot) { 178 | return (M) COMMON_PARSER.newErrorResult(e, isRoot); 179 | } 180 | 181 | 182 | public String parse(RequestMethod method, String request, HttpSession session) { 183 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER && ! Log.DEBUG) { 184 | return JSON.toJSONString( 185 | newErrorResult( 186 | new IllegalArgumentException("APIJSONVerifier.ENABLE_APIJSON_ROUTER = true 已启用 router," + 187 | "Log.DEBUG = false 时不允许调用 /router/{method}/{tag} 外的万能通用接口!" 188 | ) 189 | ) 190 | ); 191 | } 192 | 193 | return newParser(session, method).parse(request); 194 | } 195 | 196 | public String parseByTag(RequestMethod method, String tag, Map params, String request, HttpSession session) { 197 | if (APIJSONVerifier.ENABLE_APIJSON_ROUTER && ! Log.DEBUG) { 198 | return JSON.toJSONString( 199 | newErrorResult( 200 | new IllegalArgumentException("APIJSONVerifier.ENABLE_APIJSON_ROUTER = true 已启用 router," + 201 | "Log.DEBUG = false 时不允许调用 /router/{method}/{tag} 外的万能通用接口!" 202 | ) 203 | ) 204 | ); 205 | } 206 | 207 | APIJSONParser parser = newParser(session, method); 208 | M req = parser.wrapRequest(method, tag, JSON.parseObject(request), false); 209 | if (req == null) { 210 | req = JSON.createJSONObject(); 211 | } 212 | if (params != null && params.isEmpty() == false) { 213 | req.putAll(params); 214 | } 215 | 216 | return parser.parse(req); 217 | } 218 | 219 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 220 | 221 | /**全能增删改查统一入口,这个一个方法可替代以下所有万能通用方法,一个接口通用增删改查 222 | * @param request 223 | * @param session 224 | * @return 225 | */ 226 | public String crudAll(String request, HttpSession session) { 227 | return parse(CRUD, request, session); 228 | } 229 | 230 | /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一点路由解析性能来提升一些开发效率 231 | * @param method 232 | * @param request 233 | * @param session 234 | * @return 235 | */ 236 | public String crud(String method, String request, HttpSession session) { 237 | if (METHODS.contains(method)) { 238 | return parse(RequestMethod.valueOf(method.toUpperCase()), request, session); 239 | } 240 | 241 | return toJSONString(newErrorResult( 242 | new IllegalArgumentException("URL 路径 /{method} 中 method 值 " 243 | + method + " 错误!只允许 " + METHODS + " 中的一个!") 244 | )); 245 | } 246 | 247 | /**获取 248 | * @param request 只用String,避免encode后未decode 249 | * @param session 250 | * @return 251 | * @see {@link RequestMethod#GET} 252 | */ 253 | public String get(String request, HttpSession session) { 254 | return parse(GET, request, session); 255 | } 256 | 257 | /**计数 258 | * @param request 只用String,避免encode后未decode 259 | * @param session 260 | * @return 261 | * @see {@link RequestMethod#HEAD} 262 | */ 263 | public String head(String request, HttpSession session) { 264 | return parse(HEAD, request, session); 265 | } 266 | 267 | /**限制性GET,request和response都非明文,浏览器看不到,用于对安全性要求高的GET请求 268 | * @param request 只用String,避免encode后未decode 269 | * @param session 270 | * @return 271 | * @see {@link RequestMethod#GETS} 272 | */ 273 | public String gets(String request, HttpSession session) { 274 | return parse(GETS, request, session); 275 | } 276 | 277 | /**限制性HEAD,request和response都非明文,浏览器看不到,用于对安全性要求高的HEAD请求 278 | * @param request 只用String,避免encode后未decode 279 | * @param session 280 | * @return 281 | * @see {@link RequestMethod#HEADS} 282 | */ 283 | public String heads(String request, HttpSession session) { 284 | return parse(HEADS, request, session); 285 | } 286 | 287 | /**新增 288 | * @param request 只用String,避免encode后未decode 289 | * @param session 290 | * @return 291 | * @see {@link RequestMethod#POST} 292 | */ 293 | public String post(String request, HttpSession session) { 294 | return parse(POST, request, session); 295 | } 296 | 297 | /**修改 298 | * @param request 只用String,避免encode后未decode 299 | * @param session 300 | * @return 301 | * @see {@link RequestMethod#PUT} 302 | */ 303 | public String put(String request, HttpSession session) { 304 | return parse(PUT, request, session); 305 | } 306 | 307 | /**删除 308 | * @param request 只用String,避免encode后未decode 309 | * @param session 310 | * @return 311 | * @see {@link RequestMethod#DELETE} 312 | */ 313 | public String delete(String request, HttpSession session) { 314 | return parse(DELETE, request, session); 315 | } 316 | 317 | /**支持全局事物、批量执行多条语句 318 | * @param request 只用String,避免encode后未decode 319 | * @param session 320 | * @return 321 | * @see {@link RequestMethod#GET} 322 | */ 323 | public String crud(String request, HttpSession session) { 324 | return parse(CRUD, request, session); 325 | } 326 | 327 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 328 | 329 | 330 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 331 | 332 | 333 | /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一些路由解析性能来提升一点开发效率 334 | * @param method 335 | * @param tag 336 | * @param params 337 | * @param request 338 | * @param session 339 | * @return 340 | */ 341 | public String crudByTag(String method, String tag, Map params, String request, HttpSession session) { 342 | if (METHODS.contains(method)) { 343 | return parseByTag(RequestMethod.valueOf(method.toUpperCase()), tag, params, request, session); 344 | } 345 | 346 | return toJSONString(newErrorResult( 347 | new IllegalArgumentException("URL 路径 /{method}/{tag} 中 method 值 " 348 | + method + " 错误!只允许 " + METHODS + " 中的一个!") 349 | )); 350 | } 351 | 352 | 353 | // /**获取列表 354 | // * @param request 只用String,避免encode后未decode 355 | // * @param session 356 | // * @return 357 | // * @see {@link RequestMethod#GET} 358 | // */ 359 | // public String listByTag(String tag, String request, HttpSession session) { 360 | // return parseByTag(GET, tag + apijson.JSONMap.KEY_ARRAY, request, session); 361 | // } 362 | 363 | /**获取 364 | * @param request 只用String,避免encode后未decode 365 | * @param session 366 | * @return 367 | * @see {@link RequestMethod#GET} 368 | */ 369 | public String getByTag(String tag, Map params, String request, HttpSession session) { 370 | return parseByTag(GET, tag, params, request, session); 371 | } 372 | 373 | 374 | /**计数 375 | * @param request 只用String,避免encode后未decode 376 | * @param session 377 | * @return 378 | * @see {@link RequestMethod#HEAD} 379 | */ 380 | public String headByTag(String tag, Map params, String request, HttpSession session) { 381 | return parseByTag(HEAD, tag, params, request, session); 382 | } 383 | 384 | /**限制性GET,request和response都非明文,浏览器看不到,用于对安全性要求高的GET请求 385 | * @param request 只用String,避免encode后未decode 386 | * @param session 387 | * @return 388 | * @see {@link RequestMethod#GETS} 389 | */ 390 | public String getsByTag(String tag, Map params, String request, HttpSession session) { 391 | return parseByTag(GETS, tag, params, request, session); 392 | } 393 | 394 | /**限制性HEAD,request和response都非明文,浏览器看不到,用于对安全性要求高的HEAD请求 395 | * @param request 只用String,避免encode后未decode 396 | * @param session 397 | * @return 398 | * @see {@link RequestMethod#HEADS} 399 | */ 400 | public String headsByTag(String tag, Map params, String request, HttpSession session) { 401 | return parseByTag(HEADS, tag, params, request, session); 402 | } 403 | 404 | /**新增 405 | * @param request 只用String,避免encode后未decode 406 | * @param session 407 | * @return 408 | * @see {@link RequestMethod#POST} 409 | */ 410 | public String postByTag(String tag, Map params, String request, HttpSession session) { 411 | return parseByTag(POST, tag, params, request, session); 412 | } 413 | 414 | /**修改 415 | * @param request 只用String,避免encode后未decode 416 | * @param session 417 | * @return 418 | * @see {@link RequestMethod#PUT} 419 | */ 420 | public String putByTag(String tag, Map params, String request, HttpSession session) { 421 | return parseByTag(PUT, tag, params, request, session); 422 | } 423 | 424 | /**删除 425 | * @param request 只用String,避免encode后未decode 426 | * @param session 427 | * @return 428 | * @see {@link RequestMethod#DELETE} 429 | */ 430 | public String deleteByTag(String tag, Map params, String request, HttpSession session) { 431 | return parseByTag(DELETE, tag, params, request, session); 432 | } 433 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 434 | 435 | /**增删改查统一的类 RESTful API 入口,牺牲一些路由解析性能来提升一点开发效率 436 | * compatCommonAPI = Log.DEBUG 437 | * @param method 438 | * @param tag 439 | * @param params 440 | * @param request 441 | * @param session 442 | * @return 443 | */ 444 | public String router(String method, String tag, Map params, String request, HttpSession session) { 445 | return router(method, tag, params, request, session, Log.DEBUG); 446 | } 447 | /**增删改查统一的类 RESTful API 入口,牺牲一些路由解析性能来提升一点开发效率 448 | * @param method 449 | * @param tag 450 | * @param params 451 | * @param request 452 | * @param session 453 | * @param compatCommonAPI 兼容万能通用 API,当没有映射 APIJSON 格式请求时,自动转到万能通用 API 454 | * @return 455 | */ 456 | public String router(String method, String tag, Map params, String request, HttpSession session, boolean compatCommonAPI) { 457 | if (! APIJSONVerifier.ENABLE_APIJSON_ROUTER) { 458 | return JSON.toJSONString( 459 | newErrorResult( 460 | new IllegalArgumentException("未启用 router!请配置 APIJSONVerifier.ENABLE_APIJSON_ROUTER = true !" 461 | ) 462 | ) 463 | ); 464 | } 465 | 466 | RequestMethod requestMethod = null; 467 | try { 468 | requestMethod = RequestMethod.valueOf(method.toUpperCase()); 469 | } catch (Throwable e) { 470 | // 下方 METHODS.contains(method) 会抛异常 471 | } 472 | Parser parser = newParser(session, requestMethod); 473 | 474 | if (METHODS.contains(method) == false) { 475 | return JSON.toJSONString( 476 | newErrorResult( 477 | new IllegalArgumentException("URL 路径 /{method}/{tag} 中 method 值 " 478 | + method + " 错误!只允许 " + METHODS + " 中的一个!" 479 | ) 480 | ) 481 | ); 482 | } 483 | 484 | String t = compatCommonAPI && tag != null && tag.endsWith("[]") ? tag.substring(0, tag.length() - 2) : tag; 485 | if (StringUtil.isName(t) == false) { 486 | return JSON.toJSONString( 487 | newErrorResult( 488 | new IllegalArgumentException("URL 路径 /" + method + "/{tag} 的 tag 中 " 489 | + t + " 错误!tag 不能为空,且只允许变量命名格式!" 490 | ) 491 | ) 492 | ); 493 | } 494 | 495 | String versionStr = params == null ? null : params.remove(APIJSONConstant.VERSION); 496 | Integer version; 497 | try { 498 | version = StringUtil.isEmpty(versionStr, false) ? null : Integer.valueOf(versionStr); 499 | } 500 | catch (Exception e) { 501 | return JSON.toJSONString( 502 | newErrorResult(new IllegalArgumentException("URL 路径 /" + method + "/" 503 | + tag + "?version=value 中 value 值 " + versionStr + " 错误!必须符合整数格式!") 504 | ) 505 | ); 506 | } 507 | 508 | if (version == null) { 509 | version = 0; 510 | } 511 | 512 | try { 513 | // 从 Document 查这样的接口 514 | String cacheKey = AbstractVerifier.getCacheKeyForRequest(method, tag); 515 | SortedMap> versionedMap = APIJSONVerifier.DOCUMENT_MAP.get(cacheKey); 516 | 517 | Map result = versionedMap == null ? null : versionedMap.get(version); 518 | if (result == null) { // version <= 0 时使用最新,version > 0 时使用 > version 的最接近版本(最小版本) 519 | Set>> set = versionedMap == null ? null : versionedMap.entrySet(); 520 | 521 | if (set != null && set.isEmpty() == false) { 522 | Map.Entry> maxEntry = null; 523 | 524 | for (Map.Entry> entry : set) { 525 | if (entry == null || entry.getKey() == null || entry.getValue() == null) { 526 | continue; 527 | } 528 | 529 | if (version == null || version <= 0 || version == entry.getKey()) { // 这里应该不会出现相等,因为上面 versionedMap.get(Integer.valueOf(version)) 530 | maxEntry = entry; 531 | break; 532 | } 533 | 534 | if (entry.getKey() < version) { 535 | break; 536 | } 537 | 538 | maxEntry = entry; 539 | } 540 | 541 | result = maxEntry == null ? null : maxEntry.getValue(); 542 | } 543 | 544 | if (result != null) { // 加快下次查询,查到值的话组合情况其实是有限的,不属于恶意请求 545 | if (versionedMap == null) { 546 | versionedMap = new TreeMap<>((o1, o2) -> { 547 | return o2 == null ? -1 : o2.compareTo(o1); // 降序 548 | }); 549 | } 550 | 551 | versionedMap.put(version, result); 552 | APIJSONVerifier.DOCUMENT_MAP.put(cacheKey, versionedMap); 553 | } 554 | } 555 | 556 | @SuppressWarnings("unchecked") 557 | APIJSONCreator creator = (APIJSONCreator) APIJSONApplication.DEFAULT_APIJSON_CREATOR; 558 | if (result == null && Log.DEBUG && APIJSONVerifier.DOCUMENT_MAP.isEmpty()) { 559 | 560 | //获取指定的JSON结构 <<<<<<<<<<<<<< 561 | SQLConfig config = creator.createSQLConfig().setMethod(GET).setTable(APIJSONConstant.DOCUMENT_); 562 | config.setPrepared(false); 563 | config.setColumn(Arrays.asList("request,apijson")); 564 | 565 | Map where = new HashMap(); 566 | where.put("url", "/" + method + "/" + tag); 567 | where.put("apijson{}", "length(apijson)>0"); 568 | 569 | if (version > 0) { 570 | where.put(JSONRequest.KEY_VERSION + ">=", version); 571 | } 572 | config.setWhere(where); 573 | config.setOrder(JSONRequest.KEY_VERSION + (version > 0 ? "+" : "-")); 574 | config.setCount(1); 575 | 576 | //too many connections error: 不try-catch,可以让客户端看到是服务器内部异常 577 | result = creator.createSQLExecutor().execute(config, false); 578 | 579 | // version, method, tag 组合情况太多了,JDK 里又没有 LRUCache,所以要么启动时一次性缓存全部后面只用缓存,要么每次都查数据库 580 | // versionedMap.put(Integer.valueOf(version), result); 581 | // DOCUMENT_MAP.put(cacheKey, versionedMap); 582 | } 583 | 584 | String apijson = result == null ? null : getString(result, "apijson"); 585 | if (StringUtil.isEmpty(apijson, true)) { // 586 | if (compatCommonAPI) { 587 | return crudByTag(method, tag, params, request, session); 588 | } 589 | 590 | throw new IllegalArgumentException("URL 路径 /" + method 591 | + "/" + tag + (versionStr == null ? "" : "?version=" + versionStr) + " 对应的接口不存在!"); 592 | } 593 | 594 | M rawReq = JSON.parseObject(request); 595 | if (rawReq == null) { 596 | rawReq = JSON.createJSONObject(); 597 | } 598 | if (params != null && params.isEmpty() == false) { 599 | rawReq.putAll(params); 600 | } 601 | 602 | if (parser.isNeedVerifyContent()) { 603 | Verifier verifier = parser.getVerifier(); 604 | 605 | //获取指定的JSON结构 <<<<<<<<<<<< 606 | Map target = parser.getStructure("Request", method.toUpperCase(), tag, version); 607 | if (target == null) { //empty表示随意操作 || object.isEmpty()) { 608 | throw new UnsupportedOperationException("找不到 version: " + version + ", method: " + method.toUpperCase() + ", tag: " + tag + " 对应的 structure !" 609 | + "非开放请求必须是后端 Request 表中校验规则允许的操作!如果需要则在 Request 表中新增配置!"); 610 | } 611 | 612 | //M clone 浅拷贝没用,Structure.parse 会导致 structure 里面被清空,第二次从缓存里取到的就是 {} 613 | verifier.verifyRequest(requestMethod, "", JSON.createJSONObject(target), rawReq, 0, null, null); 614 | } 615 | 616 | M apijsonReq = JSON.parseObject(apijson); 617 | if (apijsonReq == null) { 618 | apijsonReq = JSON.createJSONObject(); 619 | } 620 | 621 | Set> rawSet = rawReq.entrySet(); 622 | if (rawSet != null && rawSet.isEmpty() == false) { 623 | for (Map.Entry entry : rawSet) { 624 | String key = entry == null ? null : entry.getKey(); 625 | if (key == null) { // value 为 null 有效 626 | continue; 627 | } 628 | 629 | String[] pathKeys = key.split("\\."); 630 | //逐层到达child的直接容器JSONObject parent 631 | int last = pathKeys.length - 1; 632 | M parent = apijsonReq; 633 | for (int i = 0; i < last; i++) {//一步一步到达指定位置 634 | M p = getJSONObject(parent, pathKeys[i]); 635 | if (p == null) { 636 | p = JSON.createJSONObject(); 637 | parent.put(key, p); 638 | } 639 | parent = p; 640 | } 641 | 642 | parent.put(pathKeys[last], entry.getValue()); 643 | } 644 | } 645 | 646 | // 没必要,已经是预设好的实际参数了,如果要 tag 就在 apijson 字段配置 apijsonReq.put(JSONRequest.KEY_TAG, tag); 647 | 648 | return parser.setNeedVerifyContent(false).parse(apijsonReq); 649 | } 650 | catch (Exception e) { 651 | return JSON.toJSONString(newErrorResult(e)); 652 | } 653 | } 654 | 655 | //通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 656 | 657 | 658 | 659 | 660 | /**重新加载配置 661 | * @return 662 | * @see 663 | *
664 | 	{
665 | 	"type": "ALL",  //重载对象,ALL, FUNCTION, REQUEST, ACCESS,非必须
666 | 	"phone": "13000082001",
667 | 	"verify": "1234567" //验证码,对应类型为 Verify.TYPE_RELOAD
668 | 	}
669 | 	 * 
670 | */ 671 | public M reload(String type) { 672 | M result = newSuccessResult(); 673 | 674 | boolean reloadAll = StringUtil.isEmpty(type, true) || "ALL".equals(type); 675 | 676 | if (reloadAll || "ACCESS".equals(type)) { 677 | try { 678 | if (reloadAll == false && APIJSONVerifier.ENABLE_VERIFY_ROLE == false) { 679 | throw new UnsupportedOperationException("AbstractVerifier.ENABLE_VERIFY_ROLE == false 时不支持校验角色权限!" + 680 | "如需支持则设置 AbstractVerifier.ENABLE_VERIFY_ROLE = true !"); 681 | } 682 | 683 | if (APIJSONVerifier.ENABLE_VERIFY_ROLE) { 684 | result.put(ACCESS_, APIJSONVerifier.initAccess()); 685 | } 686 | } catch (ServerException e) { 687 | e.printStackTrace(); 688 | result.put(ACCESS_, newErrorResult(e)); 689 | } 690 | } 691 | 692 | if (reloadAll || "FUNCTION".equals(type)) { 693 | try { 694 | if (reloadAll == false && APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION == false) { 695 | throw new UnsupportedOperationException("AbstractFunctionParser.ENABLE_REMOTE_FUNCTION" + 696 | " == false 时不支持远程函数!如需支持则设置 AbstractFunctionParser.ENABLE_REMOTE_FUNCTION = true !"); 697 | } 698 | 699 | if (APIJSONFunctionParser.ENABLE_REMOTE_FUNCTION) { 700 | result.put(FUNCTION_, APIJSONFunctionParser.init()); 701 | } 702 | } catch (ServerException e) { 703 | e.printStackTrace(); 704 | result.put(FUNCTION_, newErrorResult(e)); 705 | } 706 | } 707 | 708 | if (reloadAll || "REQUEST".equals(type)) { 709 | try { 710 | if (reloadAll == false && APIJSONVerifier.ENABLE_VERIFY_CONTENT == false) { 711 | throw new UnsupportedOperationException("AbstractVerifier.ENABLE_VERIFY_CONTENT == false 时不支持校验请求传参内容!" + 712 | "如需支持则设置 AbstractVerifier.ENABLE_VERIFY_CONTENT = true !"); 713 | } 714 | 715 | if (APIJSONVerifier.ENABLE_VERIFY_CONTENT) { 716 | result.put(REQUEST_, APIJSONVerifier.initRequest()); 717 | } 718 | } catch (ServerException e) { 719 | e.printStackTrace(); 720 | result.put(REQUEST_, newErrorResult(e)); 721 | } 722 | } 723 | 724 | return result; 725 | } 726 | 727 | 728 | /**用户登录 729 | * @param session 730 | * @param visitor 731 | * @param version 732 | * @param format 733 | * @param defaults 734 | * @return 返回类型设置为 Object 是为了子类重写时可以有返回值,避免因为冲突而另写一个有返回值的登录方法 735 | */ 736 | public Object login(@NotNull HttpSession session, @NotNull Visitor visitor, Integer version, Boolean format, M defaults) { 737 | //登录状态保存至session 738 | session.setAttribute(VISITOR_ID, visitor.getId()); //用户id 739 | session.setAttribute(VISITOR_, visitor); //用户 740 | session.setAttribute(VERSION, version); //全局默认版本号 741 | session.setAttribute(FORMAT, format); //全局默认格式化配置 742 | session.setAttribute(DEFAULTS, defaults); //给每个请求JSON最外层加的字段 743 | return null; 744 | } 745 | 746 | /**退出登录,清空session 747 | * @param session 748 | * @return 返回类型设置为 Object 是为了子类重写时可以有返回值,避免因为冲突而另写一个有返回值的登录方法 749 | */ 750 | public Object logout(@NotNull HttpSession session) { 751 | Object userId = APIJSONVerifier.getVisitorId(session);//必须在session.invalidate();前! 752 | Log.d(TAG, "logout userId = " + userId + "; session.getId() = " + (session == null ? null : session.getId())); 753 | session.invalidate(); 754 | return null; 755 | } 756 | 757 | 758 | 759 | // public JSONMap listMethod(String request) { 760 | // if (Log.DEBUG == false) { 761 | // return APIJSONParser.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用 UnitAuto 单元测试!")); 762 | // } 763 | // return MethodUtil.listMethod(request); 764 | // } 765 | // 766 | // public void invokeMethod(String request, HttpServletRequest servletRequest) { 767 | // AsyncContext asyncContext = servletRequest.startAsync(); 768 | // 769 | // final boolean[] called = new boolean[] { false }; 770 | // MethodUtil.Listener listener = new MethodUtil.Listener() { 771 | // 772 | // @Override 773 | // public void complete(JSONMap data, Method method, InterfaceProxy proxy, Object... extras) throws Exception { 774 | // 775 | // ServletResponse servletResponse = called[0] ? null : asyncContext.getResponse(); 776 | // if (servletResponse == null) { // || servletResponse.isCommitted()) { // isCommitted 在高并发时可能不准,导致写入多次 777 | // Log.w(TAG, "invokeMethod listener.complete servletResponse == null || servletResponse.isCommitted() >> return;"); 778 | // return; 779 | // } 780 | // called[0] = true; 781 | // 782 | // servletResponse.setCharacterEncoding(servletRequest.getCharacterEncoding()); 783 | // servletResponse.setContentType(servletRequest.getContentType()); 784 | // servletResponse.getWriter().println(data); 785 | // asyncContext.complete(); 786 | // } 787 | // }; 788 | // 789 | // if (Log.DEBUG == false) { 790 | // try { 791 | // listener.complete(MethodUtil.JSON_CALLBACK.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用 UnitAuto 单元测试!"))); 792 | // } 793 | // catch (Exception e1) { 794 | // e1.printStackTrace(); 795 | // asyncContext.complete(); 796 | // } 797 | // 798 | // return; 799 | // } 800 | // 801 | // 802 | // try { 803 | // MethodUtil.invokeMethod(request, null, listener); 804 | // } 805 | // catch (Exception e) { 806 | // Log.e(TAG, "invokeMethod try { JSONMap req = JSON.parseObject(request); ... } catch (Exception e) { \n" + e.getMessage()); 807 | // try { 808 | // listener.complete(MethodUtil.JSON_CALLBACK.newErrorResult(e)); 809 | // } 810 | // catch (Exception e1) { 811 | // e1.printStackTrace(); 812 | // asyncContext.complete(); 813 | // } 814 | // } 815 | // } 816 | 817 | } 818 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONCreator.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.orm.*; 18 | 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | 23 | /**APIJSON相关创建器 24 | * @author Lemon 25 | */ 26 | public class APIJSONCreator, L extends List> 27 | implements ParserCreator, VerifierCreator, SQLCreator { 28 | 29 | @Override 30 | public APIJSONParser createParser() { 31 | return new APIJSONParser<>(); 32 | } 33 | 34 | @Override 35 | public APIJSONFunctionParser createFunctionParser() { 36 | return new APIJSONFunctionParser<>(); 37 | } 38 | 39 | @Override 40 | public APIJSONVerifier createVerifier() { 41 | return new APIJSONVerifier<>(); 42 | } 43 | 44 | @Override 45 | public APIJSONSQLConfig createSQLConfig() { 46 | return new APIJSONSQLConfig<>(); 47 | } 48 | 49 | @Override 50 | public APIJSONSQLExecutor createSQLExecutor() { 51 | return new APIJSONSQLExecutor<>(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONObjectParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.NotNull; 18 | import apijson.RequestMethod; 19 | import apijson.framework.javax.*; 20 | import apijson.orm.AbstractObjectParser; 21 | import apijson.orm.Join; 22 | import apijson.orm.Parser; 23 | import apijson.orm.SQLConfig; 24 | import javax.servlet.http.HttpSession; 25 | 26 | import java.util.List; 27 | import java.util.Map; 28 | 29 | 30 | /**简化Parser,getObject和getArray(getArrayConfig)都能用 31 | * @author Lemon 32 | */ 33 | public class APIJSONObjectParser, L extends List> 34 | extends AbstractObjectParser { 35 | public static final String TAG = "APIJSONObjectParser"; 36 | 37 | /**for single object 38 | * @param session 39 | * @param request 40 | * @param parentPath 41 | * @param arrayConfig 42 | * @param isSubquery 43 | * @param isTable 44 | * @param isArrayMainTable 45 | * @throws Exception 46 | */ 47 | public APIJSONObjectParser(HttpSession session, @NotNull M request, String parentPath, SQLConfig arrayConfig 48 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 49 | super(request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable); 50 | } 51 | 52 | @Override 53 | public APIJSONObjectParser setMethod(RequestMethod method) { 54 | super.setMethod(method); 55 | return this; 56 | } 57 | 58 | @Override 59 | public APIJSONObjectParser setParser(Parser parser) { 60 | super.setParser(parser); 61 | return this; 62 | } 63 | 64 | 65 | @Override 66 | public SQLConfig newSQLConfig(RequestMethod method, String table, String alias, M request 67 | , List> joinList, boolean isProcedure) throws Exception { 68 | return APIJSONSQLConfig.newSQLConfig(method, table, alias, request, joinList, isProcedure); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONParser.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import static apijson.framework.javax.APIJSONConstant.DEFAULTS; 18 | import static apijson.framework.javax.APIJSONConstant.FORMAT; 19 | import static apijson.framework.javax.APIJSONConstant.VERSION; 20 | 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | import javax.servlet.http.HttpSession; 26 | 27 | import apijson.NotNull; 28 | import apijson.RequestMethod; 29 | import apijson.orm.AbstractParser; 30 | import apijson.orm.FunctionParser; 31 | import apijson.orm.SQLConfig; 32 | 33 | 34 | /**请求解析器 35 | * @author Lemon 36 | */ 37 | public class APIJSONParser, L extends List> extends AbstractParser { 38 | public static final String TAG = "APIJSONParser"; 39 | 40 | 41 | public APIJSONParser() { 42 | super(); 43 | } 44 | public APIJSONParser(RequestMethod method) { 45 | super(method); 46 | } 47 | public APIJSONParser(RequestMethod method, boolean needVerify) { 48 | super(method, needVerify); 49 | } 50 | 51 | private HttpSession session; 52 | public HttpSession getSession() { 53 | return session; 54 | } 55 | public APIJSONParser setSession(HttpSession session) { 56 | this.session = session; 57 | setVisitor(APIJSONVerifier.getVisitor(session)); 58 | return this; 59 | } 60 | 61 | @SuppressWarnings("unchecked") 62 | @Override 63 | public APIJSONParser createParser() { 64 | return APIJSONApplication.createParser(); 65 | } 66 | @Override 67 | public APIJSONFunctionParser createFunctionParser() { 68 | return APIJSONApplication.createFunctionParser(); 69 | } 70 | 71 | @SuppressWarnings("unchecked") 72 | @Override 73 | public APIJSONVerifier createVerifier() { 74 | return APIJSONApplication.createVerifier(); 75 | } 76 | 77 | @Override 78 | public APIJSONSQLConfig createSQLConfig() { 79 | return APIJSONApplication.createSQLConfig(); 80 | } 81 | @Override 82 | public APIJSONSQLExecutor createSQLExecutor() { 83 | return APIJSONApplication.createSQLExecutor(); 84 | } 85 | 86 | @Override 87 | public APIJSONParser setNeedVerify(boolean needVerify) { 88 | super.setNeedVerify(needVerify); 89 | return this; 90 | } 91 | 92 | @Override 93 | public APIJSONParser setNeedVerifyLogin(boolean needVerifyLogin) { 94 | super.setNeedVerifyLogin(needVerifyLogin); 95 | return this; 96 | } 97 | 98 | @Override 99 | public APIJSONParser setNeedVerifyRole(boolean needVerifyRole) { 100 | super.setNeedVerifyRole(needVerifyRole); 101 | return this; 102 | } 103 | 104 | @Override 105 | public APIJSONParser setNeedVerifyContent(boolean needVerifyContent) { 106 | super.setNeedVerifyContent(needVerifyContent); 107 | return this; 108 | } 109 | 110 | @Override 111 | public M parseResponse(M request) { 112 | //补充format 113 | if (session != null && request != null) { 114 | if (request.get(FORMAT) == null) { 115 | request.put(FORMAT, session.getAttribute(FORMAT)); 116 | } 117 | if (request.get(VERSION) == null) { 118 | request.put(VERSION, session.getAttribute(VERSION)); 119 | } 120 | 121 | if (request.get(DEFAULTS) == null) { 122 | M defaults = (M) session.getAttribute(DEFAULTS); 123 | Set> set = defaults == null ? null : defaults.entrySet(); 124 | 125 | if (set != null) { 126 | for (Map.Entry e : set) { 127 | if (e != null && request.get(e.getKey()) == null) { 128 | request.put(e.getKey(), e.getValue()); 129 | } 130 | } 131 | } 132 | } 133 | } 134 | 135 | return super.parseResponse(request); 136 | } 137 | 138 | private FunctionParser functionParser; 139 | public FunctionParser getFunctionParser() { 140 | return functionParser; 141 | } 142 | @Override 143 | public Object onFunctionParse(String key, String function, String parentPath, String currentName, M currentObject, boolean containRaw) throws Exception { 144 | if (functionParser == null) { 145 | functionParser = createFunctionParser(); 146 | functionParser.setParser(this); 147 | functionParser.setMethod(getMethod()); 148 | functionParser.setTag(getTag()); 149 | functionParser.setVersion(getVersion()); 150 | functionParser.setRequest(requestObject); 151 | 152 | if (functionParser instanceof APIJSONFunctionParser) { 153 | ((APIJSONFunctionParser) functionParser).setSession(getSession()); 154 | } 155 | } 156 | functionParser.setKey(key); 157 | functionParser.setParentPath(parentPath); 158 | functionParser.setCurrentName(currentName); 159 | functionParser.setCurrentObject(currentObject); 160 | 161 | return functionParser.invoke(function, currentObject, containRaw); 162 | } 163 | 164 | 165 | @Override 166 | public APIJSONObjectParser createObjectParser(@NotNull M request, String parentPath, SQLConfig arrayConfig 167 | , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { 168 | 169 | return new APIJSONObjectParser(getSession(), request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable) { 170 | 171 | // @Override 172 | // protected APIJSONSQLConfig newQueryConfig() { 173 | // if (itemConfig != null) { 174 | // return itemConfig; 175 | // } 176 | // return super.newQueryConfig(); 177 | // } 178 | 179 | // 导致最多评论的(Strong 30个)的那个动态详情界面Android(82001)无姓名和头像,即User=null 180 | // @Override 181 | // protected void onComplete() { 182 | // if (response != null) { 183 | // putQueryResult(path, response); // 解决获取关联数据时requestObject里不存在需要的关联数据 184 | // } 185 | // } 186 | 187 | }.setMethod(getMethod()).setParser(this); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONSQLConfig.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.RequestMethod; 18 | import apijson.orm.AbstractSQLConfig; 19 | import apijson.orm.Join; 20 | import apijson.orm.SQLConfig; 21 | 22 | import java.util.LinkedHashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | import static apijson.framework.javax.APIJSONConstant.*; 27 | 28 | 29 | /**SQL配置 30 | * TiDB 用法和 MySQL 一致 31 | * @author Lemon 32 | */ 33 | public class APIJSONSQLConfig, L extends List> extends AbstractSQLConfig { 34 | public static final String TAG = "APIJSONSQLConfig"; 35 | 36 | public static boolean ENABLE_COLUMN_CONFIG = false; 37 | 38 | public static Callback, ? extends List> SIMPLE_CALLBACK; 39 | 40 | static { 41 | DEFAULT_DATABASE = DATABASE_MYSQL; //TODO 默认数据库类型,改成你自己的 42 | DEFAULT_SCHEMA = "sys"; //TODO 默认模式名,改成你自己的,默认情况是 MySQL: sys, PostgreSQL: public, SQL Server: dbo, Oracle: 43 | // TABLE_KEY_MAP.put(Access.class.getSimpleName(), "apijson_access"); 44 | 45 | // 由 APIJSONVerifier.init 方法读取数据库 Access 表来替代手动输入配置 46 | // //表名映射,隐藏真实表名,对安全要求很高的表可以这么做 47 | // TABLE_KEY_MAP.put(User.class.getSimpleName(), "apijson_user"); 48 | // TABLE_KEY_MAP.put(Privacy.class.getSimpleName(), "apijson_privacy"); 49 | 50 | SIMPLE_CALLBACK = new SimpleCallback, List>() { 51 | 52 | @Override 53 | public SQLConfig, List> getSQLConfig( 54 | RequestMethod method, String database, String schema, String datasource, String table) { 55 | SQLConfig, List> config = APIJSONApplication.createSQLConfig(); 56 | config.setMethod(method); 57 | config.setDatabase(database); 58 | config.setDatasource(datasource); 59 | config.setSchema(schema); 60 | config.setTable(table); 61 | return config; 62 | } 63 | 64 | //取消注释来实现自定义各个表的主键名 65 | // @Override 66 | // public String getIdKey(String database, String schema, String datasource, String table) { 67 | // return StringUtil.firstCase(table + "Id"); // userId, comemntId ... 68 | // // return StringUtil.toLowerCase(t) + "_id"; // user_id, comemnt_id ... 69 | // // return StringUtil.toUpperCase(t) + "_ID"; // USER_ID, COMMENT_ID ... 70 | // } 71 | 72 | @Override 73 | public String getUserIdKey(String database, String schema, String datasource, String table) { 74 | return USER_.equals(table) || PRIVACY_.equals(table) ? ID : USER_ID; // id / userId 75 | } 76 | 77 | //取消注释来实现数据库自增 id 78 | // @Override 79 | // public Object newId(RequestMethod method, String database, String schema, String datasource, String table) { 80 | // return null; // return null 则不生成 id,一般用于数据库自增 id 81 | // } 82 | }; 83 | 84 | } 85 | 86 | /**获取SQL配置 87 | * @param table 88 | * @param alias 89 | * @param request 90 | * @param isProcedure 91 | * @return 92 | * @throws Exception 93 | */ 94 | public static , L extends List> SQLConfig newSQLConfig( 95 | RequestMethod method, String table, String alias, M request, List> joinList, boolean isProcedure) throws Exception { 96 | return newSQLConfig(method, table, alias, request, joinList, isProcedure, (SimpleCallback) SIMPLE_CALLBACK); 97 | } 98 | 99 | public APIJSONSQLConfig() { 100 | this(RequestMethod.GET); 101 | } 102 | public APIJSONSQLConfig(RequestMethod method) { 103 | super(method); 104 | } 105 | public APIJSONSQLConfig(RequestMethod method, String table) { 106 | super(method, table); 107 | } 108 | public APIJSONSQLConfig(RequestMethod method, int count, int page) { 109 | super(method, count, page); 110 | } 111 | 112 | 113 | public String gainDBVersion() { 114 | if (isMySQL()) { 115 | return "5.7.22"; //"8.0.11"; //TODO 改成你自己的 MySQL 或 PostgreSQL 数据库版本号 //MYSQL 8 和 7 使用的 JDBC 配置不一样 116 | } 117 | if (isPostgreSQL()) { 118 | return "9.6.15"; //TODO 改成你自己的 119 | } 120 | if (isSQLServer()) { 121 | return "2016"; //TODO 改成你自己的 122 | } 123 | if (isOracle()) { 124 | return "18c"; //TODO 改成你自己的 125 | } 126 | return null; 127 | } 128 | 129 | public String gainDBUri() { 130 | if (isMySQL()) { 131 | return "jdbc:mysql://localhost:3306"; 132 | } 133 | if (isTiDB()) { 134 | return "jdbc:mysql://localhost:4000"; 135 | } 136 | if (isPostgreSQL()) { // PG JDBC 必须在 URI 传 catalog 137 | return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 138 | } 139 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 140 | // return "jdbc:postgresql://localhost:26257/movr?sslmode=require"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach && cockroach demo 141 | // // return "jdbc:postgresql://localhost:26258/postgres?sslmode=disable"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach # && start 3 nodes and init cluster 142 | //} 143 | if (isSQLServer()) { 144 | return "jdbc:jtds:sqlserver://localhost:1433/pubs;instance=SQLEXPRESS"; //TODO 改成你自己的 145 | } 146 | if (isOracle()) { 147 | return "jdbc:oracle:thin:@localhost:1521:orcl"; //TODO 改成你自己的 148 | } 149 | if (isDb2()) { 150 | return "jdbc:db2://localhost:50000/BLUDB"; //TODO 改成你自己的 151 | } 152 | if (isSQLite()) { 153 | return "jdbc:sqlite:sample.db"; //TODO 改成你自己的 154 | } 155 | if (isDameng()) { 156 | return "jdbc:dm://localhost:5236"; //TODO 改成你自己的 157 | } 158 | if (isTDengine()) { 159 | // return "jdbc:TAOS://localhost:6030"; //TODO 改成你自己的 160 | return "jdbc:TAOS-RS://localhost:6041"; //TODO 改成你自己的 161 | } 162 | if (isTimescaleDB()) { // PG JDBC 必须在 URI 传 catalog 163 | return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 164 | } 165 | if (isQuestDB()) { // PG JDBC 必须在 URI 传 catalog 166 | return "jdbc:postgresql://localhost:8812/qdb"; //TODO 改成你自己的 167 | } 168 | if (isInfluxDB()) { 169 | return "http://203.189.6.3:8086"; //TODO 改成你自己的 170 | } 171 | if (isMilvus()) { 172 | return "http://localhost:19530"; //TODO 改成你自己的 173 | } 174 | if (isManticore()) { 175 | return "jdbc:mysql://localhost:9306?characterEncoding=utf8&maxAllowedPacket=512000"; 176 | } 177 | if (isIoTDB()) { 178 | return "jdbc:iotdb://localhost:6667"; // ?charset=GB18030 加参数会报错 URI 格式错误 179 | } 180 | if (isMongoDB()) { 181 | return "jdbc:mongodb://atlas-sql-6593c65c296c5865121e6ebe-xxskv.a.query.mongodb.net/myVirtualDatabase?ssl=true&authSource=admin"; 182 | } 183 | if (isCassandra()) { 184 | return "http://localhost:7001"; 185 | } 186 | if (isDuckDB()) { 187 | return "jdbc:duckdb:/Users/root/my_database.duckdb"; 188 | } 189 | if (isSurrealDB()) { 190 | // return "memory"; 191 | // return "surrealkv://localhost:8000"; 192 | return "ws://localhost:8000"; 193 | } 194 | if (isOpenGauss()) { 195 | return "jdbc:opengauss://127.0.0.1:5432/postgres?currentSchema=" + DEFAULT_SCHEMA; 196 | } 197 | if (isDoris()) { 198 | return "jdbc:mysql://localhost:9030"; 199 | } 200 | return null; 201 | } 202 | 203 | public String gainDBAccount() { 204 | if (isMySQL()) { 205 | return "root"; //TODO 改成你自己的 206 | } 207 | if (isPostgreSQL()) { 208 | return "postgres"; //TODO 改成你自己的 209 | } 210 | if (isSQLServer()) { 211 | return "sa"; //TODO 改成你自己的 212 | } 213 | if (isOracle()) { 214 | return "scott"; //TODO 改成你自己的 215 | } 216 | if (isMySQL()) { 217 | return "root"; // ""apijson"; //TODO 改成你自己的 218 | } 219 | if (isPostgreSQL()) { 220 | return "postgres"; //TODO 改成你自己的 221 | } 222 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 223 | // return "demo"; //TODO 改成你自己的 224 | // //return "postgres"; //TODO 改成你自己的 225 | //} 226 | if (isSQLServer()) { 227 | return "sa"; //TODO 改成你自己的 228 | } 229 | if (isOracle()) { 230 | return "scott"; //TODO 改成你自己的 231 | } 232 | if (isDb2()) { 233 | return "db2admin"; //TODO 改成你自己的 234 | } 235 | // if (isSQLite()) { 236 | // return "root"; //TODO 改成你自己的 237 | // } 238 | if (isDameng()) { 239 | return "SYSDBA"; 240 | } 241 | if (isTDengine()) { 242 | return "root"; //TODO 改成你自己的 243 | } 244 | //if (isTimescaleDB()) { 245 | // return "postgres"; //TODO 改成你自己的 246 | //} 247 | if (isQuestDB()) { 248 | return "admin"; //TODO 改成你自己的 249 | } 250 | if (isInfluxDB()) { 251 | return "iotos"; 252 | } 253 | if (isMilvus()) { 254 | return "root"; 255 | } 256 | if (isManticore()) { 257 | return null; // "root"; 258 | } 259 | if (isIoTDB()) { 260 | return "root"; 261 | } 262 | if (isMongoDB()) { 263 | return "root"; //TODO 改成你自己的 264 | } 265 | if (isCassandra()) { 266 | return "root"; //TODO 改成你自己的 267 | } 268 | if (isDuckDB()) { 269 | return "root"; //TODO 改成你自己的 270 | } 271 | if (isSurrealDB()) { 272 | return "root"; //TODO 改成你自己的 273 | } 274 | if (isOpenGauss()) { 275 | return "postgres"; //TODO 改成你自己的 276 | // 不允许用初始账号,需要 CREATE USER 创建新账号并 GRANT 授权 return "opengauss"; //TODO 改成你自己的 277 | } 278 | if (isDoris()) { 279 | return "root"; //TODO 改成你自己的 280 | } 281 | 282 | return null; 283 | } 284 | 285 | public String gainDBPassword() { 286 | if (isMySQL()) { 287 | return "yourPassword@123"; 288 | } 289 | if (isTiDB()) { 290 | return ""; 291 | } 292 | if (isPostgreSQL()) { 293 | return null; 294 | } 295 | if (isSQLServer()) { 296 | return "yourPassword@123"; 297 | } 298 | if (isOracle()) { 299 | return "tiger"; 300 | } 301 | //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog 302 | // return "demo39865"; 303 | // // return null 304 | //} 305 | if (isSQLServer()) { 306 | return "yourPassword@123"; 307 | } 308 | if (isOracle()) { 309 | return "tiger"; 310 | } 311 | if (isDb2()) { 312 | return "123"; 313 | } 314 | if (isSQLite()) { 315 | return "yourPassword@123"; 316 | } 317 | if (isDameng()) { 318 | return "SYSDBA"; 319 | } 320 | if (isTDengine()) { 321 | return "taosdata"; 322 | } 323 | if (isTimescaleDB()) { 324 | return "password"; 325 | } 326 | if (isQuestDB()) { 327 | return "quest"; 328 | } 329 | if (isInfluxDB()) { 330 | return "yourPassword@123"; 331 | } 332 | if (isMilvus()) { 333 | return "yourPassword@123"; 334 | } 335 | //if (isManticore()) { 336 | // return null; 337 | //} 338 | //if (isIoTDB()) { 339 | // return "root"; 340 | //} 341 | if (isMongoDB()) { 342 | return "yourPassword@123"; 343 | } 344 | if (isCassandra()) { 345 | return "yourPassword@123"; 346 | } 347 | if (isDuckDB()) { 348 | return ""; 349 | } 350 | if (isSurrealDB()) { 351 | return "root"; 352 | } 353 | if (isOpenGauss()) { 354 | return "yourPassword@123"; 355 | } 356 | if (isDoris()) { 357 | return ""; 358 | } 359 | 360 | return null; 361 | } 362 | 363 | /**获取 APIJSON 配置表所在数据库模式 database,默认与业务表一块 364 | * @return 365 | */ 366 | public String getConfigDatabase() { 367 | return getDatabase(); 368 | } 369 | /**获取 APIJSON 配置表所在数据库模式 schema,默认与业务表一块 370 | * @return 371 | */ 372 | public String getConfigSchema() { 373 | return getSchema(); 374 | } 375 | /**是否为 APIJSON 配置表,如果和业务表一块,可以重写这个方法,固定 return false 来提高性能 376 | * @return 377 | */ 378 | public boolean isConfigTable() { 379 | return CONFIG_TABLE_LIST.contains(getTable()); 380 | } 381 | @Override 382 | public String gainSQLDatabase() { 383 | String db = isConfigTable() ? getConfigDatabase() : super.gainSQLDatabase(); 384 | return db == null ? DEFAULT_DATABASE : db; 385 | } 386 | @Override 387 | public String gainSQLSchema() { 388 | String sch = isConfigTable() ? getConfigSchema() : super.gainSQLSchema(); 389 | return sch == null ? DEFAULT_SCHEMA : sch; 390 | } 391 | 392 | 393 | @Override 394 | public String getIdKey() { 395 | return SIMPLE_CALLBACK.getIdKey(getDatabase(), getSchema(), getDatasource(), getTable()); 396 | } 397 | 398 | @Override 399 | public String getUserIdKey() { 400 | return SIMPLE_CALLBACK.getUserIdKey(getDatabase(), getSchema(), getDatasource(), getTable()); 401 | } 402 | 403 | 404 | // 支持 !key 反选字段 和 字段名映射,依赖插件 https://github.com/APIJSON/apijson-column 405 | @Override 406 | public APIJSONSQLConfig setColumn(List column) { 407 | if (ENABLE_COLUMN_CONFIG) { 408 | column = ColumnUtil.compatInputColumn(column, getTable(), getMethod(), getVersion(), ! isConfigTable()); 409 | } 410 | super.setColumn(column); 411 | return this; 412 | } 413 | 414 | @Override 415 | public String gainKey(String key) { 416 | if (ENABLE_COLUMN_CONFIG) { 417 | key = ColumnUtil.compatInputKey(key, getTable(), getMethod()); 418 | } 419 | return super.gainKey(key); 420 | } 421 | 422 | } 423 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/APIJSONSQLExecutor.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | 21 | /**executor for query(read) or update(write) MySQL database 22 | * @author Lemon 23 | */ 24 | public class APIJSONSQLExecutor, L extends List> extends apijson.framework.APIJSONSQLExecutor {} -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/AssertUtil.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | 18 | /**简单断言工具类,不用额外引入 JUnit 等库 19 | * @author Lemon 20 | */ 21 | public class AssertUtil extends apijson.framework.AssertUtil {} 22 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/BaseModel.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | /**base model for reduce model codes 18 | * @author Lemon 19 | * @use extends BaseModel 20 | */ 21 | public abstract class BaseModel extends apijson.framework.BaseModel {} 22 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/ColumnUtil.java: -------------------------------------------------------------------------------- 1 | /*Copyright ©2016 APIJSON(https://github.com/APIJSON) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License.*/ 14 | 15 | package apijson.framework.javax; 16 | 17 | import apijson.RequestMethod; 18 | import apijson.StringUtil; 19 | import apijson.orm.AbstractSQLConfig; 20 | import apijson.orm.AbstractSQLExecutor; 21 | 22 | import java.util.*; 23 | import java.util.Map.Entry; 24 | 25 | 26 | /**表字段相关工具类 27 | * @author Lemon 28 | * @see 先提前配置 {@link #VERSIONED_TABLE_COLUMN_MAP}, {@link #VERSIONED_KEY_COLUMN_MAP} 等,然后调用相关方法。 29 | * 不支持直接关联 database, schema, datasource,可以把这些与 table 拼接为一个字符串传给参数 table,格式可以是 database-schema-datasource-table 30 | */ 31 | public class ColumnUtil extends apijson.framework.ColumnUtil {} 32 | -------------------------------------------------------------------------------- /src/main/java/apijson/framework/javax/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * javax 包,兼容 JDK 1.8~16,使用 javax.servlet 3 | */ 4 | /** 5 | * @author Lemon 6 | * 7 | */ 8 | package apijson.framework.javax; -------------------------------------------------------------------------------- /src/main/java/apijson/framework/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 服务端框架 3 | */ 4 | /** 5 | * @author Lemon 6 | * 7 | */ 8 | package apijson.framework; -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APIJSON/apijson-framework/8f88df2504b147791e0d7c59bf093705b7d6d90e/src/main/resources/application.properties --------------------------------------------------------------------------------