├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml ├── src ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── alenfive │ │ │ └── rocketapi │ │ │ ├── RocketAPIApplication.java │ │ │ ├── annotation │ │ │ ├── ApiId.java │ │ │ ├── ApiTable.java │ │ │ └── ApiUpdateField.java │ │ │ ├── config │ │ │ ├── DefaultDataSourceManager.java │ │ │ ├── QLRequestMappingFactory.java │ │ │ ├── RedisClusterNotifyConfig.java │ │ │ ├── RefreshApiConfig.java │ │ │ ├── RocketApiAutoConfig.java │ │ │ ├── RocketApiProperties.java │ │ │ ├── SpringContextUtils.java │ │ │ └── SysApiPager.java │ │ │ ├── controller │ │ │ ├── ApiController.java │ │ │ ├── RemoteController.java │ │ │ └── ViewController.java │ │ │ ├── datasource │ │ │ ├── ClickHouseDataSource.java │ │ │ ├── DB2DataSource.java │ │ │ ├── DataSourceDialect.java │ │ │ ├── DataSourceManager.java │ │ │ ├── DialectTransactionManager.java │ │ │ ├── JdbcDataSource.java │ │ │ ├── MongoDataSource.java │ │ │ ├── MySQLDataSource.java │ │ │ ├── OracleDataSource.java │ │ │ ├── PostgreSQLDataSource.java │ │ │ ├── PrestoDataSource.java │ │ │ ├── SQLServerDataSource.java │ │ │ └── factory │ │ │ │ ├── ClickHouseDriver.java │ │ │ │ ├── IDataSourceDialectDriver.java │ │ │ │ ├── JdbcDriver.java │ │ │ │ ├── MongoDriver.java │ │ │ │ ├── MySQLDriver.java │ │ │ │ ├── OracleDriver.java │ │ │ │ ├── PostgreSQLDriver.java │ │ │ │ ├── PrestoDriver.java │ │ │ │ └── SQLServerDriver.java │ │ │ ├── entity │ │ │ ├── ApiConfig.java │ │ │ ├── ApiDirectory.java │ │ │ ├── ApiEntity.java │ │ │ ├── ApiExample.java │ │ │ ├── ApiInfo.java │ │ │ ├── ApiInfoHistory.java │ │ │ ├── ApiInfoRole.java │ │ │ ├── ApiParams.java │ │ │ ├── ApiResult.java │ │ │ ├── ApiTableName.java │ │ │ ├── ApiType.java │ │ │ ├── ConfigType.java │ │ │ ├── DBConfig.java │ │ │ ├── DataSourceProperty.java │ │ │ ├── LRUHashMap.java │ │ │ ├── ParamScope.java │ │ │ ├── ResultWrapper.java │ │ │ └── vo │ │ │ │ ├── AcceptApiInfoSyncReq.java │ │ │ │ ├── ArrVar.java │ │ │ │ ├── ClazzVo.java │ │ │ │ ├── ClusterType.java │ │ │ │ ├── CompletionResult.java │ │ │ │ ├── ConditionMatcher.java │ │ │ │ ├── DeleteExamleReq.java │ │ │ │ ├── DocApi.java │ │ │ │ ├── DocsInfo.java │ │ │ │ ├── ExportReq.java │ │ │ │ ├── ExportRes.java │ │ │ │ ├── FieldInfo.java │ │ │ │ ├── IgnoreWrapper.java │ │ │ │ ├── IndexScope.java │ │ │ │ ├── LoginVo.java │ │ │ │ ├── MappingVo.java │ │ │ │ ├── MethodVo.java │ │ │ │ ├── NewOldApiInfo.java │ │ │ │ ├── NotifyEntity.java │ │ │ │ ├── NotifyEventType.java │ │ │ │ ├── Page.java │ │ │ │ ├── ProvideCompletionReq.java │ │ │ │ ├── RefreshDB.java │ │ │ │ ├── RefreshMapping.java │ │ │ │ ├── RemoteApiInfoSyncReq.java │ │ │ │ ├── RenameGroupReq.java │ │ │ │ ├── RunApiReq.java │ │ │ │ ├── RunApiRes.java │ │ │ │ ├── ScriptContext.java │ │ │ │ ├── ScriptLanguageParam.java │ │ │ │ └── TableInfo.java │ │ │ ├── extend │ │ │ ├── ApiInfoContent.java │ │ │ ├── ApiInfoInterceptor.java │ │ │ ├── DefaultApiDocSync.java │ │ │ ├── DefaultApiInfoCache.java │ │ │ ├── DefaultApiInfoInterceptor.java │ │ │ ├── DefaultApiPager.java │ │ │ ├── DefaultAssertException.java │ │ │ ├── DefaultClusterNotify.java │ │ │ ├── DefaultDBCache.java │ │ │ ├── DefaultResultWrapper.java │ │ │ ├── DefaultSQLInterceptor.java │ │ │ ├── DefaultScriptEncrypt.java │ │ │ ├── DefaultUserAuthorization.java │ │ │ ├── IApiDocSync.java │ │ │ ├── IApiInfoCache.java │ │ │ ├── IApiPager.java │ │ │ ├── IApiSync.java │ │ │ ├── IAssertException.java │ │ │ ├── IClusterNotify.java │ │ │ ├── IConfigListener.java │ │ │ ├── IDBCache.java │ │ │ ├── IResultWrapper.java │ │ │ ├── ISQLInterceptor.java │ │ │ ├── IScriptEncrypt.java │ │ │ ├── IUserAuthorization.java │ │ │ ├── RedisApiInfoCache.java │ │ │ └── RedisClusterNotify.java │ │ │ ├── function │ │ │ ├── AssertFunction.java │ │ │ ├── ContextFunction.java │ │ │ ├── DbFunction.java │ │ │ ├── EnvFunction.java │ │ │ ├── IFunction.java │ │ │ ├── LogFunction.java │ │ │ ├── MongoFunction.java │ │ │ ├── PagerFunction.java │ │ │ └── UtilsFunction.java │ │ │ ├── script │ │ │ ├── GroovyScriptParse.java │ │ │ ├── IScriptParse.java │ │ │ └── JavaScriptScriptParse.java │ │ │ ├── service │ │ │ ├── ApiInfoService.java │ │ │ ├── CompletionService.java │ │ │ ├── ConfigService.java │ │ │ ├── DataSourceService.java │ │ │ ├── EncryptChangeService.java │ │ │ ├── LoginService.java │ │ │ ├── RequestMappingService.java │ │ │ └── ScriptParseService.java │ │ │ └── utils │ │ │ ├── ApiAnnotationUtil.java │ │ │ ├── ApiJpaUtil.java │ │ │ ├── CsvUtils.java │ │ │ ├── DataSourceUtils.java │ │ │ ├── ExcelUtils.java │ │ │ ├── FieldUtils.java │ │ │ ├── GenerateId.java │ │ │ ├── LogFormatUtils.java │ │ │ ├── MD5Utils.java │ │ │ ├── MongoDBUtils.java │ │ │ ├── PackageUtil.java │ │ │ ├── PackageUtils.java │ │ │ ├── RequestUtils.java │ │ │ ├── SignUtils.java │ │ │ └── SqlUtils.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yml │ │ ├── static │ │ └── rocketapi │ │ │ ├── css │ │ │ ├── font-awesome.3.2.1.enriched-for-client.css │ │ │ ├── font-awesome.4.2.0.min.css │ │ │ ├── prism.css │ │ │ ├── select2-4.0.3.min.css │ │ │ ├── simple-line-icons.css │ │ │ ├── sourceSansPro.css │ │ │ └── talend-icons-webfont.css │ │ │ ├── devhttpclient │ │ │ ├── 539661FD89DA706B002DCBFD57F74A0A.cache.js │ │ │ └── devhttpclient.nocache.js │ │ │ ├── dist │ │ │ └── chromeapp.css │ │ │ ├── fonts │ │ │ ├── Simple-Line-Icons.woff2 │ │ │ ├── api-tester.ttf │ │ │ ├── api-tester │ │ │ │ └── style.css │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── source-sans-pro-v9-latin-regular.woff2 │ │ │ └── talendicons.woff2 │ │ │ ├── images │ │ │ ├── ClickHouse.png │ │ │ ├── MongoDB.png │ │ │ ├── MySQL.png │ │ │ ├── Oracle.png │ │ │ ├── PostgreSQL.png │ │ │ ├── Presto.png │ │ │ ├── SQLServer.png │ │ │ └── search-icon-white-compressed.png │ │ │ ├── js │ │ │ ├── bootstrap-2.3.2.min.js │ │ │ ├── bootstrap-select.min.js │ │ │ ├── jquery-1.12.2.min.js │ │ │ ├── jquery.form.js │ │ │ └── tester_boot.js │ │ │ └── monaco-editor │ │ │ └── min │ │ │ └── vs │ │ │ ├── base │ │ │ ├── browser │ │ │ │ └── ui │ │ │ │ │ └── codiconLabel │ │ │ │ │ └── codicon │ │ │ │ │ └── codicon.ttf │ │ │ └── worker │ │ │ │ └── workerMain.js │ │ │ ├── basic-languages │ │ │ └── yaml │ │ │ │ └── yaml.js │ │ │ ├── editor │ │ │ ├── editor.main.css │ │ │ ├── editor.main.js │ │ │ └── editor.main.nls.js │ │ │ ├── language │ │ │ └── json │ │ │ │ ├── jsonMode.js │ │ │ │ └── jsonWorker.js │ │ │ ├── loader.js │ │ │ └── rocket-language.js │ │ └── templates │ │ └── rocketapi │ │ ├── api-index.html │ │ ├── bottom.html │ │ ├── console.html │ │ ├── editor.html │ │ ├── example.html │ │ ├── history-api.html │ │ ├── history-example.html │ │ ├── repository.html │ │ ├── request.html │ │ ├── response.html │ │ └── top.html └── test │ └── java │ └── com │ └── github │ └── alenfive │ └── rocketapi │ ├── ApplicationTests.java │ ├── ScriptLanguageTests.java │ └── Test.java └── 升级脚本 /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | /src/main/resources/application-default.yml 33 | 34 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![输入图片说明](https://images.gitee.com/uploads/images/2020/1119/195027_6ae6ae9d_5139840.png "QQ图片20201119194317.png") 3 | ### 定位 4 | 拒绝CRUD。用尽可能简单的方式,完成尽可能多的需求。通过约定的方式 实现统一的标准。告别加班,拒绝重复劳动,远离搬砖 5 | 6 | ### 概述 7 | "Rocket-API" 基于spring boot 的API敏捷开发框架,服务端50%以上的功能只需要写SQL或者 mongodb原始执行脚本就能完成开发,另外30%也在不停的完善公共组件,比如文件上传,下载,导出,预览,分页等等通过一二行代码也能完成开发,剩下的20%也能依赖于动态编译技术生成class的形式,不需要发布部署,不需要重启来实现研发团队的快速编码,提测以及回归。 8 | 实现了服务端研发效率300%-500%的提升,人力成本减少了3倍 9 | ### 特性 10 | 1. 用于快速开发API接口。不再定义`Controller`,`Service`,`Dao`,`Mybatis`,`xml`,`Entity`,`VO`等对象和方法. 11 | 2. 可视化界面,将入参自动封装到可执行的脚本上,支持所有关系性数据库SQL执行语句,非关系型`MONGODB`查询语句. 12 | 3. 完全基于springboot2.x 作为springboot项目的stater方式集成,无侵入性,新老项目都能快速集成 13 | 4. 只需编写一行代码即可完成大部分的业务需求开发,使用难度级别(测试 or 运维)也可参与开发 14 | 5. 在线动态编译,无需重启,即时生效,多数据源操作 15 | 6. 版本控制,历史记录比对,回滚等功能 16 | 7. 远程一键发布到线上环境 17 | 8. 线上POSTMAN调试,保存POSTMAN信息或三方文档的自动生成,历史调用记录存储,回塑 18 | 9. 代码提示,SQL提示,语法提示 19 | 10. 用户管理控制,安全性控制,以及历史行为记录 20 | 11. 动态数据源管理,2.3.0.RELEASE 新增功能 21 | 12. 经过多次项目验证,传统业务型开发,服务端效率能够提升3-5倍,前后端联调提升效率1倍,测试效率2倍提升 22 | 23 | ### 工作原理 24 | 1.将API信息,请求方式,请求PATH,处理逻辑存储于数据库中,调用springboot提供的RequestMappingHandlerMapping.registerMapping/unregisterMapping 实现动态管理RequestMapping。 25 | 2.依赖于java1.8提供的ScriptEngineManager方法,调用Groovy引擎,赋于数据处理能力以及使代码逻辑能够实现动态编译,发布,而不用重启 26 | 3.以springboot starter形式,集成在业务项目中 27 | 28 | 29 | ### 资源地址 30 | 31 | >在线演示:http://39.98.181.90:8081/interface-ui?id=5f433b40f8b91c43f8835d3c&page=editor 32 | 33 | >代码仓库:https://gitee.com/alenfive/rocket-api 34 | 35 | >文档地址: https://alenfive.gitbook.io/rocket-api/ 36 | 37 | >一分钟系列: https://blog.csdn.net/maple_son/article/details/108196584 38 | 39 | ### 项目预览 40 | ![输入图片说明](https://images.gitee.com/uploads/images/2020/0922/162539_b59a4464_5139840.png "屏幕截图.png") 41 | ![输入图片说明](https://images.gitee.com/uploads/images/2020/0922/162711_70f6adb8_5139840.png "屏幕截图.png") 42 | 43 | 44 | ### 相关开源 45 | 46 | > Dataway[ https://www.hasor.net/doc/display/dataway ]( https://www.hasor.net/doc/display/dataway ) 47 | 48 | > Magic-API [https://ssssssss.org/guide/intro.html](https://ssssssss.org/guide/intro.html) 49 | 50 | > Rocket-API-Platform [https://gitee.com/alenfive/rocket-api-platform ](https://gitee.com/alenfive/rocket-api-platform ) 51 | 52 | > APIjson [http://apijson.org/](http://apijson.org/) 53 | 54 | > Graphql [https://graphql.cn/](https://graphql.cn/) 55 | 56 | ### 问题反馈 57 | 微信号: freedom-Union 58 | 邮件交流: kobe96688@126.com 59 | 报告issue: https://github.com/alenfive/rocket-api/issues 60 | ![输入图片说明](https://images.gitee.com/uploads/images/2020/0915/183440_93549b7f_5139840.png "屏幕截图.png") 61 | 62 | ### 一分钟快速项目集成 63 | https://alenfive.gitbook.io/rocket-api/fast-start 64 | 65 | ### FAQ 66 | https://alenfive.gitbook.io/rocket-api/faq 67 | 68 | ## 来都来了,不点亮个星(Star)? 69 | 70 | 71 | ## Known Users 72 | 如果您在使用Rocket-API,请让我们知道,您的使用对我们非常重要:https://gitee.com/alenfive/rocket-api/issues/I23ZE9 (按登记顺序排列) 73 | 74 | 75 | ![输入图片说明](https://images.gitee.com/uploads/images/2020/1126/111619_404464b7_5139840.png "屏幕截图.png") 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/RocketAPIApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RocketAPIApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(RocketAPIApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/annotation/ApiId.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.FIELD) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface ApiId { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/annotation/ApiTable.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface ApiTable { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/annotation/ApiUpdateField.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.annotation; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.FIELD) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface ApiUpdateField { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/DefaultDataSourceManager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.DataSourceManager; 5 | import com.github.alenfive.rocketapi.datasource.MongoDataSource; 6 | import com.github.alenfive.rocketapi.datasource.MySQLDataSource; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.mongodb.core.MongoTemplate; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.annotation.PostConstruct; 12 | import javax.sql.DataSource; 13 | import java.util.LinkedHashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * 默认数据源管理器 18 | */ 19 | @Component 20 | public class DefaultDataSourceManager extends DataSourceManager { 21 | 22 | @Autowired 23 | private DataSource dataSource; 24 | 25 | @Autowired 26 | private MongoTemplate mongoTemplate; 27 | 28 | @PostConstruct 29 | public void init() { 30 | Map dialectMap = new LinkedHashMap<>(); 31 | dialectMap.put("mysql",new MySQLDataSource(dataSource,true)); 32 | dialectMap.put("mongodb",new MongoDataSource(mongoTemplate)); 33 | super.setDialectMap(dialectMap); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/RedisClusterNotifyConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import com.github.alenfive.rocketapi.extend.IClusterNotify; 4 | import com.github.alenfive.rocketapi.extend.RedisClusterNotify; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.listener.PatternTopic; 10 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; 11 | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; 12 | 13 | @Configuration 14 | @ConditionalOnProperty(value = "spring.rocket-api.cluster-type",havingValue = "redis") 15 | public class RedisClusterNotifyConfig { 16 | 17 | @Bean 18 | public IClusterNotify getClusterNotify(){ 19 | return new RedisClusterNotify(); 20 | } 21 | 22 | @Bean 23 | public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, 24 | MessageListenerAdapter listenerAdapter, 25 | RedisClusterNotify clusterNotify) { 26 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 27 | container.setConnectionFactory(connectionFactory); 28 | String channelName = clusterNotify.buildChannelName(); 29 | container.addMessageListener(listenerAdapter, new PatternTopic(channelName)); 30 | return container; 31 | } 32 | 33 | @Bean 34 | public MessageListenerAdapter listenerAdapter(RedisClusterNotify clusterNotify) { 35 | return new MessageListenerAdapter(clusterNotify, "onMessage"); 36 | } 37 | 38 | 39 | } -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/RefreshApiConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.cloud.context.refresh.ContextRefresher; 5 | 6 | /** 7 | * 配置bean 刷新 8 | */ 9 | 10 | public class RefreshApiConfig { 11 | 12 | @Autowired 13 | private ContextRefresher contextRefresher; 14 | 15 | public void refresh(){ 16 | contextRefresher.refresh(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/RocketApiProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.ClusterType; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | 9 | /** 10 | * 配置属性 11 | */ 12 | @ConfigurationProperties(prefix = "spring.rocket-api") 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class RocketApiProperties { 17 | 18 | /** 19 | * 系统名称 20 | */ 21 | private String serviceTitle = "Rocket API"; 22 | /** 23 | * 服务名称 24 | * 所有数据以此作隔离 25 | */ 26 | private String serviceName = "rocket-api"; 27 | 28 | /** 29 | * 基础注册路径 30 | */ 31 | private String baseRegisterPath = "/interface-ui"; 32 | 33 | /** 34 | * 密钥KEY 35 | */ 36 | private String secretKey = "123456789"; 37 | 38 | /** 39 | * post传参 操作整个body部分的key值 40 | * 在脚本中执行return bodyRoot;将返回整个body对象 41 | */ 42 | private String bodyRootKey = "bodyRoot"; 43 | 44 | /** 45 | * 启用编辑管理界面,默认true,生产环境如果访问地址暴露在了外网,建议关闭 46 | */ 47 | private boolean viewEnabled = true; 48 | 49 | /** 50 | * 驼峰自动转换配置,默认true 51 | */ 52 | private boolean mapUnderscoreToCamelCase = true; 53 | 54 | /** 55 | * 启用远程发布入口,默认true,生产环境如果访问地址暴露在了外网,建议关闭 56 | * 当为false时,不接收远程发布过来的API更新或者新增 57 | * 当为true时,配合secretKey使用,来达到安全远程部署的目的 58 | */ 59 | private boolean syncEnabled = true; 60 | 61 | /** 62 | * 启用YML配置,默认false 63 | */ 64 | private boolean configEnabled = false; 65 | 66 | /** 67 | * 集群类型 68 | * ClusterType.None 默认值,默认为单例 69 | * ClusterType.Redis 以Redis模式实现集群共享, 70 | */ 71 | private ClusterType clusterType = ClusterType.None; 72 | 73 | /** 74 | * 表名称自定义 75 | * 用于自定义Rocket-API表名称时使用 76 | */ 77 | private ApiTableName tableName = new ApiTableName(); 78 | 79 | @Data 80 | public static class ApiTableName{ 81 | private String api_config = "api_config"; 82 | private String api_directory = "api_directory"; 83 | private String api_example = "api_example"; 84 | private String api_info = "api_info"; 85 | private String api_info_history = "api_info_history"; 86 | 87 | } 88 | 89 | /** 90 | * 纯SQL模式下,通过脚本能自动识别增删改查数据库行为,但查询又分为分页,计数,返回一条,和列表,四种不种的返回格式 91 | * 这四种行为将通过url后缀形式来识别,配置如下: 92 | * 未定义的将返回列表结构 93 | */ 94 | private ApiSqlModel sqlModel = new ApiSqlModel(); 95 | 96 | @Data 97 | public static class ApiSqlModel{ 98 | /** 99 | * 分页查询,api将返回分页查询 100 | */ 101 | private String pagerSuffix = "/page"; 102 | /** 103 | * 计数查询,api将返回数量 104 | */ 105 | private String countSuffix = "/count"; 106 | /** 107 | * 返回首条,api将返回列表中的第一条记录 108 | */ 109 | private String findOneSuffix = "/first"; 110 | 111 | /** 112 | * 其他返回list,所有查询结果 113 | */ 114 | } 115 | 116 | /** 117 | * 分页参数配置 118 | */ 119 | private Pager pager = new Pager(); 120 | 121 | @Data 122 | public static class Pager{ 123 | /** 124 | * 每页大小变量名 125 | */ 126 | private String pageSizeVarName = "pageSize"; 127 | /** 128 | * 第几页变量名 129 | */ 130 | private String pageNoVarName = "pageNo"; 131 | /** 132 | * limit offset变量名 133 | */ 134 | private String offsetVarName = "offset"; 135 | 136 | /** 137 | * 分页list查询结果变量名 138 | */ 139 | private String dataVarName = "data"; 140 | 141 | /** 142 | * 分页count查询结果变量名 143 | */ 144 | private String totalRecordsVarName = "totalRecords"; 145 | 146 | /** 147 | * 总页数变量名 148 | */ 149 | private String totalPagesVarName = "totalPages"; 150 | 151 | /** 152 | * 默认每页大小 153 | */ 154 | private Integer defaultPageSizeValue = 15; 155 | /** 156 | * 默认第几页 157 | */ 158 | private Integer defaultPageNoValue = 1; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/SpringContextUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import org.springframework.context.ApplicationContext; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class SpringContextUtils { 8 | 9 | private static ApplicationContext applicationContext; 10 | 11 | public SpringContextUtils(ApplicationContext applicationContext){ 12 | SpringContextUtils.applicationContext = applicationContext; 13 | } 14 | 15 | public static ApplicationContext getApplicationContext() { 16 | return applicationContext; 17 | } 18 | 19 | public ApplicationContext getContext(){ 20 | return SpringContextUtils.applicationContext; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/config/SysApiPager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.config; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import com.github.alenfive.rocketapi.entity.ApiParams; 5 | import com.github.alenfive.rocketapi.extend.IApiPager; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 系统分页数据构建器 13 | */ 14 | public class SysApiPager implements IApiPager { 15 | 16 | 17 | @Override 18 | public Object buildPager(Long totalRecords, List data, ApiInfo apiInfo, ApiParams apiParams) { 19 | Map pager = new HashMap<>(); 20 | pager.put("totalRecords",totalRecords); 21 | pager.put("data",data); 22 | return pager; 23 | } 24 | 25 | @Override 26 | public String getPageSizeVarName() { 27 | return "pageSize"; 28 | } 29 | 30 | @Override 31 | public String getPageNoVarName() { 32 | return "pageNo"; 33 | } 34 | 35 | @Override 36 | public String getOffsetVarName() { 37 | return "index"; 38 | } 39 | 40 | @Override 41 | public Integer getOffset(Integer pageSize, Integer pageNo) { 42 | return (pageNo-1)*pageSize; 43 | } 44 | 45 | @Override 46 | public Integer getPageNo() { 47 | return null; 48 | } 49 | 50 | @Override 51 | public Integer getPageSize() { 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/controller/RemoteController.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.controller; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.github.alenfive.rocketapi.config.QLRequestMappingFactory; 5 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 6 | import com.github.alenfive.rocketapi.entity.ApiResult; 7 | import com.github.alenfive.rocketapi.entity.vo.AcceptApiInfoSyncReq; 8 | import com.github.alenfive.rocketapi.service.ApiInfoService; 9 | import com.github.alenfive.rocketapi.utils.SignUtils; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.util.StringUtils; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RequestBody; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | /** 22 | * 远程操作 23 | */ 24 | @Slf4j 25 | @RestController 26 | @RequestMapping("${spring.rocket-api.base-register-path:/interface-ui}") 27 | public class RemoteController { 28 | 29 | @Autowired 30 | private QLRequestMappingFactory mappingFactory; 31 | 32 | @Autowired 33 | private ObjectMapper objectMapper; 34 | 35 | @Autowired 36 | private RocketApiProperties rocketApiProperties; 37 | 38 | @Autowired 39 | private ApiInfoService apiInfoService; 40 | 41 | /** 42 | * 接收远程同步过来的API INFO信息 43 | * @param syncReq 44 | */ 45 | @PostMapping("/accept-sync") 46 | public ApiResult apiInfoSync(@RequestBody AcceptApiInfoSyncReq syncReq) throws Exception { 47 | if (syncReq == null 48 | || StringUtils.isEmpty(syncReq.getSign()) 49 | || syncReq.getApiInfos() == null 50 | || syncReq.getTimestamp() == null 51 | || syncReq.getIncrement() == null){ 52 | return ApiResult.fail("Parameter is missing"); 53 | } 54 | 55 | if (!rocketApiProperties.isSyncEnabled()){ 56 | return ApiResult.fail("Accept Sync already Disabled"); 57 | } 58 | 59 | //签名验证 60 | Map signMap = new HashMap<>(); 61 | signMap.put("timestamp",syncReq.getTimestamp()); 62 | signMap.put("increment",syncReq.getIncrement()); 63 | signMap.put("apiInfos",objectMapper.writeValueAsString(syncReq.getApiInfos())); 64 | signMap.put("directories",objectMapper.writeValueAsString(syncReq.getDirectories())); 65 | String sign = SignUtils.build(rocketApiProperties.getSecretKey(),signMap); 66 | if (!syncReq.getSign().equals(sign)){ 67 | return ApiResult.fail("Signature abnormal"); 68 | } 69 | try { 70 | Object result = apiInfoService.apiInfoSync(syncReq.getDirectories(),syncReq.getApiInfos(),syncReq.getIncrement() == 1); 71 | 72 | //刷新缓存 73 | apiInfoService.reLoadApiInfo(false); 74 | 75 | return ApiResult.success(result); 76 | }catch (Exception e){ 77 | e.printStackTrace(); 78 | return ApiResult.fail(e.getMessage()); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/controller/ViewController.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.controller; 2 | 3 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 4 | import com.github.alenfive.rocketapi.datasource.DataSourceManager; 5 | import com.github.alenfive.rocketapi.utils.PackageUtils; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.ui.Model; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | 15 | /** 16 | * Api ui 页面显示 17 | */ 18 | @Controller 19 | @RequestMapping("${spring.rocket-api.base-register-path:/interface-ui}") 20 | @ConditionalOnProperty(name = "spring.rocket-api.view-enabled",havingValue = "true",matchIfMissing = true) 21 | public class ViewController { 22 | 23 | @Autowired 24 | private DataSourceManager dataSourceManager; 25 | 26 | @Autowired 27 | private RocketApiProperties rocketApiProperties; 28 | 29 | @GetMapping 30 | public String index(Model model, HttpServletRequest request){ 31 | model.addAttribute("dataSourceList",dataSourceManager.getDialectMap().keySet()); 32 | model.addAttribute("service", rocketApiProperties.getServiceName()); 33 | model.addAttribute("title", rocketApiProperties.getServiceTitle()); 34 | model.addAttribute("configEnabled", rocketApiProperties.isConfigEnabled()); 35 | model.addAttribute("version", PackageUtils.getVersion()); 36 | if (request.getRequestURI().endsWith("/")){ 37 | return "redirect:"+ rocketApiProperties.getBaseRegisterPath(); 38 | } 39 | return "rocketapi/api-index"; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/ClickHouseDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiEntity; 4 | import com.github.alenfive.rocketapi.entity.vo.Page; 5 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 6 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 7 | import com.github.alenfive.rocketapi.extend.IApiPager; 8 | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 9 | import org.springframework.jdbc.support.GeneratedKeyHolder; 10 | import org.springframework.jdbc.support.KeyHolder; 11 | 12 | import javax.sql.DataSource; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * mongodb 数据源操作 19 | */ 20 | public class ClickHouseDataSource extends JdbcDataSource { 21 | 22 | public ClickHouseDataSource(DataSource dataSource) { 23 | super(dataSource); 24 | } 25 | 26 | @Override 27 | public void saveEntity(T entity) { 28 | 29 | } 30 | 31 | @Override 32 | public T findEntityById(T entity) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public void removeEntityById(T entity) { 38 | 39 | } 40 | 41 | @Override 42 | public void updateEntityById(T entity) { 43 | 44 | } 45 | 46 | @Override 47 | public List listByEntity(T entity) { 48 | return null; 49 | } 50 | 51 | @Override 52 | public List pageByEntity(T entity, IApiPager apiPager, Page page) { 53 | return null; 54 | } 55 | 56 | @Override 57 | public List> find(ScriptContext scriptContext) { 58 | List> resultList = jdbcTemplate.queryForList(scriptContext.getScript().toString(), scriptContext.getParams()[0]); 59 | return resultList.stream().map(this::toReplaceKeyLow).collect(Collectors.toList()); 60 | } 61 | 62 | @Override 63 | public int update(ScriptContext scriptContext) { 64 | throw new UnsupportedOperationException("The operation is not allowed"); 65 | } 66 | 67 | @Override 68 | public int remove(ScriptContext scriptContext) { 69 | throw new UnsupportedOperationException("The operation is not allowed"); 70 | } 71 | 72 | @Override 73 | public Object insert(ScriptContext scriptContext) { 74 | KeyHolder keyHolder = new GeneratedKeyHolder(); 75 | jdbcTemplate.update(scriptContext.getScript().toString(), new MapSqlParameterSource(scriptContext.getParams()[0]), keyHolder); 76 | return keyHolder.getKeyList().stream().map(item->item.get("GENERATED_KEY")).collect(Collectors.toList()); 77 | } 78 | 79 | @Override 80 | public String buildCountScript(String script,IApiPager apiPager,Page page) { 81 | return script; 82 | } 83 | 84 | @Override 85 | public String buildPageScript(String script,IApiPager apiPager,Page page) { 86 | return script; 87 | } 88 | 89 | @Override 90 | public String transcoding(String param) { 91 | return param 92 | .replace("\'","\\\'"); 93 | } 94 | 95 | @Override 96 | public List buildTableInfo() { 97 | return null; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/DB2DataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.Page; 4 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 5 | import com.github.alenfive.rocketapi.extend.IApiPager; 6 | 7 | import javax.sql.DataSource; 8 | import java.util.List; 9 | 10 | /** 11 | * db2 数据源 12 | */ 13 | public class DB2DataSource extends JdbcDataSource { 14 | 15 | public DB2DataSource(DataSource dataSource) { 16 | super(dataSource); 17 | } 18 | 19 | public DB2DataSource(DataSource dataSource, boolean storeApi) { 20 | super(dataSource,storeApi); 21 | } 22 | 23 | @Override 24 | public String buildCountScript(String script, IApiPager apiPager, Page page) { 25 | return "select count(1) from ("+script+") t1"; 26 | } 27 | 28 | @Override 29 | public String buildPageScript(String script, IApiPager apiPager, Page page) { 30 | Integer offset = apiPager.getOffset(page.getPageSize(),page.getPageNo()); 31 | return "SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS ROW_ID FROM ( " + script + 32 | " ) AS TMP_PAGE) TMP_PAGE WHERE ROW_ID BETWEEN "+(offset+1)+" AND "+(offset + page.getPageSize()); 33 | } 34 | 35 | @Override 36 | public List buildTableInfo() { 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/DataSourceDialect.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 4 | import com.github.alenfive.rocketapi.config.SpringContextUtils; 5 | import com.github.alenfive.rocketapi.entity.ApiEntity; 6 | import com.github.alenfive.rocketapi.entity.vo.Page; 7 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 8 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 9 | import com.github.alenfive.rocketapi.extend.IApiPager; 10 | import com.github.alenfive.rocketapi.utils.FieldUtils; 11 | 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | /** 17 | * 数据源方言抽象类 18 | */ 19 | public abstract class DataSourceDialect { 20 | 21 | private boolean isDynamic = false; 22 | 23 | protected boolean storeApi = false; 24 | 25 | public boolean isStoreApi() { 26 | return storeApi; 27 | } 28 | 29 | public boolean isDynamic() { 30 | return isDynamic; 31 | } 32 | 33 | public void setDynamic(boolean dynamic) { 34 | isDynamic = dynamic; 35 | } 36 | 37 | public abstract void saveEntity( T entity); 38 | public abstract T findEntityById( T entity); 39 | public abstract void removeEntityById(T entity); 40 | public abstract void updateEntityById(T entity); 41 | public abstract List listByEntity(T entity); 42 | public abstract List pageByEntity(T entity, IApiPager apiPager, Page page); 43 | 44 | //查询对象 45 | public abstract List> find(ScriptContext scriptContext) throws Exception; 46 | 47 | //返回影响的行数 48 | public abstract int update(ScriptContext scriptContext) throws Exception; 49 | 50 | //返回执行状态 51 | public abstract int[] batchUpdate(ScriptContext scriptContext) throws Exception; 52 | 53 | //返回影响的行数 54 | public abstract int remove(ScriptContext scriptContext) throws Exception; 55 | 56 | //返回主键 57 | public abstract Object insert(ScriptContext scriptContext) throws Exception; 58 | 59 | /** 60 | * 替换key 61 | */ 62 | protected Map toReplaceKeyLow(Map map){ 63 | RocketApiProperties properties = SpringContextUtils.getApplicationContext().getBean(RocketApiProperties.class); 64 | if (!properties.isMapUnderscoreToCamelCase()){ 65 | return map; 66 | } 67 | Map result = new HashMap<>(map.size()); 68 | for(String key : map.keySet()){ 69 | result.put(FieldUtils.underlineToCamel(key),map.get(key)); 70 | } 71 | return result; 72 | } 73 | 74 | public abstract String buildCountScript(String script, IApiPager apiPager, Page page); 75 | 76 | public abstract String buildPageScript(String script, IApiPager apiPager, Page page); 77 | 78 | //入参转码 79 | public abstract String transcoding(String param); 80 | public abstract List buildTableInfo(); 81 | public abstract void close(); 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/DataSourceManager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 4 | import com.github.alenfive.rocketapi.service.ScriptParseService; 5 | import org.springframework.util.StringUtils; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 数据源管理器代理类,实现指定数据源操作的路由 13 | */ 14 | public abstract class DataSourceManager { 15 | 16 | private Map dialectMap; 17 | 18 | private ScriptParseService parseService; 19 | 20 | private DataSourceDialect storeApiDataSource; 21 | 22 | public void setParseService(ScriptParseService parseService) { 23 | this.parseService = parseService; 24 | } 25 | 26 | /** 27 | * 获取api存储的数据源 28 | * @return 29 | */ 30 | public DataSourceDialect getStoreApiDataSource(){ 31 | return storeApiDataSource; 32 | } 33 | 34 | public Map getDialectMap() { 35 | return dialectMap; 36 | } 37 | 38 | public void setDialectMap(Map dialectMap) { 39 | String storeApiName = dialectMap.keySet().stream().filter(key->dialectMap.get(key).isStoreApi()).findFirst().orElseThrow(()->new IllegalArgumentException("storeApi is not found")); 40 | this.storeApiDataSource = dialectMap.get(storeApiName); 41 | this.dialectMap = dialectMap; 42 | } 43 | 44 | public ScriptContext buildScriptContext(StringBuilder script, DataSourceDialect dataSourceDialect, Map params){ 45 | return ScriptContext.builder() 46 | .script(script) 47 | .dataSourceDialect(dataSourceDialect) 48 | .params(new Map[]{parseService.parse(script,dataSourceDialect,params)}) 49 | .build(); 50 | } 51 | 52 | /** 53 | * 批量脚本构建,要求: 54 | * 1. 仅支持jdbc数据源 55 | * 2. 要求变量名以":varname" 形式定义 56 | * @param script 57 | * @param dataSourceDialect 58 | * @param params 59 | * @return 60 | */ 61 | public ScriptContext buildScriptContext(StringBuilder script, DataSourceDialect dataSourceDialect, List> params){ 62 | if (!(dataSourceDialect instanceof JdbcDataSource)){ 63 | throw new UnsupportedOperationException("Only JDBC data sources are supported"); 64 | } 65 | return ScriptContext.builder() 66 | .script(script) 67 | .dataSourceDialect(dataSourceDialect) 68 | .params(params.toArray(new HashMap[params.size()])) 69 | .build(); 70 | } 71 | 72 | public DataSourceDialect getDataSourceDialect(String datasource, String specifyDataSource){ 73 | String dataSourceKey = StringUtils.isEmpty(specifyDataSource)?datasource:specifyDataSource; 74 | DataSourceDialect dataSourceDialect = this.dialectMap.get(dataSourceKey); 75 | if (dataSourceDialect == null){ 76 | throw new IllegalArgumentException("unknown datasource `"+dataSourceKey+"`"); 77 | } 78 | 79 | return dataSourceDialect; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/DialectTransactionManager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import org.springframework.transaction.PlatformTransactionManager; 4 | 5 | public interface DialectTransactionManager { 6 | public PlatformTransactionManager getTransactionManager(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/JdbcDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiEntity; 4 | import com.github.alenfive.rocketapi.entity.vo.Page; 5 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 6 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 7 | import com.github.alenfive.rocketapi.extend.IApiPager; 8 | import com.github.alenfive.rocketapi.utils.ApiJpaUtil; 9 | import com.github.alenfive.rocketapi.utils.DataSourceUtils; 10 | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 11 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 12 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 13 | import org.springframework.jdbc.support.GeneratedKeyHolder; 14 | import org.springframework.jdbc.support.KeyHolder; 15 | import org.springframework.transaction.PlatformTransactionManager; 16 | 17 | import javax.sql.DataSource; 18 | import java.util.List; 19 | import java.util.Map; 20 | import java.util.stream.Collectors; 21 | 22 | /** 23 | * 关系型数据源,JdbcTemplate所操作的数据源 24 | */ 25 | public class JdbcDataSource extends DataSourceDialect implements DialectTransactionManager { 26 | 27 | protected DataSource dataSource; 28 | 29 | protected NamedParameterJdbcTemplate jdbcTemplate; 30 | 31 | protected PlatformTransactionManager transactionManager; 32 | 33 | private JdbcDataSource(){} 34 | 35 | public JdbcDataSource(DataSource dataSource) { 36 | this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); 37 | this.transactionManager = new DataSourceTransactionManager(dataSource); 38 | this.dataSource = dataSource; 39 | } 40 | 41 | public JdbcDataSource(DataSource dataSource, boolean storeApi) { 42 | this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); 43 | this.transactionManager = new DataSourceTransactionManager(dataSource); 44 | this.dataSource = dataSource; 45 | this.storeApi = storeApi; 46 | } 47 | 48 | @Override 49 | public PlatformTransactionManager getTransactionManager() { 50 | return transactionManager; 51 | } 52 | 53 | public NamedParameterJdbcTemplate getJdbcTemplate(){ 54 | return this.jdbcTemplate; 55 | } 56 | 57 | 58 | @Override 59 | public void saveEntity(T entity) { 60 | ApiJpaUtil.insert(jdbcTemplate,entity); 61 | } 62 | 63 | @Override 64 | public T findEntityById(T entity) { 65 | return ApiJpaUtil.findById(jdbcTemplate,entity); 66 | } 67 | 68 | @Override 69 | public void removeEntityById(T entity) { 70 | ApiJpaUtil.deleteById(jdbcTemplate,entity); 71 | } 72 | 73 | @Override 74 | public void updateEntityById(T entity) { 75 | ApiJpaUtil.updateById(jdbcTemplate,entity); 76 | } 77 | 78 | @Override 79 | public List listByEntity(T entity) { 80 | return ApiJpaUtil.listByEntity(jdbcTemplate,entity); 81 | } 82 | 83 | @Override 84 | public List pageByEntity(T entity, IApiPager apiPager, Page page) { 85 | return ApiJpaUtil.pageByEntity(jdbcTemplate,entity,this,apiPager,page); 86 | } 87 | 88 | @Override 89 | public List> find(ScriptContext scriptContext) { 90 | List> resultList = jdbcTemplate.queryForList(scriptContext.getScript().toString(), scriptContext.getParams()[0]); 91 | return resultList.stream().map(this::toReplaceKeyLow).collect(Collectors.toList()); 92 | } 93 | 94 | @Override 95 | public int update(ScriptContext scriptContext) { 96 | return jdbcTemplate.update(scriptContext.getScript().toString(), scriptContext.getParams()[0]); 97 | } 98 | 99 | @Override 100 | public int[] batchUpdate(ScriptContext scriptContext) throws Exception { 101 | return jdbcTemplate.batchUpdate(scriptContext.getScript().toString(),scriptContext.getParams()); 102 | } 103 | 104 | @Override 105 | public int remove(ScriptContext scriptContext) { 106 | return jdbcTemplate.update(scriptContext.getScript().toString(), scriptContext.getParams()[0]); 107 | } 108 | 109 | @Override 110 | public Object insert(ScriptContext scriptContext) { 111 | KeyHolder keyHolder = new GeneratedKeyHolder(); 112 | jdbcTemplate.update(scriptContext.getScript().toString(), new MapSqlParameterSource(scriptContext.getParams()[0]), keyHolder); 113 | return keyHolder.getKeyList().stream().map(item->item.get("GENERATED_KEY")).collect(Collectors.toList()); 114 | } 115 | 116 | @Override 117 | public String buildCountScript(String script, IApiPager apiPager, Page page){ 118 | return script; 119 | } 120 | 121 | @Override 122 | public String buildPageScript(String script, IApiPager apiPager, Page page){ 123 | return script; 124 | } 125 | 126 | @Override 127 | public String transcoding(String param) { 128 | return param 129 | .replace("\'","\\\'"); 130 | } 131 | 132 | @Override 133 | public List buildTableInfo() { 134 | return null; 135 | } 136 | 137 | @Override 138 | public void close() { 139 | DataSourceUtils.closeDataSource(dataSource); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/MySQLDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.FieldInfo; 4 | import com.github.alenfive.rocketapi.entity.vo.Page; 5 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 6 | import com.github.alenfive.rocketapi.extend.IApiPager; 7 | import com.github.alenfive.rocketapi.utils.SqlUtils; 8 | 9 | import javax.sql.DataSource; 10 | import java.util.*; 11 | 12 | /** 13 | * mysql 数据源 14 | */ 15 | public class MySQLDataSource extends JdbcDataSource { 16 | 17 | 18 | public MySQLDataSource(DataSource dataSource) { 19 | super(dataSource); 20 | } 21 | 22 | public MySQLDataSource(DataSource dataSource, boolean storeApi) { 23 | super(dataSource, storeApi); 24 | } 25 | 26 | @Override 27 | public String buildCountScript(String script, IApiPager apiPager, Page page) { 28 | return "select count(1) from ("+script+") t1"; 29 | } 30 | 31 | @Override 32 | public String buildPageScript(String script, IApiPager apiPager, Page page) { 33 | Integer offset = apiPager.getOffset(page.getPageSize(),page.getPageNo()); 34 | return script + " limit "+offset+","+page.getPageSize(); 35 | } 36 | 37 | @Override 38 | public String transcoding(String param) { 39 | return param 40 | .replace("\\","\\\\") 41 | .replace("\"","\\\"") 42 | .replace("\'","\\\'"); 43 | } 44 | 45 | @Override 46 | public List buildTableInfo(){ 47 | try { 48 | List tableInfos = new ArrayList<>(); 49 | List> tables = jdbcTemplate.queryForList("show tables",Collections.EMPTY_MAP); 50 | for (Map table : tables){ 51 | Set keys = table.keySet(); 52 | String tableName = table.get(keys.toArray(new String[]{})[0]).toString(); 53 | Map fields = jdbcTemplate.queryForMap("show create table "+tableName,Collections.EMPTY_MAP); 54 | 55 | //只处理逻辑表 56 | if (fields.get("Create Table") == null){ 57 | continue; 58 | } 59 | String tableInfo = fields.get("Create Table").toString(); 60 | String tableComment = SqlUtils.getByPattern(tableInfo, "\\) .* COMMENT='(.*)'", 1); 61 | List fieldInfos = new ArrayList<>(); 62 | tableInfos.add(TableInfo.builder() 63 | .name(tableName) 64 | .comment(tableComment) 65 | .fields(fieldInfos) 66 | .build()); 67 | List fieldStrList = SqlUtils.getColumnSqls(tableInfo); 68 | for (String oneLine : fieldStrList) { 69 | String fieldName = SqlUtils.getByPattern(oneLine, "`(.*)`", 1); 70 | String fieldComment = SqlUtils.getByPattern(oneLine, "COMMENT '(.*)'", 1); 71 | String fieldType = SqlUtils.getByPattern(oneLine, "`" + fieldName + "` ([A-Za-z]*)", 1); 72 | fieldInfos.add(FieldInfo.builder() 73 | .name(fieldName) 74 | .comment(fieldComment) 75 | .type(fieldType) 76 | .build()); 77 | } 78 | } 79 | return tableInfos; 80 | }catch (Exception e){ 81 | e.printStackTrace(); 82 | } 83 | return Collections.emptyList(); 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/OracleDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.Page; 4 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 5 | import com.github.alenfive.rocketapi.extend.IApiPager; 6 | 7 | import javax.sql.DataSource; 8 | import java.util.List; 9 | 10 | /** 11 | * oracle 数据源 12 | */ 13 | public class OracleDataSource extends JdbcDataSource { 14 | 15 | 16 | public OracleDataSource(DataSource dataSource) { 17 | super(dataSource); 18 | } 19 | 20 | public OracleDataSource(DataSource dataSource, boolean storeApi) { 21 | super(dataSource, storeApi); 22 | } 23 | 24 | @Override 25 | public String buildCountScript(String script, IApiPager apiPager, Page page) { 26 | return "select count(1) from ("+script+") t1"; 27 | } 28 | 29 | @Override 30 | public String buildPageScript(String script,IApiPager apiPager, Page page) { 31 | Integer offset = apiPager.getOffset(page.getPageSize(),page.getPageNo()); 32 | Integer endIndex = offset + page.getPageSize(); 33 | return "SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( " + 34 | script + " ) TMP WHERE ROWNUM <= "+endIndex+" ) WHERE ROW_ID > "+offset; 35 | } 36 | 37 | @Override 38 | public String transcoding(String param) { 39 | return param 40 | .replace("'", "''"); 41 | } 42 | 43 | @Override 44 | public List buildTableInfo() { 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/PostgreSQLDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.Page; 4 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 5 | import com.github.alenfive.rocketapi.extend.IApiPager; 6 | 7 | import javax.sql.DataSource; 8 | import java.util.List; 9 | 10 | /** 11 | * PostgreSQL 数据源 12 | */ 13 | public class PostgreSQLDataSource extends JdbcDataSource { 14 | 15 | public PostgreSQLDataSource(DataSource dataSource) { 16 | super(dataSource); 17 | } 18 | 19 | public PostgreSQLDataSource(DataSource dataSource, boolean storeApi) { 20 | super(dataSource, storeApi); 21 | } 22 | 23 | @Override 24 | public String buildCountScript(String script, IApiPager apiPager, Page page) { 25 | return "select count(1) from ("+script+") t1"; 26 | } 27 | 28 | @Override 29 | public String buildPageScript(String script, IApiPager apiPager, Page page) { 30 | Integer offset = apiPager.getOffset(page.getPageSize(),page.getPageNo()); 31 | return script + " limit "+page.getPageSize()+" offset "+offset; 32 | } 33 | 34 | @Override 35 | public String transcoding(String param) { 36 | return param 37 | .replace("'","''"); 38 | } 39 | 40 | @Override 41 | public List buildTableInfo() { 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/PrestoDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiEntity; 4 | import com.github.alenfive.rocketapi.entity.vo.Page; 5 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 6 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 7 | import com.github.alenfive.rocketapi.extend.IApiPager; 8 | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 9 | import org.springframework.jdbc.support.GeneratedKeyHolder; 10 | import org.springframework.jdbc.support.KeyHolder; 11 | 12 | import javax.sql.DataSource; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.stream.Collectors; 16 | 17 | /** 18 | * presto 数据源操作 19 | */ 20 | public class PrestoDataSource extends JdbcDataSource { 21 | 22 | public PrestoDataSource(DataSource dataSource) { 23 | super(dataSource); 24 | } 25 | 26 | @Override 27 | public void saveEntity(T entity) { 28 | 29 | } 30 | 31 | @Override 32 | public T findEntityById(T entity) { 33 | return null; 34 | } 35 | 36 | @Override 37 | public void removeEntityById(T entity) { 38 | 39 | } 40 | 41 | @Override 42 | public void updateEntityById(T entity) { 43 | 44 | } 45 | 46 | @Override 47 | public List listByEntity(T entity) { 48 | return null; 49 | } 50 | 51 | @Override 52 | public List pageByEntity(T entity, IApiPager apiPager, Page page) { 53 | return null; 54 | } 55 | 56 | @Override 57 | public List> find(ScriptContext scriptContext) { 58 | List> resultList = jdbcTemplate.queryForList(scriptContext.getScript().toString(), scriptContext.getParams()[0]); 59 | return resultList.stream().map(this::toReplaceKeyLow).collect(Collectors.toList()); 60 | } 61 | 62 | @Override 63 | public int update(ScriptContext scriptContext) { 64 | throw new UnsupportedOperationException("The operation is not allowed"); 65 | } 66 | 67 | @Override 68 | public int remove(ScriptContext scriptContext) { 69 | throw new UnsupportedOperationException("The operation is not allowed"); 70 | } 71 | 72 | @Override 73 | public Object insert(ScriptContext scriptContext) { 74 | KeyHolder keyHolder = new GeneratedKeyHolder(); 75 | jdbcTemplate.update(scriptContext.getScript().toString(), new MapSqlParameterSource(scriptContext.getParams()[0]), keyHolder); 76 | return keyHolder.getKeyList().stream().map(item->item.get("GENERATED_KEY")).collect(Collectors.toList()); 77 | } 78 | 79 | @Override 80 | public String buildCountScript(String script,IApiPager apiPager,Page page) { 81 | return script; 82 | } 83 | 84 | @Override 85 | public String buildPageScript(String script,IApiPager apiPager,Page page) { 86 | return script; 87 | } 88 | 89 | @Override 90 | public String transcoding(String param) { 91 | return param 92 | .replace("\'","\\\'"); 93 | } 94 | 95 | @Override 96 | public List buildTableInfo() { 97 | return null; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/SQLServerDataSource.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.Page; 4 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 5 | import com.github.alenfive.rocketapi.extend.IApiPager; 6 | 7 | import javax.sql.DataSource; 8 | import java.util.List; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | /** 13 | * sql server 数据源 14 | */ 15 | public class SQLServerDataSource extends JdbcDataSource { 16 | 17 | Pattern pattern = Pattern.compile("(order +by .*)",Pattern.CASE_INSENSITIVE); 18 | 19 | public SQLServerDataSource(DataSource dataSource) { 20 | super(dataSource); 21 | } 22 | 23 | public SQLServerDataSource(DataSource dataSource, boolean storeApi) { 24 | super(dataSource, storeApi); 25 | } 26 | 27 | @Override 28 | public String buildCountScript(String script, IApiPager apiPager, Page page) { 29 | Matcher matcher = pattern.matcher(script); 30 | script = matcher.replaceAll(""); 31 | return "select count(1) from ("+script+") t1"; 32 | } 33 | 34 | @Override 35 | public String buildPageScript(String script, IApiPager apiPager, Page page) { 36 | Integer offset = apiPager.getOffset(page.getPageSize(),page.getPageNo()); 37 | return script + " OFFSET "+offset+" ROWS FETCH NEXT "+page.getPageSize()+" ROWS ONLY"; 38 | } 39 | 40 | @Override 41 | public String transcoding(String param) { 42 | return param 43 | .replace("'","''"); 44 | } 45 | 46 | @Override 47 | public List buildTableInfo() { 48 | return null; 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/ClickHouseDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.ClickHouseDataSource; 4 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * SQL 构造器 10 | */ 11 | @Component 12 | public class ClickHouseDriver extends JdbcDriver { 13 | 14 | @Override 15 | public String getName() { 16 | return "ClickHouse"; 17 | } 18 | 19 | @Override 20 | public String getIcon() { 21 | return "rocketapi/images/ClickHouse.png"; 22 | } 23 | 24 | @Override 25 | public String getFormat() { 26 | return "jdbc:clickhouse://localhost:8123"; 27 | } 28 | 29 | @Override 30 | public DataSourceDialect factory(DBConfig config) throws Exception { 31 | return new ClickHouseDataSource(super.getDataSource(config)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/IDataSourceDialectDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.entity.DBConfig; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * 10 | */ 11 | 12 | public abstract class IDataSourceDialectDriver implements Serializable { 13 | public abstract String getName(); 14 | public abstract String getIcon(); 15 | public abstract String getFormat(); 16 | public String getDriver(){ 17 | return this.getClass().getName(); 18 | } 19 | public abstract DataSourceDialect factory(DBConfig config) throws Exception; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/JdbcDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.entity.DBConfig; 4 | import com.zaxxer.hikari.HikariConfig; 5 | import com.zaxxer.hikari.HikariDataSource; 6 | 7 | import javax.sql.DataSource; 8 | 9 | public abstract class JdbcDriver extends IDataSourceDialectDriver { 10 | 11 | protected DataSource getDataSource(DBConfig config){ 12 | HikariConfig hikariConfig = new HikariConfig(config.getProperties()); 13 | hikariConfig.setJdbcUrl(config.getUrl()); 14 | hikariConfig.setUsername(config.getUser()); 15 | hikariConfig.setPassword(config.getPassword()); 16 | return new HikariDataSource(hikariConfig); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/MongoDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.MongoDataSource; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import com.github.alenfive.rocketapi.utils.MongoDBUtils; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * mongodb 构造器 11 | */ 12 | @Component 13 | public class MongoDriver extends IDataSourceDialectDriver { 14 | 15 | @Override 16 | public String getName() { 17 | return "MongoDB"; 18 | } 19 | 20 | @Override 21 | public String getIcon() { 22 | return "rocketapi/images/MongoDB.png"; 23 | } 24 | 25 | @Override 26 | public String getFormat() { 27 | return "mongodb://localhost:27017/test"; 28 | } 29 | 30 | @Override 31 | public DataSourceDialect factory(DBConfig config) { 32 | return new MongoDataSource(MongoDBUtils.getMongoTemplate(config)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/MySQLDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.MySQLDataSource; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * SQL 构造器 10 | */ 11 | @Component 12 | public class MySQLDriver extends JdbcDriver { 13 | 14 | @Override 15 | public String getName() { 16 | return "MySQL"; 17 | } 18 | 19 | @Override 20 | public String getIcon() { 21 | return "rocketapi/images/MySQL.png"; 22 | } 23 | 24 | @Override 25 | public String getFormat() { 26 | return "jdbc:mysql://localhost:3306/test"; 27 | } 28 | 29 | @Override 30 | public DataSourceDialect factory(DBConfig config) throws Exception { 31 | return new MySQLDataSource(super.getDataSource(config)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/OracleDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.OracleDataSource; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class OracleDriver extends JdbcDriver { 10 | 11 | @Override 12 | public String getName() { 13 | return "Oracle"; 14 | } 15 | 16 | @Override 17 | public String getIcon() { 18 | return "rocketapi/images/Oracle.png"; 19 | } 20 | 21 | @Override 22 | public String getFormat() { 23 | return "jdbc:oracle:thin:@localhost:1521/test"; 24 | } 25 | 26 | @Override 27 | public DataSourceDialect factory(DBConfig config) throws Exception { 28 | return new OracleDataSource(super.getDataSource(config)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/PostgreSQLDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.PostgreSQLDataSource; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * postgre SQL 构造器 10 | */ 11 | @Component 12 | public class PostgreSQLDriver extends JdbcDriver { 13 | 14 | @Override 15 | public String getName() { 16 | return "PostgreSQL"; 17 | } 18 | 19 | @Override 20 | public String getIcon() { 21 | return "rocketapi/images/PostgreSQL.png"; 22 | } 23 | 24 | @Override 25 | public String getFormat() { 26 | return "jdbc:postgresql://localhost:5432/postgres"; 27 | } 28 | 29 | @Override 30 | public DataSourceDialect factory(DBConfig config) throws Exception { 31 | return new PostgreSQLDataSource(super.getDataSource(config)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/PrestoDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.PrestoDataSource; 5 | import com.github.alenfive.rocketapi.entity.DBConfig; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * Presto 构造器 10 | */ 11 | @Component 12 | public class PrestoDriver extends JdbcDriver { 13 | 14 | @Override 15 | public String getName() { 16 | return "Presto"; 17 | } 18 | 19 | @Override 20 | public String getIcon() { 21 | return "rocketapi/images/Presto.png"; 22 | } 23 | 24 | @Override 25 | public String getFormat() { 26 | return "jdbc:presto://127.0.0.1:8443/hive"; 27 | } 28 | 29 | @Override 30 | public DataSourceDialect factory(DBConfig config) { 31 | return new PrestoDataSource(super.getDataSource(config)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/datasource/factory/SQLServerDriver.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.datasource.factory; 2 | 3 | 4 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 5 | import com.github.alenfive.rocketapi.datasource.SQLServerDataSource; 6 | import com.github.alenfive.rocketapi.entity.DBConfig; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * SQL 构造器 11 | */ 12 | @Component 13 | public class SQLServerDriver extends JdbcDriver { 14 | 15 | @Override 16 | public String getName() { 17 | return "Microsoft SQL Server"; 18 | } 19 | 20 | @Override 21 | public String getIcon() { 22 | return "rocketapi/images/SQLServer.png"; 23 | } 24 | 25 | @Override 26 | public String getFormat() { 27 | return "jdbc:sqlserver://localhost:1433;database=test"; 28 | } 29 | 30 | @Override 31 | public DataSourceDialect factory(DBConfig config) throws Exception { 32 | return new SQLServerDataSource(super.getDataSource(config)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiTable; 4 | import com.github.alenfive.rocketapi.annotation.ApiUpdateField; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | /** 11 | * API 配置对象 12 | */ 13 | 14 | @Data 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @Builder 18 | @ApiTable("api_config") 19 | public class ApiConfig extends ApiEntity{ 20 | 21 | /** 22 | * 配置可视化标识符 23 | */ 24 | private String service; 25 | 26 | /** 27 | * 配置分类 28 | * @ConfigType 29 | */ 30 | private String type; 31 | 32 | /** 33 | * 配置明细 34 | */ 35 | @ApiUpdateField 36 | private String configContext; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiDirectory.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiTable; 4 | import com.github.alenfive.rocketapi.annotation.ApiUpdateField; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Data 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @ApiTable("api_directory") 15 | public class ApiDirectory extends ApiEntity{ 16 | 17 | @ApiUpdateField 18 | private String service; 19 | 20 | @ApiUpdateField 21 | private String name; 22 | 23 | @ApiUpdateField 24 | private String path; 25 | 26 | @ApiUpdateField 27 | private String parentId; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiEntity.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiId; 4 | import lombok.Data; 5 | 6 | @Data 7 | public abstract class ApiEntity { 8 | /** 9 | * 唯一标识符 10 | */ 11 | @ApiId 12 | private String id; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiExample.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiTable; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * 模拟参数实体对象 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ApiTable("api_example") 17 | public class ApiExample extends ApiEntity{ 18 | private String apiInfoId; 19 | private String url; 20 | private String method; 21 | private String requestHeader; 22 | private String requestBody; 23 | private String responseHeader; 24 | private String responseBody; 25 | private String status; 26 | private Integer elapsedTime; 27 | private String editor; 28 | private String options; 29 | private String createTime; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiTable; 4 | import com.github.alenfive.rocketapi.annotation.ApiUpdateField; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | /** 11 | * API 实体对象 12 | */ 13 | @Data 14 | @Builder 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | @ApiTable("api_info") 18 | public class ApiInfo extends ApiEntity{ 19 | 20 | /** 21 | * 路径 22 | */ 23 | @ApiUpdateField 24 | private String path; 25 | /** 26 | * 完整路径=directory_path+this_path 27 | */ 28 | @ApiUpdateField 29 | private String fullPath; 30 | /** 31 | * 方法支持列表 32 | */ 33 | @ApiUpdateField 34 | private String method; 35 | /** 36 | * API选项 37 | */ 38 | @ApiUpdateField 39 | private String options; 40 | /** 41 | * API模式,CODE/QL,分别为代码模式,或QL模式 42 | */ 43 | private String type; 44 | /** 45 | * 注释说明 46 | */ 47 | @ApiUpdateField 48 | private String name; 49 | /** 50 | * 数据源 51 | */ 52 | @ApiUpdateField 53 | private String datasource; 54 | /** 55 | * SQL模式下的执行脚本 56 | */ 57 | @ApiUpdateField 58 | private String script; 59 | /** 60 | * 服务 61 | */ 62 | @ApiUpdateField 63 | private String service; 64 | 65 | /** 66 | * 所属目录 67 | */ 68 | @ApiUpdateField 69 | private String directoryId; 70 | 71 | /** 72 | * 最后一次编辑者 73 | */ 74 | @ApiUpdateField 75 | private String editor; 76 | 77 | /** 78 | * 创建时间 79 | */ 80 | private String createTime; 81 | /** 82 | * 更新时间 83 | */ 84 | @ApiUpdateField 85 | private String updateTime; 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiInfoHistory.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiTable; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | /** 10 | * API history 实体 11 | */ 12 | @Data 13 | @Builder 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @ApiTable("api_info_history") 17 | public class ApiInfoHistory extends ApiEntity{ 18 | 19 | /** 20 | * api info id 21 | */ 22 | private String apiInfoId; 23 | /** 24 | * 路径 25 | */ 26 | private String path; 27 | /** 28 | * 完整路径 29 | */ 30 | private String fullPath; 31 | /** 32 | * 所在目录 33 | */ 34 | private String directoryId; 35 | /** 36 | * 方法支持列表 37 | */ 38 | private String method; 39 | /** 40 | * API选项 41 | */ 42 | private String options; 43 | /** 44 | * API模式,CODE/SQL,分别为代码模式,或SQL模式 45 | */ 46 | private String type; 47 | /** 48 | * 注释说明 49 | */ 50 | private String name; 51 | /** 52 | * 数据源 53 | */ 54 | private String datasource; 55 | /** 56 | * SQL模式下的执行脚本 57 | */ 58 | private String script; 59 | /** 60 | * 服务 61 | */ 62 | private String service; 63 | 64 | /** 65 | * 最后一次编辑者 66 | */ 67 | private String editor; 68 | 69 | /** 70 | * 创建时间 71 | */ 72 | private String createTime; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiInfoRole.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | public enum ApiInfoRole { 4 | Test,Developer,Master 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiParams.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * api 接口入参实体 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class ApiParams { 21 | private Map pathVar; 22 | private Map param; 23 | private Map body; 24 | private Map header; 25 | private Map cookie; 26 | private Map session; 27 | private HttpServletRequest request; 28 | private HttpServletResponse response; 29 | 30 | public ApiParams putParam(String key,Object value){ 31 | if (param == null){ 32 | param = new HashMap<>(); 33 | } 34 | param.put(key,value); 35 | return this; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiResult.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * api ui 界面接口返回实体 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class ApiResult { 16 | private Integer unpack = 1; 17 | private Integer code = 200; 18 | private String msg = "success"; 19 | private Object data; 20 | 21 | public static ApiResult success(Object data){ 22 | ApiResult apiResult = new ApiResult(); 23 | apiResult.setData(data); 24 | return apiResult; 25 | } 26 | 27 | public static ApiResult fail(String msg){ 28 | ApiResult apiResult = new ApiResult(); 29 | apiResult.setCode(-1); 30 | apiResult.setMsg(msg); 31 | return apiResult; 32 | } 33 | 34 | public static ApiResult fail(String msg,Object data){ 35 | ApiResult apiResult = new ApiResult(); 36 | apiResult.setCode(-1); 37 | apiResult.setMsg(msg); 38 | apiResult.setData(data); 39 | return apiResult; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiTableName.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ApiType.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | /** 4 | * API模式,分别为代码模式以及通过本Rcoket Api生成的API 5 | */ 6 | 7 | public enum ApiType { 8 | Code, Ql 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ConfigType.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | public enum ConfigType { 4 | Yml,DB 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/DBConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Properties; 9 | 10 | /** 11 | * 12 | */ 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Builder 17 | public class DBConfig extends ApiEntity{ 18 | 19 | private String driver; 20 | private String name; 21 | private String comment; 22 | 23 | private String url; 24 | private String user; 25 | private String password; 26 | 27 | private boolean enabled; 28 | 29 | private Properties properties; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/DataSourceProperty.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.Map; 8 | 9 | /** 10 | * 11 | */ 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class DataSourceProperty { 16 | private String name; 17 | private String factoryClassName; 18 | private Map config; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/LRUHashMap.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | public class LRUHashMap extends LinkedHashMap { 7 | 8 | private Integer maxCacheSize = null; 9 | 10 | private LRUHashMap(){ 11 | 12 | } 13 | 14 | public LRUHashMap(Integer maxCacheSize){ 15 | this.maxCacheSize = maxCacheSize; 16 | } 17 | 18 | @Override 19 | protected boolean removeEldestEntry(Map.Entry eldest) { 20 | if (size()>maxCacheSize){ 21 | return true; 22 | } 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ParamScope.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | /** 4 | * 参数变量作用域 枚举 5 | */ 6 | public enum ParamScope { 7 | content,pathVar, param, body, header, cookie,session 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/ResultWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | /** 7 | * 结果包装类 8 | */ 9 | @Data 10 | @AllArgsConstructor 11 | public class ResultWrapper { 12 | private String code; 13 | private String action; 14 | private String msg; 15 | private Object data; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/AcceptApiInfoSyncReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiDirectory; 4 | import com.github.alenfive.rocketapi.entity.ApiInfo; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * API远程同步入参 14 | */ 15 | @Data 16 | @Builder 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class AcceptApiInfoSyncReq { 20 | /** 21 | * 0:全量,1:增量 22 | */ 23 | private Integer increment; 24 | private String sign; 25 | private Long timestamp; 26 | private List apiInfos; 27 | private List directories; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ArrVar.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | /** 7 | * 数组变量对象 8 | */ 9 | @Data 10 | @AllArgsConstructor 11 | public class ArrVar { 12 | private String varName; 13 | private Integer index; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ClazzVo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 自动完成,类型 12 | */ 13 | @Data 14 | @Builder 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class ClazzVo { 18 | /** 19 | * 类全名,包含包名 20 | */ 21 | private String varName; 22 | /** 23 | * 方法 24 | */ 25 | private List methods; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ClusterType.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | public enum ClusterType { 4 | None,Redis 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/CompletionResult.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 13 | */ 14 | @Data 15 | @Builder 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class CompletionResult { 19 | 20 | /** 21 | * java类描述 22 | */ 23 | private Map> clazzs; 24 | 25 | /** 26 | * 变量描述 27 | */ 28 | private Map variables; 29 | 30 | /** 31 | * 常用语法 32 | */ 33 | private Map syntax; 34 | 35 | /** 36 | * 数据库描述 37 | */ 38 | private Map> dbInfos; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ConditionMatcher.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @AllArgsConstructor 9 | @Builder 10 | @NoArgsConstructor 11 | @Data 12 | public class ConditionMatcher { 13 | private String condition; 14 | private int start; 15 | private int end; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/DeleteExamleReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiExample; 4 | import lombok.Data; 5 | 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * 删除模拟请求数据 10 | */ 11 | @Data 12 | public class DeleteExamleReq { 13 | ArrayList apiExampleList; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/DocApi.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiExample; 4 | import com.github.alenfive.rocketapi.entity.ApiInfo; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Data 11 | @Builder 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class DocApi { 15 | private ApiInfo apiInfo; 16 | private ApiExample apiExample; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/DocsInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiDirectory; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.List; 10 | 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class DocsInfo { 16 | private List directoryList; 17 | private List docApiList; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ExportReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | 6 | @Data 7 | public class ExportReq { 8 | private String token; 9 | private String fileName; 10 | private String apiInfoIds; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ExportRes.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiDirectory; 4 | import com.github.alenfive.rocketapi.entity.ApiInfo; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import java.util.Collection; 11 | 12 | @Data 13 | @Builder 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class ExportRes { 17 | private Collection directories; 18 | private Collection apiInfos; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/FieldInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 字段描述 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class FieldInfo { 16 | /** 17 | * 字段名 18 | */ 19 | private String name; 20 | /** 21 | * 注释 22 | */ 23 | private String comment; 24 | /** 25 | * 类型 26 | */ 27 | private String type; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/IgnoreWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 取消返回结构体的封装 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class IgnoreWrapper { 16 | private Object data; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/IndexScope.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 位置范围 7 | */ 8 | @Data 9 | public class IndexScope { 10 | private String token; 11 | private Integer beginIndex; 12 | private Integer endIndex; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/LoginVo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 登录入参实体 9 | */ 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class LoginVo { 14 | private String username; 15 | private String password; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/MappingVo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @Builder 13 | public class MappingVo { 14 | private String method; 15 | private String fullPath; 16 | 17 | private ApiInfo apiInfo; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/MethodVo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 方法 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class MethodVo { 16 | /** 17 | * 类型 18 | * static,public,field 19 | */ 20 | private String type; 21 | /** 22 | * 变量名,用于替换和匹配输入项 23 | */ 24 | private String varName; 25 | /** 26 | * 返回类型,用于匹配子对象方法 27 | */ 28 | private String resultType; 29 | /** 30 | * 参数,用于提示项 31 | */ 32 | private String params; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/NewOldApiInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @Builder 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class NewOldApiInfo { 14 | private String apiInfoId; 15 | private ApiInfo newApiInfo; 16 | private ApiInfo oldApiInfo; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/NotifyEntity.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class NotifyEntity { 13 | 14 | /** 15 | * 发送者实例ID 16 | */ 17 | private String instanceId; 18 | 19 | /** 20 | * 事件类型 21 | */ 22 | private NotifyEventType eventType; 23 | 24 | /** 25 | * eventType=@link NotifyEventType.UpdateMapping时存在 26 | */ 27 | private RefreshMapping refreshMapping; 28 | 29 | /** 30 | * eventType=@link NotifyEventType.UpdateDB时存在 31 | */ 32 | private RefreshDB refreshDB; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/NotifyEventType.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | public enum NotifyEventType { 4 | ReInit, //重新初始化所有信息 5 | RefreshMapping, //更新mapping 6 | RefreshDB, //刷新数据源 7 | RefreshConfig //刷新配置 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/Page.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 分页对象 10 | */ 11 | @Data 12 | @Builder 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class Page { 16 | private Integer pageSize; 17 | private Integer pageNo; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ProvideCompletionReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * 7 | */ 8 | @Data 9 | public class ProvideCompletionReq { 10 | private String clazz; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RefreshDB.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class RefreshDB { 13 | private String oldDBName; 14 | 15 | private String newDBName; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RefreshMapping.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @Builder 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class RefreshMapping { 14 | 15 | private ApiInfo oldMapping; 16 | 17 | private ApiInfo newMapping; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RemoteApiInfoSyncReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * API远程同步入参 12 | */ 13 | @Data 14 | @Builder 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class RemoteApiInfoSyncReq { 18 | private String remoteUrl; 19 | private Integer increment; 20 | private String secretKey; 21 | private List apiInfoIds; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RenameGroupReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * API组名修改入参 7 | */ 8 | @Data 9 | public class RenameGroupReq { 10 | private String newGroupName; 11 | private String oldGroupName; 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RunApiReq.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * 脚本在线运行入参 9 | */ 10 | @Data 11 | public class RunApiReq { 12 | private boolean debug; 13 | private String pattern; 14 | private String url; 15 | private String options; 16 | private Map header; 17 | private Object body; 18 | private String datasource; 19 | private String script; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/RunApiRes.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 脚本在线运行返回实体 9 | */ 10 | @Data 11 | public class RunApiRes { 12 | private List logs = null; 13 | private Object data = null; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ScriptContext.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.util.Map; 10 | 11 | @Data 12 | @Builder 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class ScriptContext { 16 | 17 | /** 18 | * 执行脚本 19 | */ 20 | private StringBuilder script; 21 | /** 22 | * 脚本参数 23 | */ 24 | private Map[] params; 25 | 26 | /** 27 | * 执行脚本数据源 28 | */ 29 | private DataSourceDialect dataSourceDialect; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/ScriptLanguageParam.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @Builder 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class ScriptLanguageParam { 13 | private Integer sqlType; 14 | private String scriptLanguage; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/entity/vo/TableInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 表信息描述 12 | */ 13 | @Data 14 | @Builder 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class TableInfo { 18 | /** 19 | * 表名 20 | */ 21 | private String name; 22 | /** 23 | * 注释 24 | */ 25 | private String comment; 26 | /** 27 | * 字段描述 28 | */ 29 | List fields; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/ApiInfoContent.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import com.github.alenfive.rocketapi.entity.ApiParams; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.script.Bindings; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 脚本执行上下文变量 13 | */ 14 | 15 | @Component 16 | public class ApiInfoContent { 17 | 18 | private ThreadLocal isDebug = new InheritableThreadLocal<>(); 19 | private ThreadLocal apiInfo = new InheritableThreadLocal<>(); 20 | private ThreadLocal apiParams = new InheritableThreadLocal<>(); 21 | private ThreadLocal> logs = new InheritableThreadLocal<>(); 22 | private ThreadLocal engineBindings = new InheritableThreadLocal<>(); 23 | 24 | public Boolean getIsDebug() { 25 | return isDebug.get() == null?false:isDebug.get(); 26 | } 27 | 28 | public void setIsDebug(Boolean isDebug) { 29 | this.isDebug.set(isDebug);; 30 | } 31 | 32 | public List getLogs(){ 33 | return logs.get(); 34 | } 35 | public void putLog(String log){ 36 | if (logs.get() == null){ 37 | logs.set(new ArrayList<>()); 38 | } 39 | logs.get().add(log); 40 | } 41 | 42 | public ApiInfo getApiInfo() { 43 | return apiInfo.get(); 44 | } 45 | 46 | public void setApiInfo(ApiInfo apiInfo) { 47 | this.apiInfo.set(apiInfo); 48 | } 49 | 50 | public ApiParams getApiParams() { 51 | return apiParams.get(); 52 | } 53 | 54 | public void setApiParams(ApiParams apiParams) { 55 | this.apiParams.set(apiParams); 56 | } 57 | 58 | public void setEngineBindings(Bindings bindings) { 59 | this.engineBindings.set(bindings); 60 | } 61 | 62 | public Bindings getEngineBindings() { 63 | return engineBindings.get(); 64 | } 65 | 66 | public void removeAll(){ 67 | apiInfo.remove(); 68 | apiParams.remove(); 69 | logs.remove(); 70 | engineBindings.remove(); 71 | isDebug.remove(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/ApiInfoInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | /** 4 | * API INFO 拦截器抽象接口类,可获取 apiInfo相关信息 5 | */ 6 | 7 | import com.github.alenfive.rocketapi.config.SpringContextUtils; 8 | import com.github.alenfive.rocketapi.entity.ApiInfo; 9 | import com.github.alenfive.rocketapi.utils.RequestUtils; 10 | import org.springframework.web.servlet.HandlerInterceptor; 11 | import org.springframework.web.servlet.ModelAndView; 12 | 13 | import javax.servlet.http.HttpServletRequest; 14 | import javax.servlet.http.HttpServletResponse; 15 | 16 | public abstract class ApiInfoInterceptor implements HandlerInterceptor { 17 | 18 | private ApiInfo getApiInfo(HttpServletRequest request) { 19 | String pattern = RequestUtils.buildPattern(request); 20 | if (pattern == null){ 21 | return null; 22 | } 23 | IApiInfoCache apiInfoCache = SpringContextUtils.getApplicationContext().getBean(IApiInfoCache.class); 24 | String method = request.getMethod(); 25 | return apiInfoCache.get(ApiInfo.builder().fullPath(pattern).method(method).build()); 26 | } 27 | 28 | @Override 29 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 30 | ApiInfo apiInfo = getApiInfo(request); 31 | if (apiInfo == null)return true; 32 | return this.preHandle(request, response, handler,apiInfo); 33 | } 34 | 35 | @Override 36 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 37 | ApiInfo apiInfo = getApiInfo(request); 38 | if (apiInfo == null)return; 39 | this.postHandle(request, response, handler,modelAndView,apiInfo); 40 | } 41 | 42 | @Override 43 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 44 | 45 | } 46 | 47 | public abstract boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ApiInfo apiInfo); 48 | 49 | public abstract void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView,ApiInfo apiInfo); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultApiDocSync.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.DocsInfo; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 默认API信息接口同步, 9 | */ 10 | @Slf4j 11 | @Component 12 | public class DefaultApiDocSync implements IApiDocSync { 13 | 14 | @Override 15 | public String sync(DocsInfo docsInfo) { 16 | return "Successful push"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultApiInfoCache.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import com.github.alenfive.rocketapi.utils.GenerateId; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.util.Collection; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * API信息缓存 13 | */ 14 | @Component 15 | public class DefaultApiInfoCache implements IApiInfoCache { 16 | 17 | private Map cacheApiInfo = new ConcurrentHashMap<>(); 18 | 19 | private String instanceId = GenerateId.get().toHexString(); 20 | 21 | @Override 22 | public ApiInfo get(ApiInfo apiInfo){ 23 | return cacheApiInfo.get(buildApiInfoKey(apiInfo)); 24 | } 25 | 26 | @Override 27 | public Collection getAll() { 28 | return cacheApiInfo.values(); 29 | } 30 | 31 | @Override 32 | public void removeAll() { 33 | cacheApiInfo.clear(); 34 | } 35 | 36 | @Override 37 | public void remove(ApiInfo apiInfo) { 38 | cacheApiInfo.remove(buildApiInfoKey(apiInfo)); 39 | } 40 | 41 | @Override 42 | public void put(ApiInfo apiInfo) { 43 | cacheApiInfo.put(buildApiInfoKey(apiInfo),apiInfo); 44 | } 45 | 46 | private String buildApiInfoKey(ApiInfo apiInfo) { 47 | return apiInfo.getMethod() +" "+ apiInfo.getFullPath(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultApiInfoInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import org.springframework.web.servlet.ModelAndView; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | /** 10 | * API INFO 拦截器实现 11 | */ 12 | public class DefaultApiInfoInterceptor extends ApiInfoInterceptor { 13 | 14 | @Override 15 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ApiInfo apiInfo) { 16 | return true; 17 | } 18 | 19 | @Override 20 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView, ApiInfo apiInfo) { 21 | return; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultApiPager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 4 | import com.github.alenfive.rocketapi.entity.ApiInfo; 5 | import com.github.alenfive.rocketapi.entity.ApiParams; 6 | import com.github.alenfive.rocketapi.service.ScriptParseService; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.util.StringUtils; 10 | 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | /** 16 | * 默认分页数据构建器 17 | */ 18 | @Component 19 | public class DefaultApiPager implements IApiPager { 20 | 21 | @Autowired 22 | private ScriptParseService parseService; 23 | 24 | @Autowired 25 | private RocketApiProperties rocketApiProperties; 26 | 27 | @Override 28 | public Object buildPager(Long totalRecords, List data, ApiInfo apiInfo, ApiParams apiParams) { 29 | Map pager = new HashMap<>(); 30 | 31 | Integer pageNo = this.getPageNo(); 32 | Integer pageSize = this.getPageSize(); 33 | Integer offset = this.getOffset(pageSize,pageNo); 34 | 35 | pager.put(rocketApiProperties.getPager().getTotalRecordsVarName(),totalRecords); 36 | pager.put(rocketApiProperties.getPager().getTotalPagesVarName(),(pageSize == null || pageNo == null || offset == null)?0:((totalRecords + pageSize - 1) / pageSize)); 37 | pager.put(rocketApiProperties.getPager().getDataVarName(),data); 38 | pager.put(this.getPageNoVarName(),pageNo); 39 | pager.put(this.getPageSizeVarName(),pageSize); 40 | pager.put(this.getOffsetVarName(),offset); 41 | return pager; 42 | } 43 | 44 | @Override 45 | public String getPageSizeVarName() { 46 | return rocketApiProperties.getPager().getPageSizeVarName(); 47 | } 48 | 49 | @Override 50 | public String getPageNoVarName() { 51 | return rocketApiProperties.getPager().getPageNoVarName(); 52 | } 53 | 54 | @Override 55 | public String getOffsetVarName() { 56 | return rocketApiProperties.getPager().getOffsetVarName(); 57 | } 58 | 59 | @Override 60 | public Integer getOffset(Integer pageSize, Integer pageNo) { 61 | return (pageNo-1)*pageSize; 62 | } 63 | 64 | @Override 65 | public Integer getPageNo() { 66 | Object value = parseService.buildContentScopeParamItem(null,this.getPageNoVarName()); 67 | if (StringUtils.isEmpty(value)){ 68 | return rocketApiProperties.getPager().getDefaultPageNoValue(); 69 | } 70 | return Integer.valueOf(value.toString()); 71 | } 72 | 73 | @Override 74 | public Integer getPageSize() { 75 | Object value = parseService.buildContentScopeParamItem(null,this.getPageSizeVarName()); 76 | if (StringUtils.isEmpty(value)){ 77 | return rocketApiProperties.getPager().getDefaultPageSizeValue(); 78 | } 79 | return Integer.valueOf(value.toString()); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultAssertException.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * 默认参数验证异常处理类 7 | */ 8 | @Component 9 | public class DefaultAssertException implements IAssertException { 10 | 11 | @Override 12 | public void exception(String throwMsg,String... input) { 13 | throw new RuntimeException(throwMsg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultClusterNotify.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.config.QLRequestMappingFactory; 4 | import com.github.alenfive.rocketapi.entity.vo.NotifyEntity; 5 | import com.github.alenfive.rocketapi.entity.vo.NotifyEventType; 6 | import com.github.alenfive.rocketapi.service.ApiInfoService; 7 | import com.github.alenfive.rocketapi.service.ConfigService; 8 | import com.github.alenfive.rocketapi.service.DataSourceService; 9 | import com.github.alenfive.rocketapi.utils.GenerateId; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | /** 13 | * 集群通知 14 | */ 15 | public class DefaultClusterNotify implements IClusterNotify { 16 | 17 | 18 | private String instanceId = GenerateId.get().toHexString(); 19 | 20 | @Autowired 21 | private ApiInfoService apiInfoService; 22 | 23 | @Autowired 24 | private QLRequestMappingFactory mappingFactory; 25 | 26 | @Autowired 27 | private DataSourceService dataSourceService; 28 | 29 | @Autowired 30 | private ConfigService configService; 31 | 32 | /** 33 | * 发送系统缓存刷新的通知 34 | * 1. 在页面触发"Rebuild API List"操作时,会触发此方法 35 | * 2. 在页面触发接口编辑"Save"操作时,会触发此方法 36 | * 3. 动态数据源变更时,会触发此方法 37 | * 以达到分布式环境下多实例部署系统更新问题 38 | */ 39 | @Override 40 | public void sendNotify(NotifyEntity notifyEntity) { 41 | notifyEntity.setInstanceId(instanceId); 42 | } 43 | 44 | /** 45 | * 监听 "@refreshNotify"行为,来重载本地request mapping等本地实体行为的重新初始化 46 | * @param notifyEntity 47 | */ 48 | @Override 49 | public void receiveNotify(NotifyEntity notifyEntity) { 50 | //避免本实例重复初始化 51 | if (this.instanceId.equals(notifyEntity.getInstanceId())){ 52 | return; 53 | } 54 | 55 | //重新初始化 56 | if (NotifyEventType.ReInit.equals(notifyEntity.getEventType())){ 57 | try { 58 | mappingFactory.reInit(false); 59 | }catch (Exception e){ 60 | e.printStackTrace(); 61 | } 62 | return; 63 | } 64 | 65 | //刷新单个接口 66 | if (NotifyEventType.RefreshMapping.equals(notifyEntity.getEventType())){ 67 | try { 68 | apiInfoService.refreshMapping(notifyEntity.getRefreshMapping()); 69 | } catch (NoSuchMethodException e) { 70 | e.printStackTrace(); 71 | } 72 | return; 73 | } 74 | 75 | //刷新数据源 76 | if (NotifyEventType.RefreshDB.equals(notifyEntity.getEventType())){ 77 | try { 78 | dataSourceService.refreshDB(notifyEntity.getRefreshDB()); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | 84 | //刷新全局配置 85 | if (NotifyEventType.RefreshConfig.equals(notifyEntity.getEventType())){ 86 | configService.refreshConfig(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultDBCache.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.LRUHashMap; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.annotation.PostConstruct; 8 | import java.util.HashMap; 9 | import java.util.Set; 10 | import java.util.Timer; 11 | import java.util.TimerTask; 12 | 13 | 14 | /** 15 | * 默认数据库查询缓存操作 16 | */ 17 | @Component 18 | @Slf4j 19 | public class DefaultDBCache implements IDBCache{ 20 | 21 | private Integer maxCacheSize = 1024; 22 | 23 | // 定时器 24 | private Timer timer = new Timer(); 25 | 26 | //过期检测周期 27 | private static final long CHECK_TIME_SECOND = 10 * 1000; 28 | 29 | private LRUHashMap cacheMap = new LRUHashMap<>(maxCacheSize); 30 | private HashMap expiresTime = new HashMap<>(); 31 | 32 | //过期处理 33 | private TimerTask timerTask = new TimerTask() { 34 | @Override 35 | public void run() { 36 | Set keys = expiresTime.keySet(); 37 | for (String key : keys){ 38 | if (expiresTime.get(key) <= System.currentTimeMillis()){ 39 | synchronized (this){ 40 | expiresTime.remove(key); 41 | cacheMap.remove(key); 42 | log.debug("Automatic cache expiration:{}",key); 43 | } 44 | } 45 | } 46 | } 47 | }; 48 | 49 | 50 | @PostConstruct 51 | public void init(){ 52 | timer.schedule(timerTask, CHECK_TIME_SECOND,CHECK_TIME_SECOND); 53 | } 54 | 55 | @Override 56 | public void set(String cacheKey, Object value, Long cacheTime) { 57 | synchronized (this){ 58 | this.cacheMap.put(cacheKey,value); 59 | this.expiresTime.put(cacheKey,System.currentTimeMillis()+cacheTime); 60 | } 61 | } 62 | 63 | @Override 64 | public Object get(String cacheKey) { 65 | return this.cacheMap.get(cacheKey); 66 | } 67 | 68 | @Override 69 | public void remove(String cacheKey) { 70 | synchronized (this){ 71 | this.cacheMap.remove(cacheKey); 72 | this.expiresTime.remove(cacheKey); 73 | } 74 | } 75 | 76 | @Override 77 | public void clear() { 78 | synchronized (this){ 79 | this.cacheMap.clear(); 80 | this.expiresTime.clear(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultResultWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ResultWrapper; 4 | import org.springframework.stereotype.Component; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | /** 10 | * 默认结果包装类 11 | */ 12 | @Component 13 | public class DefaultResultWrapper implements IResultWrapper{ 14 | 15 | @Override 16 | public Object wrapper(Object data, HttpServletRequest request, HttpServletResponse response) { 17 | return new ResultWrapper("0",request.getRequestURI(),"succeed",data); 18 | } 19 | 20 | @Override 21 | public Object throwable(Throwable throwable, HttpServletRequest request, HttpServletResponse response) { 22 | return new ResultWrapper("500",request.getRequestURI(),throwable.getMessage(),null); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultSQLInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class DefaultSQLInterceptor implements ISQLInterceptor { 7 | 8 | @Override 9 | public String before(String script) { 10 | return script; 11 | } 12 | 13 | @Override 14 | public void after(String script) { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultScriptEncrypt.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * 代码加解密默认实现类 7 | */ 8 | 9 | @Component 10 | public class DefaultScriptEncrypt implements IScriptEncrypt { 11 | 12 | @Override 13 | public String encrypt(String source) throws Exception { 14 | return source; 15 | } 16 | 17 | @Override 18 | public String decrypt(String encrypt) throws Exception { 19 | return encrypt; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/DefaultUserAuthorization.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import org.springframework.stereotype.Component; 4 | import org.springframework.util.StringUtils; 5 | 6 | /** 7 | * 默认用户授权实现类 8 | */ 9 | 10 | @Component 11 | public class DefaultUserAuthorization implements IUserAuthorization { 12 | 13 | @Override 14 | public String validate(String username, String password) { 15 | return StringUtils.isEmpty(username)?"admin":username; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IApiDocSync.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.DocsInfo; 4 | 5 | /** 6 | * API信息接口同步, 7 | */ 8 | public interface IApiDocSync { 9 | public String sync(DocsInfo docsInfo); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IApiInfoCache.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | 5 | import java.util.Collection; 6 | 7 | /** 8 | * API信息缓存 9 | */ 10 | public interface IApiInfoCache { 11 | public ApiInfo get(ApiInfo apiInfo); 12 | public void put(ApiInfo apiInfo); 13 | public void remove(ApiInfo apiInfo); 14 | public void removeAll(); 15 | public Collection getAll(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IApiPager.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import com.github.alenfive.rocketapi.entity.ApiParams; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 分页构造器接口 10 | */ 11 | public interface IApiPager { 12 | 13 | /** 14 | * 15 | * @param totalRecords 查询得到的总记录数 16 | * @param data 分页列表数据 17 | * @param apiInfo 该API信息 18 | * @param apiParams 参数信息 19 | */ 20 | Object buildPager(Long totalRecords, List data, ApiInfo apiInfo, ApiParams apiParams); 21 | 22 | /** 23 | * 每页大小参数名 24 | */ 25 | String getPageSizeVarName(); 26 | 27 | /** 28 | * 第几页参数名 29 | */ 30 | String getPageNoVarName(); 31 | 32 | /** 33 | * skip变量名,由页码和每页大小计算获得, 34 | */ 35 | String getOffsetVarName(); 36 | 37 | /** 38 | * 计算skip变量的值 39 | */ 40 | Integer getOffset(Integer pageSize,Integer pageNo); 41 | 42 | /** 43 | * 获取页码 44 | * @return 45 | */ 46 | Integer getPageNo(); 47 | 48 | /** 49 | * 获取每页大小 50 | */ 51 | Integer getPageSize(); 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IApiSync.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * API信息接口同步, 9 | */ 10 | public interface IApiSync { 11 | public void sync(List apiInfos); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IAssertException.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | /** 4 | * 断言接口类 5 | */ 6 | public interface IAssertException { 7 | void exception(String throwMsg,String... express); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IClusterNotify.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.NotifyEntity; 4 | 5 | /** 6 | * API信息缓存 7 | */ 8 | public interface IClusterNotify { 9 | public void sendNotify(NotifyEntity notifyEntity); 10 | public void receiveNotify(NotifyEntity notifyEntity); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IConfigListener.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | 5 | /** 6 | * 配置变更监听 7 | */ 8 | public abstract class IConfigListener{ 9 | public Class getTClass(){ 10 | Object clazz = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 11 | if (!(clazz instanceof ParameterizedType)){ 12 | return (Class)clazz; 13 | } 14 | return (Class) ((ParameterizedType)clazz).getRawType(); 15 | } 16 | public abstract void execute(T property) throws Exception; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IDBCache.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | /** 4 | * 数据库缓存操作 5 | */ 6 | public interface IDBCache { 7 | public void set(String cacheKey,Object value,Long cacheTime); 8 | public Object get(String cacheKey); 9 | public void remove(String cacheKey); 10 | public void clear(); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IResultWrapper.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | /** 7 | * 执行结果返回 8 | */ 9 | 10 | public interface IResultWrapper { 11 | public Object wrapper(Object data, HttpServletRequest request, HttpServletResponse response); 12 | public Object throwable(Throwable throwable,HttpServletRequest request, HttpServletResponse response); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/ISQLInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | public interface ISQLInterceptor { 4 | String before(String script); 5 | 6 | void after(String script); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IScriptEncrypt.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | /** 4 | * 代码加解密抽象接口 5 | */ 6 | public interface IScriptEncrypt { 7 | String encrypt(String source) throws Exception; 8 | String decrypt(String encrypt) throws Exception; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/IUserAuthorization.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | /** 4 | * 用户授权接口 5 | */ 6 | public interface IUserAuthorization { 7 | public String validate(String username, String password); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/RedisApiInfoCache.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 7 | import com.github.alenfive.rocketapi.entity.ApiInfo; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.redis.core.ConvertingCursor; 10 | import org.springframework.data.redis.core.Cursor; 11 | import org.springframework.data.redis.core.ScanOptions; 12 | import org.springframework.data.redis.core.StringRedisTemplate; 13 | import org.springframework.data.redis.serializer.RedisSerializer; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.Collection; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | 21 | /** 22 | * 集群通知 23 | */ 24 | public class RedisApiInfoCache implements IApiInfoCache{ 25 | 26 | @Autowired 27 | private StringRedisTemplate redisTemplate; 28 | 29 | @Autowired 30 | private ObjectMapper objectMapper; 31 | 32 | @Autowired 33 | private RocketApiProperties rocketApiProperties; 34 | 35 | private String buildPrefix(){ 36 | return "rocket-api:"+rocketApiProperties.getServiceName(); 37 | } 38 | 39 | private String buildApiInfoKey(ApiInfo apiInfo) { 40 | return buildPrefix()+":"+apiInfo.getMethod() +"-"+ apiInfo.getFullPath(); 41 | } 42 | 43 | @Override 44 | public ApiInfo get(ApiInfo apiInfo) { 45 | String strValue = redisTemplate.opsForValue().get(buildApiInfoKey(apiInfo)); 46 | try { 47 | return objectMapper.readValue(strValue,ApiInfo.class); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | return null; 52 | } 53 | 54 | @Override 55 | public void put(ApiInfo apiInfo) { 56 | try { 57 | String strValue = objectMapper.writeValueAsString(apiInfo); 58 | redisTemplate.opsForValue().set(buildApiInfoKey(apiInfo),strValue); 59 | } catch (JsonProcessingException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | @Override 65 | public void remove(ApiInfo apiInfo) { 66 | redisTemplate.delete(buildApiInfoKey(apiInfo)); 67 | } 68 | 69 | @Override 70 | public void removeAll() { 71 | redisTemplate.delete(getKeys()); 72 | } 73 | 74 | private List getKeys(){ 75 | String patternKey = buildPrefix()+":*"; 76 | ScanOptions options = ScanOptions.scanOptions() 77 | .count(10000) 78 | .match(patternKey).build(); 79 | RedisSerializer redisSerializer = (RedisSerializer) redisTemplate.getKeySerializer(); 80 | Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize)); 81 | List keys = new ArrayList<>(); 82 | while(cursor.hasNext()){ 83 | keys.add(cursor.next().toString()); 84 | } 85 | try { 86 | cursor.close(); 87 | } catch (IOException e) { 88 | e.printStackTrace(); 89 | } 90 | return keys; 91 | } 92 | 93 | @Override 94 | public Collection getAll() { 95 | return redisTemplate.opsForValue().multiGet(getKeys()).stream().map(item->{ 96 | try { 97 | return objectMapper.readValue(item,ApiInfo.class); 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } 101 | return null; 102 | }).collect(Collectors.toList()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/extend/RedisClusterNotify.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.extend; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.github.alenfive.rocketapi.config.QLRequestMappingFactory; 6 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 7 | import com.github.alenfive.rocketapi.entity.vo.NotifyEntity; 8 | import com.github.alenfive.rocketapi.entity.vo.NotifyEventType; 9 | import com.github.alenfive.rocketapi.service.ApiInfoService; 10 | import com.github.alenfive.rocketapi.service.ConfigService; 11 | import com.github.alenfive.rocketapi.service.DataSourceService; 12 | import com.github.alenfive.rocketapi.utils.GenerateId; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.data.redis.connection.Message; 15 | import org.springframework.data.redis.connection.MessageListener; 16 | import org.springframework.data.redis.core.StringRedisTemplate; 17 | 18 | /** 19 | * 集群通知 20 | */ 21 | public class RedisClusterNotify implements IClusterNotify,MessageListener { 22 | 23 | 24 | private String instanceId = GenerateId.get().toHexString(); 25 | 26 | @Autowired 27 | private ApiInfoService apiInfoService; 28 | 29 | @Autowired 30 | private QLRequestMappingFactory mappingFactory; 31 | 32 | @Autowired 33 | private DataSourceService dataSourceService; 34 | 35 | @Autowired 36 | private ObjectMapper objectMapper; 37 | 38 | @Autowired 39 | private StringRedisTemplate redisTemplate; 40 | 41 | @Autowired 42 | private RocketApiProperties rocketApiProperties; 43 | 44 | @Autowired 45 | private ConfigService configService; 46 | 47 | public String buildChannelName(){ 48 | return "rocket-api:"+rocketApiProperties.getServiceName()+":channel"; 49 | } 50 | 51 | /** 52 | * 发送系统缓存刷新的通知 53 | * 1. 在页面触发"Rebuild API List"操作时,会触发此方法 54 | * 2. 在页面触发接口编辑"Save"操作时,会触发此方法 55 | * 3. 动态数据源变更时,会触发此方法 56 | * 以达到分布式环境下多实例部署系统更新问题 57 | */ 58 | @Override 59 | public void sendNotify(NotifyEntity notifyEntity) { 60 | notifyEntity.setInstanceId(instanceId); 61 | 62 | String messageStr = null; 63 | try { 64 | messageStr = objectMapper.writeValueAsString(notifyEntity); 65 | } catch (JsonProcessingException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | redisTemplate.convertAndSend(buildChannelName(), messageStr); 70 | } 71 | 72 | /** 73 | * 监听 "@refreshNotify"行为,来重载本地request mapping等本地实体行为的重新初始化 74 | * @param notifyEntity 75 | */ 76 | @Override 77 | public void receiveNotify(NotifyEntity notifyEntity) { 78 | //避免本实例重复初始化 79 | if (this.instanceId.equals(notifyEntity.getInstanceId())){ 80 | return; 81 | } 82 | 83 | //重新初始化 84 | if (NotifyEventType.ReInit.equals(notifyEntity.getEventType())){ 85 | try { 86 | mappingFactory.reInit(false); 87 | }catch (Exception e){ 88 | e.printStackTrace(); 89 | } 90 | return; 91 | } 92 | 93 | //刷新单个接口 94 | if (NotifyEventType.RefreshMapping.equals(notifyEntity.getEventType())){ 95 | try { 96 | apiInfoService.refreshMapping(notifyEntity.getRefreshMapping()); 97 | } catch (NoSuchMethodException e) { 98 | e.printStackTrace(); 99 | } 100 | return; 101 | } 102 | 103 | //刷新数据源 104 | if (NotifyEventType.RefreshDB.equals(notifyEntity.getEventType())){ 105 | try { 106 | dataSourceService.refreshDB(notifyEntity.getRefreshDB()); 107 | } catch (Exception e) { 108 | e.printStackTrace(); 109 | } 110 | } 111 | 112 | //刷新全局配置 113 | if (NotifyEventType.RefreshConfig.equals(notifyEntity.getEventType())){ 114 | configService.refreshConfig(); 115 | } 116 | } 117 | 118 | @Override 119 | public void onMessage(Message message, byte[] bytes) { 120 | String messageStr = new String(message.getBody()); 121 | NotifyEntity notifyEntity = null; 122 | try { 123 | notifyEntity = objectMapper.readValue(messageStr, NotifyEntity.class); 124 | } catch (Exception e) { 125 | e.printStackTrace(); 126 | } 127 | this.receiveNotify(notifyEntity); 128 | } 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/AssertFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | import com.github.alenfive.rocketapi.extend.IAssertException; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.util.StringUtils; 7 | 8 | import java.util.Objects; 9 | 10 | /** 11 | * 异常断言函数 12 | */ 13 | @Component 14 | public class AssertFunction implements IFunction{ 15 | 16 | @Autowired 17 | private IAssertException assertException; 18 | 19 | @Override 20 | public String getVarName() { 21 | return "Assert"; 22 | } 23 | 24 | public void isNotEmpty(Object input,String ... msg){ 25 | boolean validate = !StringUtils.isEmpty(input); 26 | if (!validate){ 27 | String throwMsg = msg.length>0?msg[0]:("`"+input+"` is empty"); 28 | assertException.exception(throwMsg,msg); 29 | } 30 | } 31 | 32 | public void isEmpty(Object input,String ... msg){ 33 | boolean validate = StringUtils.isEmpty(input); 34 | if (!validate){ 35 | String throwMsg = msg.length>0?msg[0]:("`"+input+"` is not empty"); 36 | assertException.exception(throwMsg,msg); 37 | } 38 | } 39 | 40 | public void equals(Object input,Object input2,String ... msg){ 41 | boolean validate = Objects.equals(input,input2); 42 | if (!validate){ 43 | String throwMsg = msg.length>0?msg[0]:("`"+input+"` is not equals"); 44 | assertException.exception(throwMsg,msg); 45 | } 46 | } 47 | 48 | public void isTrue(boolean validate,String ... msg){ 49 | if (!validate){ 50 | String throwMsg = msg.length>0?msg[0]:("input is false"); 51 | assertException.exception(throwMsg,msg); 52 | } 53 | } 54 | 55 | public void regex(String regex,String input,String ... msg){ 56 | boolean validate = input == null?false:input.matches(regex); 57 | if (!validate){ 58 | String throwMsg = msg.length>0?msg[0]:("`"+input+"`is not matches"); 59 | assertException.exception(throwMsg,msg); 60 | } 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/ContextFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 异常断言函数 9 | */ 10 | @Component 11 | public class ContextFunction implements IFunction{ 12 | 13 | @Autowired 14 | private ApplicationContext context; 15 | 16 | @Override 17 | public String getVarName() { 18 | return "springContext"; 19 | } 20 | 21 | public Object getBean(String beanName){ 22 | return context.getBean(beanName); 23 | } 24 | public T getBean(Class beanType){ 25 | return context.getBean(beanType); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/EnvFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.core.env.Environment; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * spring环境变量函数 9 | */ 10 | @Component 11 | public class EnvFunction implements IFunction{ 12 | 13 | @Autowired 14 | private Environment environment; 15 | 16 | @Override 17 | public String getVarName() { 18 | return "env"; 19 | } 20 | 21 | public String get(String key){ 22 | return environment.getProperty(key); 23 | } 24 | 25 | public String get(String key,String defaultValue){ 26 | return environment.getProperty(key,defaultValue); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/IFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | /** 4 | * 函数接口,实现此接口可自动注册到脚本执行上下文中 5 | */ 6 | public interface IFunction { 7 | String getVarName(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/LogFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | import com.github.alenfive.rocketapi.extend.ApiInfoContent; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.slf4j.helpers.MessageFormatter; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * 日志输出函数 11 | */ 12 | @Component 13 | @Slf4j 14 | public class LogFunction implements IFunction{ 15 | 16 | @Autowired 17 | private ApiInfoContent apiInfoContent; 18 | 19 | @Override 20 | public String getVarName() { 21 | return "log"; 22 | } 23 | 24 | public void info(Object format,Object ... args){ 25 | log.info(format.toString(),args); 26 | apiInfoContent.putLog("info:"+ MessageFormatter.arrayFormat(format.toString(), args).getMessage()); 27 | } 28 | 29 | public void debug(Object format,Object ... args){ 30 | log.debug(format.toString(),args); 31 | apiInfoContent.putLog("debug: "+ MessageFormatter.arrayFormat(format.toString(), args).getMessage()); 32 | } 33 | 34 | public void error(Object format,Object ... args){ 35 | log.error(format.toString(),args); 36 | apiInfoContent.putLog("error: "+ MessageFormatter.arrayFormat(format.toString(), args).getMessage()); 37 | } 38 | 39 | public void warn(Object format,Object ... args){ 40 | log.warn(format.toString(),args); 41 | apiInfoContent.putLog("warn: "+ MessageFormatter.arrayFormat(format.toString(), args).getMessage()); 42 | } 43 | 44 | public void trace(Object format,Object ... args){ 45 | log.trace(format.toString(),args); 46 | apiInfoContent.putLog("trace: "+ MessageFormatter.arrayFormat(format.toString(), args).getMessage()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/function/PagerFunction.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.function; 2 | 3 | import com.github.alenfive.rocketapi.extend.ApiInfoContent; 4 | import com.github.alenfive.rocketapi.extend.IApiPager; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 分页封装函数 13 | * @Deprecated 已将方法迁移到 @Link DbFunciton.db.pager(Long total,List list) 14 | */ 15 | @Component 16 | @Deprecated 17 | public class PagerFunction implements IFunction{ 18 | 19 | @Autowired 20 | private IApiPager pager; 21 | 22 | @Autowired 23 | private ApiInfoContent apiInfoContent; 24 | 25 | @Override 26 | public String getVarName() { 27 | return "Pager"; 28 | } 29 | 30 | public Object build(Long total, List> list){ 31 | return pager.buildPager(total,list,apiInfoContent.getApiInfo(),apiInfoContent.getApiParams()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/script/IScriptParse.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.script; 2 | 3 | import com.github.alenfive.rocketapi.entity.ApiInfo; 4 | import com.github.alenfive.rocketapi.entity.ApiParams; 5 | 6 | import javax.script.Bindings; 7 | 8 | /** 9 | * 脚本执行器接口,实现此接口可自定义脚本执行引擎 10 | */ 11 | public interface IScriptParse { 12 | public Object runScript(String script, ApiInfo apiInfo, ApiParams apiParams) throws Throwable; 13 | 14 | public Object engineEval(String script, Bindings bindings) throws Throwable; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/script/JavaScriptScriptParse.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.script; 2 | 3 | /** 4 | * js脚本执行器 5 | */ 6 | 7 | import com.github.alenfive.rocketapi.entity.ApiInfo; 8 | import com.github.alenfive.rocketapi.entity.ApiParams; 9 | import com.github.alenfive.rocketapi.extend.ApiInfoContent; 10 | import com.github.alenfive.rocketapi.function.IFunction; 11 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.context.ApplicationContext; 14 | import org.springframework.transaction.annotation.Transactional; 15 | import org.springframework.util.CollectionUtils; 16 | 17 | import javax.annotation.PostConstruct; 18 | import javax.script.Bindings; 19 | import javax.script.Invocable; 20 | import javax.script.ScriptEngine; 21 | import javax.script.ScriptEngineManager; 22 | import java.util.Collection; 23 | 24 | 25 | public class JavaScriptScriptParse implements IScriptParse{ 26 | 27 | @Autowired 28 | private ApiInfoContent apiInfoContent; 29 | 30 | @Autowired 31 | private ApplicationContext context; 32 | 33 | private Collection functionList; 34 | 35 | @PostConstruct 36 | public void init(){ 37 | //加载函数 38 | functionList = context.getBeansOfType(IFunction.class).values(); 39 | } 40 | 41 | @Override 42 | @Transactional 43 | public Object runScript(String script, ApiInfo apiInfo, ApiParams apiParams) throws Throwable { 44 | try { 45 | //注入变量 46 | apiInfoContent.setApiInfo(apiInfo); 47 | apiInfoContent.setApiParams(apiParams); 48 | 49 | //注入函数 50 | StringBuilder scriptContent = new StringBuilder(); 51 | 52 | scriptContent.append("function run(){"); 53 | scriptContent.append(script); 54 | scriptContent.append("}"); 55 | ScriptEngineManager factory = new ScriptEngineManager(); 56 | ScriptEngine engine = factory.getEngineByName("js"); 57 | 58 | for(IFunction function : functionList){ 59 | engine.put(function.getVarName(),function); 60 | } 61 | 62 | //注入属性变量 63 | buildScriptParams(engine,apiParams); 64 | 65 | engine.eval(scriptContent.toString()); 66 | Invocable inv = (Invocable) engine; 67 | Object result = inv.invokeFunction("run"); 68 | if (!(result instanceof ScriptObjectMirror)){ 69 | return result; 70 | } 71 | ScriptObjectMirror som = (ScriptObjectMirror)result ; 72 | if (som.isArray()){ 73 | return som.values(); 74 | } 75 | return som; 76 | }catch (Exception e){ 77 | if (e.getCause() != null && e.getCause().getCause() != null){ 78 | throw e.getCause().getCause(); 79 | }else{ 80 | throw e; 81 | } 82 | } 83 | } 84 | 85 | @Override 86 | public Object engineEval(String script, Bindings bindings) throws Throwable { 87 | return null; 88 | } 89 | 90 | private void buildScriptParams(ScriptEngine engine, ApiParams apiParams) { 91 | engine.put("pathVar",apiParams.getPathVar()); 92 | engine.put("param",apiParams.getParam()); 93 | engine.put("body",apiParams.getBody()); 94 | engine.put("header",apiParams.getHeader()); 95 | engine.put("cookie",apiParams.getCookie()); 96 | engine.put("session",apiParams.getSession()); 97 | 98 | if (!CollectionUtils.isEmpty(apiParams.getSession())){ 99 | apiParams.getSession().forEach((key,value)->{ 100 | engine.put(key,value); 101 | }); 102 | } 103 | 104 | if (!CollectionUtils.isEmpty(apiParams.getCookie())){ 105 | apiParams.getCookie().forEach((key,value)->{ 106 | engine.put(key,value); 107 | }); 108 | } 109 | 110 | if (!CollectionUtils.isEmpty(apiParams.getHeader())){ 111 | apiParams.getHeader().forEach((key,value)->{ 112 | engine.put(key,value); 113 | }); 114 | } 115 | 116 | if (!CollectionUtils.isEmpty(apiParams.getBody())){ 117 | apiParams.getBody().forEach((key,value)->{ 118 | engine.put(key,value); 119 | }); 120 | } 121 | 122 | if (!CollectionUtils.isEmpty(apiParams.getParam())){ 123 | apiParams.getParam().forEach((key,value)->{ 124 | engine.put(key,value); 125 | }); 126 | } 127 | 128 | if (!CollectionUtils.isEmpty(apiParams.getPathVar())){ 129 | apiParams.getPathVar().forEach((key,value)->{ 130 | engine.put(key,value); 131 | }); 132 | } 133 | 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/service/CompletionService.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.service; 2 | 3 | import com.github.alenfive.rocketapi.datasource.DataSourceDialect; 4 | import com.github.alenfive.rocketapi.datasource.DataSourceManager; 5 | import com.github.alenfive.rocketapi.datasource.factory.IDataSourceDialectDriver; 6 | import com.github.alenfive.rocketapi.entity.vo.CompletionResult; 7 | import com.github.alenfive.rocketapi.entity.vo.MethodVo; 8 | import com.github.alenfive.rocketapi.entity.vo.TableInfo; 9 | import com.github.alenfive.rocketapi.function.IFunction; 10 | import com.github.alenfive.rocketapi.utils.PackageUtil; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.context.ApplicationContext; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.lang.reflect.Field; 16 | import java.lang.reflect.Method; 17 | import java.lang.reflect.Modifier; 18 | import java.util.*; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | import java.util.stream.Collectors; 21 | import java.util.stream.Stream; 22 | 23 | @Service 24 | public class CompletionService { 25 | 26 | @Autowired 27 | private ApplicationContext context; 28 | 29 | @Autowired 30 | private DataSourceManager dataSourceManager; 31 | 32 | private Map cache = new ConcurrentHashMap<>(); 33 | 34 | public CompletionResult provideCompletionTypes() throws Exception { 35 | String cacheKey = "completion-items-cache"; 36 | CompletionResult result = null; 37 | if ((result = (CompletionResult) cache.get(cacheKey)) != null){ 38 | return result; 39 | } 40 | 41 | result = new CompletionResult(); 42 | Map> clazzs = new LinkedHashMap<>(); 43 | Map variables = new HashMap<>(); 44 | Map syntax = new HashMap<>(); 45 | Map> dbInfos = new HashMap<>(); 46 | result.setClazzs(clazzs); 47 | result.setVariables(variables); 48 | result.setSyntax(syntax); 49 | result.setDbInfos(dbInfos); 50 | 51 | //获取内置自定义函数变量 52 | Collection functionList = context.getBeansOfType(IFunction.class).values(); 53 | functionList.forEach(item->{ 54 | variables.put(item.getVarName(),item.getClass().getName()); 55 | }); 56 | 57 | //spring bean对象获取 58 | Map beans = context.getBeansOfType(Object.class); 59 | 60 | for (String key : beans.keySet()){ 61 | buildClazz(clazzs,beans.get(key).getClass()); 62 | } 63 | 64 | //本包JAVA类 65 | List classList = PackageUtil.loadClassByLoader(Thread.currentThread().getContextClassLoader()); 66 | for (Class clazz : classList){ 67 | buildClazz(clazzs,clazz); 68 | } 69 | 70 | //基础包 java.util java类 71 | List classNames = PackageUtil.scan(); 72 | for (String clazz : classNames){ 73 | buildClazz(clazzs,clazz); 74 | } 75 | 76 | //常用语法提示 77 | syntax.put("foreach","for(item in ${1:collection}){\n\t\n}"); 78 | syntax.put("fori","for(${1:i}=0;${1:i}<;${1:i}++){\n\t\n}"); 79 | syntax.put("for","for(${1}){\n\t\n}"); 80 | syntax.put("if","if(${1:condition}){\n\n}"); 81 | syntax.put("ifelse","if(${1:condition}){\n\t\n}else{\n\t\n}"); 82 | syntax.put("import","import "); 83 | syntax.put("continue","continue;"); 84 | syntax.put("break","break;"); 85 | 86 | //数据库信息获取 87 | Map dataSourceDialectMap = dataSourceManager.getDialectMap(); 88 | dataSourceDialectMap.forEach((key,value)->{ 89 | List tableInfos = value.buildTableInfo(); 90 | if (tableInfos != null){ 91 | dbInfos.put(key,tableInfos); 92 | } 93 | }); 94 | 95 | //常用工具类获取 96 | 97 | cache.put(cacheKey,result); 98 | return result; 99 | } 100 | 101 | private void buildClazz(Map> clazzs, String clazz) { 102 | if (clazzs.get(clazz) != null || clazz.indexOf("$") !=-1){ 103 | return; 104 | } 105 | clazzs.put(clazz,Collections.EMPTY_LIST); 106 | } 107 | 108 | private void buildClazz(Map> clazzs, Class clazz) { 109 | if (clazzs.get(clazz.getName()) != null || clazz.getName().indexOf("$") !=-1){ 110 | return; 111 | } 112 | clazzs.put(clazz.getName(),buildMethod(clazz)); 113 | } 114 | 115 | public List buildMethod(Class clazz){ 116 | List methodVos = new ArrayList<>(); 117 | //成员变量 118 | for(Field field : clazz.getFields()){ 119 | methodVos.add(MethodVo.builder() 120 | .type("field") 121 | .varName(field.getName()) 122 | .resultType(field.getType().getName()) 123 | .build()); 124 | } 125 | 126 | //方法 127 | for (Method method : clazz.getMethods()){ 128 | boolean isStatic = Modifier.isStatic(method.getModifiers()); 129 | String params = Stream.of(method.getParameters()).map(item->item.getType().getSimpleName()+" "+item.getName()).collect(Collectors.joining(",")); 130 | methodVos.add(MethodVo.builder() 131 | .type(isStatic?"static":"public") 132 | .varName(method.getName()) 133 | .params(params) 134 | .resultType(method.getReturnType().getName()) 135 | .build()); 136 | } 137 | return methodVos; 138 | } 139 | 140 | public Collection getDriver() { 141 | return context.getBeansOfType(IDataSourceDialectDriver.class).values(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/service/ConfigService.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.service; 2 | 3 | import com.github.alenfive.rocketapi.config.RefreshApiConfig; 4 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 5 | import com.github.alenfive.rocketapi.datasource.DataSourceManager; 6 | import com.github.alenfive.rocketapi.entity.ApiConfig; 7 | import com.github.alenfive.rocketapi.entity.ConfigType; 8 | import com.github.alenfive.rocketapi.entity.vo.NotifyEntity; 9 | import com.github.alenfive.rocketapi.entity.vo.NotifyEventType; 10 | import com.github.alenfive.rocketapi.extend.IClusterNotify; 11 | import com.github.alenfive.rocketapi.utils.GenerateId; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; 14 | import org.springframework.context.annotation.Lazy; 15 | import org.springframework.core.env.ConfigurableEnvironment; 16 | import org.springframework.core.env.MutablePropertySources; 17 | import org.springframework.core.env.PropertiesPropertySource; 18 | import org.springframework.core.env.PropertySource; 19 | import org.springframework.core.io.ByteArrayResource; 20 | import org.springframework.stereotype.Service; 21 | import org.springframework.util.StringUtils; 22 | 23 | import java.util.List; 24 | import java.util.Properties; 25 | import java.util.regex.Pattern; 26 | 27 | @Service 28 | public class ConfigService { 29 | 30 | @Autowired(required = false) 31 | private RefreshApiConfig refreshApiConfig; 32 | 33 | @Autowired 34 | private DataSourceManager dataSourceManager; 35 | 36 | @Autowired 37 | private ConfigurableEnvironment environment; 38 | 39 | @Autowired 40 | private RocketApiProperties rocketApiProperties; 41 | 42 | @Autowired 43 | @Lazy 44 | private IClusterNotify clusterNotify; 45 | 46 | /** 47 | * 加载配置 48 | * 49 | */ 50 | public void reloadApiConfig(Boolean isStart) { 51 | 52 | refreshConfig(); 53 | 54 | if (!isStart){ 55 | clusterNotify.sendNotify(NotifyEntity.builder().eventType(NotifyEventType.RefreshConfig).build()); 56 | } 57 | } 58 | 59 | /** 60 | * 配置更新 61 | * 62 | * @param configContext 63 | * @return 64 | */ 65 | public void saveYmlConfig(String configContext) throws Exception { 66 | ApiConfig apiConfig = this.getYmlConfig(); 67 | if (apiConfig == null) { 68 | apiConfig = ApiConfig.builder() 69 | .configContext(configContext) 70 | .type(ConfigType.Yml.name()) 71 | .service(rocketApiProperties.getServiceName()) 72 | .build(); 73 | apiConfig.setId(GenerateId.get().toHexString()); 74 | dataSourceManager.getStoreApiDataSource().saveEntity(apiConfig); 75 | } else { 76 | apiConfig.setConfigContext(configContext); 77 | dataSourceManager.getStoreApiDataSource().updateEntityById(apiConfig); 78 | } 79 | 80 | reloadApiConfig(false); 81 | } 82 | 83 | public ApiConfig getConfigById(String id){ 84 | ApiConfig apiConfig = new ApiConfig(); 85 | apiConfig.setId(id); 86 | return dataSourceManager.getStoreApiDataSource().findEntityById(apiConfig); 87 | } 88 | 89 | public void removeConfigById(String id){ 90 | ApiConfig apiConfig = new ApiConfig(); 91 | apiConfig.setId(id); 92 | dataSourceManager.getStoreApiDataSource().removeEntityById(apiConfig); 93 | } 94 | 95 | public ApiConfig getYmlConfig(){ 96 | List list = dataSourceManager.getStoreApiDataSource().listByEntity(ApiConfig.builder().service(rocketApiProperties.getServiceName()).type(ConfigType.Yml.name()).build()); 97 | return list.stream().findFirst().orElse(null); 98 | } 99 | 100 | public void refreshConfig() { 101 | MutablePropertySources propertySources = environment.getPropertySources(); 102 | String apiConfigName = "applicationConfig:[db:/rocket-api.yml]"; 103 | if (!rocketApiProperties.isConfigEnabled()) { 104 | propertySources.remove(apiConfigName); 105 | return; 106 | } 107 | 108 | ApiConfig apiConfig = this.getYmlConfig(); 109 | 110 | YamlPropertiesFactoryBean factoryBean = new YamlPropertiesFactoryBean(); 111 | if (apiConfig != null && !StringUtils.isEmpty(apiConfig.getConfigContext())) { 112 | factoryBean.setResources(new ByteArrayResource(apiConfig.getConfigContext().getBytes())); 113 | } 114 | 115 | Properties properties = factoryBean.getObject(); 116 | 117 | PropertiesPropertySource constants = new PropertiesPropertySource(apiConfigName, properties); 118 | 119 | Pattern p = Pattern.compile("^applicationConfig.*"); 120 | String name = null; 121 | boolean exists = propertySources.contains(apiConfigName); 122 | 123 | if (exists) { 124 | name = apiConfigName; 125 | } else { 126 | for (PropertySource source : propertySources) { 127 | if (p.matcher(source.getName()).matches()) { 128 | name = source.getName(); 129 | break; 130 | } 131 | } 132 | } 133 | 134 | if (exists) { 135 | propertySources.replace(name, constants); 136 | } else if (name != null) { 137 | propertySources.addBefore(name, constants); 138 | } else { 139 | propertySources.addFirst(constants); 140 | } 141 | 142 | //配置刷新 143 | if (refreshApiConfig != null) { 144 | refreshApiConfig.refresh(); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/service/EncryptChangeService.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.service; 2 | 3 | import com.github.alenfive.rocketapi.config.QLRequestMappingFactory; 4 | import com.github.alenfive.rocketapi.datasource.DataSourceManager; 5 | import com.github.alenfive.rocketapi.entity.ApiInfo; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.function.UnaryOperator; 10 | 11 | /** 12 | * 密钥修改,只对APIINFO信息有效,对于历史记录解释时可能存在异常 13 | */ 14 | @Service 15 | public class EncryptChangeService { 16 | 17 | @Autowired 18 | private QLRequestMappingFactory mappingFactory; 19 | 20 | @Autowired 21 | private DataSourceManager dataSourceManager; 22 | 23 | @Autowired 24 | private ApiInfoService apiInfoService; 25 | 26 | public void convert(UnaryOperator predicate) throws Exception { 27 | for (ApiInfo apiInfo : apiInfoService.getPathList(false) ){ 28 | apiInfo.setScript(predicate.apply(apiInfo.getScript())); 29 | dataSourceManager.getStoreApiDataSource().updateEntityById(apiInfo); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/service/LoginService.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.service; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.github.alenfive.rocketapi.entity.vo.LoginVo; 6 | import com.github.alenfive.rocketapi.extend.IUserAuthorization; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.util.StringUtils; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.io.IOException; 13 | import java.util.Base64; 14 | 15 | /** 16 | * 登录工具类 17 | */ 18 | @Component 19 | public class LoginService { 20 | 21 | @Autowired 22 | private ObjectMapper objectMapper; 23 | 24 | @Autowired 25 | private IUserAuthorization userAuthorization; 26 | 27 | private final static String rocketUserToken = "rocket-user-token"; 28 | 29 | /** 30 | * 根据token 验证登录用户 31 | * @param request 32 | */ 33 | public String getUser(HttpServletRequest request){ 34 | String token = request.getHeader(rocketUserToken); 35 | return getUser(token); 36 | } 37 | public String getUser(String token){ 38 | if (StringUtils.isEmpty(token)){ 39 | return null; 40 | } 41 | try { 42 | LoginVo loginVo = objectMapper.readValue(Base64.getDecoder().decode(token), LoginVo.class); 43 | String user = userAuthorization.validate(loginVo.getUsername(), loginVo.getPassword()); 44 | return user; 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | return null; 48 | } 49 | } 50 | 51 | /** 52 | * 生成token 53 | */ 54 | public String getToken(LoginVo loginVo) throws JsonProcessingException { 55 | String user = userAuthorization.validate(loginVo.getUsername(), loginVo.getPassword()); 56 | if (StringUtils.isEmpty(user)){ 57 | return null; 58 | } 59 | String token = new String(Base64.getEncoder().encode(objectMapper.writeValueAsBytes(loginVo))); 60 | return token; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/ApiAnnotationUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import com.github.alenfive.rocketapi.annotation.ApiId; 4 | import com.github.alenfive.rocketapi.config.RocketApiProperties; 5 | import com.github.alenfive.rocketapi.config.SpringContextUtils; 6 | import com.github.alenfive.rocketapi.entity.*; 7 | import org.springframework.util.StringUtils; 8 | 9 | import java.util.Arrays; 10 | 11 | 12 | public class ApiAnnotationUtil { 13 | public static String getApiTableName(Class clazz){ 14 | RocketApiProperties rocketApiProperties = SpringContextUtils.getApplicationContext().getBean(RocketApiProperties.class); 15 | RocketApiProperties.ApiTableName apiTableName = rocketApiProperties.getTableName(); 16 | String tableName = null; 17 | if (clazz.equals(ApiInfo.class)){ 18 | tableName = apiTableName.getApi_info(); 19 | }else if (clazz.equals(ApiConfig.class)){ 20 | tableName = apiTableName.getApi_config(); 21 | }else if (clazz.equals(ApiExample.class)){ 22 | tableName = apiTableName.getApi_example(); 23 | }else if (clazz.equals(ApiInfoHistory.class)){ 24 | tableName = apiTableName.getApi_info_history(); 25 | }else if (clazz.equals(ApiDirectory.class)){ 26 | tableName = apiTableName.getApi_directory(); 27 | } 28 | 29 | if (StringUtils.isEmpty(tableName)) 30 | throw new IllegalArgumentException("not found tableName for class :`"+clazz.getClass()+"`"); 31 | return tableName; 32 | } 33 | 34 | public static String getApiIdFieldName(Class clazz) { 35 | String fieldName = Arrays.asList(clazz.getSuperclass().getDeclaredFields()).stream() 36 | .filter(item->item.getAnnotation(ApiId.class) != null).findFirst() 37 | .orElseThrow(()-> new IllegalArgumentException("not found @ApiId Annotation")).getName(); 38 | return fieldName; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/CsvUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import lombok.Cleanup; 4 | 5 | import java.io.*; 6 | import java.text.SimpleDateFormat; 7 | import java.util.*; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * csv 处理 12 | */ 13 | public class CsvUtils { 14 | public static ByteArrayInputStream writeCsv(Map title, List> list) throws UnsupportedEncodingException { 15 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 16 | StringBuilder sb = new StringBuilder(); 17 | sb.append(title.values().stream().collect(Collectors.joining(", "))).append("\r\n"); 18 | Set titleKeys = title.keySet(); 19 | for(Map info : list){ 20 | for(String key : titleKeys){ 21 | Object valObj = info.get(key); 22 | String valStr = null; 23 | if (valObj instanceof Date){ 24 | valStr = valObj == null?"":sdf.format(valObj); 25 | }else { 26 | valStr = valObj == null?"":valObj.toString(); 27 | } 28 | valStr = valStr.replaceAll("\"","\\\\\"").replaceAll(",","\\\\,"); 29 | sb.append(valStr+"\t").append(","); 30 | } 31 | sb.append("\r\n"); 32 | } 33 | 34 | return new ByteArrayInputStream(sb.toString().getBytes("utf-8")); 35 | } 36 | 37 | public static List> parseCsv(InputStream in) throws IOException { 38 | List> result = new ArrayList<>(); 39 | String line = null; 40 | List titles = null; 41 | @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 42 | boolean isFirst = true; 43 | while((line=reader.readLine())!=null){ 44 | if (isFirst){ 45 | titles = Arrays.asList(line.split(",")).stream().map(item->item.trim()).collect(Collectors.toList()); 46 | isFirst = false; 47 | continue; 48 | } 49 | Map item = new LinkedHashMap<>(); 50 | List itemData = Arrays.asList(line.split(",")); 51 | for (int i=0;i> parseCsv(List titles, InputStream in) throws IOException { 60 | List> result = new ArrayList<>(); 61 | String line = null; 62 | @Cleanup BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 63 | while((line=reader.readLine())!=null){ 64 | Map item = new LinkedHashMap<>(); 65 | List itemData = Arrays.asList(line.split(",")); 66 | for (int i=0;i allTableFields(Class clazz){ 17 | return FieldUtils.allFields(clazz).stream().map(item->humpToLine2(item.getName())).collect(Collectors.toList()); 18 | } 19 | 20 | public static List allNameParamsFields(Class clazz){ 21 | return FieldUtils.allFields(clazz).stream().map(item->":"+item.getName()).collect(Collectors.toList()); 22 | } 23 | 24 | public static List allFields(Class clazz){ 25 | ArrayList fields = new ArrayList<>(); 26 | fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); 27 | fields.addAll(Arrays.asList(clazz.getDeclaredFields())); 28 | return fields; 29 | } 30 | 31 | /** 32 | * 所有字母大写时toLower(), 33 | * 所有字母小写时启用驼峰转换, 34 | * 大小写字母都有,不转换 35 | * 下划线转驼峰 36 | */ 37 | public static String underlineToCamel(String name){ 38 | boolean allUpper = true; 39 | boolean allLower = true; 40 | for (int i = 0; i < name.length(); i++) { 41 | char c = name.charAt(i); 42 | if(Character.isLowerCase(c)){ 43 | allUpper = false; 44 | }else if (Character.isUpperCase(c)){ 45 | allLower = false; 46 | } 47 | } 48 | 49 | if (allUpper){ 50 | name = name.toLowerCase(); 51 | allLower = true; 52 | } 53 | if (!allLower){ 54 | return name; 55 | } 56 | 57 | StringBuilder sb = new StringBuilder(name.length()); 58 | for (int i = 0; i < name.length(); i++) { 59 | char c = name.charAt(i); 60 | if ('_' == c) { 61 | if (++i < name.length()){ 62 | sb.append(Character.toUpperCase(name.charAt(i))); 63 | } 64 | }else { 65 | sb.append(c); 66 | } 67 | } 68 | return sb.toString(); 69 | } 70 | 71 | /** 72 | * 驼峰转下划线 73 | */ 74 | public static String humpToLine2(String str) { 75 | Matcher matcher = humpPattern.matcher(str); 76 | StringBuffer sb = new StringBuffer(); 77 | while (matcher.find()) { 78 | matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); 79 | } 80 | matcher.appendTail(sb); 81 | return sb.toString(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/LogFormatUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import com.github.alenfive.rocketapi.entity.vo.ScriptContext; 4 | import com.github.alenfive.rocketapi.service.ScriptParseService; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.util.Collection; 8 | import java.util.Map; 9 | 10 | @Slf4j 11 | public class LogFormatUtils { 12 | 13 | public static String sqlParam(StringBuilder script, ScriptParseService parseService, ScriptContext scriptContext){ 14 | try { 15 | StringBuilder res = new StringBuilder(); 16 | for (Map item : scriptContext.getParams()){ 17 | String itemStr = script.toString(); 18 | for(String key : item.keySet()){ 19 | String replacement = java.util.regex.Matcher.quoteReplacement(parseService.buildFormatValue(item.get(key),scriptContext.getDataSourceDialect())); 20 | itemStr = itemStr.replaceAll(":"+key,replacement); 21 | } 22 | res.append("\r\n").append(itemStr); 23 | } 24 | return res.toString(); 25 | }catch (Exception e){ 26 | StringBuilder res = new StringBuilder("sql param format error:").append(script); 27 | return res.toString(); 28 | } 29 | } 30 | 31 | private static String buildValue(Object value) { 32 | if (value == null){ 33 | return "null"; 34 | } 35 | if (value instanceof String){ 36 | return "'"+value.toString()+"'"; 37 | } 38 | if (value instanceof Collection){ 39 | Collection list = (Collection)(value); 40 | 41 | } 42 | return value.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import java.security.MessageDigest; 4 | 5 | /** 6 | * MD 7 | */ 8 | public class MD5Utils { 9 | 10 | public static String getMD5Str(String str) { 11 | MessageDigest messageDigest = null; 12 | try { 13 | messageDigest = MessageDigest.getInstance("MD5"); 14 | messageDigest.reset(); 15 | messageDigest.update(str.getBytes("UTF-8")); 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | return null; 19 | } 20 | byte[] byteArray = messageDigest.digest(); 21 | StringBuilder md5StrBuff = new StringBuilder(); 22 | for (int i = 0; i < byteArray.length; i++) { 23 | if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) { 24 | md5StrBuff.append("0").append( 25 | Integer.toHexString(0xFF & byteArray[i])); 26 | } else { 27 | md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i])); 28 | } 29 | } 30 | return md5StrBuff.toString(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/MongoDBUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import com.github.alenfive.rocketapi.entity.DBConfig; 4 | import com.mongodb.MongoClientURI; 5 | import org.springframework.data.mongodb.MongoDbFactory; 6 | import org.springframework.data.mongodb.core.MongoTemplate; 7 | import org.springframework.data.mongodb.core.SimpleMongoDbFactory; 8 | 9 | public class MongoDBUtils { 10 | public static MongoTemplate getMongoTemplate(DBConfig config){ 11 | MongoClientURI mongoClientURI = new MongoClientURI(config.getUrl()); 12 | MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoClientURI); 13 | return new MongoTemplate(mongoDbFactory); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/PackageUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import com.github.alenfive.rocketapi.RocketAPIApplication; 4 | 5 | 6 | public class PackageUtils { 7 | public static String getVersion() { 8 | Package pkg = RocketAPIApplication.class.getPackage(); 9 | return (pkg != null ? pkg.getImplementationVersion() : null); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/RequestUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import org.springframework.web.servlet.HandlerMapping; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import java.io.UnsupportedEncodingException; 7 | import java.util.Enumeration; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * 请求工具类 13 | */ 14 | public class RequestUtils { 15 | 16 | public static String buildPattern(HttpServletRequest request) { 17 | return (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); 18 | } 19 | 20 | public static Map buildSessionParams(HttpServletRequest request) { 21 | Enumeration keys = request.getSession().getAttributeNames(); 22 | Map result = new HashMap<>(); 23 | while (keys.hasMoreElements()){ 24 | String key = keys.nextElement(); 25 | result.put(key,request.getSession().getAttribute(key)); 26 | } 27 | return result; 28 | } 29 | 30 | public static Map buildHeaderParams(HttpServletRequest request) throws UnsupportedEncodingException { 31 | Enumeration headerKeys = request.getHeaderNames(); 32 | Map result = new HashMap<>(); 33 | while (headerKeys.hasMoreElements()){ 34 | String key = headerKeys.nextElement(); 35 | String value = request.getHeader(key); 36 | result.put(key, value); 37 | } 38 | return result; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/SignUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * API同步签名 7 | */ 8 | public class SignUtils { 9 | public static String build(String secret, Map params) { 10 | StringBuilder para_str = new StringBuilder(); 11 | params.keySet().stream().sorted(String::compareTo).forEach(key->{ 12 | para_str.append(key).append(params.get(key)); 13 | }); 14 | para_str.append(secret); 15 | return MD5Utils.getMD5Str(para_str.toString()).toUpperCase(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/alenfive/rocketapi/utils/SqlUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Scanner; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | /** 10 | * 表结构解析 11 | */ 12 | public class SqlUtils { 13 | public static String getByPattern(String sql, String pattern, int group) { 14 | Pattern compile = Pattern.compile(pattern); 15 | Matcher matcher = compile.matcher(sql); 16 | while (matcher.find()) { 17 | return matcher.group(group); 18 | } 19 | return null; 20 | } 21 | 22 | public static List getColumnSqls(String sql) { 23 | List lines = new ArrayList<>(); 24 | Scanner scanner = new Scanner(sql); 25 | boolean start = false; 26 | while (scanner.hasNextLine()) { 27 | String nextLine = scanner.nextLine(); 28 | if (nextLine.indexOf("CREATE TABLE") != -1) { 29 | start = true; 30 | continue; 31 | } 32 | if (nextLine.indexOf("KEY") != -1 || nextLine.indexOf("ENGINE=") != -1) { 33 | start = false; 34 | continue; 35 | } 36 | if (start) { 37 | lines.add(nextLine); 38 | } 39 | } 40 | return lines; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 | com.github.alenfive.rocketapi.config.RocketApiAutoConfig,\ 4 | com.github.alenfive.rocketapi.config.RedisClusterNotifyConfig -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: rocket-api 4 | jackson: 5 | default-property-inclusion: non_null 6 | date-format: yyyy-MM-dd HH:mm:ss 7 | time-zone: GMT+8 8 | mvc: 9 | format: 10 | dateTime: yyyy-MM-dd HH:mm:ss 11 | datasource: 12 | url: jdbc:mysql://127.0.0.1:3306/dataway2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai 13 | username: root 14 | password: 123456 15 | driver-class-name: com.mysql.cj.jdbc.Driver 16 | data: 17 | mongodb: 18 | host: 127.0.0.1 19 | database: dataway2 20 | username: root 21 | password: 123456 22 | port: 27017 23 | thymeleaf: 24 | cache: false 25 | check-template: true 26 | check-template-location: true 27 | enabled: true 28 | encoding: utf-8 29 | mode: HTML5 30 | prefix: classpath:/templates/ 31 | suffix: .html 32 | resources: 33 | cache: 34 | period: 0h 35 | 36 | logging: 37 | level: 38 | com.github.alenfive.rocketapi: debug 39 | #server: 40 | # servlet: 41 | # context-path: /rocket-api 42 | server: 43 | compression: 44 | enabled: true -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/css/sourceSansPro.css: -------------------------------------------------------------------------------- 1 | /* source-sans-pro-200 - latin */ 2 | @font-face { 3 | font-family: 'Source Sans Pro'; 4 | font-style: normal; 5 | font-weight: 200; 6 | src: local('Source Sans Pro ExtraLight'), local('SourceSansPro-ExtraLight'), 7 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-200.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */ url('../fonts/sourceSansPro/source-sans-pro-v9-latin-200.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ 8 | } 9 | 10 | /* source-sans-pro-200italic - latin */ 11 | @font-face { 12 | font-family: 'Source Sans Pro'; 13 | font-style: italic; 14 | font-weight: 200; 15 | src: local('Source Sans Pro ExtraLight Italic'), local('SourceSansPro-ExtraLightIt'), 16 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-200italic.woff2') format('woff2'), 17 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-200italic.woff') format('woff'); 18 | } 19 | 20 | /* source-sans-pro-300 - latin */ 21 | @font-face { 22 | font-family: 'Source Sans Pro'; 23 | font-style: normal; 24 | font-weight: 300; 25 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), 26 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-300.woff2') format('woff2'), 27 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-300.woff') format('woff'); 28 | } 29 | 30 | /* source-sans-pro-300italic - latin */ 31 | @font-face { 32 | font-family: 'Source Sans Pro'; 33 | font-style: italic; 34 | font-weight: 300; 35 | src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightIt'), 36 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-300italic.woff2') format('woff2'), 37 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-300italic.woff') format('woff'); 38 | } 39 | 40 | /* source-sans-pro-regular - latin */ 41 | @font-face { 42 | font-family: 'Source Sans Pro'; 43 | font-style: normal; 44 | font-weight: 400; 45 | src: local('Source Sans Pro'), local('SourceSansPro-Regular'), 46 | url('../fonts/source-sans-pro-v9-latin-regular.woff2') format('woff'); 47 | } 48 | 49 | /* source-sans-pro-italic - latin */ 50 | @font-face { 51 | font-family: 'Source Sans Pro'; 52 | font-style: italic; 53 | font-weight: 400; 54 | src: local('Source Sans Pro Italic'), local('SourceSansPro-It'), 55 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-italic.woff2') format('woff2'), 56 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-italic.woff') format('woff'); 57 | } 58 | 59 | /* source-sans-pro-600 - latin */ 60 | @font-face { 61 | font-family: 'Source Sans Pro'; 62 | font-style: normal; 63 | font-weight: 600; 64 | src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), 65 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-600.woff2') format('woff2'), 66 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-600.woff') format('woff'); 67 | } 68 | 69 | /* source-sans-pro-600italic - latin */ 70 | @font-face { 71 | font-family: 'Source Sans Pro'; 72 | font-style: italic; 73 | font-weight: 600; 74 | src: local('Source Sans Pro Semibold Italic'), local('SourceSansPro-SemiboldIt'), 75 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-600italic.woff2') format('woff2'), 76 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-600italic.woff') format('woff'); 77 | } 78 | 79 | /* source-sans-pro-700 - latin */ 80 | @font-face { 81 | font-family: 'Source Sans Pro'; 82 | font-style: normal; 83 | font-weight: 700; 84 | src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), 85 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-700.woff2') format('woff2'), 86 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-700.woff') format('woff'); 87 | } 88 | 89 | /* source-sans-pro-700italic - latin */ 90 | @font-face { 91 | font-family: 'Source Sans Pro'; 92 | font-style: italic; 93 | font-weight: 700; 94 | src: local('Source Sans Pro Bold Italic'), local('SourceSansPro-BoldIt'), 95 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-700italic.woff2') format('woff2'), 96 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-700italic.woff') format('woff'); 97 | } 98 | 99 | /* source-sans-pro-900 - latin */ 100 | @font-face { 101 | font-family: 'Source Sans Pro'; 102 | font-style: normal; 103 | font-weight: 900; 104 | src: local('Source Sans Pro Black'), local('SourceSansPro-Black'), 105 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-900.woff2') format('woff2'), 106 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-900.woff') format('woff'); 107 | } 108 | 109 | /* source-sans-pro-900italic - latin */ 110 | @font-face { 111 | font-family: 'Source Sans Pro'; 112 | font-style: italic; 113 | font-weight: 900; 114 | src: local('Source Sans Pro Black Italic'), local('SourceSansPro-BlackIt'), 115 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-900italic.woff2') format('woff2'), 116 | url('../fonts/sourceSansPro/source-sans-pro-v9-latin-900italic.woff') format('woff'); 117 | } 118 | -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/devhttpclient/539661FD89DA706B002DCBFD57F74A0A.cache.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/devhttpclient/539661FD89DA706B002DCBFD57F74A0A.cache.js -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/Simple-Line-Icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/fonts/Simple-Line-Icons.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/api-tester.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/fonts/api-tester.ttf -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/api-tester/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'api-tester'; 3 | src: 4 | url('../api-tester.ttf?i6761g') format('truetype'), 5 | url('../api-tester.woff?i6761g') format('woff'), 6 | url('../api-tester.svg?i6761g#api-tester') format('svg'); 7 | font-weight: normal; 8 | font-style: normal; 9 | } 10 | 11 | .api-tester-icon { 12 | /* use !important to prevent issues with browser extensions that change fonts */ 13 | font-family: 'api-tester' !important; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | 21 | /* Better Font Rendering =========== */ 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .api-tester-history:before { 27 | content: "\e900"; 28 | } 29 | .api-tester-drive:before { 30 | content: "\e901"; 31 | } 32 | .api-tester-project:before { 33 | content: "\e902"; 34 | } 35 | .api-tester-service:before { 36 | content: "\e903"; 37 | } 38 | .api-tester-repository:before { 39 | content: "\e904"; 40 | } 41 | .api-tester-request:before { 42 | content: "\e905"; 43 | } 44 | .api-tester-scenario:before { 45 | content: "\e906"; 46 | } 47 | .api-tester-multi-plus:before { 48 | content: "\e907"; 49 | } 50 | .api-tester-shared-project:before { 51 | content: "\e908"; 52 | } 53 | -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/source-sans-pro-v9-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/fonts/source-sans-pro-v9-latin-regular.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/fonts/talendicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/fonts/talendicons.woff2 -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/ClickHouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/ClickHouse.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/MongoDB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/MongoDB.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/MySQL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/MySQL.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/Oracle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/Oracle.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/PostgreSQL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/PostgreSQL.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/Presto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/Presto.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/SQLServer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/SQLServer.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/images/search-icon-white-compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/images/search-icon-white-compressed.png -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/monaco-editor/min/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mihuajun/rocket-api/555070b5e146bf2d78f37cdf7e747e2dedf3d896/src/main/resources/static/rocketapi/monaco-editor/min/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf -------------------------------------------------------------------------------- /src/main/resources/static/rocketapi/monaco-editor/min/vs/basic-languages/yaml/yaml.js: -------------------------------------------------------------------------------- 1 | /*!----------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * monaco-languages version: 2.5.0(19ce286ce42684fd0d08b19a2b8f36a7cfd830dd) 4 | * Released under the MIT license 5 | * https://github.com/Microsoft/monaco-languages/blob/master/LICENSE.md 6 | *-----------------------------------------------------------------------------*/ 7 | define("vs/basic-languages/yaml/yaml",["require","exports"],(function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.language=n.conf=void 0,n.conf={comments:{lineComment:"#"},brackets:[["{","}"],["[","]"],["(",")"]],autoClosingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],surroundingPairs:[{open:"{",close:"}"},{open:"[",close:"]"},{open:"(",close:")"},{open:'"',close:'"'},{open:"'",close:"'"}],folding:{offSide:!0}},n.language={tokenPostfix:".yaml",brackets:[{token:"delimiter.bracket",open:"{",close:"}"},{token:"delimiter.square",open:"[",close:"]"}],keywords:["true","True","TRUE","false","False","FALSE","null","Null","Null","~"],numberInteger:/(?:0|[+-]?[0-9]+)/,numberFloat:/(?:0|[+-]?[0-9]+)(?:\.[0-9]+)?(?:e[-+][1-9][0-9]*)?/,numberOctal:/0o[0-7]+/,numberHex:/0x[0-9a-fA-F]+/,numberInfinity:/[+-]?\.(?:inf|Inf|INF)/,numberNaN:/\.(?:nan|Nan|NAN)/,numberDate:/\d{4}-\d\d-\d\d([Tt ]\d\d:\d\d:\d\d(\.\d+)?(( ?[+-]\d\d?(:\d\d)?)|Z)?)?/,escapes:/\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/,tokenizer:{root:[{include:"@whitespace"},{include:"@comment"},[/%[^ ]+.*$/,"meta.directive"],[/---/,"operators.directivesEnd"],[/\.{3}/,"operators.documentEnd"],[/[-?:](?= )/,"operators"],{include:"@anchor"},{include:"@tagHandle"},{include:"@flowCollections"},{include:"@blockStyle"},[/@numberInteger(?![ \t]*\S+)/,"number"],[/@numberFloat(?![ \t]*\S+)/,"number.float"],[/@numberOctal(?![ \t]*\S+)/,"number.octal"],[/@numberHex(?![ \t]*\S+)/,"number.hex"],[/@numberInfinity(?![ \t]*\S+)/,"number.infinity"],[/@numberNaN(?![ \t]*\S+)/,"number.nan"],[/@numberDate(?![ \t]*\S+)/,"number.date"],[/(".*?"|'.*?'|.*?)([ \t]*)(:)( |$)/,["type","white","operators","white"]],{include:"@flowScalars"},[/[^#]+/,{cases:{"@keywords":"keyword","@default":"string"}}]],object:[{include:"@whitespace"},{include:"@comment"},[/\}/,"@brackets","@pop"],[/,/,"delimiter.comma"],[/:(?= )/,"operators"],[/(?:".*?"|'.*?'|[^,\{\[]+?)(?=: )/,"type"],{include:"@flowCollections"},{include:"@flowScalars"},{include:"@tagHandle"},{include:"@anchor"},{include:"@flowNumber"},[/[^\},]+/,{cases:{"@keywords":"keyword","@default":"string"}}]],array:[{include:"@whitespace"},{include:"@comment"},[/\]/,"@brackets","@pop"],[/,/,"delimiter.comma"],{include:"@flowCollections"},{include:"@flowScalars"},{include:"@tagHandle"},{include:"@anchor"},{include:"@flowNumber"},[/[^\],]+/,{cases:{"@keywords":"keyword","@default":"string"}}]],multiString:[[/^( +).+$/,"string","@multiStringContinued.$1"]],multiStringContinued:[[/^( *).+$/,{cases:{"$1==$S2":"string","@default":{token:"@rematch",next:"@popall"}}}]],whitespace:[[/[ \t\r\n]+/,"white"]],comment:[[/#.*$/,"comment"]],flowCollections:[[/\[/,"@brackets","@array"],[/\{/,"@brackets","@object"]],flowScalars:[[/"([^"\\]|\\.)*$/,"string.invalid"],[/'([^'\\]|\\.)*$/,"string.invalid"],[/'[^']*'/,"string"],[/"/,"string","@doubleQuotedString"]],doubleQuotedString:[[/[^\\"]+/,"string"],[/@escapes/,"string.escape"],[/\\./,"string.escape.invalid"],[/"/,"string","@pop"]],blockStyle:[[/[>|][0-9]*[+-]?$/,"operators","@multiString"]],flowNumber:[[/@numberInteger(?=[ \t]*[,\]\}])/,"number"],[/@numberFloat(?=[ \t]*[,\]\}])/,"number.float"],[/@numberOctal(?=[ \t]*[,\]\}])/,"number.octal"],[/@numberHex(?=[ \t]*[,\]\}])/,"number.hex"],[/@numberInfinity(?=[ \t]*[,\]\}])/,"number.infinity"],[/@numberNaN(?=[ \t]*[,\]\}])/,"number.nan"],[/@numberDate(?=[ \t]*[,\]\}])/,"number.date"]],tagHandle:[[/\![^ ]*/,"tag"]],anchor:[[/[&*][^ ]+/,"namespace"]]}}})); -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/bottom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/console.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/history-api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/history-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | 27 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/repository.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 |
9 |
[0]
10 | 23 |
24 |
    25 |
      26 |
    27 |
    28 |
    29 |
    30 | 38 |
    39 |
    40 | 41 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
    Response 6 | 14 |
    15 |
    16 |

    Not available, a request has not been sent 17 | yet.

    18 |
    19 |
    20 |
    21 |
    22 |
    23 |
    24 |
    Headers 25 | 27 | 38 |
    39 |
    40 |
    41 | 42 | 43 | 44 | 45 | 46 | 47 |
    48 |
    49 |
    50 |
    51 |
    52 |
    Headers [8]
    56 |
    57 |
    58 |
    59 |
    Body 62 |
    63 |
    64 |
    65 |
    Body 68 |
    69 |
    70 |
    71 |
    72 |
    73 |
    74 |
    75 |
    76 | 77 | -------------------------------------------------------------------------------- /src/main/resources/templates/rocketapi/top.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
    6 |
    7 | 8 | 9 | 10 | 11 | 51 | 80 |
    81 |
    Trying to synchronize... You can still work on your projects 82 | in the meantime. 83 |
    84 | 85 | 86 |
    87 | 88 | -------------------------------------------------------------------------------- /src/test/java/com/github/alenfive/rocketapi/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi; 2 | 3 | import com.github.alenfive.rocketapi.extend.IApiPager; 4 | import com.github.alenfive.rocketapi.service.ScriptParseService; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import org.springframework.util.StringUtils; 12 | 13 | import javax.script.ScriptEngine; 14 | import javax.script.ScriptEngineManager; 15 | import javax.script.ScriptException; 16 | import java.util.*; 17 | 18 | /** 19 | * 数据为操作解析器测试 20 | */ 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest(classes={RocketAPIApplication.class})// 指定启动类 23 | @Slf4j 24 | public class ApplicationTests { 25 | 26 | @Autowired 27 | private ScriptParseService parseService; 28 | 29 | @Test 30 | public void testVar() { 31 | StringBuilder script = new StringBuilder("from ${table} where id in = #{id} and name=#{name123456789}#{name123456789}"); 32 | Map params = new HashMap<>(); 33 | params.put("id","123"); 34 | params.put("table","t_user"); 35 | params.put("name123456789"," and #{phone}"); 36 | parseService.buildParams(script,null,params); 37 | log.info("testVar:{}",script); 38 | assert script.toString().equals("from t_user where id in = '123' and name=' and #{phone}'' and #{phone}'"); 39 | } 40 | 41 | @Test 42 | public void testArrayVar(){ 43 | StringBuilder script = new StringBuilder("where id in (#{idList})"); 44 | Map params = new HashMap<>(); 45 | params.put("idList", Arrays.asList("11",22)); 46 | parseService.buildParams(script,null,params); 47 | log.info("testFor:{}",script); 48 | assert script.toString().equals("where id in ('11',22)"); 49 | } 50 | 51 | @Test 52 | public void testRandomArrayVar(){ 53 | StringBuilder script = new StringBuilder("where id = #{idList[1].name}"); 54 | Map params = new HashMap<>(); 55 | Map child = new HashMap<>(); 56 | child.put("name","王"); 57 | 58 | List list = new ArrayList<>(); 59 | list.add(1); 60 | list.add(child); 61 | params.put("idList", list); 62 | parseService.buildParams(script,null,params); 63 | log.info("testRandomArrayVar:{}",script); 64 | assert script.toString().equals("where id = '王'"); 65 | } 66 | 67 | @Test 68 | public void testIf(){ 69 | StringBuilder script = new StringBuilder("where ?{id,and id=#{id}} and 1=1"); 70 | Map params = new HashMap<>(); 71 | params.put("id","123"); 72 | parseService.buildIf(script,params); 73 | log.info("testIf:{}",script.toString()); 74 | assert script.toString().equals("where and id=#{id} and 1=1"); 75 | 76 | script = new StringBuilder("where ?{id,and id=#{id}} and 1=1"); 77 | params = new HashMap<>(); 78 | parseService.buildIf(script,params); 79 | log.info("testIf:{}",script.toString()); 80 | assert script.toString().equals("where and 1=1"); 81 | } 82 | 83 | @Test 84 | public void testFor(){ 85 | List> ss = new ArrayList<>(); 86 | 87 | } 88 | 89 | 90 | @Autowired 91 | private IApiPager apiPager; 92 | 93 | @Test 94 | public void testPager(){ 95 | 96 | 97 | } 98 | 99 | @Test 100 | public void jsScript() throws ScriptException { 101 | String str = "4+5"; 102 | ScriptEngineManager manager = new ScriptEngineManager(); 103 | ScriptEngine engine = manager.getEngineByName("JavaScript"); 104 | System.out.println(engine.eval(str)); 105 | } 106 | } -------------------------------------------------------------------------------- /src/test/java/com/github/alenfive/rocketapi/ScriptLanguageTests.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi; 2 | 3 | import groovy.lang.GroovyShell; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.codehaus.groovy.control.ErrorCollector; 6 | import org.codehaus.groovy.control.MultipleCompilationErrorsException; 7 | import org.junit.Test; 8 | 9 | import javax.script.ScriptEngine; 10 | import javax.script.ScriptEngineManager; 11 | import javax.script.ScriptException; 12 | import java.util.regex.Pattern; 13 | 14 | /** 15 | * 脚本引擎测试 16 | */ 17 | @Slf4j 18 | public class ScriptLanguageTests { 19 | public static void main(String[] args) throws ScriptException { 20 | ScriptEngineManager factory = new ScriptEngineManager(); 21 | ScriptEngine engine = factory.getEngineByName("js"); 22 | engine.eval("var fruits = [\"Banana\", \"Orange\", \"Apple\", \"Mango\"]; var d = fruits.toString();"); 23 | System.out.println(engine.get("fruits") instanceof Object[]); 24 | System.out.println(engine.get("d").getClass()); 25 | System.out.println(engine.get("d")); 26 | } 27 | 28 | 29 | @Test 30 | public void grammarCheck() { 31 | try { 32 | String expression = "if(a==1) return 1;"; 33 | new GroovyShell().parse(expression); 34 | } catch(MultipleCompilationErrorsException cfe) { 35 | ErrorCollector errorCollector = cfe.getErrorCollector(); 36 | System.out.println("Errors: "+errorCollector.getErrorCount()); 37 | } 38 | } 39 | 40 | 41 | @Test 42 | public void testIndexOf(){ 43 | int start = 0; 44 | String str = "12345612"; 45 | int index = str.indexOf("1",start); 46 | log.info("index:{}",index); 47 | StringBuilder sb = new StringBuilder(str); 48 | 49 | log.info("sub str:{}",sb.replace(0,2,"---")); 50 | } 51 | 52 | @Test 53 | public void testParamGet(){ 54 | Pattern r = Pattern.compile("(#|\\$)\\{(.*?)\\}"); 55 | StringBuilder script = new StringBuilder("where id = #{if(a>1){return \"1}else{return 2}} and name = #{\"name}"); 56 | //Matcher matcher = r.matcher(str); 57 | 58 | String flag = "#{"; 59 | //匹配参数#{} 60 | do { 61 | int startIf = script.indexOf(flag); 62 | if (startIf == -1) { 63 | break; 64 | } 65 | 66 | int ifCloseIndex = -1; 67 | int quotationMark = 0; 68 | int bigBracket = 1; 69 | 70 | for(int i=startIf+flag.length();i 0){ 74 | if (c == '\\') { 75 | i++; 76 | continue; 77 | } 78 | if (c == '"'){ 79 | quotationMark --; 80 | } 81 | continue; 82 | } 83 | 84 | if (c == '"'){ 85 | quotationMark ++; 86 | continue; 87 | } 88 | 89 | 90 | if (c == '{'){ 91 | bigBracket ++ ; 92 | } 93 | 94 | if (c == '}'){ 95 | bigBracket -- ; 96 | } 97 | 98 | if (c == '}' && bigBracket == 0){ 99 | ifCloseIndex = i; 100 | break; 101 | } 102 | } 103 | 104 | if (ifCloseIndex == -1){ 105 | throw new IllegalArgumentException("missed if close '}'"); 106 | } 107 | 108 | script = script.replace(startIf,ifCloseIndex+1,""); 109 | log.info("script:{}",script.substring(startIf+flag.length(),ifCloseIndex)); 110 | }while (true); 111 | 112 | 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/github/alenfive/rocketapi/Test.java: -------------------------------------------------------------------------------- 1 | package com.github.alenfive.rocketapi; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | public class Test { 6 | public static void main(String[] args) { 7 | String str = " delete from -user "; 8 | String selectReg = "^( *select )"; 9 | String insertReg = "^( *(replace|insert) +into )"; 10 | String updateReg = "^( *update [A-Za-z\\-0-9_]+ +set )"; 11 | String deleteReg = "^( *delete +from +[A-Za-z\\-0-9_]+)"; 12 | Pattern test_ = Pattern.compile(deleteReg, Pattern.CASE_INSENSITIVE); 13 | 14 | System.out.println(test_.matcher(str).find()); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /升级脚本: -------------------------------------------------------------------------------- 1 | ALTER TABLE `api_config` 2 | ADD COLUMN `type` VARCHAR(45) NULL AFTER `config_context`; 3 | 4 | ALTER TABLE `api_config` 5 | DROP INDEX `service_UNIQUE` ; 6 | 7 | --------------------------------------------------------------------------------