diff --git a/README.md b/README.md index 504688de..1ee3b8dd 100644 --- a/README.md +++ b/README.md @@ -103,11 +103,11 @@ System.out.println(responseData); ## 界面预览 -![服务列表](https://images.gitee.com/uploads/images/2019/0711/174825_2856281f_332975.png "服务列表") +![服务列表](https://images.gitee.com/uploads/images/2020/1016/134354_c1915902_332975.png "service.png") -![路由管理](https://images.gitee.com/uploads/images/2019/0711/174843_1648591c_332975.png "路由管理") +![路由管理](https://images.gitee.com/uploads/images/2020/1016/134039_bed1608d_332975.png "route.png") -![限流管理](https://images.gitee.com/uploads/images/2019/0711/174900_9315cc8e_332975.png "限流管理") +![限流管理](https://images.gitee.com/uploads/images/2020/1016/134102_f2dcfb25_332975.png "limit.png") ![秘钥信息](https://images.gitee.com/uploads/images/2019/0711/174921_bd817533_332975.png "秘钥信息") diff --git a/doc/docs/files/10010_快速体验.md b/doc/docs/files/10010_快速体验.md index 7d217d5a..a28b020e 100644 --- a/doc/docs/files/10010_快速体验.md +++ b/doc/docs/files/10010_快速体验.md @@ -1,5 +1,7 @@ # 快速体验 +## 方式1 + > 运行环境:JDK8,Maven3,[Nacos](https://nacos.io/zh-cn/docs/what-is-nacos.html),Mysql - 安装并启动Nacos,[安装教程](https://nacos.io/zh-cn/docs/quick-start.html) @@ -14,6 +16,20 @@ 2. 运行`SopStoryApplication.java` - 找到sop-test,运行`com.gitee.sop.test.AlipayClientPostTest.testGet`进行接口调用测试 +## 方式2(docker) + +> 前提:安装好docker + +- 安装并启动Nacos,[安装教程](https://nacos.io/zh-cn/docs/quick-start.html) +- 执行Mysql脚本`sop.sql`(Mysql版本5.6+),5.6以下运行`sop-mysql5.6以下版本.sql` +- 打开`docker-entrypoint.sh`,修改mysql,nacos配置 +- 执行`docker-build.sh` +- 找到sop-test,运行`com.gitee.sop.test.AlipayClientPostTest.testGet`进行接口调用测试 + + +> - admin地址:http://ip:8082 登录账号:admin/123456 +> - 文档地址:http://ip:8083/ + ## 使用admin - 找到`sop-admin/sop-admin-server`工程,打开sop-admin-server下的`application-dev.properties`,修改相关配置 diff --git a/doc/docs/files/10100_提供restful接口.md b/doc/docs/files/10100_提供restful接口.md index 1be388a3..c1218423 100644 --- a/doc/docs/files/10100_提供restful接口.md +++ b/doc/docs/files/10100_提供restful接口.md @@ -6,8 +6,6 @@ `http://ip:port/rest/服务id/your_path`,其中`http://ip:port/rest/`为固定部分,后面跟微服务请求路径。 -> 可在微服务端指定一个配置:`sop.restful.prefix=xxx`。请求路径将变成:`http://ip:port/rest/xxx/your_path` - 下面是一个微服务的接口例子 ```java @@ -36,6 +34,10 @@ public class TraditionalWebappController { 微服务之间的调用可以使用dubbo或feign,有了版本号的管理,可以做到服务的平滑升级,对用户来说都是无感知的。结合SOP-Admin提供的上下线功能, 可实现预发布环境功能。 +默认情况下,`http://ip:port/rest/`为固定部分,如果想要更改`rest`,可在网关配置文件指定:`sop.restful.path=/aaa` + +请求前缀将变成:`http://ip:port/aaa/` + - 封装请求工具【可选】 封装请求,方便调用,针对vue的封装如下: diff --git a/doc/docs/files/90011_原理分析之如何存储路由.md b/doc/docs/files/90011_原理分析之如何存储路由.md index 662248c7..575e5f82 100644 --- a/doc/docs/files/90011_原理分析之如何存储路由.md +++ b/doc/docs/files/90011_原理分析之如何存储路由.md @@ -1,52 +1,37 @@ # 原理分析之如何存储路由 -SOP基于spring cloud,因此会涉及到网关路由。但是开发者不用去配置文件定义路由的隐射关系,SOP自动帮你解决了这个问题。 +SOP基于spring cloud,因此会涉及到网关路由。但是开发者不用去配置文件定义路由的隐射关系,SOP帮你解决了这个问题。 ## 获取路由信息 -首先明确一点,路由信息由各微服务提供,因此网关需要从注册中心获取各微服务实例,这个通过nacos提供的`watch`来实现。 -当有新的微服务加入时,Nacos会触发一个事件推送,详见`NacosWatch.java`类 +网关启动成后会触发一个事件,代码见:`com.gitee.sop.gatewaycommon.config.AbstractConfiguration.listenEvent` -```java -this.publisher.publishEvent(new HeartbeatEvent(this, this.nacosWatchIndex.getAndIncrement())); -``` +这个事件会取拉取微服务中提供的路由信息 -因此,只要注册了`HeartbeatEvent`事件就能随时感知到微服务实例的变化。如何注册呢,config类实现`ApplicationListener`接口即可。 +下面以nacos为例,介绍拉取路由过程 -```java -public class AbstractConfiguration implements ApplicationContextAware, ApplicationListener { - @EventListener(classes = HeartbeatEvent.class) - public void listenEvent(ApplicationEvent heartbeatEvent) { - // 有服务注册进来 - } -} -``` +1.从nacos中获取微服务实例 -然后,每个微服务提供一个restful接口,接口地址为:`http://ip:port/sop/routes`,用来返回自身路由信息。网关请求这个接口用来获取路由信息。 +入口代码:`com.gitee.sop.bridge.route.NacosRegistryListener.onEvent` -加载路由伪代码如下: +2.拿到微服务信息,调用微服务提供的接口拉取路由数据 -```java -@Override -public void onAddInstance(InstanceDefinition instance) { - String serviceName = instance.getServiceId(); - String url = getRouteRequestUrl(instance); - log.info("拉取路由配置,serviceId: {}, url: {}", serviceName, url); - ResponseEntity responseEntity = getRestTemplate().getForEntity(url, String.class); - if (responseEntity.getStatusCode() == HttpStatus.OK) { - String body = responseEntity.getBody(); - ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class); - baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance)); - } else { - log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody()); - } -} -``` +入口代码:`com.gitee.sop.gatewaycommon.route.BaseRegistryListener.pullRoutes` + +最终落实到:`com.gitee.sop.gatewaycommon.route.ServiceRouteListener.onAddInstance` + +微服务提供一个url:`http://ip:port/sop/routes`,对应Controller在:`com.gitee.sop.servercommon.route.ServiceRouteController.listRoutes` + +微服务找到被`@Open`注解的方法,然后封装成一个路由对象,放到List中,最后返回给网关。 + +3.网关拿到路由信息,经过处理,转化成网关路由配置 + +关联方法: + +`com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache.add` -参考代码: +`com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache.refresh` -- `com.gitee.sop.gatewaycommon.route.RegistryListener`以及实现类 -- `com.gitee.sop.gatewaycommon.route.ServiceRouteListener` 路由的存储方式是一个Map,key为路由id,即接口名+版本号。 @@ -57,5 +42,5 @@ public void onAddInstance(InstanceDefinition instance) { private static final Map routes = synchronizedMap(new LinkedHashMap<>()); ``` -因为客户端调用接口都会传递一个接口名和版本号,因此通过这两个字段能够很快查询出路由信息,进行路由转发操作。 +因为客户端调用接口都会传递一个接口名和版本号,因此通过这两个字段能够很快查询出路由信息,然后进行路由转发操作。 diff --git a/docker-build.sh b/docker-build.sh new file mode 100644 index 00000000..e9aa01f0 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# 打包 +mvn clean package +# 创建镜像 +docker build -t gitee.com/sop . + +# 获取镜像id +image_id=`docker images gitee.com/sop --format "{{.ID}}" | awk '{print $1}'` + +# 运行镜像 +docker run --name sop -p 8081:8081 -p 8082:8082 -p 8083:8083 -p 8087:8087 -p 2222:2222 -d $image_id \ No newline at end of file diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 00000000..73b6894c --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +JAVA_OPTS="-Xms128m -Xmx128m" + +# mysql, nacos配置 +args="--mysql.host=10.1.30.110:3306 --mysql.username=root --mysql.password=root --register.url=10.1.30.110:8848" + +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-gateway/sop-gateway.jar $args --logging.file.path=/sop/sop-gateway/log & +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-admin/sop-admin.jar $args --logging.file.path=/sop/sop-admin/log & +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-website/sop-website.jar $args --logging.file.path=/sop/sop-website/log & +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-auth/sop-auth.jar $args --logging.file.path=/sop/sop-auth/log & +# 最后一条没有& +java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /sop/sop-story/sop-story.jar $args --logging.file.path=/sop/sop-story/log \ No newline at end of file diff --git a/dockerfile b/dockerfile new file mode 100644 index 00000000..3d585900 --- /dev/null +++ b/dockerfile @@ -0,0 +1,16 @@ +FROM java:8 +VOLUME /tmp +VOLUME /sop + +# 将所有应用放到一个镜像当中 +ADD sop-gateway/target/*.jar sop/sop-gateway/sop-gateway.jar +ADD sop-admin/sop-admin-server/target/*.jar sop/sop-admin/sop-admin.jar +ADD sop-website/target/*.jar sop/sop-website/sop-website.jar +ADD sop-auth/target/*.jar sop/sop-auth/sop-auth.jar +ADD sop-example/sop-story/target/*.jar sop/sop-story/sop-story.jar + +# 拷贝启动脚本 +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/pom.xml b/pom.xml index a48783b3..989d13f2 100644 --- a/pom.xml +++ b/pom.xml @@ -237,19 +237,6 @@ UTF-8 - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar-no-fork - - - - diff --git a/sop-admin/sop-admin-server/src/main/resources/META-INF/sop-admin.properties b/sop-admin/sop-admin-server/src/main/resources/META-INF/sop-admin.properties index beaecf0d..8be31f05 100644 --- a/sop-admin/sop-admin-server/src/main/resources/META-INF/sop-admin.properties +++ b/sop-admin/sop-admin-server/src/main/resources/META-INF/sop-admin.properties @@ -27,6 +27,10 @@ spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEn spring.datasource.username=${mysql.username} spring.datasource.password=${mysql.password} +#连接池 +spring.datasource.hikari.pool-name=DatebookHikariCP +spring.datasource.hikari.max-lifetime=500000 + # 固定不用改 mybatis.mapper-locations=classpath:mybatis/mapper/*.xml easyopen.show-doc=false diff --git a/sop-admin/sop-admin-server/src/main/resources/public/index.html b/sop-admin/sop-admin-server/src/main/resources/public/index.html index 8cd304ab..affdfbe0 100644 --- a/sop-admin/sop-admin-server/src/main/resources/public/index.html +++ b/sop-admin/sop-admin-server/src/main/resources/public/index.html @@ -1 +1 @@ -SOP Admin
\ No newline at end of file +SOP Admin
\ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.00a89f91.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.eac43cde.js similarity index 98% rename from sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.00a89f91.js rename to sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.eac43cde.js index ec7da7fb..ae542f28 100644 --- a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.00a89f91.js +++ b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-25908fca.eac43cde.js @@ -1 +1 @@ -(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-25908fca"],{"021d":function(e,t,a){},"0bac":function(e,t,a){"use strict";var s=a("021d"),i=a.n(s);i.a},cb56:function(e,t,a){"use strict";a.r(t);var s=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("div",{staticClass:"app-container"},[a("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:e.searchFormData,size:"mini"}},[a("el-form-item",{attrs:{label:"appId"}},[a("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"appId"},model:{value:e.searchFormData.appKey,callback:function(t){e.$set(e.searchFormData,"appKey",t)},expression:"searchFormData.appKey"}})],1),e._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:e.onSearchTable}},[e._v("查询")])],1)],1),e._v(" "),a("el-button",{staticStyle:{"margin-bottom":"10px"},attrs:{type:"primary",size:"mini",icon:"el-icon-plus"},on:{click:e.onAdd}},[e._v("新增ISV")]),e._v(" "),a("el-table",{attrs:{data:e.pageInfo.list,border:"",fit:"","highlight-current-row":""}},[a("el-table-column",{attrs:{prop:"appKey",label:"AppId",width:"250"}}),e._v(" "),a("el-table-column",{attrs:{prop:"",label:"秘钥",width:"80"},scopedSlots:e._u([{key:"default",fn:function(t){return[a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onShowKeys(t.row)}}},[e._v("查看")])]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"roleList",label:"角色",width:"150","show-overflow-tooltip":!0},scopedSlots:e._u([{key:"default",fn:function(t){return[a("span",{domProps:{innerHTML:e._s(e.roleRender(t.row))}})]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"status",label:"状态",width:"80"},scopedSlots:e._u([{key:"default",fn:function(t){return[1===t.row.status?a("span",{staticStyle:{color:"#67C23A"}},[e._v("启用")]):e._e(),e._v(" "),2===t.row.status?a("span",{staticStyle:{color:"#F56C6C"}},[e._v("禁用")]):e._e()]}}])}),e._v(" "),a("el-table-column",{attrs:{prop:"gmtCreate",label:"添加时间",width:"160"}}),e._v(" "),a("el-table-column",{attrs:{prop:"remark",label:"备注",width:"200","show-overflow-tooltip":!0}}),e._v(" "),a("el-table-column",{attrs:{label:"操作",width:"200"},scopedSlots:e._u([{key:"default",fn:function(t){return[a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onTableUpdate(t.row)}}},[e._v("修改")]),e._v(" "),a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onKeysUpdate(t.row)}}},[e._v("秘钥管理")]),e._v(" "),a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return e.onExportKeys(t.row)}}},[e._v("导出秘钥")])]}}])})],1),e._v(" "),a("el-pagination",{staticStyle:{"margin-top":"5px"},attrs:{background:"","current-page":e.searchFormData.pageIndex,"page-size":e.searchFormData.pageSize,"page-sizes":[5,10,20,40],total:e.pageInfo.total,layout:"total, sizes, prev, pager, next"},on:{"size-change":e.onSizeChange,"current-change":e.onPageIndexChange}}),e._v(" "),a("el-dialog",{attrs:{title:e.isvDialogTitle,visible:e.isvDialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){e.isvDialogVisible=t},close:e.onIsvDialogClose}},[a("el-form",{ref:"isvForm",attrs:{rules:e.rulesIsvForm,model:e.isvDialogFormData,"label-width":"120px",size:"mini"}},[a("el-form-item",{attrs:{label:"appId"}},[0===e.isvDialogFormData.id?a("span",{staticStyle:{color:"gray"}},[e._v("(系统自动生成)")]):a("span",[e._v(e._s(e.isvDialogFormData.appKey))])]),e._v(" "),a("el-form-item",{attrs:{label:"角色"}},[a("el-checkbox-group",{model:{value:e.isvDialogFormData.roleCode,callback:function(t){e.$set(e.isvDialogFormData,"roleCode",t)},expression:"isvDialogFormData.roleCode"}},e._l(e.roles,function(t){return a("el-checkbox",{key:t.roleCode,attrs:{label:t.roleCode}},[e._v(e._s(t.description))])}),1)],1),e._v(" "),a("el-form-item",{attrs:{label:"备注",prop:"remark"}},[a("el-input",{attrs:{type:"textarea"},model:{value:e.isvDialogFormData.remark,callback:function(t){e.$set(e.isvDialogFormData,"remark",t)},expression:"isvDialogFormData.remark"}})],1),e._v(" "),a("el-form-item",{attrs:{label:"状态"}},[a("el-radio-group",{model:{value:e.isvDialogFormData.status,callback:function(t){e.$set(e.isvDialogFormData,"status",t)},expression:"isvDialogFormData.status"}},[a("el-radio",{attrs:{label:1,name:"status"}},[e._v("启用")]),e._v(" "),a("el-radio",{attrs:{label:2,name:"status"}},[e._v("禁用")])],1)],1)],1),e._v(" "),a("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{on:{click:function(t){e.isvDialogVisible=!1}}},[e._v("取 消")]),e._v(" "),a("el-button",{attrs:{type:"primary",disabled:e.isSaveButtonDisabled},on:{click:e.onIsvDialogSave}},[e._v("保 存")])],1)],1),e._v(" "),a("el-dialog",{attrs:{title:"秘钥信息",visible:e.isvKeysDialogVisible},on:{"update:visible":function(t){e.isvKeysDialogVisible=t},close:function(t){return e.resetForm("isvKeysFrom")}}},[a("el-form",{ref:"isvKeysFrom",staticClass:"key-view",attrs:{model:e.isvKeysFormData,"label-width":"160px",size:"mini"}},[a("el-form-item",{attrs:{label:""}},[a("el-alert",{attrs:{title:"带 ★ 的分配给开发者",type:"warning",closable:!1}})],1),e._v(" "),a("el-form-item",{attrs:{label:e.selfLabel("appId")}},[a("span",[e._v(e._s(e.isvKeysFormData.appKey))])]),e._v(" "),a("el-form-item",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}],attrs:{label:"秘钥格式"}},[1===e.isvKeysFormData.keyFormat?a("span",[e._v("PKCS8(JAVA适用)")]):e._e(),e._v(" "),2===e.isvKeysFormData.keyFormat?a("span",[e._v("PKCS1(非JAVA适用)")]):e._e()]),e._v(" "),a("el-form-item",{directives:[{name:"show",rawName:"v-show",value:2===e.isvKeysFormData.signType,expression:"isvKeysFormData.signType === 2"}],attrs:{label:e.selfLabel("secret")}},[a("span",[e._v(e._s(e.isvKeysFormData.secret))])]),e._v(" "),a("el-tabs",{directives:[{name:"show",rawName:"v-show",value:e.showKeys(),expression:"showKeys()"}],staticClass:"keyTabs",attrs:{type:"card"},model:{value:e.activeName,callback:function(t){e.activeName=t},expression:"activeName"}},[a("el-tab-pane",{attrs:{label:"ISV公私钥",name:"first"}},[a("el-form-item",{attrs:{label:"ISV公钥"}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.publicKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyIsv",t)},expression:"isvKeysFormData.publicKeyIsv"}})],1),e._v(" "),a("el-form-item",{attrs:{label:e.selfLabel("ISV私钥")}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.privateKeyIsv,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyIsv",t)},expression:"isvKeysFormData.privateKeyIsv"}})],1)],1),e._v(" "),a("el-tab-pane",{attrs:{label:"平台公私钥[可选]",name:"second"}},[a("el-form-item",{attrs:{label:"平台公钥"}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.publicKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"publicKeyPlatform",t)},expression:"isvKeysFormData.publicKeyPlatform"}})],1),e._v(" "),a("el-form-item",{attrs:{prop:"privateKeyPlatform",label:"平台私钥"}},[a("el-input",{attrs:{type:"textarea",readonly:""},model:{value:e.isvKeysFormData.privateKeyPlatform,callback:function(t){e.$set(e.isvKeysFormData,"privateKeyPlatform",t)},expression:"isvKeysFormData.privateKeyPlatform"}})],1)],1)],1)],1),e._v(" "),a("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{on:{click:function(t){e.isvKeysDialogVisible=!1}}},[e._v("关 闭")])],1)],1)],1)},i=[],o={data:function(){return{searchFormData:{appKey:"",pageIndex:1,pageSize:10},pageInfo:{list:[],total:0},roles:[],isvDialogVisible:!1,isvDialogTitle:"新增ISV",isvDialogFormData:{id:0,status:1,remark:"",roleCode:[]},rulesIsvForm:{remark:[{min:0,max:100,message:"长度在 1 到 100 个字符",trigger:"blur"}]},activeName:"first",isSaveButtonDisabled:!1,isvKeysDialogVisible:!1,isvKeysFormData:{appKey:"",secret:"",publicKeyIsv:"",privateKeyIsv:"",publicKeyPlatform:"",privateKeyPlatform:"",signType:""}}},created:function(){this.loadTable(),this.loadRouteRole()},methods:{loadTable:function(){this.post("isv.info.page",this.searchFormData,function(e){this.pageInfo=e.data})},loadRouteRole:function(){0===this.roles.length&&this.post("role.listall",{},function(e){this.roles=e.data})},onShowKeys:function(e){this.post("isv.keys.get",{appKey:e.appKey},function(e){var t=this;this.isvKeysDialogVisible=!0,this.$nextTick(function(){Object.assign(t.isvKeysFormData,e.data)})})},onSearchTable:function(){this.loadTable()},onTableUpdate:function(e){var t=this;this.isvDialogTitle="修改ISV",this.isvDialogVisible=!0,this.$nextTick(function(){t.post("isv.info.get",{id:e.id},function(e){for(var t=e.data,a=t.roleList,s=[],i=0;i
- - + + 查询 diff --git a/sop-common/sop-bridge-eureka/.gitignore b/sop-common/sop-bridge-eureka/.gitignore new file mode 100644 index 00000000..c456c4a3 --- /dev/null +++ b/sop-common/sop-bridge-eureka/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ diff --git a/sop-common/sop-bridge-nacos/.gitignore b/sop-common/sop-bridge-nacos/.gitignore new file mode 100644 index 00000000..c456c4a3 --- /dev/null +++ b/sop-common/sop-bridge-nacos/.gitignore @@ -0,0 +1,25 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index 8fb92151..e73688bf 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -44,7 +44,6 @@ public class ServerWebExchangeUtil { private static final String THROWABLE_KEY = "sop.throwable"; private static final String UNKNOWN_PATH = "/sop/unknown"; - private static final String REST_PATH = "/rest"; private static final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); @@ -77,10 +76,10 @@ public class ServerWebExchangeUtil { return ServerRequest.create(exchange, messageReaders); } - public static String getRestfulPath(String path) { - int index = path.indexOf(REST_PATH); + public static String getRestfulPath(String path, String prefix) { + int index = path.indexOf(prefix); // 取"/rest"的后面部分 - return path.substring(index + REST_PATH.length()); + return path.substring(index + prefix.length()); } /** diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java index b5f9efaf..6903c71a 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/IndexFilter.java @@ -5,6 +5,7 @@ import com.gitee.sop.gatewaycommon.bean.SopConstants; import com.gitee.sop.gatewaycommon.exception.ApiException; import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.gateway.route.GatewayForwardChooser; +import com.gitee.sop.gatewaycommon.manager.EnvironmentKeys; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.route.ForwardInfo; import com.gitee.sop.gatewaycommon.util.RouteInterceptorUtil; @@ -44,8 +45,6 @@ import java.util.Objects; @Order(Ordered.HIGHEST_PRECEDENCE) public class IndexFilter implements WebFilter { - private static final String REST_PATH_PREFIX = "/rest"; - /** 路径白名单 */ private static final List PATH_WHITE_LIST = Arrays.asList( "/sop", "/actuator" @@ -69,9 +68,9 @@ public class IndexFilter implements WebFilter { return chain.filter(exchange); } // 如果是restful请求,直接转发 - if (path.startsWith(REST_PATH_PREFIX)) { + if (path.startsWith(EnvironmentKeys.SOP_RESTFUL_PATH.getValue())) { exchange.getAttributes().put(SopConstants.RESTFUL_REQUEST, true); - String restfulPath = ServerWebExchangeUtil.getRestfulPath(path); + String restfulPath = ServerWebExchangeUtil.getRestfulPath(path, EnvironmentKeys.SOP_RESTFUL_PATH.getValue()); ServerWebExchange newExchange = ServerWebExchangeUtil.getForwardExchange(exchange, restfulPath); return chain.filter(newExchange); } diff --git a/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/Example1001_BaseController.java b/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/Example1001_BaseController.java index 42747c1e..7e70af33 100644 --- a/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/Example1001_BaseController.java +++ b/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/Example1001_BaseController.java @@ -22,9 +22,11 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -135,6 +137,19 @@ public class Example1001_BaseController { return testResult; } + // 获取header + @Open(value = "test.head",version = "1.0") + @GetMapping("/get/header/v1") + public StoryResult header(@RequestBody StoryParam story, HttpServletRequest request) { + HttpServletRequest servletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + StoryResult storyResult = new StoryResult(); + storyResult.setId(1L); + storyResult.setName(story.getName() + + ", token1:" + request.getHeader("token") + + ", token2:" + servletRequest.getHeader("token")); + return storyResult; + } + // 返回数组结果 @ApiOperation(value = "返回数组结果(第二)", notes = "返回数组结果", position = -99) @Open("story.list") diff --git a/sop-example/sop-story/src/main/resources/application-dev.properties b/sop-example/sop-story/src/main/resources/application-dev.properties index 8d5ebeea..ff5fc397 100644 --- a/sop-example/sop-story/src/main/resources/application-dev.properties +++ b/sop-example/sop-story/src/main/resources/application-dev.properties @@ -1,5 +1,6 @@ server.port=2222 spring.application.name=story-service +register.url=http://localhost:1111/eureka/ # 注册中心 -eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/ +eureka.client.serviceUrl.defaultZone=${register.url} diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml index 88c31a07..935120b9 100644 --- a/sop-gateway/pom.xml +++ b/sop-gateway/pom.xml @@ -59,6 +59,10 @@ mysql-connector-java runtime + + javax.servlet + javax.servlet-api + @@ -73,12 +77,6 @@ 1.18.4 provided - - javax.servlet - javax.servlet-api - 3.1.0 - provided - diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java deleted file mode 100644 index cd52de97..00000000 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigRouteLimit.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.gitee.sop.gateway.entity; - -import lombok.Data; - -import javax.persistence.Column; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; -import java.util.Date; - - -/** - * 表名:config_route_limit - * 备注:路由限流配置 - * - * @author tanghc - */ -@Table(name = "config_route_limit") -@Data -public class ConfigRouteLimit { - @Id - @Column(name = "id") - @GeneratedValue(strategy = GenerationType.IDENTITY) - /** 数据库字段:id */ - private Integer id; - - /** 路由id, 数据库字段:route_id */ - private String routeId; - - /** 限流策略,1:窗口策略,2:令牌桶策略, 数据库字段:limit_type */ - private Byte limitType; - - /** 每秒可处理请求数, 数据库字段:exec_count_per_second */ - private Integer execCountPerSecond; - - /** 返回的错误码, 数据库字段:limit_code */ - private String limitCode; - - /** 返回的错误信息, 数据库字段:limit_msg */ - private String limitMsg; - - /** 令牌桶容量, 数据库字段:token_bucket_count */ - private Integer tokenBucketCount; - - /** 1:开启,0关闭, 数据库字段:limit_status */ - private Byte limitStatus; - - /** 数据库字段:gmt_create */ - private Date gmtCreate; - - /** 数据库字段:gmt_modified */ - private Date gmtModified; -} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java index 0108cffd..5c5aac2e 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java @@ -1,6 +1,5 @@ package com.gitee.sop.gateway.manager; -import com.gitee.sop.gateway.mapper.ConfigRouteLimitMapper; import com.gitee.sop.gateway.mapper.ConfigRouteMapper; import com.gitee.sop.gatewaycommon.bean.ChannelMsg; import com.gitee.sop.gatewaycommon.bean.RouteConfig; @@ -21,13 +20,10 @@ import java.util.List; public class DbRouteConfigManager extends DefaultRouteConfigManager { @Autowired - ConfigRouteLimitMapper configRouteLimitMapper; + private ConfigRouteMapper configRouteMapper; @Autowired - ConfigRouteMapper configRouteMapper; - - @Autowired - Environment environment; + private Environment environment; @Override public void load(String serviceId) { diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java deleted file mode 100644 index 4dfb7f86..00000000 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigRouteLimitMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.gitee.sop.gateway.mapper; - -import com.gitee.fastmybatis.core.mapper.CrudMapper; -import com.gitee.sop.gateway.entity.ConfigRouteLimit; - - -/** - * @author tanghc - */ -public interface ConfigRouteLimitMapper extends CrudMapper { -} diff --git a/sop-gateway/src/main/resources/META-INF/gateway.properties b/sop-gateway/src/main/resources/META-INF/gateway.properties index d59b5f1b..8974b391 100644 --- a/sop-gateway/src/main/resources/META-INF/gateway.properties +++ b/sop-gateway/src/main/resources/META-INF/gateway.properties @@ -18,6 +18,9 @@ spring.datasource.url=jdbc:mysql://${mysql.host}/sop?useUnicode=true&characterEn spring.datasource.username=${mysql.username} spring.datasource.password=${mysql.password} +#连接池 +spring.datasource.hikari.pool-name=DatebookHikariCP +spring.datasource.hikari.max-lifetime=500000 spring.cloud.gateway.discovery.locator.lower-case-service-id=true spring.cloud.gateway.discovery.locator.enabled=true diff --git a/sop-mysql5.6以下版本.sql b/sop-mysql5.6以下版本.sql index bc1e43a2..8e02579a 100644 --- a/sop-mysql5.6以下版本.sql +++ b/sop-mysql5.6以下版本.sql @@ -9,7 +9,6 @@ DROP TABLE IF EXISTS `perm_role`; DROP TABLE IF EXISTS `perm_isv_role`; DROP TABLE IF EXISTS `isv_keys`; DROP TABLE IF EXISTS `isv_info`; -DROP TABLE IF EXISTS `config_route_limit`; DROP TABLE IF EXISTS `config_route_base`; DROP TABLE IF EXISTS `config_limit`; DROP TABLE IF EXISTS `config_ip_blacklist`; @@ -113,22 +112,6 @@ CREATE TABLE `config_route_base` ( ) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='路由配置表'; -CREATE TABLE `config_route_limit` ( - `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - `route_id` VARCHAR(64) NOT NULL COMMENT '路由id', - `service_id` VARCHAR(64) NOT NULL DEFAULT '', - `limit_type` TINYINT(4) NOT NULL DEFAULT '1' COMMENT '限流策略,1:窗口策略,2:令牌桶策略', - `exec_count_per_second` INT(11) DEFAULT NULL COMMENT '每秒可处理请求数', - `limit_code` VARCHAR(64) DEFAULT NULL COMMENT '返回的错误码', - `limit_msg` VARCHAR(100) DEFAULT NULL COMMENT '返回的错误信息', - `token_bucket_count` INT(11) DEFAULT NULL COMMENT '令牌桶容量', - `limit_status` TINYINT(4) NOT NULL DEFAULT '0' COMMENT '限流开启状态,1:开启,0关闭', - `gmt_create` DATETIME DEFAULT NULL, - `gmt_modified` DATETIME DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_routeid` (`route_id`) USING BTREE -) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='路由限流配置'; - CREATE TABLE `isv_info` ( `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, @@ -241,13 +224,6 @@ INSERT INTO `config_route_base` (`id`, `route_id`, `status`, `gmt_create`, `gmt_ (8,'goods.add1.0',1,'2019-05-13 17:23:00','2019-05-13 17:23:11'); -INSERT INTO `config_route_limit` (`id`, `route_id`, `service_id`, `limit_type`, `exec_count_per_second`, `limit_code`, `limit_msg`, `token_bucket_count`, `limit_status`, `gmt_create`, `gmt_modified`) VALUES - (1,'alipay.story.find1.0','story-service',1,10,'isp.service-busy','服务器正忙',NULL,1,'2019-04-10 20:55:08','2019-04-10 21:04:35'), - (2,'alipay.story.get1.0','story-service',2,5,'isp.service-busy','服务器正忙',5,0,'2019-04-10 21:05:51','2019-04-11 18:18:03'), - (3,'alipay.story.get1.2','story-service',2,10,'isp.service-busy','服务器正忙',3,1,'2019-04-11 17:26:04','2019-04-11 18:19:33'), - (4,'alipay.category.get1.0','story-service',1,5,'error-code','服务器忙',5,1,'2019-05-07 12:22:04','2019-05-07 12:25:06'); - - INSERT INTO `isv_info` (`id`, `app_key`, `status`, `sign_type`, `remark`, `gmt_create`, `gmt_modified`) VALUES (1,'2019032617262200001',1,1,NULL,'2019-03-27 10:10:34','2019-05-09 11:10:38'), (3,'asdfasdf',2,1,NULL,'2019-03-27 11:01:11','2019-05-11 10:45:01'), diff --git a/sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java b/sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java index 266ee47e..dca10c54 100644 --- a/sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java +++ b/sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java @@ -112,10 +112,16 @@ public class AllInOneTest extends TestBase { */ public void testJSR303() { Client client = new Client(url, appId, privateKey); + Map headers = new HashMap<>(8); + headers.put("accept-language", "zh-CN"); Client.RequestBuilder requestBuilder = new Client.RequestBuilder() .method("goods.add") .version("1.0") - .bizContent(new BizContent().add("goods_name", "iphone6").add("goods_remark", "iphone6").add("goods_comment", "1")) + .header(headers) + .bizContent(new BizContent() + .add("goods_name", "iphone6") + .add("goods_remark", "iphone6") + .add("goods_comment", "1")) .httpMethod(HttpTool.HTTPMethod.POST) .callback((requestInfo, responseData) -> { System.out.println(responseData); @@ -218,6 +224,22 @@ public class AllInOneTest extends TestBase { client.execute(requestBuilder); } + /** + * 传递header + */ + public void testHeader() { + Map header = new HashMap<>(8); + header.put("token", "aaaabbbb"); + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("test.head") + .version("1.0") + .header(header) + .bizContent(new BizContent().add("id", "1").add("name", "葫芦娃")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + /** * 测试post提交大文本内容 * @throws IOException diff --git a/sop.sql b/sop.sql index 2f850206..3b44a9e7 100644 --- a/sop.sql +++ b/sop.sql @@ -12,7 +12,6 @@ DROP TABLE IF EXISTS `perm_isv_role`; DROP TABLE IF EXISTS `isv_keys`; DROP TABLE IF EXISTS `isv_info`; DROP TABLE IF EXISTS `config_service_route`; -DROP TABLE IF EXISTS `config_route_limit`; DROP TABLE IF EXISTS `config_route_base`; DROP TABLE IF EXISTS `config_limit`; DROP TABLE IF EXISTS `config_ip_blacklist`; @@ -115,23 +114,6 @@ CREATE TABLE `config_route_base` ( ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='路由配置表'; -CREATE TABLE `config_route_limit` ( - `id` int(11) unsigned NOT NULL AUTO_INCREMENT, - `route_id` varchar(64) NOT NULL COMMENT '路由id', - `service_id` varchar(64) NOT NULL DEFAULT '', - `limit_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '限流策略,1:窗口策略,2:令牌桶策略', - `exec_count_per_second` int(11) DEFAULT NULL COMMENT '每秒可处理请求数', - `limit_code` varchar(64) DEFAULT NULL COMMENT '返回的错误码', - `limit_msg` varchar(100) DEFAULT NULL COMMENT '返回的错误信息', - `token_bucket_count` int(11) DEFAULT NULL COMMENT '令牌桶容量', - `limit_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '限流开启状态,1:开启,0关闭', - `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_routeid` (`route_id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='路由限流配置'; - - CREATE TABLE `config_service_route` ( `id` varchar(128) NOT NULL DEFAULT '' COMMENT '路由id', `service_id` varchar(128) NOT NULL DEFAULT '', @@ -244,13 +226,6 @@ INSERT INTO `config_route_base` (`id`, `route_id`, `status`, `gmt_create`, `gmt_ (8,'goods.add1.0',1,'2019-05-13 17:23:00','2019-05-13 17:23:11'); -INSERT INTO `config_route_limit` (`id`, `route_id`, `service_id`, `limit_type`, `exec_count_per_second`, `limit_code`, `limit_msg`, `token_bucket_count`, `limit_status`, `gmt_create`, `gmt_modified`) VALUES - (1,'alipay.story.find1.0','story-service',1,10,'isp.service-busy','服务器正忙',NULL,1,'2019-04-10 20:55:08','2019-04-10 21:04:35'), - (2,'alipay.story.get1.0','story-service',2,5,'isp.service-busy','服务器正忙',5,0,'2019-04-10 21:05:51','2019-04-11 18:18:03'), - (3,'alipay.story.get1.2','story-service',2,10,'isp.service-busy','服务器正忙',3,1,'2019-04-11 17:26:04','2019-04-11 18:19:33'), - (4,'alipay.category.get1.0','story-service',1,5,'error-code','服务器忙',5,1,'2019-05-07 12:22:04','2019-05-07 12:25:06'); - - INSERT INTO `isv_info` (`id`, `app_key`, `status`, `sign_type`, `remark`, `gmt_create`, `gmt_modified`) VALUES (1,'2019032617262200001',1,1,NULL,'2019-03-27 10:10:34','2019-05-09 11:10:38'), (3,'asdfasdf',2,1,NULL,'2019-03-27 11:01:11','2019-05-11 10:45:01'),