diff --git a/changelog.md b/changelog.md index 402cd345..a0646c53 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # changelog +## 1.15.0 + +- 优化预发布、灰度 +- 网关动态修改请求参数 +- 支持swagger-bootstrap插件 +- admin服务列表在线/离线筛选(在线靠前) +- 文档刷新逻辑 +- 测试all in one +- 修复中文乱码问题 + ## 1.14.0 - 支持预发布、灰度发布环境 diff --git a/doc/docs/_sidebar.md b/doc/docs/_sidebar.md index 2afb8a41..5704f389 100644 --- a/doc/docs/_sidebar.md +++ b/doc/docs/_sidebar.md @@ -1,33 +1,34 @@ -* [首页](/?t=1565165921486) +* [首页](/?t=1565681110217) * 开发文档 - * [快速体验](files/10010_快速体验.md?t=1565165921490) - * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1565165921508) - * [新增接口](files/10020_新增接口.md?t=1565165921508) - * [业务参数校验](files/10030_业务参数校验.md?t=1565165921509) - * [错误处理](files/10040_错误处理.md?t=1565165921509) - * [编写文档](files/10041_编写文档.md?t=1565165921509) - * [接口交互详解](files/10050_接口交互详解.md?t=1565165921509) - * [easyopen支持](files/10070_easyopen支持.md?t=1565165921509) - * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1565165921509) - * [ISV管理](files/10085_ISV管理.md?t=1565165921509) - * [自定义路由](files/10086_自定义路由.md?t=1565165921509) - * [自定义返回结果](files/10087_自定义返回结果.md?t=1565165921510) - * [自定义过滤器](files/10088_自定义过滤器.md?t=1565165921510) - * [路由授权](files/10090_路由授权.md?t=1565165921510) - * [接口限流](files/10092_接口限流.md?t=1565165921510) - * [监控日志](files/10093_监控日志.md?t=1565165921510) - * [SDK开发](files/10095_SDK开发.md?t=1565165921510) - * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1565165921510) - * [应用授权](files/10097_应用授权.md?t=1565165921510) - * [传统web开发](files/10100_传统web开发.md?t=1565165921510) - * [文件上传](files/10104_文件上传.md?t=1565165921510) - * [nacos注册中心](files/10106_nacos注册中心.md?t=1565165921510) - * [扩展其它注册中心](files/10107_扩展其它注册中心.md?t=1565165921511) - * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1565165921511) - * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1565165921511) + * [快速体验](files/10010_快速体验.md?t=1565681110219) + * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1565681110236) + * [新增接口](files/10020_新增接口.md?t=1565681110236) + * [业务参数校验](files/10030_业务参数校验.md?t=1565681110236) + * [错误处理](files/10040_错误处理.md?t=1565681110236) + * [编写文档](files/10041_编写文档.md?t=1565681110236) + * [接口交互详解](files/10050_接口交互详解.md?t=1565681110236) + * [easyopen支持](files/10070_easyopen支持.md?t=1565681110236) + * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1565681110237) + * [ISV管理](files/10085_ISV管理.md?t=1565681110237) + * [自定义路由](files/10086_自定义路由.md?t=1565681110237) + * [自定义返回结果](files/10087_自定义返回结果.md?t=1565681110237) + * [自定义过滤器](files/10088_自定义过滤器.md?t=1565681110237) + * [路由授权](files/10090_路由授权.md?t=1565681110237) + * [接口限流](files/10092_接口限流.md?t=1565681110237) + * [监控日志](files/10093_监控日志.md?t=1565681110237) + * [SDK开发](files/10095_SDK开发.md?t=1565681110237) + * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1565681110237) + * [应用授权](files/10097_应用授权.md?t=1565681110238) + * [传统web开发](files/10100_传统web开发.md?t=1565681110238) + * [文件上传](files/10104_文件上传.md?t=1565681110238) + * [nacos注册中心](files/10106_nacos注册中心.md?t=1565681110238) + * [扩展其它注册中心](files/10107_扩展其它注册中心.md?t=1565681110238) + * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1565681110238) + * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1565681110238) + * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1565681110238) * 原理分析 - * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1565165921511) - * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1565165921511) - * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1565165921511) - * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1565165921511) - * [常见问题](files/90100_常见问题.md?t=1565165921511) + * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1565681110238) + * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1565681110238) + * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1565681110238) + * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1565681110239) + * [常见问题](files/90100_常见问题.md?t=1565681110239) diff --git a/doc/docs/files/10010_快速体验.md b/doc/docs/files/10010_快速体验.md index 53cf1ce7..af68270a 100644 --- a/doc/docs/files/10010_快速体验.md +++ b/doc/docs/files/10010_快速体验.md @@ -13,7 +13,7 @@ - 启动微服务:打开sop-story-web下的`application-dev.properties`文件 1. 指定zookeeper地址,如果zookeeper安装在本机则不用改 2. 运行`SopStoryApplication.java` -- 找到sop-test,打开测试用例,进行接口调用测试,运行com.gitee.sop.AlipayClientPostTest.testPost() +- 找到sop-test,打开`AllInOneTest.java`进行接口调用测试 确保注册中心先启动 diff --git a/doc/docs/files/10111_动态修改请求参数.md b/doc/docs/files/10111_动态修改请求参数.md new file mode 100644 index 00000000..90f2f7f4 --- /dev/null +++ b/doc/docs/files/10111_动态修改请求参数.md @@ -0,0 +1,33 @@ +# 动态修改请求参数 + +自1.14.0开始,zuul网关支持动态修改请求参数。即在网关修改客户端传递过来的参数,然后发送到微服务端。 + +``` +客户端参数{"name": "jim"} --> zuul中修改为{"name": "Lucy"} --> 微服务端将收到{"name": "Lucy"} +``` + +使用场景:客户端请求参数经过加密,在网关解密后,再次发送明文参数给微服务端 + +- 如何使用 + +在网关springboot启动函数中添加如下代码 + +```java +public static void main(String[] args) { + ApiConfig.getInstance().setZuulParameterFormatter(requestParams -> { + // 获取biz_content + JSONObject jsonObject = requestParams.getJSONObject(ParamNames.BIZ_CONTENT_NAME); + // 修改biz_content中的值 + jsonObject.put("name", "name修改了111"); + jsonObject.put("remark", "remark修改了222"); + // 重新设置biz_content + requestParams.put(ParamNames.BIZ_CONTENT_NAME, jsonObject); + }); + SpringApplication.run(SopGatewayApplication.class, args); +} + +``` + +其中requestParams是客户端传递过来的参数,直接修改其中的值即可。 + +更多参考:com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter.java diff --git a/sop-admin/sop-admin-server/pom.xml b/sop-admin/sop-admin-server/pom.xml index 774bb777..0f992bb7 100644 --- a/sop-admin/sop-admin-server/pom.xml +++ b/sop-admin/sop-admin-server/pom.xml @@ -30,7 +30,7 @@ com.gitee.sop sop-registry-api - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java index bbe5f788..76f814b3 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java @@ -288,7 +288,7 @@ public class ZookeeperContext { } /** - * 监听一个节点 + * 监听一个临时节点 * * @param path * @param listenCallback 回调 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 f98e3700..86191448 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-9f479afe.2db777db.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-9f479afe.2db777db.js deleted file mode 100644 index 160472ba..00000000 --- a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-9f479afe.2db777db.js +++ /dev/null @@ -1 +0,0 @@ -(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-9f479afe"],{"02f4":function(e,t,n){var r=n("4588"),i=n("be13");e.exports=function(e){return function(t,n){var o,a,s=String(i(t)),l=r(n),c=s.length;return l<0||l>=c?e?"":void 0:(o=s.charCodeAt(l),o<55296||o>56319||l+1===c||(a=s.charCodeAt(l+1))<56320||a>57343?e?s.charAt(l):o:e?s.slice(l,l+2):a-56320+(o-55296<<10)+65536)}}},"0390":function(e,t,n){"use strict";var r=n("02f4")(!0);e.exports=function(e,t,n){return t+(n?r(e,t).length:1)}},"0bfb":function(e,t,n){"use strict";var r=n("cb7c");e.exports=function(){var e=r(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t}},"214f":function(e,t,n){"use strict";n("b0c5");var r=n("2aba"),i=n("32e9"),o=n("79e5"),a=n("be13"),s=n("2b4c"),l=n("520a"),c=s("species"),u=!o(function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")}),f=function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();e.exports=function(e,t,n){var d=s(e),v=!o(function(){var t={};return t[d]=function(){return 7},7!=""[e](t)}),p=v?!o(function(){var t=!1,n=/a/;return n.exec=function(){return t=!0,null},"split"===e&&(n.constructor={},n.constructor[c]=function(){return n}),n[d](""),!t}):void 0;if(!v||!p||"replace"===e&&!u||"split"===e&&!f){var g=/./[d],h=n(a,d,""[e],function(e,t,n,r,i){return t.exec===l?v&&!i?{done:!0,value:g.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),m=h[0],y=h[1];r(String.prototype,e,m),i(RegExp.prototype,d,2==t?function(e,t){return y.call(e,this,t)}:function(e){return y.call(e,this)})}}},"28a5":function(e,t,n){"use strict";var r=n("aae3"),i=n("cb7c"),o=n("ebd6"),a=n("0390"),s=n("9def"),l=n("5f1b"),c=n("520a"),u=n("79e5"),f=Math.min,d=[].push,v="split",p="length",g="lastIndex",h=4294967295,m=!u(function(){RegExp(h,"y")});n("214f")("split",2,function(e,t,n,u){var y;return y="c"=="abbc"[v](/(b)*/)[1]||4!="test"[v](/(?:)/,-1)[p]||2!="ab"[v](/(?:ab)*/)[p]||4!="."[v](/(.?)(.?)/)[p]||"."[v](/()()/)[p]>1||""[v](/.?/)[p]?function(e,t){var i=String(this);if(void 0===e&&0===t)return[];if(!r(e))return n.call(i,e,t);var o,a,s,l=[],u=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),f=0,v=void 0===t?h:t>>>0,m=new RegExp(e.source,u+"g");while(o=c.call(m,i)){if(a=m[g],a>f&&(l.push(i.slice(f,o.index)),o[p]>1&&o.index=v))break;m[g]===o.index&&m[g]++}return f===i[p]?!s&&m.test("")||l.push(""):l.push(i.slice(f)),l[p]>v?l.slice(0,v):l}:"0"[v](void 0,0)[p]?function(e,t){return void 0===e&&0===t?[]:n.call(this,e,t)}:n,[function(n,r){var i=e(this),o=void 0==n?void 0:n[t];return void 0!==o?o.call(n,i,r):y.call(String(i),n,r)},function(e,t){var r=u(y,e,this,t,y!==n);if(r.done)return r.value;var c=i(e),d=String(this),v=o(c,RegExp),p=c.unicode,g=(c.ignoreCase?"i":"")+(c.multiline?"m":"")+(c.unicode?"u":"")+(m?"y":"g"),b=new v(m?c:"^(?:"+c.source+")",g),_=void 0===t?h:t>>>0;if(0===_)return[];if(0===d.length)return null===l(b,d)?[d]:[];var w=0,x=0,I=[];while(x1&&o.call(a[0],n,function(){for(u=1;u0&&"pre"===t.row.metadata.env?n("el-tag",{attrs:{type:"warning"}},[e._v("预发布")]):e._e(),e._v(" "),t.row.parentId>0&&"gray"===t.row.metadata.env?n("el-tag",{attrs:{type:"info"}},[e._v("灰度")]):e._e(),e._v(" "),t.row.parentId>0&&!t.row.metadata.env?n("el-tag",{attrs:{type:"success"}},[e._v("线上")]):e._e()],1):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"metadata",label:"metadata",width:"250"},scopedSlots:e._u([{key:"default",fn:function(t){return[t.row.parentId>0?n("span",[e._v(e._s(JSON.stringify(t.row.metadata)))]):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"status",label:"服务状态",width:"100"},scopedSlots:e._u([{key:"default",fn:function(t){return[t.row.parentId>0&&"UP"===t.row.status?n("el-tag",{attrs:{type:"success"}},[e._v("正常")]):e._e(),e._v(" "),t.row.parentId>0&&"STARTING"===t.row.status?n("el-tag",{attrs:{type:"info"}},[e._v("正在启动")]):e._e(),e._v(" "),t.row.parentId>0&&"UNKNOWN"===t.row.status?n("el-tag",[e._v("未知")]):e._e(),e._v(" "),t.row.parentId>0&&("OUT_OF_SERVICE"===t.row.status||"DOWN"===t.row.status)?n("el-tag",{attrs:{type:"danger"}},[e._v("已禁用")]):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"updateTime",label:"最后更新时间",width:"160"}}),e._v(" "),n("el-table-column",{attrs:{label:"操作",width:"250"},scopedSlots:e._u([{key:"default",fn:function(t){return[0===t.row.parentId?n("div",[n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onGrayConfigUpdate(t.row)}}},[e._v("设置灰度参数")])],1):e._e(),e._v(" "),t.row.parentId>0?n("div",["UP"===t.row.status?n("span",["pre"===t.row.metadata.env?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvPreClose(t.row)}}},[e._v("结束预发布")]):e._e(),e._v(" "),"gray"===t.row.metadata.env?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvGrayClose(t.row)}}},[e._v("结束灰度")]):e._e(),e._v(" "),t.row.metadata.env?e._e():n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvPreOpen(t.row)}}},[e._v("开启预发布")]),e._v(" "),t.row.metadata.env?e._e():n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvGrayOpen(t.row)}}},[e._v("开启灰度")])],1):e._e(),e._v(" "),"UP"===t.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onDisable(t.row)}}},[e._v("禁用")]):e._e(),e._v(" "),"OUT_OF_SERVICE"===t.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnable(t.row)}}},[e._v("启用")]):e._e()],1):e._e()]}}])})],1),e._v(" "),n("el-dialog",{attrs:{title:"灰度设置",visible:e.grayDialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){e.grayDialogVisible=t},close:function(t){return e.resetForm("grayForm")}}},[n("el-form",{ref:"grayForm",attrs:{model:e.grayForm,rules:e.grayFormRules,size:"mini"}},[n("el-form-item",{attrs:{label:"serviceId"}},[e._v("\n "+e._s(e.grayForm.serviceId)+"\n ")]),e._v(" "),n("el-tabs",{attrs:{type:"card"},model:{value:e.tabsActiveName,callback:function(t){e.tabsActiveName=t},expression:"tabsActiveName"}},[n("el-tab-pane",{attrs:{label:"灰度用户",name:"first"}},[n("el-alert",{staticStyle:{"margin-bottom":"20px"},attrs:{title:"可以是appId,或userId,多个用英文逗号隔开",type:"info",closable:!1}}),e._v(" "),n("el-form-item",{attrs:{prop:"userKeyContent"}},[n("el-input",{attrs:{placeholder:"可以是appId,或userId,多个用英文逗号隔开",type:"textarea",rows:6},model:{value:e.grayForm.userKeyContent,callback:function(t){e.$set(e.grayForm,"userKeyContent",t)},expression:"grayForm.userKeyContent"}})],1)],1),e._v(" "),n("el-tab-pane",{attrs:{label:"接口配置",name:"second"}},[n("el-form-item",[n("el-button",{attrs:{type:"text"},on:{click:e.addNameVersion}},[e._v("新增灰度接口")])],1),e._v(" "),n("table",{attrs:{cellpadding:"0",cellspacing:"0"}},e._l(e.grayForm.grayRouteConfigList,function(t,r){return n("tr",{key:t.key},[n("td",[n("el-form-item",{key:t.key,attrs:{prop:"grayRouteConfigList."+r+".oldRouteId",rules:{required:!0,message:"不能为空",trigger:["blur","change"]}}},[e._v("\n 老接口:\n "),n("el-select",{staticStyle:{"margin-right":"10px"},on:{change:function(n){return e.onChangeOldRoute(t)}},model:{value:t.oldRouteId,callback:function(n){e.$set(t,"oldRouteId",n)},expression:"grayRouteConfig.oldRouteId"}},e._l(e.routeList,function(e){return n("el-option",{key:e.id,attrs:{label:e.name+"("+e.version+")",value:e.id}})}),1)],1)],1),e._v(" "),n("td",[n("el-form-item",{key:t.key+1,attrs:{prop:"grayRouteConfigList."+r+".newVersion",rules:{required:!0,message:"不能为空",trigger:["blur","change"]}}},[e._v("\n 灰度接口:\n "),n("el-select",{attrs:{"no-data-text":"无数据"},model:{value:t.newVersion,callback:function(n){e.$set(t,"newVersion",n)},expression:"grayRouteConfig.newVersion"}},e._l(e.getGraySelectData(t.oldRouteId),function(e){return n("el-option",{key:e.id,attrs:{label:e.name+"("+e.version+")",value:e.version}})}),1)],1)],1),e._v(" "),n("td",{staticStyle:{"vertical-align":"baseline"}},[n("el-button",{directives:[{name:"show",rawName:"v-show",value:e.grayForm.grayRouteConfigList.length>1,expression:"grayForm.grayRouteConfigList.length > 1"}],attrs:{type:"text"},on:{click:function(n){return n.preventDefault(),e.removeNameVersion(t)}}},[e._v("删除")])],1)])}),0)],1)],1)],1),e._v(" "),n("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.grayDialogVisible=!1}}},[e._v("取 消")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:e.onGrayConfigSave}},[e._v("确 定")])],1)],1)],1)},i=[],o=(n("28a5"),n("ac6a"),n("7f7f"),{data:function(){var e=/^\w+(,\w+)*$/,t=function(t,n,r){""===n?r(new Error("不能为空")):(e.test(n)||r(new Error("格式不正确")),r())};return{searchFormData:{serviceId:""},grayDialogVisible:!1,grayForm:{serviceId:"",userKeyContent:"",onlyUpdateGrayUserkey:!1,grayRouteConfigList:[]},tabsActiveName:"first",routeList:[],selectNameVersion:[],grayFormRules:{userKeyContent:[{required:!0,message:"不能为空",trigger:"blur"},{validator:t,trigger:"blur"}]},tableData:[]}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("service.instance.list",this.searchFormData,function(e){this.tableData=this.buildTreeData(e.data)})},loadRouteList:function(e){0===this.routeList.length&&this.post("route.list/1.2",{serviceId:e.toLowerCase()},function(e){this.routeList=e.data})},getGraySelectData:function(e){return this.routeList.filter(function(t){return e!==t.id&&e.indexOf(t.name)>-1})},buildTreeData:function(e){return e.forEach(function(t){var n=t.parentId;0===n||e.forEach(function(e){if(e.id===n){var r=e.children;r||(r=[]),r.push(t),e.children=r}})}),e=e.filter(function(e){return 0===e.parentId}),e},onSearchTable:function(){this.loadTable()},onDisable:function(e){this.confirm("确定要禁用【"+e.serviceId+"】吗?",function(t){this.post("service.instance.offline",e,function(){this.tip("禁用成功"),t()})})},onEnable:function(e){this.confirm("确定要启用【"+e.serviceId+"】吗?",function(t){this.post("service.instance.online",e,function(){this.tip("启用成功"),t()})})},doEnvOnline:function(e,t){this.post("service.instance.env.online",e,function(){t&&t.call(this)})},onEnvPreOpen:function(e){this.confirm("确定要开启 ".concat(e.instanceId," 预发布吗?"),function(t){this.post("service.instance.env.pre.open",e,function(){this.tip("预发布成功"),t()})})},onEnvPreClose:function(e){this.confirm("确定要结束 ".concat(e.instanceId," 预发布吗?"),function(t){this.doEnvOnline(e,function(){this.tip("操作成功"),t()})})},onEnvGrayOpen:function(e){this.confirm("确定要开启 ".concat(e.instanceId," 灰度吗?"),function(t){this.post("service.instance.env.gray.open",e,function(){this.tip("开启成功"),t()})})},onEnvGrayClose:function(e){this.confirm("确定要结束 ".concat(e.instanceId," 灰度吗?"),function(t){this.doEnvOnline(e,function(){this.tip("操作成功"),t()})})},onGrayConfigUpdate:function(e){var t=e.serviceId;this.loadRouteList(t),this.post("service.gray.config.get",{serviceId:t},function(e){this.grayDialogVisible=!0;var n=e.data;Object.assign(this.grayForm,{serviceId:t,userKeyContent:n.userKeyContent||"",grayRouteConfigList:this.createGrayRouteConfigList(n.nameVersionContent)})})},onGrayConfigSave:function(){var e=this;this.$refs.grayForm.validate(function(t){if(t){for(var n=[],r=e.grayForm.grayRouteConfigList,i=0;i0){var n=e.children.filter(function(e){return"UP"===e.status}).length;t=" (".concat(n,"/").concat(e.children.length,")")}return e.serviceId+t}}}),a=o,s=n("2877"),l=Object(s["a"])(a,r,i,!1,null,null,null);t["default"]=l.exports},b0c5:function(e,t,n){"use strict";var r=n("520a");n("5ca1")({target:"RegExp",proto:!0,forced:r!==/./.exec},{exec:r})}}]); \ No newline at end of file diff --git a/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-9f479afe.53fe8d4e.js b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-9f479afe.53fe8d4e.js new file mode 100644 index 00000000..913e398e --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-9f479afe.53fe8d4e.js @@ -0,0 +1 @@ +(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-9f479afe"],{"02f4":function(e,t,n){var r=n("4588"),i=n("be13");e.exports=function(e){return function(t,n){var o,a,s=String(i(t)),l=r(n),c=s.length;return l<0||l>=c?e?"":void 0:(o=s.charCodeAt(l),o<55296||o>56319||l+1===c||(a=s.charCodeAt(l+1))<56320||a>57343?e?s.charAt(l):o:e?s.slice(l,l+2):a-56320+(o-55296<<10)+65536)}}},"0390":function(e,t,n){"use strict";var r=n("02f4")(!0);e.exports=function(e,t,n){return t+(n?r(e,t).length:1)}},"0bfb":function(e,t,n){"use strict";var r=n("cb7c");e.exports=function(){var e=r(this),t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),e.unicode&&(t+="u"),e.sticky&&(t+="y"),t}},"214f":function(e,t,n){"use strict";n("b0c5");var r=n("2aba"),i=n("32e9"),o=n("79e5"),a=n("be13"),s=n("2b4c"),l=n("520a"),c=s("species"),u=!o(function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")}),f=function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();e.exports=function(e,t,n){var d=s(e),v=!o(function(){var t={};return t[d]=function(){return 7},7!=""[e](t)}),p=v?!o(function(){var t=!1,n=/a/;return n.exec=function(){return t=!0,null},"split"===e&&(n.constructor={},n.constructor[c]=function(){return n}),n[d](""),!t}):void 0;if(!v||!p||"replace"===e&&!u||"split"===e&&!f){var g=/./[d],m=n(a,d,""[e],function(e,t,n,r,i){return t.exec===l?v&&!i?{done:!0,value:g.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),y=m[0],h=m[1];r(String.prototype,e,y),i(RegExp.prototype,d,2==t?function(e,t){return h.call(e,this,t)}:function(e){return h.call(e,this)})}}},"28a5":function(e,t,n){"use strict";var r=n("aae3"),i=n("cb7c"),o=n("ebd6"),a=n("0390"),s=n("9def"),l=n("5f1b"),c=n("520a"),u=n("79e5"),f=Math.min,d=[].push,v="split",p="length",g="lastIndex",m=4294967295,y=!u(function(){RegExp(m,"y")});n("214f")("split",2,function(e,t,n,u){var h;return h="c"=="abbc"[v](/(b)*/)[1]||4!="test"[v](/(?:)/,-1)[p]||2!="ab"[v](/(?:ab)*/)[p]||4!="."[v](/(.?)(.?)/)[p]||"."[v](/()()/)[p]>1||""[v](/.?/)[p]?function(e,t){var i=String(this);if(void 0===e&&0===t)return[];if(!r(e))return n.call(i,e,t);var o,a,s,l=[],u=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),f=0,v=void 0===t?m:t>>>0,y=new RegExp(e.source,u+"g");while(o=c.call(y,i)){if(a=y[g],a>f&&(l.push(i.slice(f,o.index)),o[p]>1&&o.index=v))break;y[g]===o.index&&y[g]++}return f===i[p]?!s&&y.test("")||l.push(""):l.push(i.slice(f)),l[p]>v?l.slice(0,v):l}:"0"[v](void 0,0)[p]?function(e,t){return void 0===e&&0===t?[]:n.call(this,e,t)}:n,[function(n,r){var i=e(this),o=void 0==n?void 0:n[t];return void 0!==o?o.call(n,i,r):h.call(String(i),n,r)},function(e,t){var r=u(h,e,this,t,h!==n);if(r.done)return r.value;var c=i(e),d=String(this),v=o(c,RegExp),p=c.unicode,g=(c.ignoreCase?"i":"")+(c.multiline?"m":"")+(c.unicode?"u":"")+(y?"y":"g"),b=new v(y?c:"^(?:"+c.source+")",g),_=void 0===t?m:t>>>0;if(0===_)return[];if(0===d.length)return null===l(b,d)?[d]:[];var w=0,x=0,I=[];while(x1&&o.call(a[0],n,function(){for(u=1;u0&&"pre"===t.row.metadata.env?n("el-tag",{attrs:{type:"warning"}},[e._v("预发布")]):e._e(),e._v(" "),t.row.parentId>0&&"gray"===t.row.metadata.env?n("el-tag",{attrs:{type:"info"}},[e._v("灰度")]):e._e(),e._v(" "),t.row.parentId>0&&!t.row.metadata.env?n("el-tag",{attrs:{type:"success"}},[e._v("线上")]):e._e()],1):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"metadata",label:"metadata",width:"250"},scopedSlots:e._u([{key:"default",fn:function(t){return[t.row.parentId>0?n("span",[e._v(e._s(JSON.stringify(t.row.metadata)))]):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"status",label:"服务状态",width:"100"},scopedSlots:e._u([{key:"default",fn:function(t){return[t.row.parentId>0&&"UP"===t.row.status?n("el-tag",{attrs:{type:"success"}},[e._v("正常")]):e._e(),e._v(" "),t.row.parentId>0&&"STARTING"===t.row.status?n("el-tag",{attrs:{type:"info"}},[e._v("正在启动")]):e._e(),e._v(" "),t.row.parentId>0&&"UNKNOWN"===t.row.status?n("el-tag",[e._v("未知")]):e._e(),e._v(" "),t.row.parentId>0&&("OUT_OF_SERVICE"===t.row.status||"DOWN"===t.row.status)?n("el-tag",{attrs:{type:"danger"}},[e._v("已禁用")]):e._e()]}}])}),e._v(" "),n("el-table-column",{attrs:{prop:"updateTime",label:"最后更新时间",width:"160"}}),e._v(" "),n("el-table-column",{attrs:{label:"操作",width:"250"},scopedSlots:e._u([{key:"default",fn:function(t){return[0===t.row.parentId?n("div",[n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onGrayConfigUpdate(t.row)}}},[e._v("设置灰度参数")])],1):e._e(),e._v(" "),t.row.parentId>0?n("div",["UP"===t.row.status?n("span",["pre"===t.row.metadata.env?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvPreClose(t.row)}}},[e._v("结束预发布")]):e._e(),e._v(" "),"gray"===t.row.metadata.env?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvGrayClose(t.row)}}},[e._v("结束灰度")]):e._e(),e._v(" "),t.row.metadata.env?e._e():n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvPreOpen(t.row)}}},[e._v("开启预发布")]),e._v(" "),t.row.metadata.env?e._e():n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnvGrayOpen(t.row)}}},[e._v("开启灰度")])],1):e._e(),e._v(" "),n("span",{staticStyle:{"margin-left":"10px"}},["UP"===t.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onDisable(t.row)}}},[e._v("禁用")]):e._e(),e._v(" "),"OUT_OF_SERVICE"===t.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return e.onEnable(t.row)}}},[e._v("启用")]):e._e()],1)]):e._e()]}}])})],1),e._v(" "),n("el-dialog",{attrs:{title:"灰度设置",visible:e.grayDialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){e.grayDialogVisible=t},close:function(t){return e.resetForm("grayForm")}}},[n("el-form",{ref:"grayForm",attrs:{model:e.grayForm,rules:e.grayFormRules,size:"mini"}},[n("el-form-item",{attrs:{label:"serviceId"}},[e._v("\n "+e._s(e.grayForm.serviceId)+"\n ")]),e._v(" "),n("el-tabs",{attrs:{type:"card"},model:{value:e.tabsActiveName,callback:function(t){e.tabsActiveName=t},expression:"tabsActiveName"}},[n("el-tab-pane",{attrs:{label:"灰度用户",name:"first"}},[n("el-alert",{staticStyle:{"margin-bottom":"20px"},attrs:{title:"可以是appId,或userId,多个用英文逗号隔开",type:"info",closable:!1}}),e._v(" "),n("el-form-item",{attrs:{prop:"userKeyContent"}},[n("el-input",{attrs:{placeholder:"可以是appId,或userId,多个用英文逗号隔开",type:"textarea",rows:6},model:{value:e.grayForm.userKeyContent,callback:function(t){e.$set(e.grayForm,"userKeyContent",t)},expression:"grayForm.userKeyContent"}})],1)],1),e._v(" "),n("el-tab-pane",{attrs:{label:"接口配置",name:"second"}},[n("el-form-item",[n("el-button",{attrs:{type:"text"},on:{click:e.addNameVersion}},[e._v("新增灰度接口")])],1),e._v(" "),n("table",{attrs:{cellpadding:"0",cellspacing:"0"}},e._l(e.grayForm.grayRouteConfigList,function(t,r){return n("tr",{key:t.key},[n("td",[n("el-form-item",{key:t.key,attrs:{prop:"grayRouteConfigList."+r+".oldRouteId",rules:{required:!0,message:"不能为空",trigger:["blur","change"]}}},[e._v("\n 老接口:\n "),n("el-select",{staticStyle:{"margin-right":"10px"},on:{change:function(n){return e.onChangeOldRoute(t)}},model:{value:t.oldRouteId,callback:function(n){e.$set(t,"oldRouteId",n)},expression:"grayRouteConfig.oldRouteId"}},e._l(e.routeList,function(e){return n("el-option",{key:e.id,attrs:{label:e.name+"("+e.version+")",value:e.id}})}),1)],1)],1),e._v(" "),n("td",[n("el-form-item",{key:t.key+1,attrs:{prop:"grayRouteConfigList."+r+".newVersion",rules:{required:!0,message:"不能为空",trigger:["blur","change"]}}},[e._v("\n 灰度接口:\n "),n("el-select",{attrs:{"no-data-text":"无数据"},model:{value:t.newVersion,callback:function(n){e.$set(t,"newVersion",n)},expression:"grayRouteConfig.newVersion"}},e._l(e.getGraySelectData(t.oldRouteId),function(e){return n("el-option",{key:e.id,attrs:{label:e.name+"("+e.version+")",value:e.version}})}),1)],1)],1),e._v(" "),n("td",{staticStyle:{"vertical-align":"baseline"}},[n("el-button",{directives:[{name:"show",rawName:"v-show",value:e.grayForm.grayRouteConfigList.length>1,expression:"grayForm.grayRouteConfigList.length > 1"}],attrs:{type:"text"},on:{click:function(n){return n.preventDefault(),e.removeNameVersion(t)}}},[e._v("删除")])],1)])}),0)],1)],1)],1),e._v(" "),n("span",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.grayDialogVisible=!1}}},[e._v("取 消")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:e.onGrayConfigSave}},[e._v("确 定")])],1)],1)],1)},i=[],o=(n("28a5"),n("ac6a"),n("7f7f"),{data:function(){var e=/^\w+(,\w+)*$/,t=function(t,n,r){""===n?r(new Error("不能为空")):(e.test(n)||r(new Error("格式不正确")),r())};return{searchFormData:{serviceId:""},grayDialogVisible:!1,grayForm:{serviceId:"",userKeyContent:"",onlyUpdateGrayUserkey:!1,grayRouteConfigList:[]},tabsActiveName:"first",routeList:[],selectNameVersion:[],grayFormRules:{userKeyContent:[{required:!0,message:"不能为空",trigger:"blur"},{validator:t,trigger:"blur"}]},tableData:[]}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("service.instance.list",this.searchFormData,function(e){this.tableData=this.buildTreeData(e.data)})},loadRouteList:function(e){this.post("route.list/1.2",{serviceId:e.toLowerCase()},function(e){this.routeList=e.data})},getGraySelectData:function(e){return this.routeList.filter(function(t){return e!==t.id&&e.indexOf(t.name)>-1})},buildTreeData:function(e){return e.forEach(function(t){var n=t.parentId;0===n||e.forEach(function(e){if(e.id===n){var r=e.children;r||(r=[]),r.push(t),e.children=r}})}),e=e.filter(function(e){return 0===e.parentId}),e},onSearchTable:function(){this.loadTable()},onDisable:function(e){this.confirm("确定要禁用【"+e.serviceId+"】吗?",function(t){this.post("service.instance.offline",e,function(){this.tip("禁用成功"),t()})})},onEnable:function(e){this.confirm("确定要启用【"+e.serviceId+"】吗?",function(t){this.post("service.instance.online",e,function(){this.tip("启用成功"),t()})})},doEnvOnline:function(e,t){this.post("service.instance.env.online",e,function(){t&&t.call(this)})},onEnvPreOpen:function(e){this.confirm("确定要开启 ".concat(e.instanceId," 预发布吗?"),function(t){this.post("service.instance.env.pre.open",e,function(){this.tip("预发布成功"),t()})})},onEnvPreClose:function(e){this.confirm("确定要结束 ".concat(e.instanceId," 预发布吗?"),function(t){this.doEnvOnline(e,function(){this.tip("操作成功"),t()})})},onEnvGrayOpen:function(e){this.confirm("确定要开启 ".concat(e.instanceId," 灰度吗?"),function(t){this.post("service.instance.env.gray.open",e,function(){this.tip("开启成功"),t()})})},onEnvGrayClose:function(e){this.confirm("确定要结束 ".concat(e.instanceId," 灰度吗?"),function(t){this.doEnvOnline(e,function(){this.tip("操作成功"),t()})})},onGrayConfigUpdate:function(e){var t=e.serviceId;this.loadRouteList(t),this.post("service.gray.config.get",{serviceId:t},function(e){this.grayDialogVisible=!0;var n=e.data;Object.assign(this.grayForm,{serviceId:t,userKeyContent:n.userKeyContent||"",grayRouteConfigList:this.createGrayRouteConfigList(n.nameVersionContent)})})},onGrayConfigSave:function(){var e=this;this.$refs.grayForm.validate(function(t){if(t){for(var n=[],r=e.grayForm.grayRouteConfigList,i=0;i开启预发布 开启灰度 - 禁用 - 启用 + + 禁用 + 启用 + @@ -234,11 +236,9 @@ export default { }) }, loadRouteList: function(serviceId) { - if (this.routeList.length === 0) { - this.post('route.list/1.2', { serviceId: serviceId.toLowerCase() }, function(resp) { - this.routeList = resp.data - }) - } + this.post('route.list/1.2', { serviceId: serviceId.toLowerCase() }, function(resp) { + this.routeList = resp.data + }) }, getGraySelectData: function(oldRouteId) { return this.routeList.filter(routeNew => { @@ -393,11 +393,14 @@ export default { }, renderServiceName: function(row) { let instanceCount = '' - if (row.children && row.children.length > 0) { - const onlineCount = row.children.filter(el => { + // 如果是父节点 + if (row.parentId === 0) { + const children = row.children || [] + const childCount = children.length + const onlineCount = children.filter(el => { return el.status === 'UP' }).length - instanceCount = ` (${onlineCount}/${row.children.length})` + instanceCount = `(${onlineCount}/${childCount})` } return row.serviceId + instanceCount } diff --git a/sop-common/pom.xml b/sop-common/pom.xml index 9a6dbde8..97fbd1be 100644 --- a/sop-common/pom.xml +++ b/sop-common/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.gitee.sop sop-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT pom diff --git a/sop-common/sop-gateway-common/pom.xml b/sop-common/sop-gateway-common/pom.xml index 41eff995..48962395 100644 --- a/sop-common/sop-gateway-common/pom.xml +++ b/sop-common/sop-gateway-common/pom.xml @@ -5,11 +5,11 @@ com.gitee.sop sop-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT ../pom.xml sop-gateway-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT jar sop-gateway-common diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index f76cd5ea..ab6fb813 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -5,18 +5,18 @@ import com.gitee.sop.gatewaycommon.gateway.result.GatewayResult; import com.gitee.sop.gatewaycommon.gateway.result.GatewayResultExecutor; import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager; import com.gitee.sop.gatewaycommon.limit.LimitManager; +import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; import com.gitee.sop.gatewaycommon.manager.DefaultIPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; +import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.result.DataNameBuilder; import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder; @@ -34,6 +34,7 @@ import com.gitee.sop.gatewaycommon.validate.Signer; import com.gitee.sop.gatewaycommon.validate.Validator; import com.gitee.sop.gatewaycommon.zuul.configuration.ZuulErrorController; import com.gitee.sop.gatewaycommon.zuul.param.ZuulParamBuilder; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; import com.gitee.sop.gatewaycommon.zuul.result.ZuulResultExecutor; import com.netflix.zuul.context.RequestContext; import lombok.Data; @@ -149,6 +150,8 @@ public class ApiConfig { */ private ZuulErrorController zuulErrorController = new ZuulErrorController(); + private ZuulParameterFormatter zuulParameterFormatter; + // -------- fields --------- /** diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java index 3fa8561f..bdfc8760 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/DefaultEnvGrayManager.java @@ -40,7 +40,7 @@ public class DefaultEnvGrayManager implements EnvGrayManager { if (serviceId == null || nameVersion == null) { return null; } - boolean opened = instanceIdServiceIdMap.values().contains(serviceId); + boolean opened = instanceIdServiceIdMap.containsValue(serviceId); // 没有开启灰度 if (!opened) { return null; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java new file mode 100644 index 00000000..8fd2caf7 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java @@ -0,0 +1,18 @@ +package com.gitee.sop.gatewaycommon.manager; + +import java.util.Map; + +/** + * 参数格式化 + * + * @author tanghc + */ +public interface ParameterFormatter> { + + /** + * 参数格式化,即动态修改请求参数 + * + * @param requestParams 原始请求参数,在此基础上追加或修改参数 + */ + void format(T requestParams); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java index 31463a1d..fccd5c23 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/validate/ApiValidator.java @@ -93,6 +93,14 @@ public class ApiValidator implements Validator { * @param param 接口参数 */ protected void checkEnable(ApiParam param) { + String name = param.fetchName(); + if (name == null) { + throw ErrorEnum.ISV_MISSING_METHOD.getErrorMeta().getException(); + } + String version = param.fetchVersion(); + if (version == null) { + throw ErrorEnum.ISV_MISSING_VERSION.getErrorMeta().getException(); + } String routeId = param.fetchNameVersion(); // 检查路由是否存在 RouteRepositoryContext.checkExist(routeId, ErrorEnum.ISV_INVALID_METHOD); diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java index 8f0287f6..e93c5a33 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java @@ -1,8 +1,10 @@ package com.gitee.sop.gatewaycommon.zuul.configuration; +import com.alibaba.fastjson.JSONObject; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter; @@ -10,6 +12,7 @@ import com.gitee.sop.gatewaycommon.zuul.filter.FormBodyWrapperFilterExt; import com.gitee.sop.gatewaycommon.zuul.filter.PostResultFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreHttpServletRequestWrapperFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreLimitFilter; +import com.gitee.sop.gatewaycommon.zuul.filter.PreParameterFormatterFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreValidateFilter; import com.gitee.sop.gatewaycommon.zuul.filter.PreVersionDecisionFilter; import com.gitee.sop.gatewaycommon.zuul.filter.Servlet30WrapperFilterExt; @@ -44,6 +47,12 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return ApiConfig.getInstance().getZuulParamBuilder(); } + @Bean + @ConditionalOnMissingBean + ParameterFormatter preParamFilter(){ + return ApiConfig.getInstance().getZuulParameterFormatter(); + } + /** * 路由存储 * @return @@ -104,6 +113,11 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return new PreValidateFilter(); } + @Bean + PreParameterFormatterFilter preParameterFormatterFilter() { + return new PreParameterFormatterFilter(); + } + /** * 开启限流 */ @@ -120,6 +134,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return new PreVersionDecisionFilter(); } + + /** * 错误处理扩展 */ diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java index 29b97e4f..2147c1f3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java @@ -23,11 +23,14 @@ public abstract class BaseZuulFilter extends ZuulFilter { /** 签名验证过滤 */ public static final int PRE_VALIDATE_FILTER_ORDER = -1000; + /** 参数格式化过滤器 */ + public static final int PRE_PARAMETER_FORMATTER_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 1; + /** 权限验证过滤 */ - public static final int PRE_ROUTE_PERMISSION_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 1; + public static final int PRE_ROUTE_PERMISSION_FILTER_ORDER = PRE_VALIDATE_FILTER_ORDER + 100; /** 限流过滤 */ - public static final int PRE_LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 1; + public static final int PRE_LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 100; private Integer filterOrder; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java new file mode 100644 index 00000000..9f88470c --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java @@ -0,0 +1,42 @@ +package com.gitee.sop.gatewaycommon.zuul.filter; + +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; +import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterUtil; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 参数格式化过滤器,动态修改参数,此过滤器放在前面校验后面 + * + * @author tanghc + */ +public class PreParameterFormatterFilter extends BaseZuulFilter { + + @Autowired(required = false) + private ZuulParameterFormatter zuulParameterFormatter; + + @Override + protected FilterType getFilterType() { + return FilterType.PRE; + } + + @Override + protected int getFilterOrder() { + return PRE_PARAMETER_FORMATTER_FILTER_ORDER; + } + + @Override + protected Object doRun(RequestContext requestContext) throws ZuulException { + ApiParam apiParam = ZuulContext.getApiParam(); + // 校验成功后进行参数转换 + if (zuulParameterFormatter != null) { + ZuulParameterUtil.format(apiParam, zuulParameterFormatter::format); + requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()); + } + return null; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java new file mode 100644 index 00000000..23885acd --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java @@ -0,0 +1,10 @@ +package com.gitee.sop.gatewaycommon.zuul.param; + +import com.alibaba.fastjson.JSONObject; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; + +/** + * @author tanghc + */ +public interface ZuulParameterFormatter extends ParameterFormatter { +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java new file mode 100644 index 00000000..d8e29c8d --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java @@ -0,0 +1,183 @@ +package com.gitee.sop.gatewaycommon.zuul.param; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.util.RequestUtil; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.http.HttpServletRequestWrapper; +import com.netflix.zuul.http.ServletInputStreamWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.cloud.netflix.zuul.util.RequestContentDataExtractor; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpOutputMessage; +import org.springframework.http.MediaType; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * zuul参数工具 + * @author tanghc + */ +@Slf4j +public class ZuulParameterUtil { + + private static FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); + + /** + * 格式化参数 + * @param apiParam 请求的参数 + * @param consumer 修改参数 + * @param 参数类型 + */ + public static > void format(T apiParam, Consumer consumer) { + RequestContext requestContext = RequestContext.getCurrentContext(); + consumer.accept(apiParam); + HttpServletRequest request = requestContext.getRequest(); + String contentType = request.getContentType(); + if (StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + String json = (apiParam instanceof JSONObject) ? + ((JSONObject) apiParam).toJSONString() + : JSON.toJSONString(apiParam); + byte[] bytes = json.getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, bytes)); + } else if(StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + List list = new ArrayList<>(apiParam.size()); + try { + for (Map.Entry entry : apiParam.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Collection) { + Collection collection = (Collection) value; + for (Object el : collection) { + list.add(key + "=" + URLEncoder.encode(String.valueOf(el), SopConstants.UTF8)); + } + } else { + list.add(key + "=" + URLEncoder.encode(String.valueOf(value), SopConstants.UTF8)); + } + } + } catch (UnsupportedEncodingException e) { + log.error("字符集不支持", e); + } + String paramsStr = StringUtils.join(list, "&"); + byte[] data = paramsStr.getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + } else if(RequestUtil.isMultipart(request)) { + FormHttpOutputMessage outputMessage = new FormHttpOutputMessage(); + try { + // 转成MultipartRequest + if (!(request instanceof MultipartHttpServletRequest)) { + CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getServletContext()); + request = commonsMultipartResolver.resolveMultipart(request); + } + // 重写新的值 + MultiValueMap builder = RequestContentDataExtractor.extract(request); + for (Map.Entry entry : apiParam.entrySet()) { + Object value = entry.getValue(); + if (value instanceof List) { + builder.put(entry.getKey(), (List)value); + } else { + builder.put(entry.getKey(), Collections.singletonList(String.valueOf(value))); + } + } + MediaType mediaType = MediaType.valueOf(request.getContentType()); + // 将字段以及上传文件重写写入到流中 + formHttpMessageConverter.write(builder, mediaType, outputMessage); + // 获取新的上传文件流 + byte[] data = outputMessage.getInput(); + + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + // 必须要重新指定content-type,因为此时的boundary已经发生改变 + requestContext.getZuulRequestHeaders().put("content-type", outputMessage.getHeaders().getContentType().toString()); + } catch (Exception e) { + log.error("修改上传文件请求参数失败, apiParam:{}", apiParam, e); + } + } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { + Map> newParams = new HashMap<>(); + for (Map.Entry entry : apiParam.entrySet()) { + Object value = entry.getValue(); + if (value instanceof List) { + List valueList = ((List) value).stream().map(String::valueOf).collect(Collectors.toList()); + newParams.put(entry.getKey(), valueList); + } else { + newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(value))); + } + } + requestContext.setRequestQueryParams(newParams); + } + } + + + private static class FormHttpOutputMessage implements HttpOutputMessage { + + private HttpHeaders headers = new HttpHeaders(); + private ByteArrayOutputStream output = new ByteArrayOutputStream(); + + @Override + public HttpHeaders getHeaders() { + return this.headers; + } + + @Override + public OutputStream getBody() throws IOException { + return this.output; + } + + public byte[] getInput() throws IOException { + this.output.flush(); + return this.output.toByteArray(); + } + + } + + private static class ChangeParamsHttpServletRequestWrapper extends HttpServletRequestWrapper { + private byte[] data; + + public ChangeParamsHttpServletRequestWrapper(HttpServletRequest request, byte[] data) { + super(request); + this.data = data; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new ServletInputStreamWrapper(data); + } + + @Override + public byte[] getContentData() { + return data; + } + + @Override + public int getContentLength() { + return data.length; + } + + @Override + public long getContentLengthLong() { + return data.length; + } + } + +} diff --git a/sop-common/sop-registry-api/pom.xml b/sop-common/sop-registry-api/pom.xml index 4e98940b..a3179a33 100644 --- a/sop-common/sop-registry-api/pom.xml +++ b/sop-common/sop-registry-api/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.gitee.sop sop-registry-api - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT UTF-8 diff --git a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java index 2d19dd58..45417810 100644 --- a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java +++ b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/bean/ServiceInfo.java @@ -1,24 +1,16 @@ package com.gitee.sop.registryapi.bean; -import lombok.Getter; -import lombok.Setter; +import lombok.Data; -import java.util.Collections; import java.util.List; /** * @author tanghc */ -@Getter -@Setter +@Data public class ServiceInfo { /** 服务名称 */ private String serviceId; /** 实例列表 */ - private List instances = Collections.emptyList(); - - @Override - public String toString() { - return "服务名称: " + serviceId + ", 实例数:" + instances.size(); - } + private List instances; } diff --git a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java index 6f7746d2..00b31d85 100644 --- a/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java +++ b/sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java @@ -18,6 +18,8 @@ import org.springframework.util.CollectionUtils; import javax.annotation.PostConstruct; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,7 +53,9 @@ public class RegistryServiceNacos implements RegistryService { ServiceInfo serviceInfo = new ServiceInfo(); serviceInfo.setServiceId(serviceName); List instanceList = namingService.getAllInstances(serviceName); - if (!CollectionUtils.isEmpty(instanceList)) { + if (CollectionUtils.isEmpty(instanceList)) { + serviceInfo.setInstances(Collections.emptyList()); + } else { serviceInfo.setInstances(new ArrayList<>(instanceList.size())); for (Instance instance : instanceList) { ServiceInstance serviceInstance = new ServiceInstance(); @@ -68,6 +72,7 @@ public class RegistryServiceNacos implements RegistryService { } serviceInfoList.add(serviceInfo); } + serviceInfoList.sort(Comparator.comparingInt(o -> o.getInstances().size())); return serviceInfoList; } diff --git a/sop-common/sop-service-common/pom.xml b/sop-common/sop-service-common/pom.xml index 8b7c7da6..bfaec2de 100644 --- a/sop-common/sop-service-common/pom.xml +++ b/sop-common/sop-service-common/pom.xml @@ -6,11 +6,11 @@ com.gitee.sop sop-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT ../pom.xml sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT jar sop-service-common diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConstants.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConstants.java index 9b596b12..7d0fe3dd 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConstants.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ServiceConstants.java @@ -8,4 +8,9 @@ public class ServiceConstants { * zookeeper存放接口路由信息的根目录 */ public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route"; + + /** + * 服务临时节点 + */ + public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp"; } diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ZookeeperTool.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ZookeeperTool.java index dbf4615b..8130d7f8 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ZookeeperTool.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/ZookeeperTool.java @@ -9,6 +9,7 @@ import org.apache.commons.lang.math.NumberUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.zookeeper.CreateMode; import org.springframework.core.env.Environment; import java.io.Closeable; @@ -94,6 +95,23 @@ public class ZookeeperTool implements Closeable { .forPath(path, data.getBytes()); } + /** + * 创建临时序列节点 + * @param path 节点路径 + * @param data 数据 + * @return 返回节点路径 + * @throws Exception + */ + public String createOrUpdateEphemeralSequentialPath(String path, String data) throws Exception { + return getClient().create() + // 如果节点存在则Curator将会使用给出的数据设置这个节点的值 + .orSetData() + // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 + .creatingParentContainersIfNeeded() + .withMode(CreateMode.EPHEMERAL_SEQUENTIAL) + .forPath(path, data.getBytes()); + } + /** * 新建或保存节点 * diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java index 2dbd418e..6648e81e 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/BaseServiceConfiguration.java @@ -14,11 +14,15 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import javax.annotation.PostConstruct; +import java.nio.charset.StandardCharsets; +import java.util.List; /** * @author tanghc @@ -44,6 +48,12 @@ public class BaseServiceConfiguration extends WebMvcConfigurationSupport super.addInterceptors(registry); } + @Override + protected void configureMessageConverters(List> converters) { + // 解决controller返回字符串中文乱码问题 + converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); + } + /** * 自定义Mapping,详见@ApiMapping * @return 返回RequestMappingHandlerMapping diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java index 6f71ec7a..10ff3503 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java @@ -10,7 +10,6 @@ import com.gitee.sop.servercommon.route.ServiceRouteInfo; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.IOUtils; import org.springframework.beans.BeanUtils; import org.springframework.core.env.Environment; import org.springframework.util.DigestUtils; @@ -81,6 +80,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { String nodeData = JSON.toJSONString(serviceRouteInfo); log.info("serviceId:{}, zookeeper保存路径:{}", serviceId, savePath); this.zookeeperTool.createPath(savePath, nodeData); + this.zookeeperTool.createPath(serviceRouteInfo.getZookeeperTempServiceIdPath(), ""); } catch (Exception e) { throw new IllegalStateException("zookeeper操作失败"); } @@ -91,8 +91,11 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager { try { ServiceRouteInfo serviceRouteInfo = this.buildServiceGatewayInfo(serviceApiInfo); this.uploadServiceRouteInfoToZookeeper(serviceRouteInfo); - } finally { - IOUtils.closeQuietly(zookeeperTool); + // 同时上传一个临时节点 + String tempPath = serviceRouteInfo.getZookeeperTempServiceIdChildPath(); + this.zookeeperTool.createOrUpdateEphemeralSequentialPath(tempPath, JSON.toJSONString(serviceRouteInfo)); + } catch (Exception e) { + log.error("上传一个临时节点失败, serviceApiInfo:{}", serviceApiInfo, e); } } diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java index 80a3bd65..31ca519f 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/param/ServiceParamValidator.java @@ -22,11 +22,10 @@ public class ServiceParamValidator implements ParamValidator { public static final String COMMA = ","; private static Object[] EMPTY_OBJ_ARRAY = {}; - private static ValidatorFactory factory; private static javax.validation.Validator validator; static { - factory = Validation.buildDefaultValidatorFactory(); + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java index 78c920a9..5041000d 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/route/ServiceRouteInfo.java @@ -13,6 +13,7 @@ import java.util.List; @Data public class ServiceRouteInfo { private static final String SOP_SERVICE_ROUTE_PATH = ServiceConstants.SOP_SERVICE_ROUTE_PATH; + private static final String SOP_SERVICE_TEMP_PATH = ServiceConstants.SOP_SERVICE_TEMP_PATH; /** 服务名称,对应spring.application.name */ private String serviceId; @@ -39,4 +40,22 @@ public class ServiceRouteInfo { public String getZookeeperPath() { return SOP_SERVICE_ROUTE_PATH + '/' + serviceId; } + + /** + * 返回zookeeper路径 + * @return 返回zookeeper路径 + */ + @JSONField(serialize = false) + public String getZookeeperTempServiceIdPath() { + return SOP_SERVICE_TEMP_PATH + '/' + serviceId; + } + + /** + * 返回zookeeper路径 + * @return 返回zookeeper路径 + */ + @JSONField(serialize = false) + public String getZookeeperTempServiceIdChildPath() { + return getZookeeperTempServiceIdPath() + "/" + serviceId; + } } \ No newline at end of file diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java index a5e2bd80..023c9c2a 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/swagger/SwaggerSupport.java @@ -29,6 +29,10 @@ public abstract class SwaggerSupport { @Bean public Docket createRestApi() { + return getDocket(); + } + + protected Docket getDocket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() diff --git a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java index 61c1d527..a99813cd 100644 --- a/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java +++ b/sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/util/OpenUtil.java @@ -67,12 +67,8 @@ public class OpenUtil { for (Map.Entry entry : entrySet) { String name = entry.getKey(); String[] values = entry.getValue(); - if (values.length == 1) { + if (values.length >= 1) { retMap.put(name, values[0]); - } else if (values.length > 1) { - retMap.put(name, values); - } else { - retMap.put(name, ""); } } diff --git a/sop-example/sop-auth/pom.xml b/sop-example/sop-auth/pom.xml index af511639..0d8c980b 100644 --- a/sop-example/sop-auth/pom.xml +++ b/sop-example/sop-auth/pom.xml @@ -26,7 +26,7 @@ com.gitee.sop sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT org.springframework.cloud diff --git a/sop-example/sop-book/sop-book-web/pom.xml b/sop-example/sop-book/sop-book-web/pom.xml index d7391a35..695145b3 100644 --- a/sop-example/sop-book/sop-book-web/pom.xml +++ b/sop-example/sop-book/sop-book-web/pom.xml @@ -24,7 +24,7 @@ com.gitee.sop sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT com.gitee.sop diff --git a/sop-example/sop-easyopen/pom.xml b/sop-example/sop-easyopen/pom.xml index 77630c70..45f84392 100644 --- a/sop-example/sop-easyopen/pom.xml +++ b/sop-example/sop-easyopen/pom.xml @@ -29,7 +29,7 @@ com.gitee.sop sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT org.springframework.cloud diff --git a/sop-example/sop-springmvc/pom.xml b/sop-example/sop-springmvc/pom.xml index 88f06728..82467950 100644 --- a/sop-example/sop-springmvc/pom.xml +++ b/sop-example/sop-springmvc/pom.xml @@ -20,7 +20,7 @@ com.gitee.sop sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT diff --git a/sop-example/sop-story/sop-story-web/pom.xml b/sop-example/sop-story/sop-story-web/pom.xml index e326ea9f..99177722 100644 --- a/sop-example/sop-story/sop-story-web/pom.xml +++ b/sop-example/sop-story/sop-story-web/pom.xml @@ -24,7 +24,7 @@ com.gitee.sop sop-service-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT com.gitee.sop @@ -79,22 +79,11 @@ io.springfox springfox-swagger2 2.9.2 - - - io.swagger - swagger-models - - - io.swagger - swagger-models - 1.5.21 - - - io.springfox - springfox-swagger-ui - 2.9.2 + com.github.xiaoymin + swagger-bootstrap-ui + 1.9.5 diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java index dd9a5f12..eb0c299f 100644 --- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java +++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/config/OpenServiceConfig.java @@ -22,15 +22,16 @@ public class OpenServiceConfig extends AlipayServiceConfiguration { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); - registry.addResourceHandler("swagger-ui.html") - .addResourceLocations("classpath:/META-INF/resources/"); - registry.addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/"); + // 支持swagger-bootstrap-ui首页 + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + // 支持默认swagger + registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } /** - * 开启文档 + * 开启文档,本地微服务文档地址:http://localhost:2222/doc.html * http://ip:port/v2/api-docs */ @Configuration @@ -43,9 +44,10 @@ public class OpenServiceConfig extends AlipayServiceConfiguration { @Override protected boolean swaggerAccessProtected() { - return true; + return false; } } + } /** diff --git a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java index 563c1721..b5e1ea49 100644 --- a/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java +++ b/sop-example/sop-story/sop-story-web/src/main/java/com/gitee/sop/storyweb/controller/AlipayController.java @@ -1,5 +1,6 @@ package com.gitee.sop.storyweb.controller; +import com.alibaba.fastjson.JSON; import com.gitee.sop.servercommon.annotation.ApiAbility; import com.gitee.sop.servercommon.annotation.ApiMapping; import com.gitee.sop.servercommon.bean.OpenContext; @@ -127,13 +128,39 @@ public class AlipayController { // http://localhost:2222/alipay.story.get/ @ApiMapping(value = "alipay.story.get") - public Story getStory() { + public Story getStory(Story param) { Story story = new Story(); story.setId(1); - story.setName("海底小纵队(alipay.story.get1.0)"); + story.setName("海底小纵队(alipay.story.get1.0), param:" + param); return story; } + /** + * + * @param param 对应biz_content中的内容,并自动JSR-303校验 + * @return + */ + @ApiMapping(value = "alipay.story.get", version = "1.2") + public Story getStory11(Story param) { + Story story2 = new Story(); + story2.setId(1); + story2.setName("海底小纵队(alipay.story.get1.2), param:" + param); + return story2; + } + + /** + * 验证字符串乱码问题 + * @param param + * @return + */ + @ApiMapping(value = "story.string.get", version = "1.0") + public String string(Story param) { + Story story2 = new Story(); + story2.setId(1); + story2.setName("海底小纵队"); + return JSON.toJSONString(story2); + } + /** * 参数绑定 * @param story 对应biz_content中的内容,并自动JSR-303校验 @@ -153,19 +180,6 @@ public class AlipayController { return storyVO; } - /** - * - * @param story 对应biz_content中的内容,并自动JSR-303校验 - * @return - */ - @ApiMapping(value = "alipay.story.get", version = "1.2") - public Story getStory11(Story story) { - Story story2 = new Story(); - story2.setId(1); - story2.setName("海底小纵队(alipay.story.get1.2)"); - return story2; - } - /** * 演示文档表格树 * @param story diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml index 3dcbf06d..a3b2ecf7 100644 --- a/sop-gateway/pom.xml +++ b/sop-gateway/pom.xml @@ -23,7 +23,7 @@ com.gitee.sop sop-gateway-common - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/RedirectController.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/RedirectController.java index 2e4a7273..a1d09f27 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/RedirectController.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/RedirectController.java @@ -1,8 +1,6 @@ package com.gitee.sop.gateway.controller; import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.gitee.sop.gatewaycommon.param.ParamNames; -import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; @@ -31,14 +29,7 @@ public class RedirectController { ) throws ServletException, IOException { request.setAttribute(SopConstants.REDIRECT_METHOD_KEY, method); request.setAttribute(SopConstants.REDIRECT_VERSION_KEY, version); - String queryString = request.getQueryString(); - String versionQuery = ParamNames.VERSION_NAME + '=' + version; - if (StringUtils.isBlank(queryString)) { - queryString = versionQuery; - } else { - queryString = queryString + '&' + versionQuery; - } - request.getRequestDispatcher(path + '?' + queryString).forward(request, response); + request.getRequestDispatcher(path).forward(request, response); } } diff --git a/sop-gateway/src/test/java/com/gitee/sop/gateway/CuratorTest.java b/sop-gateway/src/test/java/com/gitee/sop/gateway/CuratorTest.java index 9239d009..91ae48b7 100644 --- a/sop-gateway/src/test/java/com/gitee/sop/gateway/CuratorTest.java +++ b/sop-gateway/src/test/java/com/gitee/sop/gateway/CuratorTest.java @@ -31,4 +31,22 @@ public class CuratorTest extends TestCase { } catch (Exception e) { } } + + /** + * 删除临时节点 + */ + public void testDelTemp() { + String tempRoot = "/com.gitee.sop.service.tmp"; + CuratorFramework client = CuratorFrameworkFactory.builder() + .connectString(zookeeperServerAddr) + .retryPolicy(new ExponentialBackoffRetry(1000, 3)) + .build(); + + client.start(); + + try { + client.delete().deletingChildrenIfNeeded().forPath(tempRoot); + } catch (Exception e) { + } + } } diff --git a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java index 68aaf5d9..d202aef6 100644 --- a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java +++ b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java @@ -1,6 +1,7 @@ package com.gitee.sop.sdk.client; import com.gitee.sop.sdk.common.OpenConfig; +import com.gitee.sop.sdk.common.RequestMethod; import com.gitee.sop.sdk.common.UploadFile; import okhttp3.Cookie; import okhttp3.CookieJar; @@ -118,7 +119,7 @@ public class OpenHttp { * @return * @throws IOException */ - public String request(String url, Map form, Map header, HTTPMethod method) throws IOException { + public String request(String url, Map form, Map header, RequestMethod method) throws IOException { Request.Builder requestBuilder = buildRequestBuilder(url, form, method); // 添加header addHeader(requestBuilder, header); @@ -134,7 +135,7 @@ public class OpenHttp { } } - public static Request.Builder buildRequestBuilder(String url, Map form, HTTPMethod method) { + public static Request.Builder buildRequestBuilder(String url, Map form, RequestMethod method) { switch (method) { case GET: return new Request.Builder() @@ -241,22 +242,4 @@ public class OpenHttp { this.httpClient = httpClient; } - public enum HTTPMethod { - GET, - POST, - PUT, - HEAD, - DELETE; - - private HTTPMethod() { - } - - public String value() { - return this.name(); - } - - public static HTTPMethod fromValue(String v) { - return valueOf(v.toUpperCase()); - } - } } diff --git a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java index 16a2b18c..3ae9c3b3 100644 --- a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java +++ b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java @@ -100,11 +100,9 @@ public class SdkTest extends TestCase { if (response.isSuccess()) { List responseFiles = response.getFiles(); System.out.println("您上传的文件信息:"); - responseFiles.stream().forEach(file->{ - System.out.println(file); - }); + responseFiles.forEach(System.out::println); } else { - System.out.println("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg()); + System.out.println(JSON.toJSONString(response)); } System.out.println("--------------------"); } diff --git a/sop-test/src/main/java/com/gitee/sop/test/Client.java b/sop-test/src/main/java/com/gitee/sop/test/Client.java new file mode 100644 index 00000000..34e8b595 --- /dev/null +++ b/sop-test/src/main/java/com/gitee/sop/test/Client.java @@ -0,0 +1,280 @@ +package com.gitee.sop.test; + +import com.alibaba.fastjson.JSON; +import com.gitee.sop.test.alipay.AlipayApiException; +import com.gitee.sop.test.alipay.AlipaySignature; +import lombok.Data; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 简易客户端 + * + * @author tanghc + */ +@Data +public class Client { + /** + * http请求工具 + */ + private static HttpTool httpTool = new HttpTool(); + + /** + * 请求url + */ + private String url; + + /** + * 平台提供的appKey + */ + private String appId; + + /** + * 平台提供的私钥 + */ + private String privateKey; + + /** + * 请求成功后处理 + */ + private Callback callback; + + /** + * 创建一个客户端 + * + * @param url 请求url + * @param appId 平台提供的appKey + * @param privateKey 平台提供的私钥 + */ + public Client(String url, String appId, String privateKey) { + this.url = url; + this.appId = appId; + this.privateKey = privateKey; + } + + /** + * 创建一个客户端 + * + * @param url 请求url + * @param appId 平台提供的appKey + * @param privateKey 平台提供的私钥 + * @param callback 请求成功后处理 + */ + public Client(String url, String appId, String privateKey, Callback callback) { + this.url = url; + this.appId = appId; + this.privateKey = privateKey; + this.callback = callback; + } + + /** + * 发送请求 + * @param requestBuilder 请求信息 + * @return 返回结果 + */ + public String execute(RequestBuilder requestBuilder) { + RequestInfo requestInfo = requestBuilder.build(appId, privateKey); + HttpTool.HTTPMethod httpMethod = requestInfo.getHttpMethod(); + boolean postJson = requestInfo.isPostJson(); + Map form = requestInfo.getForm(); + Map header = requestInfo.getHeader(); + String requestUrl = requestInfo.getUrl() != null ? requestInfo.getUrl() : url; + String responseData = null; + try { + // 发送请求 + if (httpMethod == HttpTool.HTTPMethod.POST && postJson) { + responseData = httpTool.requestJson(requestUrl, JSON.toJSONString(form), header); + } else { + responseData = httpTool.request(requestUrl, form, header, httpMethod); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + Callback call = requestBuilder.getCallback(); + if (call == null) { + call = this.callback; + } + if (call != null) { + call.callback(requestInfo, responseData); + } + return responseData; + } + + public interface Callback { + void callback(RequestInfo requestInfo, String responseData); + } + + public static class RequestBuilder { + private static final String DEFAULT_VERSION = "1.0"; + + private String url; + private String method; + private String version = DEFAULT_VERSION; + private Map bizContent; + private HttpTool.HTTPMethod httpMethod; + private Map header; + private boolean ignoreSign; + private boolean postJson; + private Callback callback; + + /** + * 设置请求url,如果指定了将会优先使用,不指定默认使用Client中的url + * + * @param url url + * @return 返回RequestBuilder + */ + public RequestBuilder url(String url) { + this.url = url; + return this; + } + + /** + * 设置方法名 + * + * @param method 方法名 + * @return 返回RequestBuilder + */ + public RequestBuilder method(String method) { + this.method = method; + return this; + } + + /** + * 设置版本号 + * + * @param version 版本号 + * @return 返回RequestBuilder + */ + public RequestBuilder version(String version) { + this.version = version; + return this; + } + + /** + * 设置业务参数 + * + * @param bizContent 业务参数 + * @return 返回RequestBuilder + */ + public RequestBuilder bizContent(Map bizContent) { + this.bizContent = bizContent; + return this; + } + + /** + * 设置请求方法 + * + * @param httpMethod 请求方法 + * @return 返回RequestBuilder + */ + public RequestBuilder httpMethod(HttpTool.HTTPMethod httpMethod) { + this.httpMethod = httpMethod; + return this; + } + + /** + * 设置请求头 + * + * @param header 请求头 + * @return 返回RequestBuilder + */ + public RequestBuilder header(Map header) { + this.header = header; + return this; + } + + /** + * 是否忽略签名验证 + * + * @param ignoreSign 设置true,不会构建sign字段 + * @return 返回RequestBuilder + */ + public RequestBuilder ignoreSign(boolean ignoreSign) { + this.ignoreSign = ignoreSign; + return this; + } + + /** + * 是否是json请求 + * + * @param postJson 设置true,请求方式变成json(application/json) + * @return 返回RequestBuilder + */ + public RequestBuilder postJson(boolean postJson) { + this.postJson = postJson; + return this; + } + + /** + * 设置请求成功处理 + * + * @param callback 回调处理 + * @return 返回RequestBuilder + */ + public RequestBuilder callback(Callback callback) { + this.callback = callback; + return this; + } + + public Callback getCallback() { + return callback; + } + + public RequestInfo build(String appId, String privateKey) { + // 公共请求参数 + Map params = new HashMap(); + params.put("app_id", appId); + if (method != null) { + params.put("method", method); + } + if (version != null) { + params.put("version", version); + } + params.put("format", "json"); + params.put("charset", "utf-8"); + params.put("sign_type", "RSA2"); + params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + + // 业务参数 + params.put("biz_content", JSON.toJSONString(bizContent == null ? Collections.emptyMap() : bizContent)); + + if (!ignoreSign) { + String content = AlipaySignature.getSignContent(params); + String sign = null; + try { + sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8"); + } catch (AlipayApiException e) { + throw new RuntimeException(e); + } + params.put("sign", sign); + } + + RequestInfo requestInfo = new RequestInfo(); + requestInfo.setUrl(url); + requestInfo.setMethod(method); + requestInfo.setVersion(version); + requestInfo.setForm(params); + requestInfo.setHeader(header); + requestInfo.setPostJson(postJson); + requestInfo.setHttpMethod(httpMethod); + return requestInfo; + } + } + + @Data + public static class RequestInfo { + private String url; + private String method; + private String version; + private boolean postJson; + private Map form; + private Map header; + private HttpTool.HTTPMethod httpMethod; + } + +} 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 new file mode 100644 index 00000000..d179e491 --- /dev/null +++ b/sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java @@ -0,0 +1,219 @@ +package com.gitee.sop.test; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.junit.Assert; + +import java.util.HashMap; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 涵盖所有测试情况,发版前运行这个类,确保功能没有问题。 + * + * @author tanghc + */ +public class AllInOneTest extends TestBase { + + String url = "http://localhost:8081/api"; + String appId = "2019032617262200001"; + String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ="; + + private Client client = new Client(url, appId, privateKey, AllInOneTest::assertResult); + + /** + * 以get方式提交 + */ + public void testGet() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("alipay.story.get") + .version("1.0") + .bizContent(new BizContent().add("id", "1").add("name", "葫芦娃")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + + /** + * 以表单方式提交(application/x-www-form-urlencoded) + */ + public void testPostForm() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("alipay.story.get") + .version("1.0") + .bizContent(new BizContent().add("id", "1").add("name", "葫芦娃")) + .httpMethod(HttpTool.HTTPMethod.POST); + + client.execute(requestBuilder); + } + + /** + * 以json方式提交(application/json) + */ + public void testPostJSON() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("alipay.story.get") + .version("1.0") + // 以json方式提交 + .postJson(true) + .bizContent(new BizContent().add("id", "1").add("name", "葫芦娃")) + .httpMethod(HttpTool.HTTPMethod.POST); + + client.execute(requestBuilder); + } + + /** + * 测试feign。gateway -> book-service(consumer) -> story-service(provider) + */ + public void testFeign() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("alipay.book.story.get") + .version("1.0") + .bizContent(new BizContent()) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + + /** + * 测试dubbo服务,book会调用story提供的服务。参见:DemoConsumerController.java + */ + public void testDubbo() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("dubbo.story.get") + .version("1.0") + .bizContent(new BizContent().add("id", "222")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + + } + + /** + * 忽略验证,不校验签名,只需传接口名、版本号、业务参数 + */ + public void testIgnoreSign() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("story.get") + .version("2.1") + .ignoreSign(true) + .bizContent(new BizContent().add("id", "222").add("name", "忽略222")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + + /** + * JSR-303参数校验 + */ + public void testJSR303() { + 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")) + .httpMethod(HttpTool.HTTPMethod.POST); + + client.execute(requestBuilder); + } + + /** + * 测试是否有权限访问,可在sop-admin中设置权限 + */ + public void testPermission() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("permission.story.get") + .version("1.0") + .bizContent(new BizContent()) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + + /** + * 演示将接口名版本号跟在url后面,规则:http://host:port/{method}/{version}/ + */ + public void testRestful() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .url("http://localhost:8081/alipay.story.get/1.0/") + .bizContent(new BizContent().add("name", "name111")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + } + + /** + * 验证中文乱码问题 + */ + public void testString() { + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("story.string.get") + .version("1.0") + .bizContent(new BizContent().add("name", "name111")) + .httpMethod(HttpTool.HTTPMethod.GET) + .callback((requestInfo, responseData) -> { + JSONObject jsonObject = JSON.parseObject(responseData); + JSONObject data = jsonObject.getJSONObject("story_string_get_response"); + Assert.assertEquals("海底小纵队", data.getString("name")); + }); + + client.execute(requestBuilder); + } + + /** + * 限流测试,根据路由id限流 + * + * @throws InterruptedException + */ + public void testLimit() throws InterruptedException { + int threadsCount = 10; // threadsCount个线程同时提交 + final CountDownLatch countDownLatch = new CountDownLatch(1); + final CountDownLatch count = new CountDownLatch(threadsCount); + final AtomicInteger success = new AtomicInteger(); + for (int i = 0; i < threadsCount; i++) { + new Thread(new Runnable() { + @Override + public void run() { + try { + countDownLatch.await(); // 等在这里,执行countDownLatch.countDown();集体触发 + // 业务方法 + Client.RequestBuilder requestBuilder = new Client.RequestBuilder() + .method("alipay.story.get") + .version("1.2") + .bizContent(new BizContent().add("id", "1").add("name", "葫芦娃")) + .httpMethod(HttpTool.HTTPMethod.GET); + + client.execute(requestBuilder); + success.incrementAndGet(); + } catch (Exception e) { + } finally { + count.countDown(); + } + } + }).start(); + } + countDownLatch.countDown(); + count.await(); + System.out.println("成功次数:" + success); + } + + class BizContent extends HashMap { + public BizContent add(String key, String value) { + this.put(key, value); + return this; + } + } + + public static void assertResult(Client.RequestInfo requestInfo, String responseData) { + System.out.println(responseData); + String method = requestInfo.getMethod(); + if (method == null) { + return; + } + String node = method.replace('.', '_') + "_response"; + JSONObject jsonObject = JSON.parseObject(responseData).getJSONObject(node); + String code = Optional.ofNullable(jsonObject).map(json -> json.getString("code")).orElse("20000"); + Assert.assertEquals("10000", code); + } + +} diff --git a/sop-website/website-server/pom.xml b/sop-website/website-server/pom.xml index 5a13af45..827287db 100644 --- a/sop-website/website-server/pom.xml +++ b/sop-website/website-server/pom.xml @@ -25,7 +25,7 @@ com.gitee.sop sop-registry-api - 1.14.0-SNAPSHOT + 1.15.0-SNAPSHOT diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/DocInfo.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/DocInfo.java index b48b93e5..82e90129 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/DocInfo.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/DocInfo.java @@ -1,5 +1,6 @@ package com.gitee.sop.websiteserver.bean; +import com.alibaba.fastjson.annotation.JSONField; import lombok.Data; import java.util.List; @@ -10,5 +11,7 @@ import java.util.List; @Data public class DocInfo { private String title; + @JSONField(serialize = false) + private String serviceId; private List docModuleList; } diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/WebsiteConstants.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/WebsiteConstants.java index 982ab15c..fcb0b7cc 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/WebsiteConstants.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/WebsiteConstants.java @@ -8,4 +8,9 @@ public class WebsiteConstants { * zookeeper存放接口路由信息的根目录 */ public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route"; + + /** + * 服务临时节点 + */ + public static final String SOP_SERVICE_TEMP_PATH = "/com.gitee.sop.service.tmp"; } diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/ZookeeperContext.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/ZookeeperContext.java index 94ccc2a9..e2cd6a85 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/ZookeeperContext.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/bean/ZookeeperContext.java @@ -5,11 +5,18 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCache; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.framework.recipes.cache.TreeCacheListener; import org.apache.curator.retry.ExponentialBackoffRetry; import org.springframework.core.env.Environment; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.function.Consumer; /** * @author tanghc @@ -50,6 +57,10 @@ public class ZookeeperContext { return WebsiteConstants.SOP_SERVICE_ROUTE_PATH; } + public static String getServiceTempRootPath() { + return WebsiteConstants.SOP_SERVICE_TEMP_PATH; + } + public static CuratorFramework getClient() { return client; } @@ -58,10 +69,99 @@ public class ZookeeperContext { ZookeeperContext.client = client; } + public static boolean isPathExist(String path) { + try { + return client.checkExists().forPath(path) != null; + } catch (Exception e) { + return false; + } + } + + /** + * 是否有子节点 + * @param parentPath + * @return + * @throws Exception + */ + public static boolean hasChildren(String parentPath) throws Exception { + List children = client.getChildren().forPath(parentPath); + return !CollectionUtils.isEmpty(children); + } + + /** + * 创建path,如果path存在不报错,静默返回path名称 + * + * @param path + * @param data + * @return + * @throws Exception + */ + public static String createPath(String path, String data) throws Exception { + if (isPathExist(path)) { + return path; + } + return getClient().create() + // 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点 + .creatingParentContainersIfNeeded() + .forPath(path, data.getBytes()); + } + + /** + * 获取子节点信息并监听子节点 + * + * @param parentPath 父节点路径 + * @param listConsumer 子节点数据 + * @param listener 监听事件 + * @throws Exception + */ + public static void getChildrenAndListen(String parentPath, Consumer> listConsumer, PathChildrenCacheListener listener) throws Exception { + // 为子节点添加watcher + // PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件 + PathChildrenCache childrenCache = new PathChildrenCache(client, parentPath, true); + + /** + * StartMode: 初始化方式 + * POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件 + * NORMAL:异步初始化 + * BUILD_INITIAL_CACHE:同步初始化 + */ + childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); + + // 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的 + List childDataList = childrenCache.getCurrentData(); + listConsumer.accept(childDataList); + log.info("监听子节点增删改,监听路径:{}", parentPath); + // 监听根节点下面的子节点 + childrenCache.getListenable().addListener(listener); + } + + /** + * 监听子节点的增删改 + * + * @param parentPath 父节点路径 + * @param listener + * @throws Exception + */ + public static void listenChildren(String parentPath, PathChildrenCacheListener listener) throws Exception { + // 为子节点添加watcher + // PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件 + PathChildrenCache childrenCache = new PathChildrenCache(client, parentPath, true); + + /** + * StartMode: 初始化方式 + * POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件 + * NORMAL:异步初始化 + * BUILD_INITIAL_CACHE:同步初始化 + */ + childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE); + // 监听根节点下面的子节点 + childrenCache.getListenable().addListener(listener); + } + /** * 监听子节点,可以自定义层级 * @param parentPath 父节点路径 - * @param maxDepth 层级,从1开始。比如当前监听节点/t1,目录最深为/t1/t2/t3/t4,则maxDepth=3,说明下面3级子目录全 + * @param maxDepth 层级,从1开始。比如当前监听节点/t1,目录最深为/t1/t2/t3/t4,则maxDepth=3,说明下面3级子目录全部监听 * @param listener * @throws Exception */ @@ -73,7 +173,6 @@ public class ZookeeperContext { .build(); treeCache.getListenable().addListener(listener); - //没有开启模式作为入参的方法 treeCache.start(); } diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/controller/DocController.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/controller/DocController.java index 0e020f4b..957a9275 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/controller/DocController.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/controller/DocController.java @@ -1,7 +1,6 @@ package com.gitee.sop.websiteserver.controller; import com.gitee.sop.websiteserver.bean.DocInfo; -import com.gitee.sop.websiteserver.bean.DocItem; import com.gitee.sop.websiteserver.manager.DocManager; import com.gitee.sop.websiteserver.vo.DocBaseInfoVO; import com.gitee.sop.websiteserver.vo.DocInfoVO; @@ -59,11 +58,6 @@ public class DocController { return docManager.getByTitle(title); } - @GetMapping("/item/{method}/{version}/") - public DocItem getDocItem(@PathVariable("method") String method, @PathVariable("version") String version) { - return docManager.get(method, version); - } - // 后门地址,可手动更新文档内容,一般情况下用不到 @GetMapping("/reload") diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManager.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManager.java index 1deecbe4..8716e269 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManager.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManager.java @@ -1,7 +1,6 @@ package com.gitee.sop.websiteserver.manager; import com.gitee.sop.websiteserver.bean.DocInfo; -import com.gitee.sop.websiteserver.bean.DocItem; import java.util.Collection; @@ -12,8 +11,6 @@ public interface DocManager { void load(String serviceId); - DocItem get(String method, String version); - DocInfo getByTitle(String title); Collection listAll(); diff --git a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java index 11e8bb04..925ddd0d 100644 --- a/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java +++ b/sop-website/website-server/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java @@ -7,12 +7,14 @@ import com.gitee.sop.registryapi.bean.ServiceInfo; import com.gitee.sop.registryapi.bean.ServiceInstance; import com.gitee.sop.registryapi.service.RegistryService; import com.gitee.sop.websiteserver.bean.DocInfo; -import com.gitee.sop.websiteserver.bean.DocItem; import com.gitee.sop.websiteserver.bean.ZookeeperContext; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.apache.curator.framework.recipes.cache.TreeCacheEvent; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -41,21 +43,17 @@ import java.util.stream.Collectors; public class DocManagerImpl implements DocManager { // key:title - Map docDefinitionMap = new HashMap<>(); + private Map docDefinitionMap = new HashMap<>(); - // key: name+version - Map docItemMap = new HashMap<>(); + private RestTemplate restTemplate = new RestTemplate(); + private DocParser swaggerDocParser = new SwaggerDocParser(); - RestTemplate restTemplate = new RestTemplate(); + private DocParser easyopenDocParser = new EasyopenDocParser(); - DocParser swaggerDocParser = new SwaggerDocParser(); + private ExecutorService executorService = Executors.newSingleThreadExecutor(); - DocParser easyopenDocParser = new EasyopenDocParser(); - - ExecutorService executorService = Executors.newSingleThreadExecutor(); - - DelayQueue queue = new DelayQueue<>(); + private DelayQueue queue = new DelayQueue<>(); private String secret = "b749a2ec000f4f29"; @@ -65,14 +63,13 @@ public class DocManagerImpl implements DocManager { @Autowired private RegistryService registryService; - private volatile boolean listenInited; + @Value("${doc.refresh-seconds:60}") + private String refreshSeconds; @Override public void load(String serviceId) { try { List serviceInfoList = registryService.listAllService(1, 9999); - log.info("服务列表:{}", serviceInfoList); - serviceInfoList .stream() // 网关没有文档提供,需要排除 @@ -105,6 +102,7 @@ public class DocManagerImpl implements DocManager { JSONObject docRoot = JSON.parseObject(docInfoJson, Feature.OrderedField, Feature.DisableCircularReferenceDetect); DocParser docParser = this.buildDocParser(docRoot); DocInfo docInfo = docParser.parseJson(docRoot); + docInfo.setServiceId(serviceInstance.getServiceId()); docDefinitionMap.put(docInfo.getTitle(), docInfo); } catch (Exception e) { // 这里报错可能是因为有些微服务没有配置swagger文档,导致404访问不到 @@ -129,11 +127,6 @@ public class DocManagerImpl implements DocManager { } } - @Override - public DocItem get(String method, String version) { - return docItemMap.get(method + version); - } - @Override public DocInfo getByTitle(String title) { return docDefinitionMap.get(title); @@ -159,28 +152,73 @@ public class DocManagerImpl implements DocManager { executorService.execute(new Consumer(queue, this)); ZookeeperContext.setEnvironment(environment); - String routeRootPath = ZookeeperContext.getRouteRootPath(); + String serviceTempRootPath = ZookeeperContext.getServiceTempRootPath(); + ZookeeperContext.createPath(serviceTempRootPath, "{}"); // 如果节点内容有变化则自动更新文档 - ZookeeperContext.listenChildren(routeRootPath, 1, (client, event) -> { - if (listenInited) { - long id = System.currentTimeMillis(); + + ZookeeperContext.getChildrenAndListen(serviceTempRootPath, childDataList -> { + for (ChildData childData : childDataList) { + String serviceIdPath = childData.getPath(); + try { + boolean hasChildren = ZookeeperContext.hasChildren(serviceIdPath); + if (hasChildren) { + log.info("加载文档服务器,path:{}", serviceIdPath); + listenServiceIdPath(serviceIdPath); + } + } catch (Exception e) { + log.error("监听路径失败,serviceIdPath:{}", serviceIdPath); + } + } + }, (client, event) -> { + PathChildrenCacheEvent.Type type = event.getType(); + if (type == PathChildrenCacheEvent.Type.CHILD_ADDED) { + String serviceIdPath = event.getData().getPath(); + log.info("新增文档服务器,path:{}", serviceIdPath); + listenServiceIdPath(serviceIdPath); + } + }); + } + + private void listenServiceIdPath(String serviceIdPath) throws Exception { + ZookeeperContext.listenChildren(serviceIdPath, (client, event) -> { + String path = event.getData().getPath(); + PathChildrenCacheEvent.Type type = event.getType(); + log.info("服务节点变更,path:{}, eventType:{}", path, event.getType().name()); + if (type == PathChildrenCacheEvent.Type.CHILD_ADDED + || type == PathChildrenCacheEvent.Type.CHILD_UPDATED) { byte[] data = event.getData().getData(); String serviceInfoJson = new String(data); + if (StringUtils.isEmpty(serviceInfoJson)) { + return; + } ZKServiceInfo serviceInfo = JSON.parseObject(serviceInfoJson, ZKServiceInfo.class); String serviceId = serviceInfo.getServiceId(); - log.info("微服务[{}]推送更新", serviceId); - Msg msg = new Msg(id, 1000 * 20); + int delaySeconds = NumberUtils.toInt(refreshSeconds, 60); + log.info("微服务[{}]推送更新,{}秒后加载文档内容", serviceId, delaySeconds); + long id = System.currentTimeMillis(); + Msg msg = new Msg(id, delaySeconds * 1000); msg.serviceId = serviceId; // 延迟20秒执行 queue.offer(msg); - } - TreeCacheEvent.Type type = event.getType(); - if (type == TreeCacheEvent.Type.INITIALIZED) { - listenInited = true; + } else if (event.getType() == PathChildrenCacheEvent.Type.CHILD_REMOVED) { + byte[] data = event.getData().getData(); + String serviceInfoJson = new String(data); + ZKServiceInfo serviceInfo = JSON.parseObject(serviceInfoJson, ZKServiceInfo.class); + String serviceId = serviceInfo.getServiceId(); + boolean hasChildren = ZookeeperContext.hasChildren(serviceIdPath); + // 如果没有子节点就删除 + if (!hasChildren) { + log.info("服务节点已删除,删除对应文档信息,path:{}", event.getData().getPath()); + removeDoc(serviceId); + } } }); } + public void removeDoc(String serviceId) { + docDefinitionMap.entrySet().removeIf(entry -> serviceId.equalsIgnoreCase(entry.getValue().getServiceId())); + } + static class Msg implements Delayed { private long id; private long delay; @@ -197,8 +235,7 @@ public class DocManagerImpl implements DocManager { @Override public int compareTo(Delayed delayed) { Msg msg = (Msg) delayed; - return Long.valueOf(this.id) > Long.valueOf(msg.id) ? 1 - : (Long.valueOf(this.id) < Long.valueOf(msg.id) ? -1 : 0); + return Long.compare(this.id, msg.id); } // 延迟任务是否到时就是按照这个方法判断如果返回的是负数则说明到期否则还没到期 diff --git a/sop.sql b/sop.sql index d9d8cfb0..27ec44f8 100644 --- a/sop.sql +++ b/sop.sql @@ -1,4 +1,10 @@ +CREATE DATABASE IF NOT EXISTS `sop` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +USE `sop`; + + + + SET @PREVIOUS_FOREIGN_KEY_CHECKS = @@FOREIGN_KEY_CHECKS; SET FOREIGN_KEY_CHECKS = 0; @@ -7,16 +13,17 @@ DROP TABLE IF EXISTS `user_info`; DROP TABLE IF EXISTS `perm_role_permission`; 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 `admin_user_info`; -DROP TABLE IF EXISTS `config_common`; -DROP TABLE IF EXISTS `isv_keys`; DROP TABLE IF EXISTS `config_ip_blacklist`; -DROP TABLE IF EXISTS `config_gray`; DROP TABLE IF EXISTS `config_gray_instance`; +DROP TABLE IF EXISTS `config_gray`; +DROP TABLE IF EXISTS `config_common`; +DROP TABLE IF EXISTS `admin_user_info`; + CREATE TABLE `admin_user_info` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, @@ -30,6 +37,55 @@ CREATE TABLE `admin_user_info` ( ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='后台用户表'; +CREATE TABLE `config_common` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `config_group` varchar(64) NOT NULL DEFAULT '' COMMENT '配置分组', + `config_key` varchar(64) NOT NULL DEFAULT '' COMMENT '配置key', + `content` varchar(128) NOT NULL DEFAULT '' COMMENT '内容', + `remark` varchar(128) DEFAULT NULL COMMENT '备注', + `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_groupkey` (`config_group`,`config_key`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='通用配置表'; + + +CREATE TABLE `config_gray` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `service_id` varchar(64) NOT NULL DEFAULT '', + `user_key_content` text COMMENT '用户key,多个用引文逗号隔开', + `name_version_content` text COMMENT '需要灰度的接口,goods.get1.0=1.2,多个用英文逗号隔开', + `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, + `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_serviceid` (`service_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务灰度配置'; + + +CREATE TABLE `config_gray_instance` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `instance_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'instance_id', + `service_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'service_id', + `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0:禁用,1:启用', + `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, + `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_instanceid` (`instance_id`) USING BTREE, + KEY `idx_serviceid` (`service_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='开启灰度服务器实例'; + + +CREATE TABLE `config_ip_blacklist` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `ip` varchar(64) NOT NULL DEFAULT '' COMMENT 'ip', + `remark` varchar(128) DEFAULT NULL COMMENT '备注', + `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, + `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_ip` (`ip`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='IP黑名单'; + + CREATE TABLE `config_limit` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `route_id` varchar(128) DEFAULT NULL COMMENT '路由id', @@ -81,7 +137,7 @@ CREATE TABLE `config_route_limit` ( CREATE TABLE `isv_info` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `app_key` varchar(100) NOT NULL COMMENT 'appKey', - `secret` varchar(200) COMMENT 'secret', + `secret` varchar(200) DEFAULT NULL COMMENT 'secret', `pub_key` text COMMENT '公钥', `pri_key` text COMMENT '私钥', `status` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '1启用,2禁用', @@ -94,6 +150,23 @@ CREATE TABLE `isv_info` ( ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='isv信息表'; +CREATE TABLE `isv_keys` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `app_key` varchar(128) NOT NULL DEFAULT '', + `sign_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1:RSA2,2:MD5', + `secret` varchar(200) NOT NULL DEFAULT '' COMMENT 'sign_type=2时使用', + `key_format` tinyint(4) NOT NULL DEFAULT '1' COMMENT '秘钥格式,1:PKCS8(JAVA适用),2:PKCS1(非JAVA适用)', + `public_key_isv` text NOT NULL COMMENT '开发者生成的公钥', + `private_key_isv` text NOT NULL COMMENT '开发者生成的私钥(交给开发者)', + `public_key_platform` text NOT NULL COMMENT '平台生成的公钥(交给开发者)', + `private_key_platform` text NOT NULL COMMENT '平台生成的私钥', + `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, + `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `uk_appkey` (`app_key`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='ISV秘钥'; + + CREATE TABLE `perm_isv_role` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `isv_id` bigint(20) NOT NULL COMMENT 'isv_info表id', @@ -139,67 +212,7 @@ CREATE TABLE `user_info` ( ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户信息表'; -CREATE TABLE `config_common` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `config_group` varchar(64) NOT NULL DEFAULT '' COMMENT '配置分组', - `config_key` varchar(64) NOT NULL DEFAULT '' COMMENT '配置key', - `content` varchar(128) NOT NULL DEFAULT '' COMMENT '内容', - `remark` varchar(128) DEFAULT NULL COMMENT '备注', - `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_groupkey` (`config_group`,`config_key`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='通用配置表'; - -CREATE TABLE `isv_keys` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `app_key` varchar(128) NOT NULL DEFAULT '', - `sign_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1:RSA2,2:MD5', - `secret` varchar(200) NOT NULL DEFAULT '' COMMENT 'sign_type=2时使用', - `key_format` tinyint(4) NOT NULL DEFAULT '1' COMMENT '秘钥格式,1:PKCS8(JAVA适用),2:PKCS1(非JAVA适用)', - `public_key_isv` text NOT NULL COMMENT '开发者生成的公钥', - `private_key_isv` text NOT NULL COMMENT '开发者生成的私钥(交给开发者)', - `public_key_platform` text NOT NULL COMMENT '平台生成的公钥(交给开发者)', - `private_key_platform` text NOT NULL COMMENT '平台生成的私钥', - `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, - `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_appkey` (`app_key`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ISV秘钥'; - -CREATE TABLE `config_ip_blacklist` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `ip` varchar(64) NOT NULL DEFAULT '' COMMENT 'ip', - `remark` varchar(128) DEFAULT NULL COMMENT '备注', - `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, - `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_ip` (`ip`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='IP黑名单'; - -CREATE TABLE `config_gray` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `service_id` varchar(64) NOT NULL DEFAULT '', - `user_key_content` text COMMENT '用户key,多个用引文逗号隔开', - `name_version_content` text COMMENT '需要灰度的接口,goods.get1.0=1.2,多个用英文逗号隔开', - `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, - `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_serviceid` (`service_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='服务灰度配置'; - -CREATE TABLE `config_gray_instance` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `instance_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'instance_id', - `service_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'service_id', - `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0:禁用,1:启用', - `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP, - `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `uk_instanceid` (`instance_id`) USING BTREE, - KEY `idx_serviceid` (`service_id`) USING BTREE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='开启灰度服务器实例'; SET FOREIGN_KEY_CHECKS = @PREVIOUS_FOREIGN_KEY_CHECKS; @@ -216,13 +229,37 @@ ALTER TABLE `admin_user_info` ENABLE KEYS; UNLOCK TABLES; +LOCK TABLES `config_common` WRITE; +ALTER TABLE `config_common` DISABLE KEYS; +ALTER TABLE `config_common` ENABLE KEYS; +UNLOCK TABLES; + + +LOCK TABLES `config_gray` WRITE; +ALTER TABLE `config_gray` DISABLE KEYS; +ALTER TABLE `config_gray` ENABLE KEYS; +UNLOCK TABLES; + + +LOCK TABLES `config_gray_instance` WRITE; +ALTER TABLE `config_gray_instance` DISABLE KEYS; +ALTER TABLE `config_gray_instance` ENABLE KEYS; +UNLOCK TABLES; + + +LOCK TABLES `config_ip_blacklist` WRITE; +ALTER TABLE `config_ip_blacklist` DISABLE KEYS; +ALTER TABLE `config_ip_blacklist` ENABLE KEYS; +UNLOCK TABLES; + + LOCK TABLES `config_limit` WRITE; ALTER TABLE `config_limit` DISABLE KEYS; INSERT INTO `config_limit` (`id`, `route_id`, `app_key`, `limit_ip`, `service_id`, `limit_type`, `exec_count_per_second`, `limit_code`, `limit_msg`, `token_bucket_count`, `limit_status`, `order_index`, `remark`, `gmt_create`, `gmt_modified`) VALUES (1,'alipay.story.get1.0','','192.168.1.1,172.2.2.3','story-service',2,5,'','',6,1,3,NULL,'2019-05-17 19:21:35','2019-05-21 09:12:15'), - (2,'alipay.story.get1.0','2019032617262200001','','story-service',1,5,'service-budy','服务器忙',5,1,0,NULL,'2019-05-17 19:39:30','2019-05-21 15:36:52'), + (2,'alipay.story.get1.0','2019032617262200001','','story-service',2,5,'service-budy','服务器忙',10,1,0,'','2019-05-17 19:39:30','2019-05-21 15:36:52'), (3,'alipay.story.find1.0','20190331562013861008375808','','story-service',1,3,'service-busy','服务器忙',5,1,1,NULL,'2019-05-17 20:20:32','2019-05-20 17:40:17'), - (4,'alipay.story.get1.2','','','story-service',2,5,'','',3,1,1,NULL,'2019-05-20 16:27:21','2019-05-21 15:53:10'), + (4,'alipay.story.get1.2','','','story-service',1,5,'service-busy','服务器忙',3,1,1,'','2019-05-20 16:27:21','2019-05-21 15:53:10'), (5,'','20190401562373796095328256','','story-service',1,5,'service-busy','服务器忙',5,1,0,'这个appKey调用很频繁,重点照顾','2019-05-21 15:48:08','2019-05-21 18:45:32'), (6,'','','10.1.30.54','story-service',1,5,'service-busy','服务器忙',5,1,0,'这个ip在攻击我们','2019-05-21 15:55:33','2019-05-21 18:17:29'), (7,'story.get1.1','','10.1.30.54','story-service',1,5,'service-busy','服务器忙',5,1,0,NULL,'2019-05-21 16:30:48','2019-05-21 16:30:48'), @@ -259,21 +296,38 @@ UNLOCK TABLES; LOCK TABLES `isv_info` WRITE; ALTER TABLE `isv_info` DISABLE KEYS; -INSERT INTO `isv_info` (`id`, `app_key`, `secret`, `pub_key`, `pri_key`, `status`, `sign_type`, `gmt_create`, `gmt_modified`) VALUES - (1,'2019032617262200001','','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',1,1,'2019-03-27 10:10:34','2019-05-09 11:10:38'), - (3,'asdfasdf','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOJTAsGoAsNGJdzaWm835mtpcY2YxGr4NPjnhQmfUrPdT+Zgi6jmm+olYuygNeB8cOSALmTzgXlef+6SdwfRJVEMYVAO7hqF0Ood9zTOc+kolgnWJtqX54CoodfABt0SNS/bsr6hCAWu17RGnbgBaK+ZaJD3NVqXVXE8E30cYHiQIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM4lMCwagCw0Yl3Npabzfma2lxjZjEavg0+OeFCZ9Ss91P5mCLqOab6iVi7KA14Hxw5IAuZPOBeV5/7pJ3B9ElUQxhUA7uGoXQ6h33NM5z6SiWCdYm2pfngKih18AG3RI1L9uyvqEIBa7XtEaduAFor5lokPc1WpdVcTwTfRxgeJAgMBAAECgYAM3XFGL1k0aQiChiUCaEvJKTgAywLgHm/5dRC5JwKP8knqnn+I9P5QcV0jimPvaFjZ4VCdAvCjOC3EUNSvRn7wR2Lb1+BGZZePTdxtHWE2aqJ1W1SvgQTqMsLlPBRPnXo5XH/ng3WEH15ynd5NR035xAluaI0X/y+PsRxE6TlfIQJBAPSYUyXa2yaEqmvIN+ECKALCLLeDdi2YW3Kjahgz0X9V4Y4aTdrHh8y603zXC0Wy8HeOhwGoyciaS8SmjxCMn4UCQQDXweW8xsUreLH8hfVUtyiY/KgUz+R5foJDNXD7TLE9CDoPSHy09qBe99HyVCZg/gNJH4O+tNr6C4916dYaVk01AkBYZ2HOEc8ZmeOaty/zJHtfm9zbqykgi6upwISNINV8Z4bxfHJdO7bKeVANFBBf7a/aFmqXX/EmjxYJioW03o6dAkEAp7ViXJCtJpNU1pNSFZ2hgvmxtSu7zuyVWKSrw8rjYiuI5eRUe13RXsCHgzQB+Ra5exdyEsUGCaL+yosPD73RmQJBALGuM8EQUcBgrpgpeLZ39Ni1DYXYG9aj+u+ar/UL6kI1mCNFgwroO4EVIvXPVxikMxUgiE2tVaBML5nm8VDNJ7s=',2,1,'2019-03-27 11:01:11','2019-05-11 10:45:01'), - (5,'20190331562013861008375808','29864b93427447f5ac6c44df746f84ef','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4aMIx2q8rCVu5z6dgNQQSX2vwhvIcRb7FaqSk0ZK8AV9qQeE1TvfFVlAzOHlysE1yTRb0Mb6W2aw7IAS7Bkc3onYBQR4zNQYjYoDBzLukjF8o84hoVFRnh7sV8zszid2vb5H/YQr3M+5sYhlXY8KfILk3vhdbWpHM/umplcrxlwIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALhowjHarysJW7nPp2A1BBJfa/CG8hxFvsVqpKTRkrwBX2pB4TVO98VWUDM4eXKwTXJNFvQxvpbZrDsgBLsGRzeidgFBHjM1BiNigMHMu6SMXyjziGhUVGeHuxXzOzOJ3a9vkf9hCvcz7mxiGVdjwp8guTe+F1takcz+6amVyvGXAgMBAAECgYBj40LFVGoryp7n0CYeg7kX5p4GJGKCk/jY4IIcUPTFZ4zydorxoDuvpag9hmqqh/r7XeyAC23sMi4LvLUzRRxPh+7PuwL6nLce7vytsMCZQTPpBgz7dUfbi2HAxsuMOLjH3sVGycutARJsz6bT+9PyBEuVtUqwBrDGpFvwT0z6yQJBAOANC8nysb+O4rn/fbJtHIhtQoV74yu00mLnfwv8/J1+WyAEc32WZ4KYINqCe8ft1UknhPQx9UV6JaPCnlpF6w0CQQDStJhd38uQ7dVUQZHGP24xS/K38AYiSheEr7uewhkJfC2cKqE/lBk3oEG4s7asjhwlFLWLWSBLVM/Ta9Yj0hYzAkBe82hxl1bY9bcEWFBu02rqLlOouk4V8bXPkIf5DqgIHsqDkR9Ys+r+H3ac4/uNSS/ApuzjiGCHpzJYalwtqb/pAkEAvAKlSm5dCC8QAaSYXJtQyfAI3hPwhTwzjBP6iAiNqqcBU62+QCr37Wiz/Alv4LzVZEj8TSDz7gP5hZ9dbo0RfQJBALJ7NhTaeMN4jxBJ6Xg4rNZPb4yhAXuFxCp+a+FyXTsbWnW/ar8KJ3LHox0GOao6wne4qN3h7eqLOrYnnvOSFl0=',1,2,'2019-03-31 20:34:12','2019-04-19 17:30:09'), - (6,'20190331562037310372184064','d6b2a6603236491f87eed958292be136','','',2,2,'2019-03-31 22:07:20','2019-05-07 18:14:53'), - (7,'20190401562373672858288128','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOgSo6GfwM8a+rUT4m61nZa7q5cJpjL7luxQKuJvkMl/QydVrzRPinCh6zqgBJDa7YY2X6z5TyTkjYuDkYMrdyHcYvCDuJ0NpRPZMR+QDE70yp9wJ+kOqTa8bepJtxzuCYLxFz+wRsIFt0nIxC6ttCaM9OEw/Bflhws3xczw4uqQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAI6BKjoZ/Azxr6tRPibrWdlrurlwmmMvuW7FAq4m+QyX9DJ1WvNE+KcKHrOqAEkNrthjZfrPlPJOSNi4ORgyt3Idxi8IO4nQ2lE9kxH5AMTvTKn3An6Q6pNrxt6km3HO4JgvEXP7BGwgW3ScjELq20Joz04TD8F+WHCzfFzPDi6pAgMBAAECgYA/zuQ6ieILZbjUDBe5U46yxQMh/6KRoQ/14m81zauckPm+EkA8R3jTSru+lPN1wpO0vqUuLf6ylI0XxT2DcUokOgY07ZdE54pu5XAsyY0eanFwt6C1LrHYpORV3Mp9XuI3fXrxYqVlxLuj1N7MGinXUuW7aZCHaEuSnZ55OL9dkQJBANKOeFiYDISSuIFHSrndSgr+a8E44jS/2/7lE49p5l3WVOFTHh0IZQNTs/IKsKJkUnYDE4W/Ab7NTnWZpXYeM30CQQCtQrtxPEzLl4dtupPOBJJoApj2lq7Q6tIGx178K6wS9Rz3GEvkA7fz1Tpm+nmPZflWZ9mVmEaVuMTMpl3HN/edAkBylyzx8lYltIALg5QskT1hvFNChkW9tYjyMROzIkxIV4Q8WPLzlAT9iYlOOfkld/nU1hnC2VAG2k9P+z2sigU1AkBAl1AptsEqZSMn1RalBy9NdypvQ12IpQIHZOwUNnO/3YEe3P/t0TUSwbs0CMyomOuLOsvy6QHnbypu4Na1HjhBAkAWjtdhuvU15HAa5jMgiUVfQM3YFuz2k3QkRagtZZ33bqnYs4wNxEZqB5t+vEj+8r3fmSN0BpNR1VW71j53Ir0H',1,1,'2019-04-01 20:24:01','2019-04-01 20:27:33'), - (8,'20190401562373796095328256','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbxn0En2cj29t8i+m1dT7seF9XQx3cEaoClXFTlmc78Y1ZuQFbyY99VSwv8JbtpGxPvBSVD9SPmXWNBRBbSHT+gxStcdXD9QeD3knGFy/1V+z3E2Rj/6LIlFmgTlGh1fmEgttPjsUW1Dj704/ydyIrw+CAyAMKQyrFg0wYmNW+UQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJvGfQSfZyPb23yL6bV1Pux4X1dDHdwRqgKVcVOWZzvxjVm5AVvJj31VLC/wlu2kbE+8FJUP1I+ZdY0FEFtIdP6DFK1x1cP1B4PeScYXL/VX7PcTZGP/osiUWaBOUaHV+YSC20+OxRbUOPvTj/J3IivD4IDIAwpDKsWDTBiY1b5RAgMBAAECgYAE27/ycPZKjATgcYyseCeqQGbY1eMMhhCDXB3YuYwmtnXuInMEZdjv08Q5CovqhYJLSlZp/8BlaifcahgEgNIFQXmxAF0U0HsNC6W4Dk1gGgQaVmYaZv5ex7uIcFB1qFvlO60kWf82YeRnO5KsFBODOJ1XSNwqjL2GeLSHBSVyQQJBAOsvDmClBsETSdiNSFMz+D9WCnCh1Ip4AoCzA/yG+PRSwYjZDdceP2DXieiZXPlxTFZ7MIXxAafgeyeQA2hpkQUCQQCpkCUSbrZ+nd4BYdnxZOSf0//cUT0o6+3kROX7gsXV7zRAWWxojT6DkGVlduDLZM/hjWeHRjWUxKC/jgbzvundAkBckhUSrWJPNQxoFJRXS6l3JKLPWqOSLVKu3ce/6lCrurc66lSsS9eegrhhuZwDAzmNAMhEsGx6a72OAP2WZ5cRAkBd8cT4X2qw4BpePa6YdcPNYZHCqSfvgje9XwbkwGGH1A3pESJlEsxt7BShkKmfRu1+E/AmHJoXIJHHT5M+fKnpAkA+VfyAAviKeCwUSq+5oUa0B+ozEA3frp/40cKQP7k02aamocAQCDRaC1ZlWffeQqYMnYe1/Mjr/SdX/Ut3X0CC',1,1,'2019-04-01 20:24:25','2019-04-01 20:24:48'), - (9,'201904035630907729292csharp','','MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQAB','MIIEowIBAAKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQABAoIBAHFDsgrrJca+NKEan77ycwx3jnKx4WrWjOF4zVKL9AQjiSYDNgvKknJyPb3kpC/lEoHdxGERHSzJoxib7DkoIqRQYhPxj73pxj5QfYk3P7LLJNNg/LTrpXDb3nL8JV9wIflGf87qQvstZTDJEyFWE4jBs7Hr0BxovWvri8InnzkmERJ1cbGJgNHe1Y3Zo2tw0yaHxQCxLuajP+notRZhD9bEp7uKeI0w9AvlW6k8m/7y10F0BK/TlyW8rQiEC391yOiRYoMcUh4hd2Q9bMx3jngZgX8PXIvZZcup4/pvWlv1alwhB2tsnLdazP62r1MO80vLyLunzGO+7WwCjEYlVaECgYEA+lQRFmbhKaPuAuXMtY31Fbga8nedka5TjnEV7+/kX+yowE2OlNujF+ZG8UTddTxAGv56yVNi/mjRlgD74j8z0eOsgvOq9mwbCrgLhLo51H9O/wAxtb+hBKtC5l50pBr4gER6d8W6EQNTSGojnMIaLXTkAZ5Qf6Z8e2HFVdOn0X0CgYEA7SSrTokwzukt5KldNu5ukyyd+C3D1i6orbg6qD73EP9CfNMfGSBn7dDv9wMSJH01+Ty+RgTROgtjGRDbMJWnfbdt/61NePr9ar5sb6Nbsf7/I0w7cZF5dsaFYgzaOfQYquzXPbLQHkpMT64bqpv/Mwy4F2lFvaYWY5fA4pC2uckCgYEAg75Ym9ybJaoTqky8ttQ2Jy8UZ4VSVQhVC0My02sCWwWXLlXi8y7An+Rec73Ve0yxREOn5WrQT6pkmzh7V/ABWrYi5WxODpCIjtSbo0fLBa3Wqle00b0/hdCITetqIa/cFs1zUrOqICgK3bKWeXqiAkhhcwSZwwSgwOKM04Wn7ZUCgYBvhHX2mbdVJfyJ8kc+hMOE/E9RHRxiBVEXWHJlGi8PVCqNDq8qHr4g7Mdbzprig+s0yKblwHAvrpkseWvKHiZEjVTyDipHgShY4TGXEigVvUd37uppTrLi8xpYcJjS9gH/px7VCdiq1d+q/MJP6coJ1KphgATm2UrgDMYNBWaYWQKBgEHRxrmER7btUF60/YgcqPHFc8RpYQB2ZZE0kyKGDqk2Data1XYUY6vsPAU28yRLAaWr/D2H17iyLkxP80VLm6QhifxCadv90Q/Wl1DFfOJQMW6avyQ0so6G0wFq/LJxaFK4iLXQn1RJnmTp6BYiJMmK2BhFbRzw8ssMoF6ad2rr',1,1,'2019-04-03 19:54:05','2019-04-03 20:11:58'), - (10,'easyopen_test','G9w0BAQEFAAOCAQ8AMIIBCgKCA','','',1,2,'2019-04-19 17:19:34','2019-04-19 17:30:09'), - (11,'20190513577548661718777856','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ',1,1,'2019-05-13 17:24:17','2019-05-13 17:24:17'), - (12,'20190513577548661718777857','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ',1,1,'2019-05-13 17:24:17','2019-05-13 17:24:17'); +INSERT INTO `isv_info` (`id`, `app_key`, `secret`, `pub_key`, `pri_key`, `status`, `sign_type`, `remark`, `gmt_create`, `gmt_modified`) VALUES + (1,'2019032617262200001','','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',1,1,NULL,'2019-03-27 10:10:34','2019-05-09 11:10:38'), + (3,'asdfasdf','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOJTAsGoAsNGJdzaWm835mtpcY2YxGr4NPjnhQmfUrPdT+Zgi6jmm+olYuygNeB8cOSALmTzgXlef+6SdwfRJVEMYVAO7hqF0Ood9zTOc+kolgnWJtqX54CoodfABt0SNS/bsr6hCAWu17RGnbgBaK+ZaJD3NVqXVXE8E30cYHiQIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM4lMCwagCw0Yl3Npabzfma2lxjZjEavg0+OeFCZ9Ss91P5mCLqOab6iVi7KA14Hxw5IAuZPOBeV5/7pJ3B9ElUQxhUA7uGoXQ6h33NM5z6SiWCdYm2pfngKih18AG3RI1L9uyvqEIBa7XtEaduAFor5lokPc1WpdVcTwTfRxgeJAgMBAAECgYAM3XFGL1k0aQiChiUCaEvJKTgAywLgHm/5dRC5JwKP8knqnn+I9P5QcV0jimPvaFjZ4VCdAvCjOC3EUNSvRn7wR2Lb1+BGZZePTdxtHWE2aqJ1W1SvgQTqMsLlPBRPnXo5XH/ng3WEH15ynd5NR035xAluaI0X/y+PsRxE6TlfIQJBAPSYUyXa2yaEqmvIN+ECKALCLLeDdi2YW3Kjahgz0X9V4Y4aTdrHh8y603zXC0Wy8HeOhwGoyciaS8SmjxCMn4UCQQDXweW8xsUreLH8hfVUtyiY/KgUz+R5foJDNXD7TLE9CDoPSHy09qBe99HyVCZg/gNJH4O+tNr6C4916dYaVk01AkBYZ2HOEc8ZmeOaty/zJHtfm9zbqykgi6upwISNINV8Z4bxfHJdO7bKeVANFBBf7a/aFmqXX/EmjxYJioW03o6dAkEAp7ViXJCtJpNU1pNSFZ2hgvmxtSu7zuyVWKSrw8rjYiuI5eRUe13RXsCHgzQB+Ra5exdyEsUGCaL+yosPD73RmQJBALGuM8EQUcBgrpgpeLZ39Ni1DYXYG9aj+u+ar/UL6kI1mCNFgwroO4EVIvXPVxikMxUgiE2tVaBML5nm8VDNJ7s=',2,1,NULL,'2019-03-27 11:01:11','2019-05-11 10:45:01'), + (5,'20190331562013861008375808','29864b93427447f5ac6c44df746f84ef','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4aMIx2q8rCVu5z6dgNQQSX2vwhvIcRb7FaqSk0ZK8AV9qQeE1TvfFVlAzOHlysE1yTRb0Mb6W2aw7IAS7Bkc3onYBQR4zNQYjYoDBzLukjF8o84hoVFRnh7sV8zszid2vb5H/YQr3M+5sYhlXY8KfILk3vhdbWpHM/umplcrxlwIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALhowjHarysJW7nPp2A1BBJfa/CG8hxFvsVqpKTRkrwBX2pB4TVO98VWUDM4eXKwTXJNFvQxvpbZrDsgBLsGRzeidgFBHjM1BiNigMHMu6SMXyjziGhUVGeHuxXzOzOJ3a9vkf9hCvcz7mxiGVdjwp8guTe+F1takcz+6amVyvGXAgMBAAECgYBj40LFVGoryp7n0CYeg7kX5p4GJGKCk/jY4IIcUPTFZ4zydorxoDuvpag9hmqqh/r7XeyAC23sMi4LvLUzRRxPh+7PuwL6nLce7vytsMCZQTPpBgz7dUfbi2HAxsuMOLjH3sVGycutARJsz6bT+9PyBEuVtUqwBrDGpFvwT0z6yQJBAOANC8nysb+O4rn/fbJtHIhtQoV74yu00mLnfwv8/J1+WyAEc32WZ4KYINqCe8ft1UknhPQx9UV6JaPCnlpF6w0CQQDStJhd38uQ7dVUQZHGP24xS/K38AYiSheEr7uewhkJfC2cKqE/lBk3oEG4s7asjhwlFLWLWSBLVM/Ta9Yj0hYzAkBe82hxl1bY9bcEWFBu02rqLlOouk4V8bXPkIf5DqgIHsqDkR9Ys+r+H3ac4/uNSS/ApuzjiGCHpzJYalwtqb/pAkEAvAKlSm5dCC8QAaSYXJtQyfAI3hPwhTwzjBP6iAiNqqcBU62+QCr37Wiz/Alv4LzVZEj8TSDz7gP5hZ9dbo0RfQJBALJ7NhTaeMN4jxBJ6Xg4rNZPb4yhAXuFxCp+a+FyXTsbWnW/ar8KJ3LHox0GOao6wne4qN3h7eqLOrYnnvOSFl0=',1,2,NULL,'2019-03-31 20:34:12','2019-04-19 17:30:09'), + (6,'20190331562037310372184064','d6b2a6603236491f87eed958292be136','','',2,2,NULL,'2019-03-31 22:07:20','2019-05-07 18:14:53'), + (7,'20190401562373672858288128','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOgSo6GfwM8a+rUT4m61nZa7q5cJpjL7luxQKuJvkMl/QydVrzRPinCh6zqgBJDa7YY2X6z5TyTkjYuDkYMrdyHcYvCDuJ0NpRPZMR+QDE70yp9wJ+kOqTa8bepJtxzuCYLxFz+wRsIFt0nIxC6ttCaM9OEw/Bflhws3xczw4uqQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAI6BKjoZ/Azxr6tRPibrWdlrurlwmmMvuW7FAq4m+QyX9DJ1WvNE+KcKHrOqAEkNrthjZfrPlPJOSNi4ORgyt3Idxi8IO4nQ2lE9kxH5AMTvTKn3An6Q6pNrxt6km3HO4JgvEXP7BGwgW3ScjELq20Joz04TD8F+WHCzfFzPDi6pAgMBAAECgYA/zuQ6ieILZbjUDBe5U46yxQMh/6KRoQ/14m81zauckPm+EkA8R3jTSru+lPN1wpO0vqUuLf6ylI0XxT2DcUokOgY07ZdE54pu5XAsyY0eanFwt6C1LrHYpORV3Mp9XuI3fXrxYqVlxLuj1N7MGinXUuW7aZCHaEuSnZ55OL9dkQJBANKOeFiYDISSuIFHSrndSgr+a8E44jS/2/7lE49p5l3WVOFTHh0IZQNTs/IKsKJkUnYDE4W/Ab7NTnWZpXYeM30CQQCtQrtxPEzLl4dtupPOBJJoApj2lq7Q6tIGx178K6wS9Rz3GEvkA7fz1Tpm+nmPZflWZ9mVmEaVuMTMpl3HN/edAkBylyzx8lYltIALg5QskT1hvFNChkW9tYjyMROzIkxIV4Q8WPLzlAT9iYlOOfkld/nU1hnC2VAG2k9P+z2sigU1AkBAl1AptsEqZSMn1RalBy9NdypvQ12IpQIHZOwUNnO/3YEe3P/t0TUSwbs0CMyomOuLOsvy6QHnbypu4Na1HjhBAkAWjtdhuvU15HAa5jMgiUVfQM3YFuz2k3QkRagtZZ33bqnYs4wNxEZqB5t+vEj+8r3fmSN0BpNR1VW71j53Ir0H',1,1,NULL,'2019-04-01 20:24:01','2019-04-01 20:27:33'), + (8,'20190401562373796095328256','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbxn0En2cj29t8i+m1dT7seF9XQx3cEaoClXFTlmc78Y1ZuQFbyY99VSwv8JbtpGxPvBSVD9SPmXWNBRBbSHT+gxStcdXD9QeD3knGFy/1V+z3E2Rj/6LIlFmgTlGh1fmEgttPjsUW1Dj704/ydyIrw+CAyAMKQyrFg0wYmNW+UQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJvGfQSfZyPb23yL6bV1Pux4X1dDHdwRqgKVcVOWZzvxjVm5AVvJj31VLC/wlu2kbE+8FJUP1I+ZdY0FEFtIdP6DFK1x1cP1B4PeScYXL/VX7PcTZGP/osiUWaBOUaHV+YSC20+OxRbUOPvTj/J3IivD4IDIAwpDKsWDTBiY1b5RAgMBAAECgYAE27/ycPZKjATgcYyseCeqQGbY1eMMhhCDXB3YuYwmtnXuInMEZdjv08Q5CovqhYJLSlZp/8BlaifcahgEgNIFQXmxAF0U0HsNC6W4Dk1gGgQaVmYaZv5ex7uIcFB1qFvlO60kWf82YeRnO5KsFBODOJ1XSNwqjL2GeLSHBSVyQQJBAOsvDmClBsETSdiNSFMz+D9WCnCh1Ip4AoCzA/yG+PRSwYjZDdceP2DXieiZXPlxTFZ7MIXxAafgeyeQA2hpkQUCQQCpkCUSbrZ+nd4BYdnxZOSf0//cUT0o6+3kROX7gsXV7zRAWWxojT6DkGVlduDLZM/hjWeHRjWUxKC/jgbzvundAkBckhUSrWJPNQxoFJRXS6l3JKLPWqOSLVKu3ce/6lCrurc66lSsS9eegrhhuZwDAzmNAMhEsGx6a72OAP2WZ5cRAkBd8cT4X2qw4BpePa6YdcPNYZHCqSfvgje9XwbkwGGH1A3pESJlEsxt7BShkKmfRu1+E/AmHJoXIJHHT5M+fKnpAkA+VfyAAviKeCwUSq+5oUa0B+ozEA3frp/40cKQP7k02aamocAQCDRaC1ZlWffeQqYMnYe1/Mjr/SdX/Ut3X0CC',1,1,NULL,'2019-04-01 20:24:25','2019-04-01 20:24:48'), + (9,'201904035630907729292csharp','','MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQAB','MIIEowIBAAKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQABAoIBAHFDsgrrJca+NKEan77ycwx3jnKx4WrWjOF4zVKL9AQjiSYDNgvKknJyPb3kpC/lEoHdxGERHSzJoxib7DkoIqRQYhPxj73pxj5QfYk3P7LLJNNg/LTrpXDb3nL8JV9wIflGf87qQvstZTDJEyFWE4jBs7Hr0BxovWvri8InnzkmERJ1cbGJgNHe1Y3Zo2tw0yaHxQCxLuajP+notRZhD9bEp7uKeI0w9AvlW6k8m/7y10F0BK/TlyW8rQiEC391yOiRYoMcUh4hd2Q9bMx3jngZgX8PXIvZZcup4/pvWlv1alwhB2tsnLdazP62r1MO80vLyLunzGO+7WwCjEYlVaECgYEA+lQRFmbhKaPuAuXMtY31Fbga8nedka5TjnEV7+/kX+yowE2OlNujF+ZG8UTddTxAGv56yVNi/mjRlgD74j8z0eOsgvOq9mwbCrgLhLo51H9O/wAxtb+hBKtC5l50pBr4gER6d8W6EQNTSGojnMIaLXTkAZ5Qf6Z8e2HFVdOn0X0CgYEA7SSrTokwzukt5KldNu5ukyyd+C3D1i6orbg6qD73EP9CfNMfGSBn7dDv9wMSJH01+Ty+RgTROgtjGRDbMJWnfbdt/61NePr9ar5sb6Nbsf7/I0w7cZF5dsaFYgzaOfQYquzXPbLQHkpMT64bqpv/Mwy4F2lFvaYWY5fA4pC2uckCgYEAg75Ym9ybJaoTqky8ttQ2Jy8UZ4VSVQhVC0My02sCWwWXLlXi8y7An+Rec73Ve0yxREOn5WrQT6pkmzh7V/ABWrYi5WxODpCIjtSbo0fLBa3Wqle00b0/hdCITetqIa/cFs1zUrOqICgK3bKWeXqiAkhhcwSZwwSgwOKM04Wn7ZUCgYBvhHX2mbdVJfyJ8kc+hMOE/E9RHRxiBVEXWHJlGi8PVCqNDq8qHr4g7Mdbzprig+s0yKblwHAvrpkseWvKHiZEjVTyDipHgShY4TGXEigVvUd37uppTrLi8xpYcJjS9gH/px7VCdiq1d+q/MJP6coJ1KphgATm2UrgDMYNBWaYWQKBgEHRxrmER7btUF60/YgcqPHFc8RpYQB2ZZE0kyKGDqk2Data1XYUY6vsPAU28yRLAaWr/D2H17iyLkxP80VLm6QhifxCadv90Q/Wl1DFfOJQMW6avyQ0so6G0wFq/LJxaFK4iLXQn1RJnmTp6BYiJMmK2BhFbRzw8ssMoF6ad2rr',1,1,NULL,'2019-04-03 19:54:05','2019-04-03 20:11:58'), + (10,'easyopen_test','G9w0BAQEFAAOCAQ8AMIIBCgKCA','','',1,2,NULL,'2019-04-19 17:19:34','2019-04-19 17:30:09'), + (11,'20190513577548661718777856','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ',1,1,NULL,'2019-05-13 17:24:17','2019-05-13 17:24:17'), + (12,'20190513577548661718777857','','MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ',1,1,NULL,'2019-05-13 17:24:17','2019-05-13 17:24:17'); ALTER TABLE `isv_info` ENABLE KEYS; UNLOCK TABLES; +LOCK TABLES `isv_keys` WRITE; +ALTER TABLE `isv_keys` DISABLE KEYS; +INSERT INTO `isv_keys` (`id`, `app_key`, `sign_type`, `secret`, `key_format`, `public_key_isv`, `private_key_isv`, `public_key_platform`, `private_key_platform`, `gmt_create`, `gmt_modified`) VALUES + (1,'2019032617262200001',1,'',1,'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','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (2,'asdfasdf',1,'',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOJTAsGoAsNGJdzaWm835mtpcY2YxGr4NPjnhQmfUrPdT+Zgi6jmm+olYuygNeB8cOSALmTzgXlef+6SdwfRJVEMYVAO7hqF0Ood9zTOc+kolgnWJtqX54CoodfABt0SNS/bsr6hCAWu17RGnbgBaK+ZaJD3NVqXVXE8E30cYHiQIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAM4lMCwagCw0Yl3Npabzfma2lxjZjEavg0+OeFCZ9Ss91P5mCLqOab6iVi7KA14Hxw5IAuZPOBeV5/7pJ3B9ElUQxhUA7uGoXQ6h33NM5z6SiWCdYm2pfngKih18AG3RI1L9uyvqEIBa7XtEaduAFor5lokPc1WpdVcTwTfRxgeJAgMBAAECgYAM3XFGL1k0aQiChiUCaEvJKTgAywLgHm/5dRC5JwKP8knqnn+I9P5QcV0jimPvaFjZ4VCdAvCjOC3EUNSvRn7wR2Lb1+BGZZePTdxtHWE2aqJ1W1SvgQTqMsLlPBRPnXo5XH/ng3WEH15ynd5NR035xAluaI0X/y+PsRxE6TlfIQJBAPSYUyXa2yaEqmvIN+ECKALCLLeDdi2YW3Kjahgz0X9V4Y4aTdrHh8y603zXC0Wy8HeOhwGoyciaS8SmjxCMn4UCQQDXweW8xsUreLH8hfVUtyiY/KgUz+R5foJDNXD7TLE9CDoPSHy09qBe99HyVCZg/gNJH4O+tNr6C4916dYaVk01AkBYZ2HOEc8ZmeOaty/zJHtfm9zbqykgi6upwISNINV8Z4bxfHJdO7bKeVANFBBf7a/aFmqXX/EmjxYJioW03o6dAkEAp7ViXJCtJpNU1pNSFZ2hgvmxtSu7zuyVWKSrw8rjYiuI5eRUe13RXsCHgzQB+Ra5exdyEsUGCaL+yosPD73RmQJBALGuM8EQUcBgrpgpeLZ39Ni1DYXYG9aj+u+ar/UL6kI1mCNFgwroO4EVIvXPVxikMxUgiE2tVaBML5nm8VDNJ7s=','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (3,'20190331562013861008375808',2,'29864b93427447f5ac6c44df746f84ef',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4aMIx2q8rCVu5z6dgNQQSX2vwhvIcRb7FaqSk0ZK8AV9qQeE1TvfFVlAzOHlysE1yTRb0Mb6W2aw7IAS7Bkc3onYBQR4zNQYjYoDBzLukjF8o84hoVFRnh7sV8zszid2vb5H/YQr3M+5sYhlXY8KfILk3vhdbWpHM/umplcrxlwIDAQAB','MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALhowjHarysJW7nPp2A1BBJfa/CG8hxFvsVqpKTRkrwBX2pB4TVO98VWUDM4eXKwTXJNFvQxvpbZrDsgBLsGRzeidgFBHjM1BiNigMHMu6SMXyjziGhUVGeHuxXzOzOJ3a9vkf9hCvcz7mxiGVdjwp8guTe+F1takcz+6amVyvGXAgMBAAECgYBj40LFVGoryp7n0CYeg7kX5p4GJGKCk/jY4IIcUPTFZ4zydorxoDuvpag9hmqqh/r7XeyAC23sMi4LvLUzRRxPh+7PuwL6nLce7vytsMCZQTPpBgz7dUfbi2HAxsuMOLjH3sVGycutARJsz6bT+9PyBEuVtUqwBrDGpFvwT0z6yQJBAOANC8nysb+O4rn/fbJtHIhtQoV74yu00mLnfwv8/J1+WyAEc32WZ4KYINqCe8ft1UknhPQx9UV6JaPCnlpF6w0CQQDStJhd38uQ7dVUQZHGP24xS/K38AYiSheEr7uewhkJfC2cKqE/lBk3oEG4s7asjhwlFLWLWSBLVM/Ta9Yj0hYzAkBe82hxl1bY9bcEWFBu02rqLlOouk4V8bXPkIf5DqgIHsqDkR9Ys+r+H3ac4/uNSS/ApuzjiGCHpzJYalwtqb/pAkEAvAKlSm5dCC8QAaSYXJtQyfAI3hPwhTwzjBP6iAiNqqcBU62+QCr37Wiz/Alv4LzVZEj8TSDz7gP5hZ9dbo0RfQJBALJ7NhTaeMN4jxBJ6Xg4rNZPb4yhAXuFxCp+a+FyXTsbWnW/ar8KJ3LHox0GOao6wne4qN3h7eqLOrYnnvOSFl0=','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (4,'20190331562037310372184064',2,'d6b2a6603236491f87eed958292be136',1,'','','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (5,'20190401562373672858288128',1,'',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCOgSo6GfwM8a+rUT4m61nZa7q5cJpjL7luxQKuJvkMl/QydVrzRPinCh6zqgBJDa7YY2X6z5TyTkjYuDkYMrdyHcYvCDuJ0NpRPZMR+QDE70yp9wJ+kOqTa8bepJtxzuCYLxFz+wRsIFt0nIxC6ttCaM9OEw/Bflhws3xczw4uqQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAI6BKjoZ/Azxr6tRPibrWdlrurlwmmMvuW7FAq4m+QyX9DJ1WvNE+KcKHrOqAEkNrthjZfrPlPJOSNi4ORgyt3Idxi8IO4nQ2lE9kxH5AMTvTKn3An6Q6pNrxt6km3HO4JgvEXP7BGwgW3ScjELq20Joz04TD8F+WHCzfFzPDi6pAgMBAAECgYA/zuQ6ieILZbjUDBe5U46yxQMh/6KRoQ/14m81zauckPm+EkA8R3jTSru+lPN1wpO0vqUuLf6ylI0XxT2DcUokOgY07ZdE54pu5XAsyY0eanFwt6C1LrHYpORV3Mp9XuI3fXrxYqVlxLuj1N7MGinXUuW7aZCHaEuSnZ55OL9dkQJBANKOeFiYDISSuIFHSrndSgr+a8E44jS/2/7lE49p5l3WVOFTHh0IZQNTs/IKsKJkUnYDE4W/Ab7NTnWZpXYeM30CQQCtQrtxPEzLl4dtupPOBJJoApj2lq7Q6tIGx178K6wS9Rz3GEvkA7fz1Tpm+nmPZflWZ9mVmEaVuMTMpl3HN/edAkBylyzx8lYltIALg5QskT1hvFNChkW9tYjyMROzIkxIV4Q8WPLzlAT9iYlOOfkld/nU1hnC2VAG2k9P+z2sigU1AkBAl1AptsEqZSMn1RalBy9NdypvQ12IpQIHZOwUNnO/3YEe3P/t0TUSwbs0CMyomOuLOsvy6QHnbypu4Na1HjhBAkAWjtdhuvU15HAa5jMgiUVfQM3YFuz2k3QkRagtZZ33bqnYs4wNxEZqB5t+vEj+8r3fmSN0BpNR1VW71j53Ir0H','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (6,'20190401562373796095328256',1,'',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCbxn0En2cj29t8i+m1dT7seF9XQx3cEaoClXFTlmc78Y1ZuQFbyY99VSwv8JbtpGxPvBSVD9SPmXWNBRBbSHT+gxStcdXD9QeD3knGFy/1V+z3E2Rj/6LIlFmgTlGh1fmEgttPjsUW1Dj704/ydyIrw+CAyAMKQyrFg0wYmNW+UQIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJvGfQSfZyPb23yL6bV1Pux4X1dDHdwRqgKVcVOWZzvxjVm5AVvJj31VLC/wlu2kbE+8FJUP1I+ZdY0FEFtIdP6DFK1x1cP1B4PeScYXL/VX7PcTZGP/osiUWaBOUaHV+YSC20+OxRbUOPvTj/J3IivD4IDIAwpDKsWDTBiY1b5RAgMBAAECgYAE27/ycPZKjATgcYyseCeqQGbY1eMMhhCDXB3YuYwmtnXuInMEZdjv08Q5CovqhYJLSlZp/8BlaifcahgEgNIFQXmxAF0U0HsNC6W4Dk1gGgQaVmYaZv5ex7uIcFB1qFvlO60kWf82YeRnO5KsFBODOJ1XSNwqjL2GeLSHBSVyQQJBAOsvDmClBsETSdiNSFMz+D9WCnCh1Ip4AoCzA/yG+PRSwYjZDdceP2DXieiZXPlxTFZ7MIXxAafgeyeQA2hpkQUCQQCpkCUSbrZ+nd4BYdnxZOSf0//cUT0o6+3kROX7gsXV7zRAWWxojT6DkGVlduDLZM/hjWeHRjWUxKC/jgbzvundAkBckhUSrWJPNQxoFJRXS6l3JKLPWqOSLVKu3ce/6lCrurc66lSsS9eegrhhuZwDAzmNAMhEsGx6a72OAP2WZ5cRAkBd8cT4X2qw4BpePa6YdcPNYZHCqSfvgje9XwbkwGGH1A3pESJlEsxt7BShkKmfRu1+E/AmHJoXIJHHT5M+fKnpAkA+VfyAAviKeCwUSq+5oUa0B+ozEA3frp/40cKQP7k02aamocAQCDRaC1ZlWffeQqYMnYe1/Mjr/SdX/Ut3X0CC','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (7,'201904035630907729292csharp',1,'',1,'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQAB','MIIEowIBAAKCAQEA5+OvJxeSzf44NxQ/cl7Ii+BzPg2k6sRcvH4ffOtU5Dzq1/oEvg02nxIhmwOHBZmjbmuUu0aLsfglUTAwqfXftfAKZidshsgj9NNh0/kxk0avRZ1UoljWGz/FxVZA0ogbxxhohPZ9jWcD+eBQcIwF2DtHfAJqWWZrYFnCMeHD8mPzxo2kwXSvDzi0vf9I2tKiYvNG26a9FqeYtPOoi81sdS3+70HOMdxP8ejXtyfnKpKz7Dx506LCIRS5moWS3Q5eTLV3NGX/1CSJ8wpQA2DAQTjVhX5eVu7Yqz12t8W+sjWM/tHUR6cgwYYR10p7tSCeCPzkigjGxKm4cYXWtATQJQIDAQABAoIBAHFDsgrrJca+NKEan77ycwx3jnKx4WrWjOF4zVKL9AQjiSYDNgvKknJyPb3kpC/lEoHdxGERHSzJoxib7DkoIqRQYhPxj73pxj5QfYk3P7LLJNNg/LTrpXDb3nL8JV9wIflGf87qQvstZTDJEyFWE4jBs7Hr0BxovWvri8InnzkmERJ1cbGJgNHe1Y3Zo2tw0yaHxQCxLuajP+notRZhD9bEp7uKeI0w9AvlW6k8m/7y10F0BK/TlyW8rQiEC391yOiRYoMcUh4hd2Q9bMx3jngZgX8PXIvZZcup4/pvWlv1alwhB2tsnLdazP62r1MO80vLyLunzGO+7WwCjEYlVaECgYEA+lQRFmbhKaPuAuXMtY31Fbga8nedka5TjnEV7+/kX+yowE2OlNujF+ZG8UTddTxAGv56yVNi/mjRlgD74j8z0eOsgvOq9mwbCrgLhLo51H9O/wAxtb+hBKtC5l50pBr4gER6d8W6EQNTSGojnMIaLXTkAZ5Qf6Z8e2HFVdOn0X0CgYEA7SSrTokwzukt5KldNu5ukyyd+C3D1i6orbg6qD73EP9CfNMfGSBn7dDv9wMSJH01+Ty+RgTROgtjGRDbMJWnfbdt/61NePr9ar5sb6Nbsf7/I0w7cZF5dsaFYgzaOfQYquzXPbLQHkpMT64bqpv/Mwy4F2lFvaYWY5fA4pC2uckCgYEAg75Ym9ybJaoTqky8ttQ2Jy8UZ4VSVQhVC0My02sCWwWXLlXi8y7An+Rec73Ve0yxREOn5WrQT6pkmzh7V/ABWrYi5WxODpCIjtSbo0fLBa3Wqle00b0/hdCITetqIa/cFs1zUrOqICgK3bKWeXqiAkhhcwSZwwSgwOKM04Wn7ZUCgYBvhHX2mbdVJfyJ8kc+hMOE/E9RHRxiBVEXWHJlGi8PVCqNDq8qHr4g7Mdbzprig+s0yKblwHAvrpkseWvKHiZEjVTyDipHgShY4TGXEigVvUd37uppTrLi8xpYcJjS9gH/px7VCdiq1d+q/MJP6coJ1KphgATm2UrgDMYNBWaYWQKBgEHRxrmER7btUF60/YgcqPHFc8RpYQB2ZZE0kyKGDqk2Data1XYUY6vsPAU28yRLAaWr/D2H17iyLkxP80VLm6QhifxCadv90Q/Wl1DFfOJQMW6avyQ0so6G0wFq/LJxaFK4iLXQn1RJnmTp6BYiJMmK2BhFbRzw8ssMoF6ad2rr','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (8,'easyopen_test',2,'G9w0BAQEFAAOCAQ8AMIIBCgKCA',1,'','','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (9,'20190513577548661718777856',1,'',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ','','','2019-08-13 15:18:39','2019-08-13 15:18:39'), + (10,'20190513577548661718777857',1,'',1,'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdGjz3IE2VQteDjQaFacXLCAIqdEIIVcf7LW7f142V55Q0xtcjDTOHjBHExZsG64/Y5WKz4oQVWGnXwtrled8Qg0YAA7ueat8mE8NzJSm9txbfU9hwXB77nJxVkFyaSG1p0IZFrNQpbbUxTX9755deP7DdcSF148LLr091V++S3QIDAQAB','MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ0aPPcgTZVC14ONBoVpxcsIAip0QghVx/stbt/XjZXnlDTG1yMNM4eMEcTFmwbrj9jlYrPihBVYadfC2uV53xCDRgADu55q3yYTw3MlKb23Ft9T2HBcHvucnFWQXJpIbWnQhkWs1ClttTFNf3vnl14/sN1xIXXjwsuvT3VX75LdAgMBAAECgYB68z/nQDa3q/oykDocS21qujfHtfi/wTKjVylAsdezC+wnab6RRhGf8XUuhGARiGWpn8whcBNjCTC8lVju4vQ5IIx4Hb74vwDDMtNXeqwkLmARLYu2ELibauezSeqom8/J8cR3ho7Hr4VHPTiC8qvePRmu8AvXVQz2T7SOhEjDGQJBAOm8XOivr+atiknLbQhmo508ON3sjoN9VMwK9cmnup+ZPCsurJTHRja0MJQNdOXObUVJ6wJhs1PHWT+vITfXGJ8CQQCsESzxOYTkZaqBUFjbWVf1rSwjOOsylweTuq44YIJkHhwMjHf3kN/UTXbxsBPUGeT7/+2K5UwQ9snUPr0yTBcDAkA0FMezBWqxgNu+g7iA1bYBVCjrskkzHVsmuA56Z4hbBZ71lEnaQOjxSYdFhhYVGsEYXlciSbjWoyXM3e4N7jzLAkB0ejv+H33CTsAZQZalBdnxSQTz4vf0CyDp9BkzuMELnQZHyF79i2i5gqbd/N+vWMgVfq4CtC3F3gnKT54rii6ZAkAMBIvHriT5Zbs1fW+oxBP1rHqdsRvqs1zEyIadvJgKAFwFEisryfdw2mWm3vxQQ22RlOquBiZEDIlyM0z2m9PJ','','','2019-08-13 15:18:39','2019-08-13 15:18:39'); +ALTER TABLE `isv_keys` ENABLE KEYS; +UNLOCK TABLES; + + LOCK TABLES `perm_isv_role` WRITE; ALTER TABLE `perm_isv_role` DISABLE KEYS; INSERT INTO `perm_isv_role` (`id`, `isv_id`, `role_code`, `gmt_create`, `gmt_modified`) VALUES @@ -314,8 +368,7 @@ ALTER TABLE `user_info` ENABLE KEYS; UNLOCK TABLES; -INSERT INTO `sop`.`isv_keys` (`app_key`,`sign_type`, `secret`,`key_format`, `public_key_isv`, `private_key_isv`, `public_key_platform`, `private_key_platform`) -select app_key, sign_type, secret, 1, pub_key,pri_key,'','' from isv_info; + SET FOREIGN_KEY_CHECKS = @PREVIOUS_FOREIGN_KEY_CHECKS;