├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── szmirren │ │ └── vxApi │ │ ├── .gitignore │ │ ├── Main.java │ │ ├── cluster │ │ ├── VxApiCluster.java │ │ ├── VxApiClusterFactory.java │ │ ├── VxApiClusterManagerFactory.java │ │ └── impl │ │ │ └── VxApiClusterZookeeperImpl.java │ │ ├── core │ │ ├── VxApiLauncher.java │ │ ├── VxApiMain.java │ │ ├── auth │ │ │ ├── VxApiClientAuthProviderImpl.java │ │ │ ├── VxApiClientAuthUser.java │ │ │ ├── VxApiClientJsonAuth.java │ │ │ ├── VxApiClientStaticAuth.java │ │ │ ├── VxApiRolesConstant.java │ │ │ └── VxApiUserAuthUtil.java │ │ ├── common │ │ │ ├── DataSourceProviderOfDruid.java │ │ │ ├── HttpUtils.java │ │ │ ├── ParamCheckUtil.java │ │ │ ├── PathUtil.java │ │ │ ├── ResultFormat.java │ │ │ ├── ResultFormatObj.java │ │ │ ├── StrUtil.java │ │ │ ├── VxApiApplicationConverter.java │ │ │ ├── VxApiDATAStoreConstant.java │ │ │ ├── VxApiEventBusAddressConstant.java │ │ │ ├── VxApiGatewayAttribute.java │ │ │ └── VxApiRequestBodyHandler.java │ │ ├── entity │ │ │ ├── VxApiAPILimit.java │ │ │ ├── VxApiApiEntrance.java │ │ │ ├── VxApiContentType.java │ │ │ ├── VxApiDeployInfos.java │ │ │ ├── VxApiEntranceParam.java │ │ │ ├── VxApiResult.java │ │ │ ├── VxApiResultStatus.java │ │ │ ├── VxApiSecurityPolicies.java │ │ │ ├── VxApiServerEntrance.java │ │ │ ├── VxApiServerURL.java │ │ │ ├── VxApiServerURLInfo.java │ │ │ ├── VxApiServerURLPollingPolicy.java │ │ │ ├── VxApiTrackInfos.java │ │ │ └── VxApis.java │ │ ├── enums │ │ │ ├── ApiServerTypeEnum.java │ │ │ ├── ConnectProtocolEnum.java │ │ │ ├── ContentTypeEnum.java │ │ │ ├── EnterParamMapTypeEnum.java │ │ │ ├── HTTPStatusCodeMsgEnum.java │ │ │ ├── HttpMethodEnum.java │ │ │ ├── LoadBalanceEnum.java │ │ │ ├── ParamPositionEnum.java │ │ │ ├── ParamSystemVarTypeEnum.java │ │ │ ├── ParamTypeEnum.java │ │ │ └── TimeUnitEnum.java │ │ ├── handler │ │ │ ├── FreeMarkerTemplateHander.java │ │ │ └── route │ │ │ │ ├── VxApiRouteConstant.java │ │ │ │ ├── VxApiRouteHandlerApiLimit.java │ │ │ │ ├── VxApiRouteHandlerHttpService.java │ │ │ │ ├── VxApiRouteHandlerParamCheck.java │ │ │ │ ├── VxApiRouteHandlerRedirectType.java │ │ │ │ └── impl │ │ │ │ ├── VxApiRouteApiLimitImpl.java │ │ │ │ ├── VxApiRouteHandlerHttpServiceImpl.java │ │ │ │ ├── VxApiRouteHandlerParamCheckImpl.java │ │ │ │ └── VxApiRouteHandlerRedirectTypeImpl.java │ │ ├── options │ │ │ ├── VxApiApplicationDTO.java │ │ │ ├── VxApiApplicationOptions.java │ │ │ ├── VxApiCertOptions.java │ │ │ ├── VxApiCorsOptions.java │ │ │ ├── VxApiParamCheckOptions.java │ │ │ ├── VxApiParamOptions.java │ │ │ ├── VxApiServerEntranceHttpOptions.java │ │ │ ├── VxApiServerEntranceRedirectOptions.java │ │ │ ├── VxApiServerOptions.java │ │ │ └── VxApisDTO.java │ │ └── verticle │ │ │ ├── CLIVerticle.java │ │ │ ├── CURLClientVerticle.java │ │ │ ├── ClientVerticle.java │ │ │ ├── DATAVerticle.java │ │ │ ├── DeploymentVerticle.java │ │ │ ├── SysVerticle.java │ │ │ └── VxApiApplication.java │ │ └── spi │ │ ├── auth │ │ ├── VxApiAuth.java │ │ ├── VxApiAuthFactory.java │ │ ├── VxApiAuthOptions.java │ │ └── impl │ │ │ ├── VxApiAuthJwtTokenImpl.java │ │ │ └── VxApiAuthSessionTokenImpl.java │ │ ├── common │ │ └── HttpHeaderConstant.java │ │ ├── customHandler │ │ ├── VxApiCustomHandler.java │ │ ├── VxApiCustomHandlerFactory.java │ │ ├── VxApiCustomHandlerOptions.java │ │ └── impl │ │ │ ├── GetConstantValueHandler.java │ │ │ ├── GetServerUnixTimestampHandler.java │ │ │ └── SessionTokenGrantAuthHandler.java │ │ └── handler │ │ ├── VxApiAfterHandler.java │ │ ├── VxApiAfterHandlerFactory.java │ │ ├── VxApiAfterHandlerOptions.java │ │ ├── VxApiBeforeHandler.java │ │ ├── VxApiBeforeHandlerFactory.java │ │ ├── VxApiBeforeHandlerOptions.java │ │ └── impl │ │ ├── TestAfterHandlerSimple.java │ │ └── TestBeforeHandlerSimple.java └── resources │ ├── cert │ └── 目录说明.txt │ ├── conf.json │ ├── configDB.db │ ├── log4j.properties │ ├── log4j2-test.xml │ ├── log4j2.xml │ ├── static │ ├── API.html │ ├── Application.html │ ├── CreateAPI.html │ ├── CreateAPP.html │ ├── SysInfos.html │ ├── css │ │ ├── main.css │ │ └── page.css │ ├── framework │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.js │ │ └── jquery.min.js │ ├── js │ │ ├── APISelectChange.js │ │ ├── createAPP.js │ │ ├── main.js │ │ └── page.js │ └── logo.png │ ├── templates │ ├── getAPI.ftl │ ├── getAPP.ftl │ ├── updateAPI.ftl │ └── updateAPP.ftl │ ├── user.json │ ├── 目录说明.txt │ └── 配置文件说明.txt └── test └── .gitignore /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.classpath 3 | /.gitignore 4 | /.project 5 | /.settings/ 6 | /.vertx/ 7 | /.src/test/ 8 | /logs/ 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 MirrenTools 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 特殊说明 2 | 由于本人工作比较忙的原因,原计划2.0开发的工作一直耽搁着,但是Vert.x与Netty本身修复了许多bug,所以将原本vert.x依赖由3.5.2升级3.9.2 3 | 4 | 2020/06/16 5 | 6 | ## 2.0升级说明 7 | VX-API已经在本人公司运行了236天(2018-11-23),核心处理器处理了9000多万次,网关对于我们这种访问量不大的公司来说基本不是问题,但是VX-API当前1.0版本性能还有很大的控件没有压榨出来,部分设计也不是很人性化,所以本人已经在安排时间做2.0版,2.0版性能将大大提升,也会更人性化,推荐大家先加入群里或者关注该项目后等2.0版再使用,2.0版不打算兼容1.0版,但是会出工具将1.0的接口迁移到2.0 8 | 9 | # VX-API-Gateway 10 | ![logo](https://raw.githubusercontent.com/shenzhenMirren/MyGithubResources/master/image/VX-API-Gateway-Logo_small.png)
11 | VX-API-Gateway是基于Vert.x(java)开发的API网关,是一个分布式,全异步,高性能,可扩展 ,轻量级的API网关
12 | VX-API-Gateway的部分流程与页面设计灵感来自阿里云的API网关
13 | QQ交流群 : 440306757
14 | ### 软件使用说明 15 | [VX-API-Gateway使用帮助文档](http://mirren.gitee.io/vx-api-gateway-doc/)
16 | # VX-API 执行流程 17 | ![flowchart](https://raw.githubusercontent.com/shenzhenMirren/MyGithubResources/master/image/VX-API-Gateway-flowchart.png) 18 |
19 | 绿线代表一定会执行,黑线代表当存在时执行,当用户请求的时候,完整的流程按组件顺序由1开始执行到7,如果不满足任意一个组件时请求结束并响应(fail-end-response),当任意组件出现异常时统一进入异常组件(Exception Handler)请求结束并响应错误信息 20 |
21 | API的执行流程参考组件介绍 22 | ## 组件介绍 23 | ### 1.黑名单检查 24 | 该组件永远会被执行! 用户请求时第一步先经过黑名单检查,VX-API会读取请求中的remote Address并获取用户的host(也就是获取用户的IP地址),如果用户的IP地址在全局黑名单中,结束请求并响应状态码:404,状态信息:you can't access this service;反则继续执行处理... 25 | ### 2.访问限制 26 | 当创建API时开启了访问限制,该组件会被执行! 访问限制单位分别为:天/小时/分;可以设置API与IP限制,IP的限制不能大于API的限制;
27 | 假设开启API限制:1分钟可以访问1000次;如果1分钟内访问次数大于1000将结束请求并响应请求(响应内容为:创建API中定义API返回结果:访问限制返回);反则继续执行处理... 28 | ### 3.参数检查 29 | 当创建API时如果在定义API请求中添加了入参定义,该组件会被执行! 组件会根据入参定义规定的格式检查请求中的参数;
30 | 如果参数不符合入参定义结束请求并响应请求(响应内容为:创建API中定义API返回结果:网关入口参数检查失败返回);反则继续执行处理... 31 | ### 4.权限认证 32 | 当创建API时开启了安全认证,该组件会被执行! 组件会将流程交给权限认证插件,权限认证插件负责做相关处理后决定将流程交给下一个组件处理或结束请求 33 | ### 5.前置处理器 34 | 当创建API时开启了前置处理器,该组件会被执行! 组件会将流程交给前置处理器插件,前置处理器插件负责做相关处理后决定将流程交给下一个组件处理或结束请求 35 | ### 6.中心处理器(主处理器) 36 | 当前面的组件都执行通过时,该组件永远会被执行! 组件会根据服务类型做相应的处理,处理完毕后组件会判断是否开启了后置处理器,如果开启了后置处理器,组件会将流程交给后置处理器,并传递一个标识告诉后置处理器当前组件处理的结果;反则结束请求并返回服务结果; 37 | ### 7.后置处理器 38 | 当创建API时开启了后置处理器,该组件会被执行! 该组件是正常流程的最后一个组件,组件会收到主处理器的执行结果,组件做完相应操作后必须做对请求的响应用户的请求; 39 | ### 8.异常处理器 40 | 当以上任意组件在执行的过程中出现了异常,该组件会被执行! 组件会结束请求并响应请求(响应内容为:创建API中定义API返回结果:发生异常/失败返回); 41 | ## 服务类型介绍 42 | 服务类型指网关主处理器要处理的类型,详情参考类型以下的介绍 43 | ### HTTP/HTTPS 44 | 表示后台服务是常见的HTTP/HTTPS,也就是网关要将用户的请求发送的目的地,该服务支持带权重的负载均衡支持轮询与哈希策略(默认轮询),自动断路并重试连接;当网关请求后台服务地址失败时会提交给策略,如果同一个服务地址失败两次及以上时,会被策略移除,网关会检测策略中是否存在不可用的服务地址,如果存在会根据设定的重试时间进行重试,重试后如果服务地址可用则将服务地址重新添加到策略中 45 | ### 页面跳转 46 | 该服务用于做链接重定向,当用户请求该服务的API时会,网关会返回状态302,告诉浏览器跳转到指定的URL; 47 | ### 自定义服务 48 | 自定义服务其实跟前置处理器实现的功能差不多,因为前置处理器可以做完相应处理后响应用户请求,自定义服务中提供了三个默认的实现,分别为获取网关时间戳,返回常量值与Session认证的授权 49 | 50 | # 执行方式与环境要求 51 | 该项目基于vert.x 3.5.1开发,开发环境jdk1.8_121,理论上只要带有JDK/JRE 1.8以上都可以运行该项目
52 | 可以在发行版中下载已经打包好的或者自己编译打包该项目,方法如下:
53 | 执行mvn clean package appassembler:assemble 对项目进行编译打包
54 | ```html 55 | mvn clean package appassembler:assemble 56 | 打包完毕后进入target/VX-API-Gateway/bin执行相应bat/sh文件 57 | ``` 58 | 如果机器上没有JDK8环境,可以自己下载一个JRE/JDK环境并在脚本中指定软件使用哪个JRE/JDK启动
59 | 修改示例(Windows环境):
60 | 假设jre在D盘/java目录下,可以在start.bat找到%JAVACMD% %JAVA_OPTS% -Dfile....
61 | 在以上语句前cd到jre的所在bin目录,也就是在执行java之前切换到D:/java/jreXXX/bin目录在执行java,相当于设置了一个运行环境
62 | ```html 63 | cd D:/java/jreXXX/bin 64 | %JAVACMD% %JAVA_OPTS% -Dfile.encoding=UTF-8 ... 65 | ``` 66 | ### 软件目录说明: 67 | bin 执行脚本
68 | conf 配置文件与客户端静态文件
69 | lib 项目依赖的架包
70 | logs 日志文件
71 | temp 缓存/临时文件
72 | ## 项目目录说明 73 | src/main/java中core包存放核心代码,spi包存放用户可以自定义插件的接口与工厂,自定义插件时实现相应的接口并在工场中添加获取该实现的名字与实现类,同时在客户端静态文件中添加相应的名字便可
74 | ## 性能测试 75 | 后台服务输出hello
76 | Nginx Stable1.12.0 配置
77 | ![nginx-conf](http://mirren.gitee.io/vx-api-gateway-doc/image/other/nginx-conf.png) 78 |
79 | 阿里云 centos 7 1G内存1核1兆带宽环境 ab -n 1000 -c 1000 执行结果
80 | Nginx:ab结果
81 | ![nginx-linux-ab](http://mirren.gitee.io/vx-api-gateway-doc/image/other/linux-1c1n1gnqcq-nginx.png)
82 | VX-API: JVM -Xms512m -Xmx512m 其他默认 ab结果
83 | ![VX-API-linux-ab](http://mirren.gitee.io/vx-api-gateway-doc/image/other/linux-1c1n1gnqcq-vx-xsm-512m.png)
84 | Windows 10 8核8G内存 环境 ab -n 100000 -c 2000 执行结果
85 | Nginx:ab结果
86 | ![nginx-win-ab](http://mirren.gitee.io/vx-api-gateway-doc/image/other/win-8g8cn10wc2q-nginx.png)
87 | VX-API: JVM -Xms2G -Xmx2G 其他默认 ab结果
88 | ![VX-API-win-ab](http://mirren.gitee.io/vx-api-gateway-doc/image/other/win-8g8cn10wc2q-vx-xsm-2g.png)
89 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/.gitignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | /testMain/ 3 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/Main.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi; 2 | 3 | import com.szmirren.vxApi.core.VxApiLauncher; 4 | 5 | /** 6 | * 该类只是开发环境启动使用,没有什么实际的用处 7 | * 8 | * @author Mirren 9 | * 10 | */ 11 | public class Main { 12 | public static void main(String[] args) { 13 | VxApiLauncher.start(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/cluster/VxApiCluster.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.cluster; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Handler; 5 | import io.vertx.core.json.JsonArray; 6 | import io.vertx.core.json.JsonObject; 7 | 8 | /** 9 | * 集群环境获取配置文件 10 | * 11 | * @author Mirren 12 | * 13 | */ 14 | public interface VxApiCluster { 15 | /** 16 | * 在集群环境中获取应用程序的配置文件 17 | * 18 | * @return 19 | */ 20 | void getConfig(Handler> event); 21 | /** 22 | * 添加网关应用到集群环境 23 | * 24 | * @param app 25 | * @param event 26 | */ 27 | void putApplication(JsonObject app, Handler> event); 28 | 29 | /** 30 | * 在集群环境中获取所有网关应用 31 | * 32 | * @param event 33 | */ 34 | void getApplication(Handler> event); 35 | /** 36 | * 添加API到集群环境 37 | * 38 | * @param appName 39 | * @param api 40 | * @param event 41 | */ 42 | void putAPI(String appName, JsonObject api, Handler> event); 43 | /** 44 | * 在集群环境中获取指定网关应用的所有API 45 | * 46 | * @param appName 47 | * @param event 48 | */ 49 | void getAPIS(String appName, Handler> event); 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/cluster/VxApiClusterFactory.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.cluster; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.szmirren.vxApi.cluster.impl.VxApiClusterZookeeperImpl; 7 | import com.szmirren.vxApi.core.common.StrUtil; 8 | 9 | import io.vertx.core.Vertx; 10 | import io.vertx.core.json.JsonObject; 11 | 12 | /** 13 | * 配置中心工厂 14 | * 15 | * @author Mirren 16 | * 17 | */ 18 | public class VxApiClusterFactory { 19 | /** 20 | * sessionToken的实现类名称 21 | */ 22 | public final static String ZOOKEEPER = "zookeeper"; 23 | 24 | /** 25 | * 获得所有实现类的名字 26 | * 27 | * @return 28 | */ 29 | public static List getImplNames() { 30 | List result = new ArrayList<>(); 31 | result.add(ZOOKEEPER); 32 | return result; 33 | } 34 | 35 | /** 36 | * 通过名字获得配置中心的实现类 37 | * 38 | * @param name 39 | * @param options 40 | * @return 41 | * @throws NullPointerException 42 | * @throws ClassNotFoundException 43 | */ 44 | public static VxApiClusterZookeeperImpl getClusterConfig(String name, JsonObject options, Vertx vertx) 45 | throws NullPointerException, ClassNotFoundException { 46 | if (StrUtil.isNullOrEmpty(name)) { 47 | throw new NullPointerException("获取集群配置中心实现类-->失败:工厂名字不能为空"); 48 | } 49 | if (ZOOKEEPER.equalsIgnoreCase(name)) { 50 | return new VxApiClusterZookeeperImpl(options, vertx); 51 | } 52 | throw new ClassNotFoundException("没有找到名字为 : " + name + " 的集群配置中心实现类"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/cluster/VxApiClusterManagerFactory.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.cluster; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import io.vertx.core.json.JsonObject; 7 | import io.vertx.core.spi.cluster.ClusterManager; 8 | import io.vertx.spi.cluster.zookeeper.ZookeeperClusterManager; 9 | 10 | /** 11 | * VX-APi的句群管理ClusterManager工厂类 12 | * 13 | * @author Mirren 14 | * 15 | */ 16 | public class VxApiClusterManagerFactory { 17 | /** 18 | * zookeeper的实现名称 19 | */ 20 | public final static String ZOOKEEPER = "zookeeper"; 21 | 22 | /** 23 | * 获得所有实现类的名字 24 | * 25 | * @return 26 | */ 27 | public static List getImplNames() { 28 | List result = new ArrayList<>(); 29 | result.add(ZOOKEEPER); 30 | return result; 31 | } 32 | 33 | /** 34 | * 获得集群管理 35 | * 36 | * @param name 37 | * 实现类在集群中的名字 38 | * @param options 39 | * 集群实现所需要的配置文件 40 | * @return 41 | */ 42 | public static ClusterManager getClusterManager(String name, JsonObject options) { 43 | if (ZOOKEEPER.equalsIgnoreCase(name)) { 44 | return new ZookeeperClusterManager(options); 45 | } 46 | return null; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/cluster/impl/VxApiClusterZookeeperImpl.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.cluster.impl; 2 | 3 | import org.apache.curator.framework.CuratorFramework; 4 | import org.apache.curator.framework.CuratorFrameworkFactory; 5 | import org.apache.curator.retry.ExponentialBackoffRetry; 6 | 7 | import com.szmirren.vxApi.cluster.VxApiCluster; 8 | 9 | import io.vertx.core.AsyncResult; 10 | import io.vertx.core.Future; 11 | import io.vertx.core.Handler; 12 | import io.vertx.core.Vertx; 13 | import io.vertx.core.json.JsonArray; 14 | import io.vertx.core.json.JsonObject; 15 | 16 | /** 17 | * 用于集群时获取网关所需要配置信息 18 | * 19 | * @author Mirren 20 | * 21 | */ 22 | public class VxApiClusterZookeeperImpl implements VxApiCluster { 23 | private JsonObject zkConf = new JsonObject();// 配置信息 24 | private Vertx vertx; 25 | 26 | /** 27 | * 初始化一个Zookeeper的配置文件 28 | * 29 | * @param zkConf 30 | */ 31 | public VxApiClusterZookeeperImpl(JsonObject zkConf, Vertx vertx) { 32 | this.zkConf = zkConf; 33 | this.vertx = vertx; 34 | } 35 | 36 | @Override 37 | public void getConfig(Handler> event) { 38 | vertx.executeBlocking(get -> { 39 | JsonObject retry = zkConf.getJsonObject("retry", new JsonObject()); 40 | String hosts = zkConf.getString("zookeeperHosts", "127.0.0.1"); 41 | int baseSleepTimeMs = retry.getInteger("initialSleepTime", 1000); 42 | int maxRetries = retry.getInteger("maxTimes", 5); 43 | int maxSleepMs = retry.getInteger("intervalTimes", 10000); 44 | int sessionTimeoutMs = zkConf.getInteger("sessionTimeout", 20000); 45 | int connectionTimeoutMs = zkConf.getInteger("connectTimeout", 3000); 46 | ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries, maxSleepMs); 47 | String vxApiConfPath = zkConf.getString("vxApiConfPath", "/io.vertx/vx.api.gateway/conf"); 48 | CuratorFramework client = CuratorFrameworkFactory.newClient(hosts, sessionTimeoutMs, connectionTimeoutMs, retryPolicy); 49 | try { 50 | client.start(); 51 | byte[] data = client.getData().forPath(vxApiConfPath); 52 | String jsons = new String(data); 53 | get.complete(new JsonObject(jsons)); 54 | } catch (Exception e) { 55 | get.fail(e); 56 | } finally { 57 | client.close(); 58 | } 59 | }, event); 60 | } 61 | 62 | @Override 63 | public void putApplication(JsonObject app, Handler> event) { 64 | event.handle(Future.failedFuture("该方法会在后续版本实现")); 65 | } 66 | @Override 67 | public void getApplication(Handler> event) { 68 | event.handle(Future.failedFuture("该方法会在后续版本实现")); 69 | } 70 | @Override 71 | public void putAPI(String appName, JsonObject api, Handler> event) { 72 | event.handle(Future.failedFuture("该方法会在后续版本实现")); 73 | } 74 | @Override 75 | public void getAPIS(String appName, Handler> event) { 76 | event.handle(Future.failedFuture("该方法会在后续版本实现")); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiClientAuthProviderImpl.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | import com.szmirren.vxApi.core.common.PathUtil; 4 | 5 | import io.vertx.core.AsyncResult; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Handler; 8 | import io.vertx.core.Vertx; 9 | import io.vertx.core.json.JsonObject; 10 | import io.vertx.ext.auth.AuthProvider; 11 | import io.vertx.ext.auth.User; 12 | 13 | /** 14 | * 客户端通用权限认证的实现 15 | * 16 | * @author Mirren 17 | * 18 | */ 19 | public class VxApiClientAuthProviderImpl implements AuthProvider { 20 | private Vertx vertx; 21 | 22 | public VxApiClientAuthProviderImpl(Vertx vertx) { 23 | super(); 24 | this.vertx = vertx; 25 | } 26 | 27 | @Override 28 | public void authenticate(JsonObject authInfo, Handler> resultHandler) { 29 | String username = authInfo.getString("username"); 30 | if (authInfo.getString("username") == null || "".equals(authInfo.getString("username"))) { 31 | resultHandler.handle(Future.succeededFuture(null)); 32 | } else { 33 | String pwd = authInfo.getString("password"); 34 | String path = PathUtil.getPathString("user.json"); 35 | vertx.fileSystem().readFile(path, res -> { 36 | if (res.succeeded()) { 37 | JsonObject users = res.result().toJsonObject(); 38 | if (users.getValue(username) instanceof JsonObject) { 39 | JsonObject user = users.getJsonObject(username); 40 | if (pwd != null && pwd.equals(user.getString("pwd"))) { 41 | VxApiClientAuthUser authUser = new VxApiClientAuthUser(); 42 | authUser.setPrincipal(new JsonObject().put("roles", user.getJsonArray("roles"))); 43 | resultHandler.handle(Future.succeededFuture(authUser)); 44 | } else { 45 | resultHandler.handle(Future.succeededFuture(null)); 46 | } 47 | } else { 48 | resultHandler.handle(Future.succeededFuture(null)); 49 | } 50 | } else { 51 | resultHandler.handle(Future.failedFuture("找不到用户配置文件:" + path)); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | public Vertx getVertx() { 58 | return vertx; 59 | } 60 | 61 | public void setVertx(Vertx vertx) { 62 | this.vertx = vertx; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiClientAuthUser.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | import io.vertx.core.AsyncResult; 4 | import io.vertx.core.Future; 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.json.JsonArray; 7 | import io.vertx.core.json.JsonObject; 8 | import io.vertx.ext.auth.AbstractUser; 9 | import io.vertx.ext.auth.AuthProvider; 10 | 11 | /** 12 | * 客户端通用权限认证的用户 13 | * 14 | * @author Mirren 15 | * 16 | */ 17 | public class VxApiClientAuthUser extends AbstractUser { 18 | 19 | private JsonObject principal; 20 | 21 | @Override 22 | public JsonObject principal() { 23 | return principal; 24 | } 25 | 26 | /** 27 | * 设置用户附加信息 28 | * 29 | * @param principal 30 | */ 31 | public void setPrincipal(JsonObject principal) { 32 | this.principal = principal; 33 | } 34 | 35 | @Override 36 | public void setAuthProvider(AuthProvider authProvider) { 37 | } 38 | 39 | @Override 40 | protected void doIsPermitted(String permission, Handler> resultHandler) { 41 | JsonArray roles = principal.getJsonArray("roles"); 42 | resultHandler.handle(Future.succeededFuture((roles != null && roles.contains(permission)))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiClientJsonAuth.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | import com.szmirren.vxApi.core.common.PathUtil; 4 | 5 | import io.vertx.core.AsyncResult; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Handler; 8 | import io.vertx.core.Vertx; 9 | import io.vertx.core.file.FileSystem; 10 | import io.vertx.core.json.JsonObject; 11 | 12 | /** 13 | * 使用json进行相应操作的权限认证 14 | * 15 | * @author Mirren 16 | * 17 | */ 18 | public class VxApiClientJsonAuth { 19 | /** 20 | * 验证用户是否有权限 21 | * 22 | * @param user 23 | * @param vertx 24 | * @param handler 25 | */ 26 | public static void auth(JsonObject authInfo, Vertx vertx, Handler> handler) { 27 | String username = authInfo.getString(VxApiRolesConstant.USER_NAME_KEY); 28 | if (username == null) { 29 | handler.handle(Future.succeededFuture(false)); 30 | } else { 31 | String pwd = authInfo.getString(VxApiRolesConstant.USER_PWD_KEY); 32 | String role = authInfo.getString(VxApiRolesConstant.USER_ROLE_KEY); 33 | FileSystem file = vertx.fileSystem(); 34 | String path = PathUtil.getPathString("user.json"); 35 | file.readFile(path, res -> { 36 | if (res.succeeded()) { 37 | JsonObject users = res.result().toJsonObject(); 38 | if (users.getValue(username) instanceof JsonObject) { 39 | JsonObject user = users.getJsonObject(username); 40 | if (pwd != null && pwd.equals(user.getString("pwd")) 41 | && user.getJsonArray("roles").contains(role)) { 42 | handler.handle(Future.succeededFuture(true)); 43 | } else { 44 | handler.handle(Future.succeededFuture(false)); 45 | } 46 | } else { 47 | handler.handle(Future.succeededFuture(false)); 48 | } 49 | } else { 50 | handler.handle(Future.failedFuture(res.cause())); 51 | } 52 | }); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiClientStaticAuth.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | import java.util.Base64; 4 | 5 | import com.szmirren.vxApi.core.common.ResultFormat; 6 | import com.szmirren.vxApi.core.common.VxApiGatewayAttribute; 7 | import com.szmirren.vxApi.core.enums.HTTPStatusCodeMsgEnum; 8 | 9 | import io.vertx.core.Handler; 10 | import io.vertx.core.json.JsonObject; 11 | import io.vertx.ext.web.RoutingContext; 12 | 13 | /** 14 | * 使用json进行相应操作的权限认证 15 | * 16 | * @author Mirren 17 | * 18 | */ 19 | public class VxApiClientStaticAuth implements Handler { 20 | public static final String AUTHORIZATION = "Authorization"; 21 | public static final String IS_AUTH = "isAuth"; 22 | 23 | public static VxApiClientStaticAuth create() { 24 | return new VxApiClientStaticAuth(); 25 | } 26 | 27 | @Override 28 | public void handle(RoutingContext event) { 29 | if (event.session().get(AUTHORIZATION) != null) { 30 | VxApiClientAuthUser user = new VxApiClientAuthUser(); 31 | user.setPrincipal(event.session().get(AUTHORIZATION)); 32 | event.setUser(user); 33 | event.next(); 34 | } else { 35 | String auth = event.request().getHeader(AUTHORIZATION); 36 | if (auth == null) { 37 | event.response().putHeader("WWW-Authenticate", "Basic realm=\"" + VxApiGatewayAttribute.FULL_NAME + "\"").setStatusCode(401).end(); 38 | } else { 39 | if ("false".equals(event.session().get(IS_AUTH))) { 40 | event.session().remove(IS_AUTH); 41 | event.response().putHeader("WWW-Authenticate", "Basic realm=\"" + VxApiGatewayAttribute.FULL_NAME + "\"").setStatusCode(401) 42 | .end(); 43 | } else { 44 | try { 45 | final String suser; 46 | final String spass; 47 | String decoded = new String(Base64.getDecoder().decode(auth.split(" ")[1])); 48 | int colonIdx = decoded.indexOf(":"); 49 | if (colonIdx != -1) { 50 | suser = decoded.substring(0, colonIdx); 51 | spass = decoded.substring(colonIdx + 1); 52 | } else { 53 | suser = decoded; 54 | spass = null; 55 | } 56 | VxApiUserAuthUtil.auth(suser, spass, event.vertx(), res -> { 57 | if (res.succeeded()) { 58 | JsonObject u = res.result(); 59 | if (u != null) { 60 | event.session().put("userName", suser); 61 | event.session().put(IS_AUTH, "true"); 62 | event.session().put(AUTHORIZATION, u); 63 | VxApiClientAuthUser user = new VxApiClientAuthUser(); 64 | user.setPrincipal(u); 65 | event.setUser(user); 66 | event.next(); 67 | } else { 68 | event.response().putHeader("WWW-Authenticate", "Basic realm=\"" + VxApiGatewayAttribute.FULL_NAME + "\"") 69 | .setStatusCode(401).end(); 70 | } 71 | } else { 72 | event.response().end(ResultFormat.format(HTTPStatusCodeMsgEnum.C500, res.cause())); 73 | } 74 | }); 75 | } catch (Exception e) { 76 | event.response().end(ResultFormat.format(HTTPStatusCodeMsgEnum.C401, e)); 77 | } 78 | } 79 | } 80 | } 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiRolesConstant.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | /** 4 | * 用户的角色 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public interface VxApiRolesConstant { 10 | // ================================================= 11 | // ===================权限能力======================== 12 | // ================================================= 13 | /** 14 | * 读写权限 15 | */ 16 | final String WRITE = "write"; 17 | /** 18 | * 读权限 19 | */ 20 | final String READ = "read"; 21 | 22 | // ================================================= 23 | // ==============用户在传输协议中的名字=================== 24 | // ================================================= 25 | /** 26 | * 用户名字的key 27 | */ 28 | final String USER_NAME_KEY = "user"; 29 | /** 30 | * 用户密码的key 31 | */ 32 | final String USER_PWD_KEY = "pwd"; 33 | /** 34 | * 用户角色的key 35 | */ 36 | final String USER_ROLE_KEY = "role"; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/auth/VxApiUserAuthUtil.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.auth; 2 | 3 | import com.szmirren.vxApi.core.common.PathUtil; 4 | 5 | import io.vertx.core.AsyncResult; 6 | import io.vertx.core.Future; 7 | import io.vertx.core.Handler; 8 | import io.vertx.core.Vertx; 9 | import io.vertx.core.file.FileSystem; 10 | import io.vertx.core.json.JsonObject; 11 | 12 | /** 13 | * 用于验证用户是否正确 14 | * 15 | * @author Mirren 16 | * 17 | */ 18 | public class VxApiUserAuthUtil { 19 | /** 20 | * 验证用户是否正确,如果正确返回json格式的用户如果不存在返回null 21 | * 22 | * @param suser 23 | * 用户名字 24 | * @param spass 25 | * 用户密码 26 | * @param vertx 27 | * vertx 28 | * @param handler 29 | * 结果 30 | */ 31 | public static void auth(String suser, String spass, Vertx vertx, Handler> handler) { 32 | FileSystem file = vertx.fileSystem(); 33 | String path = PathUtil.getPathString("user.json"); 34 | file.readFile(path, res -> { 35 | if (res.succeeded()) { 36 | JsonObject users = res.result().toJsonObject(); 37 | if (users.getValue(suser) instanceof JsonObject) { 38 | JsonObject user = users.getJsonObject(suser); 39 | if (spass.equals(user.getString("pwd"))) { 40 | handler.handle(Future.succeededFuture(user)); 41 | } else { 42 | handler.handle(Future.succeededFuture(null)); 43 | } 44 | } else { 45 | handler.handle(Future.succeededFuture(null)); 46 | } 47 | } else { 48 | handler.handle(Future.failedFuture(res.cause())); 49 | } 50 | }); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/DataSourceProviderOfDruid.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import java.sql.SQLException; 4 | 5 | import javax.sql.DataSource; 6 | 7 | import com.alibaba.druid.filter.logging.Log4j2Filter; 8 | import com.alibaba.druid.pool.DruidDataSource; 9 | 10 | import io.vertx.core.json.JsonObject; 11 | import io.vertx.ext.jdbc.spi.DataSourceProvider; 12 | 13 | public class DataSourceProviderOfDruid extends DruidDataSource implements DataSourceProvider { 14 | private static final long serialVersionUID = 381971380983136762L; 15 | 16 | public int maximumPoolSize(DataSource dataSource, JsonObject config) throws SQLException { 17 | return config.getInteger("max_pool_size", 15).intValue(); 18 | } 19 | 20 | public DataSource getDataSource(JsonObject config) throws SQLException { 21 | Log4j2Filter log4j2 = new Log4j2Filter(); 22 | DruidDataSource ds = new DruidDataSource(); 23 | ds.getProxyFilters().add(log4j2); 24 | ds.setUrl(config.getString("url")); 25 | ds.setDriverClassName(config.getString("driver_class")); 26 | ds.setUsername(config.getString("user")); 27 | ds.setPassword(config.getString("password")); 28 | ds.setMaxActive(config.getInteger("max_pool_size", 15)); 29 | ds.setMinIdle(config.getInteger("min_pool_size", 1)); 30 | ds.setInitialSize(config.getInteger("initial_pool_size", 1)); 31 | ds.setMinEvictableIdleTimeMillis(config.getLong("max_idle_time", 60000L)); 32 | ds.setValidationQuery(config.getValue("validation_query", "select 1").toString()); 33 | return ds; 34 | } 35 | 36 | public void close(DataSource dataSource) throws SQLException { 37 | if ((dataSource instanceof DataSourceProviderOfDruid)) 38 | ((DataSourceProviderOfDruid) dataSource).close(); 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/HttpUtils.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import java.nio.charset.Charset; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import io.netty.handler.codec.http.QueryStringDecoder; 8 | import io.vertx.core.MultiMap; 9 | import io.vertx.core.http.CaseInsensitiveHeaders; 10 | 11 | /** 12 | * HTTP相关的工具 13 | * 14 | * @author Mirren 15 | * 16 | */ 17 | public class HttpUtils { 18 | /** 19 | * 解码URI中的参数,既?后面的参数 20 | * 21 | * @param uri 22 | * uri参数,默认以utf-8方式 23 | * @return 返回解码后的结果或者返回新的MultiMap 24 | */ 25 | public static MultiMap decoderUriParams(String uri) { 26 | return decoderUriParams(uri, Charset.forName("UTF-8")); 27 | } 28 | 29 | /** 30 | * 解码URI中的参数,既?后面的参数 31 | * 32 | * @param uri 33 | * uri参数 34 | * @param charset 35 | * 解码格式,如果该字段为空则默认为utf-8方式 36 | * @return 返回解码后的结果或者返回新的MultiMap,如果发生异常返回新的MultiMap 37 | */ 38 | public static MultiMap decoderUriParams(String uri, Charset charset) { 39 | try { 40 | if (charset == null) { 41 | charset = Charset.forName("UTF-8"); 42 | } 43 | QueryStringDecoder decode = new QueryStringDecoder(uri, charset, false); 44 | Map> paramMap = decode.parameters(); 45 | MultiMap params = new CaseInsensitiveHeaders(); 46 | if (!paramMap.isEmpty()) { 47 | for (Map.Entry> entry : paramMap.entrySet()) { 48 | params.add(entry.getKey(), entry.getValue()); 49 | } 50 | } 51 | return params; 52 | } catch (Exception e) { 53 | return new CaseInsensitiveHeaders(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/ParamCheckUtil.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import io.vertx.core.json.EncodeException; 4 | import io.vertx.core.json.Json; 5 | 6 | /** 7 | * 参数检查工具 8 | * 9 | * @author Mirren 10 | * 11 | */ 12 | public class ParamCheckUtil { 13 | /** 14 | * 检查是否为int类型的数据, 15 | * 16 | * @param obj 17 | * @return 18 | */ 19 | public static boolean isInt(String obj) { 20 | try { 21 | Integer.valueOf(obj); 22 | return true; 23 | } catch (NumberFormatException e) { 24 | return false; 25 | } 26 | } 27 | 28 | /** 29 | * 检查是否为int类型的数据, 30 | * 31 | * @param obj 32 | * @return 33 | */ 34 | public static boolean isInt(Object obj) { 35 | try { 36 | Integer.valueOf(obj.toString()); 37 | return true; 38 | } catch (NumberFormatException e) { 39 | return false; 40 | } 41 | } 42 | 43 | /** 44 | * 检查是否为Long类型的数据, 45 | * 46 | * @param obj 47 | * @return 48 | */ 49 | public static boolean isLong(String obj) { 50 | try { 51 | Long.valueOf(obj); 52 | return true; 53 | } catch (NumberFormatException e) { 54 | return false; 55 | } 56 | } 57 | 58 | /** 59 | * 检查否为Long类型的数据, 60 | * 61 | * @param obj 62 | * @return 63 | */ 64 | public static boolean isLong(Object obj) { 65 | try { 66 | Long.valueOf(obj.toString()); 67 | return true; 68 | } catch (NumberFormatException e) { 69 | return false; 70 | } 71 | } 72 | 73 | /** 74 | * 检查是否为Float类型的数据, 75 | * 76 | * @param obj 77 | * @return 78 | */ 79 | public static boolean isFloat(String obj) { 80 | try { 81 | Float.valueOf(obj); 82 | return true; 83 | } catch (NumberFormatException e) { 84 | return false; 85 | } 86 | } 87 | 88 | /** 89 | * 检查是否为Float类型的数据, 90 | * 91 | * @param obj 92 | * @return 93 | */ 94 | public static boolean isFloat(Object obj) { 95 | try { 96 | Float.valueOf(obj.toString()); 97 | return true; 98 | } catch (NumberFormatException e) { 99 | return false; 100 | } 101 | } 102 | 103 | /** 104 | * 检查是否为Double类型的数据, 105 | * 106 | * @param obj 107 | * @return 108 | */ 109 | public static boolean isDouble(String obj) { 110 | try { 111 | Double.valueOf(obj); 112 | return true; 113 | } catch (NumberFormatException e) { 114 | return false; 115 | } 116 | } 117 | 118 | /** 119 | * 检查是否为Double类型的数据, 120 | * 121 | * @param obj 122 | * @return 123 | */ 124 | public static boolean isDouble(Object obj) { 125 | try { 126 | Double.valueOf(obj.toString()); 127 | return true; 128 | } catch (NumberFormatException e) { 129 | return false; 130 | } 131 | } 132 | 133 | /** 134 | * 检查是否为Boolean数据 135 | * 136 | * @param obj 137 | * @return 138 | */ 139 | public static boolean isBoolean(String obj) { 140 | return (obj != null && (obj.equals("true") || obj.equals("false"))); 141 | } 142 | 143 | /** 144 | * 检查字符串是否为Boolean数据 145 | * 146 | * @param obj 147 | * @return 148 | */ 149 | public static boolean isBoolean(Object obj) { 150 | return (obj != null && (obj.equals("true") || obj.equals("false"))); 151 | } 152 | 153 | /** 154 | * 检查是否为json格式 155 | * 156 | * @param obj 157 | * @return 158 | */ 159 | public static boolean isJosn(Object obj) { 160 | try { 161 | Json.encode(obj); 162 | return true; 163 | } catch (EncodeException e) { 164 | return false; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/PathUtil.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import java.io.File; 4 | import java.io.InputStream; 5 | import java.net.URL; 6 | import java.nio.file.Path; 7 | 8 | /** 9 | * 获取相应路径的工具 10 | * 11 | * @author Mirren 12 | * 13 | */ 14 | public class PathUtil { 15 | /** 16 | * 判断是否在jar环境中运行 17 | * 18 | * @return 是返回true 19 | */ 20 | public static boolean isJarEnv() { 21 | return PathUtil.class.getResource("").getPath().contains(".jar!"); 22 | } 23 | 24 | /** 25 | * 判断是否在jar环境中运行 26 | * 27 | * @return 是返回true 28 | */ 29 | public static boolean isJarEnv(String fileName) { 30 | return Thread.currentThread().getContextClassLoader().getResource(fileName).getPath().contains(".jar!"); 31 | } 32 | 33 | /** 34 | * 获得根目录如果在jar中运行获得相对路径,反则返回当前线程运行的根目录 35 | * 36 | * @param name 37 | * @return 38 | */ 39 | public static String getPathString(String fileName) { 40 | if (fileName == null) { 41 | throw new NullPointerException("文件名字不能为空"); 42 | } 43 | URL path = Thread.currentThread().getContextClassLoader().getResource(fileName); 44 | if (path != null && path.getPath().contains(".jar!")) { 45 | return fileName; 46 | } else { 47 | String result = path == null ? "" : path.getPath(); 48 | return result; 49 | } 50 | } 51 | 52 | /** 53 | * 通过名字获得项目的Path文件 54 | * 55 | * @param fileName 56 | * @return 57 | */ 58 | public static Path getPath(String fileName) { 59 | File file = new File(PathUtil.getPathString(fileName)); 60 | return file.toPath(); 61 | } 62 | 63 | /** 64 | * 获得资源的流 65 | * 66 | * @param fileName 67 | * @return 68 | */ 69 | public static InputStream getStream(String fileName) { 70 | if (fileName == null) { 71 | throw new NullPointerException("文件名字不能为空"); 72 | } 73 | return Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/ResultFormat.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import com.szmirren.vxApi.core.enums.HTTPStatusCodeMsgEnum; 4 | 5 | import io.vertx.core.json.JsonArray; 6 | import io.vertx.core.json.JsonObject; 7 | 8 | /** 9 | * 将StatusCodeMsg转换为返回json
10 | * 返回结果
11 | * status : 状态码
12 | * msg : 信息
13 | * data : 数据
14 | * 15 | * @author Mirren 16 | * 17 | */ 18 | public class ResultFormat { 19 | /** 20 | * 格式化返回结果,code为状态码枚举类,data为数据 21 | * 22 | * @param code 23 | * @param data 24 | * @return 25 | */ 26 | public static String format(HTTPStatusCodeMsgEnum code, Object data) { 27 | ResultFormatObj result = new ResultFormatObj(code.getCode(), code.getMsg(), data); 28 | return result.toJsonStr(); 29 | } 30 | 31 | /** 32 | * 格式化返回结果,code为状态码枚举类,data为数据 33 | * 34 | * @param code 35 | * @param data 36 | * @return 37 | */ 38 | public static String format(HTTPStatusCodeMsgEnum code, JsonArray data) { 39 | JsonObject result = new JsonObject(); 40 | result.put("status", code.getCode()); 41 | result.put("msg", code.getMsg()); 42 | if (data == null) { 43 | data = new JsonArray(); 44 | } 45 | result.put("data", data); 46 | return result.toString(); 47 | } 48 | 49 | /** 50 | * 格式化返回结果,code为状态码枚举类,data为数据 51 | * 52 | * @param code 53 | * @param data 54 | * @return 55 | */ 56 | public static String format(HTTPStatusCodeMsgEnum code, JsonObject data) { 57 | JsonObject result = new JsonObject(); 58 | result.put("status", code.getCode()); 59 | result.put("msg", code.getMsg()); 60 | if (data == null) { 61 | data = new JsonObject(); 62 | } 63 | result.put("data", data); 64 | return result.toString(); 65 | } 66 | 67 | /** 68 | * 格式化返回结果其中data为null,code为状态码枚举类 69 | * 70 | * @param code 71 | * @return 72 | */ 73 | public static String formatAsNull(HTTPStatusCodeMsgEnum code) { 74 | JsonObject result = new JsonObject(); 75 | result.put("status", code.getCode()); 76 | result.put("msg", code.getMsg()); 77 | result.putNull("data"); 78 | return result.toString(); 79 | } 80 | 81 | /** 82 | * 格式化返回结果其中data为{},code为状态码枚举类 83 | * 84 | * @param code 85 | * @return 86 | */ 87 | public static String formatAsNewJson(HTTPStatusCodeMsgEnum code) { 88 | JsonObject result = new JsonObject(); 89 | result.put("status", code.getCode()); 90 | result.put("msg", code.getMsg()); 91 | result.put("data", new JsonObject()); 92 | return result.toString(); 93 | } 94 | 95 | /** 96 | * 格式化返回结果其中data为[],code为状态码枚举类 97 | * 98 | * @param code 99 | * @return 100 | */ 101 | public static String formatAsNewArray(HTTPStatusCodeMsgEnum code) { 102 | JsonObject result = new JsonObject(); 103 | result.put("status", code.getCode()); 104 | result.put("msg", code.getMsg()); 105 | result.put("data", new JsonArray()); 106 | return result.toString(); 107 | } 108 | 109 | /** 110 | * 格式化返回结果其中data为0,code为状态码枚举类 111 | * 112 | * @param code 113 | * @return 114 | */ 115 | public static String formatAsZero(HTTPStatusCodeMsgEnum code) { 116 | JsonObject result = new JsonObject(); 117 | result.put("status", code.getCode()); 118 | result.put("msg", code.getMsg()); 119 | result.put("data", 0); 120 | return result.toString(); 121 | } 122 | 123 | /** 124 | * 格式化返回结果其中data为1,code为状态码枚举类 125 | * 126 | * @param code 127 | * @return 128 | */ 129 | public static String formatAsOne(HTTPStatusCodeMsgEnum code) { 130 | JsonObject result = new JsonObject(); 131 | result.put("status", code.getCode()); 132 | result.put("msg", code.getMsg()); 133 | result.put("data", 1); 134 | return result.toString(); 135 | } 136 | 137 | /** 138 | * 自定义返回结果 139 | * 140 | * @param formatObj 141 | * @return 142 | */ 143 | public static String formatCustom(ResultFormatObj formatObj) { 144 | return formatObj.toJsonStr(); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/ResultFormatObj.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import io.vertx.core.json.Json; 4 | 5 | /** 6 | * 7 | * @author Mirren 8 | * 9 | */ 10 | public class ResultFormatObj { 11 | private int status;// 状态码 12 | private String msg;// 信息 13 | private Object data;// 数据 14 | 15 | public String getMsg() { 16 | return msg; 17 | } 18 | 19 | public void setMsg(String msg) { 20 | this.msg = msg; 21 | } 22 | 23 | public int getStatus() { 24 | return status; 25 | } 26 | 27 | public void setStatus(int status) { 28 | this.status = status; 29 | } 30 | 31 | public Object getData() { 32 | return data; 33 | } 34 | 35 | public void setData(Object data) { 36 | this.data = data; 37 | } 38 | 39 | public String toJsonStr() { 40 | return Json.encode(this); 41 | } 42 | 43 | public ResultFormatObj() { 44 | super(); 45 | } 46 | 47 | public ResultFormatObj(int status, String msg, Object data) { 48 | super(); 49 | this.msg = msg; 50 | this.status = status; 51 | this.data = data; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/VxApiApplicationConverter.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import com.szmirren.vxApi.core.options.VxApiApplicationOptions; 4 | import com.szmirren.vxApi.core.options.VxApiCorsOptions; 5 | import com.szmirren.vxApi.core.options.VxApiServerOptions; 6 | 7 | import io.vertx.core.json.Json; 8 | import io.vertx.core.json.JsonObject; 9 | 10 | /** 11 | * 该类主要用于处理VxAPIApplication的json装换 12 | * 13 | * @author Mirren 14 | * 15 | */ 16 | public class VxApiApplicationConverter { 17 | 18 | public static void fromJson(JsonObject json, VxApiApplicationOptions obj) { 19 | if (json.getValue("appName") instanceof String) { 20 | obj.setAppName((String) json.getValue("appName")); 21 | } 22 | if (json.getValue("describe") instanceof String) { 23 | obj.setDescribe((String) json.getValue("describe")); 24 | } 25 | if (json.getValue("contentLength") instanceof Number) { 26 | obj.setContentLength(((Number) json.getValue("contentLength")).longValue()); 27 | } 28 | if (json.getValue("scope") instanceof Number) { 29 | obj.setScope(((Number) json.getValue("scope")).intValue()); 30 | } 31 | if (json.getValue("sessionTimeOut") instanceof Number) { 32 | obj.setSessionTimeOut(((Number) json.getValue("sessionTimeOut")).longValue()); 33 | } 34 | if (json.getValue("sessionCookieName") instanceof String) { 35 | obj.setSessionCookieName((String) json.getValue("sessionCookieName")); 36 | } 37 | if (json.getValue("portOptions") instanceof JsonObject) { 38 | obj.setServerOptions( 39 | Json.decodeValue(json.getJsonObject("portOptions").toString(), VxApiServerOptions.class)); 40 | } 41 | if (json.getValue("corsOptions") instanceof JsonObject) { 42 | obj.setCorsOptions(Json.decodeValue(json.getJsonObject("corsOptions").toString(), VxApiCorsOptions.class)); 43 | } 44 | } 45 | 46 | public static void toJson(VxApiApplicationOptions obj, JsonObject json) { 47 | json.put("scope", obj.getScope()); 48 | json.put("sessionTimeOut", obj.getSessionTimeOut()); 49 | json.put("sessionCookieName", obj.getSessionCookieName()); 50 | json.put("portOptions", Json.encode(obj.getServerOptions())); 51 | json.put("contentLength", obj.getContentLength()); 52 | if (obj.getAppName() != null) { 53 | json.put("appName", obj.getAppName()); 54 | } 55 | if (obj.getDescribe() != null) { 56 | json.put("describe", obj.getDescribe()); 57 | } 58 | if (obj.getCorsOptions() != null) { 59 | json.put("corsOptions", Json.encode(obj.getCorsOptions())); 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/VxApiDATAStoreConstant.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | /** 4 | * 该类主要用于存放应用网关与API数据存储于传输的关键字,主要用于方便自己存储网关数据到自己的数据库中 5 | *

6 | * 应用网关存储的表结构: 7 | *

    8 | *
  • 表名 = APPLICATION_TABLE_NAME 存放网关应用的表名
  • 9 | *
  • 主键列 = APPLICATION_ID_COLUMN 字符串用于存放应用网关的名字
  • 10 | *
  • 内容列 = APPLICATION_ID_COLUMN json字符串用于存放应用网关的名字
  • 11 | *
12 | *

13 | * 应用网关属性在传输中的名字: 14 | *

    15 | *
  • 主键 = APPLICATION_ID_NAME 主键在json中的名字
  • 16 | *
  • 内容 = APPLICATION_CONTENT_COLUMN 内容在json中的名字
  • 17 | *
18 | *

19 | * API存储的表结构: 20 | *

    21 | *
  • 表名 = API_TABLE_NAME 存放API的表名
  • 22 | *
  • 主键列 = API_ID_COLUMN 字符串用于存放API的名字
  • 23 | *
  • 应用网关主键列 = API_APP_ID_COLUMN 字符串用于存放API的名字
  • 24 | *
  • 内容列 = API_CONTENT_COLUMN json字符串用于存放API的名字
  • 25 | *
26 | *

27 | * API属性在传输中的名字: 28 | *

    29 | *
  • 主键 = API_ID_NAME 主键在json中的名字
  • 30 | *
  • 主键 = API_APP_ID_NAME 应用网关主键在json中的名字
  • 31 | *
  • 内容 = API_CONTENT_NAME 内容在json中的名字
  • 32 | *
33 | *

34 | * 黑名单列表的表结构:(系统默认取黑名单列表第一行数据,) 35 | *

    36 | *
  • 表名 = BLACKLIST_TABLE_NAME 存放网关应用的黑名单的表名
  • 37 | *
  • 主键列 = BLACKLIST_ID_COLUMN 字符串用于存放应用网关黑名单主键的名字
  • 38 | *
  • 内容列 = BLACKLIST_ID_COLUMN json数组字符串用于存放应用网关黑名单内容的名字
  • 39 | *
40 | *

41 | * 黑名单列表在传输中的名字: 42 | *

    43 | *
  • 主键 = BLACKLIST_ID_NAME 黑名单主键在json中的名字
  • 44 | *
  • 内容 = BLACKLIST_CONTENT_COLUMN 黑名单内容在json中的名字
  • 45 | *
46 | *

47 | * 48 | * @author Mirren 49 | * 50 | */ 51 | public interface VxApiDATAStoreConstant { 52 | // ============================================== 53 | // ==================应用网关表结构================= 54 | // ============================================== 55 | /** 56 | * 网关应用的表名 57 | */ 58 | static final String APPLICATION_TABLE_NAME = "vx_api_application"; 59 | /** 60 | * 网关应用的主键列 61 | */ 62 | static final String APPLICATION_ID_COLUMN = "name"; 63 | /** 64 | * 网关应用json字符串内容的列名 65 | */ 66 | static final String APPLICATION_CONTENT_COLUMN = "content"; 67 | 68 | // ==================应用网关传输中获取内容的名字================= 69 | /** 70 | * 网关应用通讯传输中获取json中存放主键的属性名 71 | */ 72 | static final String APPLICATION_ID_NAME = "name"; 73 | /** 74 | * 网关应用通讯传输中获取json中存放json字符串对象的属性名 75 | */ 76 | static final String APPLICATION_CONTENT_NAME = "content"; 77 | 78 | // ============================================== 79 | // ==================API表结构==================== 80 | // ============================================== 81 | 82 | /** 83 | * 存放API的表名 84 | */ 85 | static final String API_TABLE_NAME = "vx_api_apis"; 86 | /** 87 | * 存放API的主键列 88 | */ 89 | static final String API_ID_COLUMN = "name"; 90 | /** 91 | * 存放API表中网关应用主键的列 92 | */ 93 | static final String API_APP_ID_COLUMN = "app_name"; 94 | /** 95 | * 存放API,json字符串内容的列名 96 | */ 97 | static final String API_CONTENT_COLUMN = "content"; 98 | 99 | // ==================API传输中获取内容的名字================= 100 | 101 | /** 102 | * API通讯传输中获取json中存放主键的属性名 103 | */ 104 | static final String API_ID_NAME = "name"; 105 | /** 106 | * API通讯传输中获取json中存放应用网关主键的属性名 107 | */ 108 | static final String API_APP_ID_NAME = "appName"; 109 | /** 110 | * API通讯传输中获取json中存放json字符串对象的属性名 111 | */ 112 | static final String API_CONTENT_NAME = "content"; 113 | 114 | // ============================================== 115 | // ==================黑名单列表表结构================ 116 | // ============================================== 117 | /** 118 | * 黑名单列表的表名 119 | */ 120 | static final String BLACKLIST_TABLE_NAME = "vx_api_blacklist"; 121 | /** 122 | * 黑名单列表的主键列 123 | */ 124 | static final String BLACKLIST_ID_COLUMN = "name"; 125 | /** 126 | * 黑名单列表jsonArray字符串内容的列名 127 | */ 128 | static final String BLACKLIST_CONTENT_COLUMN = "content"; 129 | 130 | // ==================应用网关传输中获取内容的名字================= 131 | /** 132 | * 黑名单列表通讯传输中获取json中存放主键的属性名 133 | */ 134 | static final String BLACKLIST_ID_NAME = "blacklist"; 135 | /** 136 | * 黑名单列表通讯传输中获取json中存放json字符串对象的属性名 137 | */ 138 | static final String BLACKLIST_CONTENT_NAME = "content"; 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/VxApiGatewayAttribute.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | /** 4 | * 存储VxApiGateway常用的属性 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public interface VxApiGatewayAttribute { 10 | /** 11 | * 网关的名字 12 | */ 13 | static final String NAME = "VX-API"; 14 | /** 15 | * 网关的全名 16 | */ 17 | static final String FULL_NAME = "VX-API-Gateway"; 18 | /** 19 | * VxApiGateway版本号 20 | */ 21 | static final String VERSION = "1.0.3"; 22 | /** 23 | * session默认的cookie名字 24 | */ 25 | static final String SESSION_COOKIE_NAME = "VX-API.session"; 26 | /** 27 | * 网关userAgent默认名字 28 | */ 29 | static final String VX_API_USER_AGENT = "VX-API-Gateway/" + VERSION; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/common/VxApiRequestBodyHandler.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.common; 2 | 3 | import com.szmirren.vxApi.core.entity.VxApiContentType; 4 | 5 | import io.vertx.core.Handler; 6 | import io.vertx.core.MultiMap; 7 | import io.vertx.core.buffer.Buffer; 8 | import io.vertx.core.http.CaseInsensitiveHeaders; 9 | import io.vertx.core.json.JsonObject; 10 | /** 11 | * 用户请求的body主体解析工具
12 | * 当前只解析Content-type=Null或者Urlencoded 13 | * 14 | * @author Mirren 15 | * 16 | */ 17 | public class VxApiRequestBodyHandler implements Handler { 18 | /** 用户请求的body参数 */ 19 | private MultiMap body = new CaseInsensitiveHeaders(); 20 | /** 用户请求的body长度 */ 21 | private long bodyLength; 22 | /** 用户请求的contentType */ 23 | private VxApiContentType contentType; 24 | /** 请求体的最大限制长度小于=0代表无限 */ 25 | private long maxContentLength; 26 | /** 用户请求的数据Buffer */ 27 | private Buffer bodyBuffer = Buffer.buffer(); 28 | /** 29 | * 实例化一个用户请求bodyhandler 30 | * 31 | * @param contentType 32 | * @param maxContentLength 33 | */ 34 | public VxApiRequestBodyHandler(VxApiContentType contentType, long maxContentLength) { 35 | super(); 36 | this.contentType = contentType; 37 | this.maxContentLength = maxContentLength; 38 | } 39 | 40 | @Override 41 | public void handle(Buffer buffer) { 42 | // 如果buffer为null或者不是支持解析的类型则返回 43 | if (buffer == null || !contentType.isDecodedSupport()) { 44 | return; 45 | } 46 | bodyLength += buffer.length(); 47 | if (maxContentLength > 0 && bodyLength > maxContentLength) { 48 | return; 49 | } 50 | bodyBuffer.appendBuffer(buffer); 51 | } 52 | /** 53 | * 获得body的参数 54 | * 55 | * @return 返回一个不为null的MultiMap 56 | */ 57 | public MultiMap getBody() { 58 | if (contentType.isApplicationJson()) { 59 | try { 60 | JsonObject object = new JsonObject(bodyBuffer); 61 | if (object.getMap() != null) { 62 | object.getMap().forEach((k, v) -> { 63 | body.add(k, v.toString()); 64 | }); 65 | } 66 | } catch (Exception e) { 67 | } 68 | } else if (contentType.isUrlencoded()) { 69 | MultiMap decoderUriParams = HttpUtils.decoderUriParams(bodyBuffer.toString(), contentType.getCharset()); 70 | if (decoderUriParams != null) { 71 | body.addAll(decoderUriParams); 72 | } 73 | } 74 | return body; 75 | } 76 | 77 | /** 78 | * 获得body的长度 79 | * 80 | * @return 81 | */ 82 | public long getBodyLength() { 83 | return bodyLength; 84 | } 85 | /** 86 | * 获得是否超过最大Content-Length限定 87 | * 88 | * @return 超过返回true , 不超过返回false 89 | */ 90 | public boolean isExceededMaxLen() { 91 | return maxContentLength > 0 && bodyLength > maxContentLength; 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return "VxApiRequestBodyHandler [body=" + body + ", bodyLength=" + bodyLength + ", contentType=" + contentType + ", maxContentLength=" 97 | + maxContentLength + "]"; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiAPILimit.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import java.time.Instant; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * 流量监控 9 | * 10 | * @author Mirren 11 | * 12 | */ 13 | public class VxApiAPILimit { 14 | private Instant timePoints = Instant.now();// 统计时间 15 | private Map userIpCurPoints = new HashMap<>();// 用户ip统计 16 | private long ipTop = -1;// ip限制的数量 17 | private long apiTop = -1;// api的限制数量 18 | private long curPoint;// 当前的数量 19 | 20 | /** 21 | * 创建一个流量限制 22 | * 23 | * @param ipTop 24 | * IP最大数 25 | * @param apiTop 26 | * api最大数 27 | */ 28 | public VxApiAPILimit(long ipTop, long apiTop) { 29 | super(); 30 | this.ipTop = ipTop; 31 | this.apiTop = apiTop; 32 | } 33 | 34 | /** 35 | * 得到统计的时间 36 | * 37 | * @return 38 | */ 39 | public Instant getTimePoints() { 40 | return timePoints; 41 | } 42 | 43 | /** 44 | * 设置统计时间 45 | * 46 | * @param timePoints 47 | */ 48 | public void setTimePoints(Instant timePoints) { 49 | this.timePoints = timePoints; 50 | } 51 | 52 | /** 53 | * 获得当前连接的用户 54 | * 55 | * @return 56 | */ 57 | public Map getUserIpCurPoints() { 58 | return userIpCurPoints; 59 | } 60 | 61 | /** 62 | * 设置当前连接的用户 63 | * 64 | * @param userIpCurPoints 65 | */ 66 | public void setUserIpCurPoints(Map userIpCurPoints) { 67 | this.userIpCurPoints = userIpCurPoints; 68 | } 69 | 70 | /** 71 | * 给当前连接用户连接数添加一个新用户,如果存在该用户将用户数据重置 72 | * 73 | * @param ip 74 | * @param points 75 | */ 76 | public void addUserIpCurPotints(String ip, long points) { 77 | this.userIpCurPoints.put(ip, points); 78 | } 79 | 80 | /** 81 | * 得到IP的最大限制数 82 | * 83 | * @return 84 | */ 85 | public long getIpTop() { 86 | return ipTop; 87 | } 88 | 89 | /** 90 | * 设置IP的最大限制数,-1表示无限 91 | * 92 | * @param ipTop 93 | */ 94 | public void setIpTop(long ipTop) { 95 | this.ipTop = ipTop; 96 | } 97 | 98 | /** 99 | * 得到API的最大限制数 100 | * 101 | * @return 102 | */ 103 | public long getApiTop() { 104 | return apiTop; 105 | } 106 | 107 | /** 108 | * 设置API的最大限制数,-1表示无限 109 | * 110 | * @param apiTop 111 | */ 112 | public void setApiTop(long apiTop) { 113 | this.apiTop = apiTop; 114 | } 115 | 116 | /** 117 | * 得到当前连接的人数 118 | * 119 | * @return 120 | */ 121 | public long getCurPoint() { 122 | return curPoint; 123 | } 124 | 125 | /** 126 | * 设置当前连接的人数 127 | * 128 | * @param curPoint 129 | */ 130 | public void setCurPoint(long curPoint) { 131 | this.curPoint = curPoint; 132 | } 133 | 134 | @Override 135 | public String toString() { 136 | return "VxApiAPILimit [timePoints=" + timePoints + ", userIpCurPoints=" + userIpCurPoints + ", ipTop=" + ipTop 137 | + ", apiTop=" + apiTop + ", curPoint=" + curPoint + "]"; 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiApiEntrance.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import java.util.List; 4 | 5 | import com.szmirren.vxApi.core.enums.HttpMethodEnum; 6 | 7 | /** 8 | * VxApi的入口 9 | * 10 | * @author Mirren 11 | * 12 | */ 13 | public class VxApiApiEntrance { 14 | private String path;// 请求路径 15 | private List methods;// 请求的方法 16 | private List paramOptions;// 参数的配置 17 | 18 | public VxApiApiEntrance() { 19 | super(); 20 | } 21 | 22 | public VxApiApiEntrance(String path, List methods, List paramOptions) { 23 | super(); 24 | this.path = path; 25 | this.methods = methods; 26 | this.paramOptions = paramOptions; 27 | } 28 | 29 | public String getPath() { 30 | return path; 31 | } 32 | 33 | public void setPath(String path) { 34 | this.path = path; 35 | } 36 | 37 | public List getMethods() { 38 | return methods; 39 | } 40 | 41 | public void setMethods(List methods) { 42 | this.methods = methods; 43 | } 44 | 45 | public List getParamOptions() { 46 | return paramOptions; 47 | } 48 | 49 | public void setParamOptions(List paramOptions) { 50 | this.paramOptions = paramOptions; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiContentType.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | public class VxApiContentType { 6 | 7 | private String contentType; 8 | private String boundary; 9 | private Charset charset; 10 | 11 | /** 12 | * 通过Content-Type字符串初始一个ContentType对象 13 | * 14 | * @param contentType 15 | */ 16 | public VxApiContentType(String contentType) { 17 | super(); 18 | if (contentType != null) { 19 | init(contentType); 20 | } 21 | } 22 | 23 | /** 24 | * 初始化 25 | * 26 | * @param contentType 27 | */ 28 | public void init(String contentType) { 29 | String[] item = contentType.split(";"); 30 | this.contentType = item[0]; 31 | if (item.length > 1) { 32 | if (item[1].indexOf("=") != -1) { 33 | String[] split = item[1].split("="); 34 | initVar(split[0].trim(), split[1].trim()); 35 | } 36 | } 37 | if (item.length > 2) { 38 | if (item[2].indexOf("=") != -1) { 39 | String[] split = item[1].split("="); 40 | initVar(split[0].trim(), split[1].trim()); 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * 根据类型进行初始化数据 47 | * 48 | * @param type 49 | * @param value 50 | */ 51 | public void initVar(String type, String value) { 52 | if ("charset".equalsIgnoreCase(type)) { 53 | try { 54 | this.charset = Charset.forName(value); 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | } else if ("boundary".equalsIgnoreCase(type)) { 59 | this.boundary = value; 60 | } 61 | } 62 | 63 | /** 64 | * 判断Content-Type类型是否支持解析 65 | * 66 | * @return 67 | */ 68 | public boolean isDecodedSupport() { 69 | return (isUrlencoded() || isApplicationJson()); 70 | } 71 | 72 | /** 73 | * Content-Type是否为:null或者application/x-www-form-urlencoded 74 | * 75 | * @return 76 | */ 77 | public boolean isNullOrUrlencoded() { 78 | return contentType == null || "application/x-www-form-urlencoded".equalsIgnoreCase(contentType); 79 | } 80 | 81 | /** 82 | * Content-Type是否为:application/x-www-form-urlencoded 83 | * 84 | * @return 85 | */ 86 | public boolean isUrlencoded() { 87 | return "application/x-www-form-urlencoded".equalsIgnoreCase(contentType); 88 | } 89 | 90 | /** 91 | * Content-Type是否为:multipart/form-data 92 | * 93 | * @return 94 | */ 95 | public boolean isFormData() { 96 | return "multipart/form-data".equalsIgnoreCase(contentType); 97 | } 98 | 99 | /** 100 | * Content-Type是否为:application/json 101 | * 102 | * @return 103 | */ 104 | public boolean isApplicationJson() { 105 | return "application/json".equalsIgnoreCase(contentType); 106 | } 107 | 108 | /** 109 | * 获得content类型 110 | * 111 | * @return 112 | */ 113 | public String getContentType() { 114 | return contentType; 115 | } 116 | 117 | /** 118 | * 获得Boundary 119 | * 120 | * @return 121 | */ 122 | public String getBoundary() { 123 | return boundary; 124 | } 125 | 126 | /** 127 | * 获得字符编码 128 | * 129 | * @return 130 | */ 131 | public Charset getCharset() { 132 | return charset; 133 | } 134 | 135 | /** 136 | * 设置content类型 137 | * 138 | * @param contentType 139 | */ 140 | public void setContentType(String contentType) { 141 | this.contentType = contentType; 142 | } 143 | /** 144 | * 设置Boundary 145 | * 146 | * @param boundary 147 | */ 148 | public void setBoundary(String boundary) { 149 | this.boundary = boundary; 150 | } 151 | /** 152 | * 设置字符编码 153 | * 154 | * @param charset 155 | */ 156 | public void setCharset(Charset charset) { 157 | this.charset = charset; 158 | } 159 | 160 | @Override 161 | public String toString() { 162 | return "VxApiContentType [contentType=" + contentType + ", boundary=" + boundary + ", charset=" + charset + "]"; 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiDeployInfos.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import com.szmirren.vxApi.core.options.VxApiServerOptions; 4 | 5 | /** 6 | * 存储已经部署的应用信息 7 | * 8 | * @author Mirren 9 | * 10 | */ 11 | public class VxApiDeployInfos { 12 | private String appName;// 应用的名称 13 | private String deployId;// 应用的部署id 14 | private Integer httpPort;// HTTP服务器的端口号 15 | private Integer httpsPort;// HTTPS服务器的端口号 16 | private Integer webSocketPort;// WebSocket服务器的端口号 17 | /** 18 | * 实例化一个没有属性的部署信息 19 | */ 20 | public VxApiDeployInfos() { 21 | super(); 22 | } 23 | /** 24 | * 实例化一个部署信息 25 | * 26 | * @param appName 27 | * 应用的名字 28 | * @param deployId 29 | * 部署的id 30 | * @param options 31 | * 服务器配置信息 32 | */ 33 | public VxApiDeployInfos(String appName, String deployId, VxApiServerOptions options) { 34 | super(); 35 | this.appName = appName; 36 | this.deployId = deployId; 37 | if (options != null) { 38 | if (options.isCreateHttp()) { 39 | this.httpPort = options.getHttpPort(); 40 | } 41 | if (options.isCreateHttps()) { 42 | this.httpsPort = options.getHttpsPort(); 43 | } 44 | if (options.isCreatewebSocket()) { 45 | this.webSocketPort = options.getWebSocketPort(); 46 | } 47 | } 48 | } 49 | /** 50 | * 实例化一个部署信息 51 | * 52 | * @param appName 53 | * 应用的名字 54 | * @param deployId 55 | * 部署的id 56 | * @param httpPort 57 | * http服务器端口号 58 | * @param httpsPort 59 | * https服务器端口号 60 | * @param webSocketPort 61 | * webSocket端口号 62 | */ 63 | public VxApiDeployInfos(String appName, String deployId, Integer httpPort, Integer httpsPort, Integer webSocketPort) { 64 | super(); 65 | this.appName = appName; 66 | this.deployId = deployId; 67 | this.httpPort = httpPort; 68 | this.httpsPort = httpsPort; 69 | this.webSocketPort = webSocketPort; 70 | } 71 | public String getAppName() { 72 | return appName; 73 | } 74 | public void setAppName(String appName) { 75 | this.appName = appName; 76 | } 77 | public String getDeployId() { 78 | return deployId; 79 | } 80 | public void setDeployId(String deployId) { 81 | this.deployId = deployId; 82 | } 83 | public Integer getHttpPort() { 84 | return httpPort; 85 | } 86 | public void setHttpPort(Integer httpPort) { 87 | this.httpPort = httpPort; 88 | } 89 | public Integer getHttpsPort() { 90 | return httpsPort; 91 | } 92 | public void setHttpsPort(Integer httpsPort) { 93 | this.httpsPort = httpsPort; 94 | } 95 | public Integer getWebSocketPort() { 96 | return webSocketPort; 97 | } 98 | public void setWebSocketPort(Integer webSocketPort) { 99 | this.webSocketPort = webSocketPort; 100 | } 101 | @Override 102 | public String toString() { 103 | return "VxApiDeployInfos [appName=" + appName + ", deployId=" + deployId + ", httpPort=" + httpPort + ", httpsPort=" + httpsPort 104 | + ", webSocketPort=" + webSocketPort + "]"; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiEntranceParam.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import com.szmirren.vxApi.core.enums.ParamPositionEnum; 4 | import com.szmirren.vxApi.core.enums.ParamTypeEnum; 5 | import com.szmirren.vxApi.core.options.VxApiParamCheckOptions; 6 | 7 | import io.vertx.core.json.JsonObject; 8 | 9 | /** 10 | * 网关的入口参数 11 | * 12 | * @author Mirren 13 | * 14 | */ 15 | public class VxApiEntranceParam { 16 | private String paramName;// 参数的名字 17 | private String describe;// 描述 18 | private ParamPositionEnum position;// 参数的位置 19 | private ParamTypeEnum paramType;// 参数类型 20 | private boolean isNotNull;// 是否可以为空 21 | private Object def;// 默认值 22 | private VxApiParamCheckOptions checkOptions;// 参数的配置 23 | 24 | /** 25 | * 将对象装换为JsonObject 26 | * 27 | * @return 28 | */ 29 | public JsonObject toJson() { 30 | JsonObject json = new JsonObject(); 31 | json.put("paramName", this.paramName); 32 | json.put("position", this.position); 33 | json.put("paramType", this.paramType); 34 | json.put("isNotNull", this.isNotNull); 35 | if (def != null) { 36 | json.put("def", this.def); 37 | } 38 | if (describe != null) { 39 | json.put("describe", this.describe); 40 | } 41 | if (checkOptions != null) { 42 | json.put("checkOptions", checkOptions.toJson()); 43 | } 44 | return json; 45 | } 46 | 47 | /** 48 | * 通过JsonObject实例化一个对象 49 | * 50 | * @param obj 51 | * @return 52 | */ 53 | public static VxApiEntranceParam fromJson(JsonObject obj) { 54 | if (obj == null) { 55 | return null; 56 | } 57 | VxApiEntranceParam option = new VxApiEntranceParam(); 58 | if (obj.getValue("paramName") instanceof String) { 59 | option.setParamName(obj.getString("paramName")); 60 | } 61 | if (obj.getValue("describe") instanceof String) { 62 | option.setDescribe(obj.getString("describe")); 63 | } 64 | if (obj.getValue("isNotNull") instanceof Boolean) { 65 | option.setNotNull(obj.getBoolean("isNotNull")); 66 | } 67 | if (obj.getValue("position") instanceof String) { 68 | option.setPosition(ParamPositionEnum.valueOf(obj.getString("position"))); 69 | } 70 | if (obj.getValue("paramType") instanceof String) { 71 | option.setParamType(ParamTypeEnum.valueOf(obj.getString("paramType"))); 72 | } 73 | if (obj.getValue("def") != null) { 74 | option.setDef(obj.getValue("def")); 75 | } 76 | if (obj.getValue("checkOptions") instanceof JsonObject) { 77 | option.setCheckOptions(VxApiParamCheckOptions.fromJson(obj.getJsonObject("checkOptions"))); 78 | } else if (obj.getValue("checkOptions") instanceof String) { 79 | option.setCheckOptions(VxApiParamCheckOptions.fromJson(new JsonObject(obj.getString("checkOptions")))); 80 | } 81 | return option; 82 | } 83 | 84 | public VxApiEntranceParam() { 85 | super(); 86 | } 87 | 88 | public String getParamName() { 89 | return paramName; 90 | } 91 | 92 | public void setParamName(String paramName) { 93 | this.paramName = paramName; 94 | } 95 | 96 | public ParamPositionEnum getPosition() { 97 | return position; 98 | } 99 | 100 | public void setPosition(ParamPositionEnum position) { 101 | this.position = position; 102 | } 103 | 104 | public ParamTypeEnum getParamType() { 105 | return paramType; 106 | } 107 | 108 | public void setParamType(ParamTypeEnum paramType) { 109 | this.paramType = paramType; 110 | } 111 | 112 | public boolean isNotNull() { 113 | return isNotNull; 114 | } 115 | 116 | public void setNotNull(boolean isNotNull) { 117 | this.isNotNull = isNotNull; 118 | } 119 | 120 | public Object getDef() { 121 | return def; 122 | } 123 | 124 | public void setDef(Object def) { 125 | this.def = def; 126 | } 127 | 128 | public String getDescribe() { 129 | return describe; 130 | } 131 | 132 | public void setDescribe(String describe) { 133 | this.describe = describe; 134 | } 135 | 136 | public VxApiParamCheckOptions getCheckOptions() { 137 | return checkOptions; 138 | } 139 | 140 | public void setCheckOptions(VxApiParamCheckOptions checkOptions) { 141 | this.checkOptions = checkOptions; 142 | } 143 | 144 | @Override 145 | public String toString() { 146 | return "VxApiEntranceParam [paramName=" + paramName + ", describe=" + describe + ", position=" + position 147 | + ", paramType=" + paramType + ", isNotNull=" + isNotNull + ", def=" + def + ", checkOptions=" 148 | + checkOptions + "]"; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiResultStatus.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import io.vertx.core.json.JsonObject; 4 | 5 | /** 6 | * API返回结果状态码 7 | * 8 | * @author Mirren 9 | * 10 | */ 11 | public class VxApiResultStatus { 12 | private String code;// 状态码 13 | private String msg;// 错误信息 14 | private String describe;// 描述 15 | 16 | /** 17 | * 将对象装换为JsonObject 18 | * 19 | * @return 20 | */ 21 | public JsonObject toJson() { 22 | JsonObject json = new JsonObject(); 23 | if (code != null) { 24 | json.put("code", this.code); 25 | } 26 | if (msg != null) { 27 | json.put("msg", this.msg); 28 | } 29 | if (describe != null) { 30 | json.put("describe", this.describe); 31 | } 32 | return json; 33 | } 34 | 35 | /** 36 | * 通过JsonObject实例化一个对象 37 | * 38 | * @param obj 39 | * @return 40 | */ 41 | public static VxApiResultStatus fromJson(JsonObject obj) { 42 | if (obj == null) { 43 | return null; 44 | } 45 | VxApiResultStatus option = new VxApiResultStatus(); 46 | if (obj.getValue("code") instanceof String) { 47 | option.setCode(obj.getString("code")); 48 | } 49 | if (obj.getValue("msg") instanceof String) { 50 | option.setMsg(obj.getString("msg")); 51 | } 52 | if (obj.getValue("describe") instanceof String) { 53 | option.setDescribe(obj.getString("describe")); 54 | } 55 | return option; 56 | } 57 | 58 | public VxApiResultStatus() { 59 | super(); 60 | } 61 | 62 | public VxApiResultStatus(String code, String msg, String describe) { 63 | super(); 64 | this.code = code; 65 | this.msg = msg; 66 | this.describe = describe; 67 | } 68 | 69 | public String getCode() { 70 | return code; 71 | } 72 | 73 | public void setCode(String code) { 74 | this.code = code; 75 | } 76 | 77 | public String getMsg() { 78 | return msg; 79 | } 80 | 81 | public void setMsg(String msg) { 82 | this.msg = msg; 83 | } 84 | 85 | public String getDescribe() { 86 | return describe; 87 | } 88 | 89 | public void setDescribe(String describe) { 90 | this.describe = describe; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "VxApiResultStatus [code=" + code + ", msg=" + msg + ", describe=" + describe + "]"; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiSecurityPolicies.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import com.szmirren.vxApi.core.enums.TimeUnitEnum; 4 | 5 | import io.vertx.core.json.JsonObject; 6 | 7 | /** 8 | * 安全策略 9 | * 10 | * @author Mirren 11 | * 12 | */ 13 | public class VxApiSecurityPolicies { 14 | private String policyName;// 安全策略的名字 15 | private String policyDescribe;// 安全策略的描述 16 | private TimeUnitEnum timeUnit;// 安全策略的限制单位 17 | private long apiLimit;// api的总限制访问数,0等于无限制,默认=0 18 | private long ipLimit;// ip的限制访问数,必须小于apiLimint,默认与apiLimit一致 19 | 20 | /** 21 | * 将对象装换为json 22 | * 23 | * @return 24 | */ 25 | public JsonObject toJson() { 26 | JsonObject json = new JsonObject(); 27 | json.put("policyName", this.policyName); 28 | json.put("policyDescribe", this.policyDescribe); 29 | json.put("timeUnit", this.timeUnit); 30 | json.put("apiLimit", this.apiLimit); 31 | json.put("ipLimit", this.ipLimit); 32 | return json; 33 | } 34 | 35 | /** 36 | * 通过json实例化一个对象 37 | * 38 | * @param json 39 | * @return 40 | */ 41 | public static VxApiSecurityPolicies fromJson(JsonObject json) { 42 | if (json == null) { 43 | return null; 44 | } 45 | VxApiSecurityPolicies option = new VxApiSecurityPolicies(); 46 | if (json.getValue("policyName") instanceof String) { 47 | option.setPolicyName(json.getString("policyName")); 48 | } 49 | if (json.getValue("policyDescribe") instanceof String) { 50 | option.setPolicyDescribe(json.getString("policyDescribe")); 51 | } 52 | if (json.getValue("timeUnit") instanceof String) { 53 | option.setTimeUnit(TimeUnitEnum.valueOf(json.getString("timeUnit"))); 54 | } 55 | if (json.getValue("apiLimit") instanceof Number) { 56 | option.setApiLimit(((Number) json.getValue("apiLimit")).longValue()); 57 | } 58 | if (json.getValue("ipLimit") instanceof Number) { 59 | option.setApiLimit(((Number) json.getValue("ipLimit")).longValue()); 60 | } 61 | return option; 62 | } 63 | 64 | public VxApiSecurityPolicies() { 65 | super(); 66 | } 67 | 68 | public VxApiSecurityPolicies(String policyName, String policyDescribe, TimeUnitEnum timeUnit, long apiLimit, 69 | long ipLimit) { 70 | super(); 71 | this.policyName = policyName; 72 | this.policyDescribe = policyDescribe; 73 | this.timeUnit = timeUnit; 74 | this.apiLimit = apiLimit; 75 | this.ipLimit = ipLimit; 76 | } 77 | 78 | /** 79 | * 获得安全策略的名字 80 | * 81 | * @return 82 | */ 83 | public String getPolicyName() { 84 | return policyName; 85 | } 86 | 87 | /** 88 | * 设置安全策略的名字 89 | * 90 | * @param policyName 91 | */ 92 | public void setPolicyName(String policyName) { 93 | this.policyName = policyName; 94 | } 95 | 96 | /** 97 | * 获得安全策略的描述 98 | * 99 | * @return 100 | */ 101 | public String getPolicyDescribe() { 102 | return policyDescribe; 103 | } 104 | 105 | /** 106 | * 安全策略的描述 107 | * 108 | * @param policyDescribe 109 | */ 110 | public void setPolicyDescribe(String policyDescribe) { 111 | this.policyDescribe = policyDescribe; 112 | } 113 | 114 | /** 115 | * 获得安全策略的限制单位 116 | * 117 | * @return 118 | */ 119 | public TimeUnitEnum getTimeUnit() { 120 | return timeUnit; 121 | } 122 | 123 | /** 124 | * 设置安全策略的限制单位 125 | * 126 | * @param timeUnit 127 | */ 128 | public void setTimeUnit(TimeUnitEnum timeUnit) { 129 | this.timeUnit = timeUnit; 130 | } 131 | 132 | /** 133 | * 获得api的总限制访问数 134 | * 135 | * @return 136 | */ 137 | public long getApiLimit() { 138 | return apiLimit; 139 | } 140 | 141 | /** 142 | * 设置api的总限制访问数,0等于无限制,默认=0 143 | * 144 | * @param apiLimit 145 | */ 146 | public void setApiLimit(long apiLimit) { 147 | this.apiLimit = apiLimit; 148 | } 149 | 150 | /** 151 | * 获得ip的限制访问数 152 | * 153 | * @return 154 | */ 155 | public long getIpLimit() { 156 | return ipLimit; 157 | } 158 | 159 | /** 160 | * 设置ip的限制访问数,必须小于apiLimint,默认与apiLimit一致 161 | * 162 | * @param ipLimit 163 | */ 164 | public void setIpLimit(long ipLimit) { 165 | this.ipLimit = ipLimit; 166 | } 167 | 168 | @Override 169 | public String toString() { 170 | return "VxSecurityPolicies [policyName=" + policyName + ", policyDescribe=" + policyDescribe + ", timeUnit=" 171 | + timeUnit + ", apiLimit=" + apiLimit + ", ipLimit=" + ipLimit + "]"; 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiServerEntrance.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import com.szmirren.vxApi.core.enums.ApiServerTypeEnum; 4 | 5 | import io.vertx.core.json.JsonObject; 6 | 7 | /** 8 | * Api服务端入口 9 | * 10 | * @author Mirren 11 | * 12 | */ 13 | public class VxApiServerEntrance { 14 | 15 | private ApiServerTypeEnum serverType;// api的服务类型 16 | private JsonObject body;// 存储后端服务的json,根据serverType而实例化相应的服务操作对象 17 | 18 | /** 19 | * 将对象转换为JsonObject 20 | * 21 | * @return 22 | */ 23 | public JsonObject toJson() { 24 | JsonObject json = new JsonObject(); 25 | json.put("serverType", this.serverType); 26 | json.put("body", this.body); 27 | return json; 28 | } 29 | 30 | /** 31 | * 通过一个JsonObject获得一个实例 32 | * 33 | * @param obj 34 | * @return 35 | */ 36 | public static VxApiServerEntrance fromJson(JsonObject obj) { 37 | if (obj == null) { 38 | return null; 39 | } 40 | VxApiServerEntrance option = new VxApiServerEntrance(); 41 | if (obj.getValue("serverType") instanceof String) { 42 | option.setServerType(ApiServerTypeEnum.valueOf(obj.getString("serverType"))); 43 | } 44 | if (obj.getValue("body") instanceof JsonObject) { 45 | option.setBody(obj.getJsonObject("body")); 46 | } 47 | return option; 48 | } 49 | 50 | public ApiServerTypeEnum getServerType() { 51 | return serverType; 52 | } 53 | 54 | public void setServerType(ApiServerTypeEnum serverType) { 55 | this.serverType = serverType; 56 | } 57 | 58 | public JsonObject getBody() { 59 | return body; 60 | } 61 | 62 | public void setBody(JsonObject body) { 63 | this.body = body; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "VxApiServerEntrance [serverType=" + serverType + ", body=" + body + "]"; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiServerURL.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import io.vertx.core.json.JsonObject; 4 | 5 | /** 6 | * 服务器地址与权重 7 | * 8 | * @author Mirren 9 | * 10 | */ 11 | public class VxApiServerURL { 12 | private String url;// 路径 13 | private int weight = 0;// 访问权重 14 | 15 | /** 16 | * 将当前对象装换为JsonObject 17 | * 18 | * @return 19 | */ 20 | public JsonObject toJson() { 21 | JsonObject json = new JsonObject(); 22 | json.put("url", url); 23 | json.put("weight", weight); 24 | return json; 25 | } 26 | 27 | /** 28 | * 通过Json配置文件得到一个服务地址对象,如果配置文件为空或者,key:url非String类型报错NullPointerException 29 | * 30 | * @param obj 31 | * @return 32 | */ 33 | public static VxApiServerURL fromJson(JsonObject obj) { 34 | if (obj == null) { 35 | throw new NullPointerException("服务地址的JSON配置文件不能是null"); 36 | } 37 | VxApiServerURL option = new VxApiServerURL(); 38 | if (obj.getValue("url") instanceof String) { 39 | option.setUrl(obj.getString("url")); 40 | } else { 41 | throw new NullPointerException("url必须为字符串类型"); 42 | } 43 | if (obj.getValue("weight") instanceof Number) { 44 | option.setWeight(((Number) obj.getValue("weight")).intValue()); 45 | } 46 | return option; 47 | } 48 | 49 | private VxApiServerURL() { 50 | super(); 51 | } 52 | 53 | public VxApiServerURL(String url) { 54 | super(); 55 | this.url = url; 56 | this.weight = 0; 57 | } 58 | 59 | public VxApiServerURL(String url, int weight) { 60 | super(); 61 | this.url = url; 62 | this.weight = weight; 63 | } 64 | 65 | public String getUrl() { 66 | return url; 67 | } 68 | 69 | public void setUrl(String url) { 70 | this.url = url; 71 | } 72 | 73 | public int getWeight() { 74 | return weight; 75 | } 76 | 77 | public void setWeight(int weight) { 78 | this.weight = weight; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiServerURLInfo.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | /** 4 | * 服务地址的信息,getUrl得到服务地址,getIndex得到这个地址对应的下标,下标用于报告地址可用或地址不可用 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public class VxApiServerURLInfo { 10 | private String url;// 路径 11 | private int index;// 路径的下标 12 | 13 | public VxApiServerURLInfo(String url, int index) { 14 | super(); 15 | this.url = url; 16 | this.index = index; 17 | } 18 | 19 | public String getUrl() { 20 | return url; 21 | } 22 | 23 | public void setUrl(String url) { 24 | this.url = url; 25 | } 26 | 27 | public int getIndex() { 28 | return index; 29 | } 30 | 31 | public void setIndex(int index) { 32 | this.index = index; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "ServerUrlInfo [url=" + url + ", index=" + index + "]"; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/entity/VxApiServerURLPollingPolicy.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.entity; 2 | 3 | import java.net.MalformedURLException; 4 | import java.net.URL; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 服务地址的轮询策略
12 | * tips:在非线程安全的环境下需要注意线程安全的问题 13 | * 14 | * @author Mirren 15 | * 16 | */ 17 | public class VxApiServerURLPollingPolicy { 18 | /** 19 | * 一共有多少个服务对象 20 | */ 21 | private int size = 1; 22 | /** 23 | * 当前服务对象坐标 24 | */ 25 | private int curIndex = 0; 26 | /** 27 | * 当前权重下标 28 | */ 29 | private int weightIndex = 0; 30 | /** 31 | * 服务的地址 32 | */ 33 | private String[] urls; 34 | /** 35 | * 服务地址权重 36 | */ 37 | private int[] weight; 38 | /** 39 | * 是否存有可用服务 40 | */ 41 | private boolean haveService = true; 42 | /** 43 | * 是否存在坏的连接 44 | */ 45 | private boolean haveBadService = false; 46 | /** 47 | * 是否正在重试检查坏的服务连接 48 | */ 49 | private boolean checkWaiting = false; 50 | /** 51 | * 存储用户的IP地址对应的下标 52 | */ 53 | private Map ipMap = new HashMap<>(); 54 | /** 55 | * 用于存储当前下标的服务地址是否可用 56 | */ 57 | private Map availableMap = new HashMap<>(); 58 | /** 59 | * 失败的次数 60 | */ 61 | private Map failureCountMap = new HashMap<>(); 62 | 63 | /** 64 | * 创建轮询策略 65 | * 66 | * @param urls 67 | * 服务连接的URL集,不能为空,size大于1,正确的URL地址 68 | * @throws NullPointerException 69 | * 服务连接集合空是抛出 70 | * @throws MalformedURLException 71 | * 不是正确的URL是抛出 72 | */ 73 | public VxApiServerURLPollingPolicy(List urls) throws NullPointerException, MalformedURLException { 74 | super(); 75 | if (urls == null || urls.size() == 0) { 76 | throw new NullPointerException("服务URL集不能为空"); 77 | } 78 | for (VxApiServerURL absoluteURI : urls) { 79 | new URL(absoluteURI.getUrl()); 80 | } 81 | size = urls.size(); 82 | this.urls = new String[size]; 83 | weight = new int[size]; 84 | for (int i = 0; i < urls.size(); i++) { 85 | // 初始化URL与权重 86 | this.urls[i] = urls.get(i).getUrl(); 87 | weight[i] = urls.get(i).getWeight(); 88 | // 默认设置所有连接可用 89 | availableMap.put(i, true); 90 | } 91 | } 92 | 93 | /** 94 | * 以轮询权重的方式得到服务URL 95 | * 96 | * @return 97 | */ 98 | public VxApiServerURLInfo getUrl() { 99 | String url = urls[curIndex]; 100 | int index = curIndex; 101 | if (size > 1) { 102 | weightIndex++; 103 | if (weightIndex >= weight[curIndex]) { 104 | weightIndex = 0; 105 | moveCurIndex();// 下标移动 106 | } 107 | } 108 | VxApiServerURLInfo urlInfo = new VxApiServerURLInfo(url, index); 109 | return urlInfo; 110 | } 111 | 112 | /** 113 | * 通过用户的IP地址获得用户对应的服务连接 114 | * 115 | * @param ip 116 | * 用户的IP 117 | * @return 118 | */ 119 | public VxApiServerURLInfo getUrl(String ip) { 120 | VxApiServerURLInfo urlInfo = null; 121 | if (haveService) { 122 | Integer index = ipMap.get(ip); 123 | if (index == null || availableMap.get(index) == false) { 124 | urlInfo = getUrl(); 125 | ipMap.put(ip, urlInfo.getIndex()); 126 | } else { 127 | urlInfo = new VxApiServerURLInfo(urls[index], index); 128 | } 129 | } else { 130 | urlInfo = new VxApiServerURLInfo(urls[0], 0); 131 | } 132 | return urlInfo; 133 | } 134 | 135 | /** 136 | * 移动当前下标 137 | */ 138 | private void moveCurIndex() { 139 | if (!haveService) { 140 | curIndex = 0; 141 | } else if (haveBadService) { 142 | updateCurIndex(); 143 | } else { 144 | if ((curIndex + 1) > size - 1) { 145 | curIndex = 0; 146 | } else { 147 | curIndex++; 148 | } 149 | } 150 | } 151 | 152 | /** 153 | * 改变当前下标 154 | */ 155 | private void updateCurIndex() { 156 | if (!haveService) { 157 | curIndex = 0; 158 | } else { 159 | if (availableMap.get(curIndex + 1) != null && availableMap.get(curIndex + 1) == true) { 160 | curIndex++; 161 | return; 162 | } 163 | boolean flag = true;// 标记当前坐标到结束是否有可用的地址 164 | for (int i = curIndex + 1; i < size; i++) { 165 | if (availableMap.get(i) == true) { 166 | curIndex = i; 167 | flag = false; 168 | break; 169 | } 170 | } 171 | if (flag) { 172 | boolean bad = false; 173 | for (int i = 0; i < size; i++) { 174 | if (availableMap.get(i) == true) { 175 | curIndex = i; 176 | break; 177 | } 178 | if (i == size - 1) { 179 | bad = true; 180 | } 181 | } 182 | if (bad) { 183 | haveService = false; 184 | } 185 | } 186 | } 187 | } 188 | 189 | /** 190 | * 提交连接失败的连接下标 191 | * 192 | * @param index 193 | */ 194 | public void reportBadService(int index) { 195 | if (index >= size || index < 0) { 196 | return; 197 | } 198 | if (failureCountMap.get(index) != null) { 199 | availableMap.put(index, false); 200 | haveBadService = true; 201 | if (index == curIndex) { 202 | updateCurIndex(); 203 | } 204 | } else { 205 | failureCountMap.put(index, 1); 206 | } 207 | } 208 | 209 | /** 210 | * 提交下标可以使用 211 | * 212 | * @param index 213 | */ 214 | public void reportGreatService(int index) { 215 | if (index >= size || index < 0) { 216 | return; 217 | } 218 | failureCountMap.remove(index); 219 | availableMap.put(index, true); 220 | haveService = true; 221 | if (failureCountMap.size() == 0) { 222 | haveBadService = false; 223 | } 224 | } 225 | 226 | /** 227 | * 获得坏的连接 228 | * 229 | * @return 返回一个不为null的List 230 | */ 231 | public List getBadService() { 232 | List result = new ArrayList<>(); 233 | failureCountMap.forEach((k, v) -> result.add(new VxApiServerURLInfo(urls[k], k))); 234 | return result; 235 | } 236 | 237 | /** 238 | * 查看是否有可用服务连接 239 | * 240 | * @return 有可用服务连接返回true,没有可用服务连接返回false 241 | */ 242 | public boolean isHaveService() { 243 | return haveService; 244 | } 245 | 246 | /** 247 | * 查看是否有坏的服务连接 248 | * 249 | * @return 存在坏的服务连接放回true,不存在返回false 250 | */ 251 | public boolean isHaveBadService() { 252 | return haveBadService; 253 | } 254 | 255 | /** 256 | * 查看是否正在重试坏的服务连接是否可用,正在检查返回true,不在检查返回false 257 | * 258 | * @return 259 | */ 260 | public boolean isCheckWaiting() { 261 | return checkWaiting; 262 | } 263 | 264 | /** 265 | * 设置是否正在重试坏的服务连接,true=正在检查,false=不在检查 266 | * 267 | * @param checkWaiting 268 | */ 269 | public void setCheckWaiting(boolean checkWaiting) { 270 | this.checkWaiting = checkWaiting; 271 | } 272 | 273 | } 274 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ApiServerTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 服务的类型 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum ApiServerTypeEnum { 10 | HTTP_HTTPS, // http或https类型 11 | REDIRECT, // 页面跳转 12 | CUSTOM;// 自定义服务类型 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ConnectProtocolEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 请求协议的类型 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum ConnectProtocolEnum { 10 | HTTP, HTTPS, WEB_SOCKET, TCP; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ContentTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 返回的ContentType类型 5 | * 6 | * @author Mirren 7 | */ 8 | public enum ContentTypeEnum { 9 | /** 内容: application/json */ 10 | JSON("application/json"), 11 | /** 内容: application/xml */ 12 | XML("application/xml"), 13 | /** 内容: text/html */ 14 | HTML("text/html"), 15 | /** 内容: text/plain */ 16 | TEXT("text/plain"), 17 | /** 内容: application/x-www-form-urlencoded */ 18 | FORM("application/x-www-form-urlencoded"), 19 | /** 内容: application/x-www-form-urlencoded */ 20 | APPLICATION_X_WWW_FORM_URLENCODED("application/x-www-form-urlencoded"), 21 | /** 内容: multipart/form-data */ 22 | MULTIPART_FORM_DATA("multipart/form-data"), 23 | /** 内容: application/octet-stream */ 24 | BINARY("application/octet-stream"), 25 | /** 内容: application/json;charset=UTF-8 */ 26 | JSON_UTF8("application/json;charset=UTF-8"), 27 | /** 内容: application/xml;charset=UTF-8 */ 28 | XML_UTF8("application/xml;charset=UTF-8"), 29 | /** 内容: text/html;charset=UTF-8 */ 30 | HTML_UTF8("text/html;charset=UTF-8"), 31 | /** 内容: text/plain;charset=UTF-8 */ 32 | TEXT_UTF8("text/plain;charset=UTF-8"), 33 | /** 内容: application/x-www-form-urlencoded;charset=UTF-8 */ 34 | FORM_UTF8("application/x-www-form-urlencoded;charset=UTF-8"), 35 | /** 内容: application/octet-stream;charset=UTF-8 */ 36 | BINARY_UTF8("application/octet-stream;charset=UTF-8"); 37 | 38 | private String type; 39 | 40 | private ContentTypeEnum(String type) { 41 | this.type = type; 42 | } 43 | 44 | public String val() { 45 | return type; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/EnterParamMapTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * API的入口参数映射类型 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum EnterParamMapTypeEnum { 10 | /** 11 | * 参数透传 12 | */ 13 | PASS, 14 | /** 15 | * 参数映射 16 | */ 17 | MAPING; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/HTTPStatusCodeMsgEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * HTTP状态码与状态信息的枚举类 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum HTTPStatusCodeMsgEnum { 10 | /** 11 | * ok 12 | */ 13 | C200(200, "ok"), 14 | /** 15 | * Bad Request 16 | */ 17 | C400(400, "Bad Request"), 18 | /** 19 | * Unauthorized 20 | */ 21 | C401(401, "Unauthorized"), 22 | /** 23 | * Forbidden 24 | */ 25 | C403(403, "Forbidden"), 26 | /** 27 | * Not Found 28 | */ 29 | C404(404, "Not Found"), 30 | /** 31 | * Internal Server Error 32 | */ 33 | C500(500, "Internal Server Error"), 34 | /** 35 | * Server Unavailable 36 | */ 37 | C503(503, "Server Unavailable"), 38 | /** 39 | * 空指针异常 40 | */ 41 | C1000(1000, "NullPointerException"), 42 | /** 43 | * 文件中缺少比用参数或者参数不正确 44 | */ 45 | C1400(1400, "Lack of request parameters or parameters is invalid"), 46 | /** 47 | * 没有找到指定文件 48 | */ 49 | C1404(1404, "No file in path can be found"), 50 | /** 51 | * 错误的json格式文件 52 | */ 53 | C1405(1405, "The specified JSON file is wrong"), 54 | /** 55 | * 文件已经存在或者数据已经存在 56 | */ 57 | C1444(1444, "The data has already existed"), 58 | 59 | /** 60 | * 当前端口被占用 61 | */ 62 | C1111(1111, "Address already in use: bind"), 63 | /** 64 | * 未知错误 65 | */ 66 | C1999(1999, "Unknown error"),; 67 | // 状态码 68 | private int code; 69 | private String msg; 70 | 71 | HTTPStatusCodeMsgEnum(int code, String msg) { 72 | this.msg = msg; 73 | this.code = code; 74 | } 75 | 76 | /** 77 | * 得到状态码 78 | * 79 | * @return 80 | */ 81 | public int getCode() { 82 | return code; 83 | } 84 | 85 | /** 86 | * 获得状态码相应的信息 87 | * 88 | * @return 89 | */ 90 | public String getMsg() { 91 | return msg; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/HttpMethodEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * http的请求方式 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum HttpMethodEnum { 10 | ALL("ALL"), OPTIONS("OPTIONS"), GET("GET"), HEAD("HEAD"), POST("POST"), 11 | PUT("PUT"), DELETE("DELETE"), TRACE("TRACE"), CONNECT("CONNECT"), PATCH("PATCH"), OTHER("OTHER"); 12 | private String val; 13 | private HttpMethodEnum(String val) { 14 | this.val = val; 15 | } 16 | public String getVal() { 17 | return val; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/LoadBalanceEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 负载均衡类型 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum LoadBalanceEnum { 10 | /** 11 | * 轮询可用 12 | */ 13 | POLLING_AVAILABLE, 14 | /** 15 | * ip哈希化 16 | */ 17 | IP_HASH, 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ParamPositionEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 参数的作用域 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum ParamPositionEnum { 10 | PATH, QUERY, BODY, HEADER; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ParamSystemVarTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * API请求后台时的产量常量 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum ParamSystemVarTypeEnum { 10 | /** 11 | * 请求客服端的ip地址 12 | */ 13 | CLIENT_HOST, 14 | /** 15 | * 请求客户端的端口 16 | */ 17 | CLIENT_PORT, 18 | /** 19 | * 请求客户端的PATH 20 | */ 21 | CLIENT_PATH, 22 | /** 23 | * 请求客户端的sessionId 24 | */ 25 | CLIENT_SESSION_ID, 26 | 27 | /** 28 | * 用户请求的完整路径 29 | */ 30 | CLIENT_ABSOLUTE_URI, 31 | /** 32 | * 用户请求的模式 33 | */ 34 | CLIENT_REQUEST_SCHEMA, 35 | /** 36 | * 获得api的名字 37 | */ 38 | SERVER_API_NAME, 39 | /** 40 | * 获得API服务器的unix时间戳 41 | */ 42 | SERVER_UNIX_TIME, 43 | /** 44 | * 获得网关USER_AGENT 45 | */ 46 | SERVER_USER_AGENT; 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/ParamTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 参数类型 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum ParamTypeEnum { 10 | String, Integer, Long, Float, Double, Boolean, JsonObject,JsonArray; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/enums/TimeUnitEnum.java: -------------------------------------------------------------------------------- 1 | package com.szmirren.vxApi.core.enums; 2 | 3 | /** 4 | * 时间单位类 5 | * 6 | * @author Mirren 7 | * 8 | */ 9 | public enum TimeUnitEnum { 10 | DAYS(86400), HOURS(3600), MINUTES(60); 11 | private long val; 12 | 13 | private TimeUnitEnum(long val) { 14 | this.val = val; 15 | } 16 | 17 | public long getVal() { 18 | return val; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/szmirren/vxApi/core/handler/FreeMarkerTemplateHander.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Red Hat, Inc. 3 | * 4 | * All rights reserved. This program and the accompanying materials 5 | * are made available under the terms of the Eclipse Public License v1.0 6 | * and Apache License v2.0 which accompanies this distribution. 7 | * 8 | * The Eclipse Public License is available at 9 | * http://www.eclipse.org/legal/epl-v10.html 10 | * 11 | * The Apache License v2.0 is available at 12 | * http://www.opensource.org/licenses/apache2.0.php 13 | * 14 | * You may elect to redistribute this code under either of these licenses. 15 | */ 16 | 17 | package com.szmirren.vxApi.core.handler; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.OutputStreamWriter; 23 | import java.util.Map; 24 | 25 | import org.apache.logging.log4j.LogManager; 26 | import org.apache.logging.log4j.Logger; 27 | 28 | import freemarker.cache.NullCacheStorage; 29 | import freemarker.template.Configuration; 30 | import freemarker.template.Template; 31 | import io.vertx.core.AsyncResult; 32 | import io.vertx.core.Future; 33 | import io.vertx.core.Handler; 34 | import io.vertx.core.Vertx; 35 | import io.vertx.core.buffer.Buffer; 36 | import io.vertx.core.file.FileSystemException; 37 | import io.vertx.core.http.HttpHeaders; 38 | import io.vertx.core.json.JsonObject; 39 | import io.vertx.ext.web.RoutingContext; 40 | import io.vertx.ext.web.common.template.CachingTemplateEngine; 41 | import io.vertx.ext.web.handler.TemplateHandler; 42 | import io.vertx.ext.web.impl.Utils; 43 | import io.vertx.ext.web.templ.freemarker.FreeMarkerTemplateEngine; 44 | import io.vertx.ext.web.templ.freemarker.impl.VertxWebObjectWrapper; 45 | 46 | /** 47 | * @author Paulo Lopes 48 | */ 49 | public class FreeMarkerTemplateHander extends CachingTemplateEngine