This commit is contained in:
tanghc
2020-10-14 21:02:41 +08:00
parent 1850d6d567
commit 0c4dd04bc7
29 changed files with 536 additions and 441 deletions

View File

@@ -15,11 +15,10 @@ boolean needToken() default false;
@ApiOperation(value="传递token", notes = "传递token")
@Open(value = "story.get.token", needToken = true/* 设置true网关会校验token是否存在 */)
@RequestMapping("token")
public StoryResult token(StoryParam story) {
public StoryResult token(StoryParam story, HttpServletRequest request) {
OpenContext openContext = ServiceContext.getCurrentContext().getOpenContext();
String appAuthToken = openContext.getAppAuthToken();
StoryResult result = new StoryResult();
result.setName("appAuthToken:" + appAuthToken);
result.setName("appAuthToken:" + openContext.getAppAuthToken());
return result;
}
```

View File

@@ -13,6 +13,7 @@ import com.gitee.sop.adminserver.api.service.param.RouteAddParam;
import com.gitee.sop.adminserver.api.service.param.RouteDeleteParam;
import com.gitee.sop.adminserver.api.service.param.RoutePermissionParam;
import com.gitee.sop.adminserver.api.service.param.RouteSearchParam;
import com.gitee.sop.adminserver.api.service.param.RouteStatusUpdateParam;
import com.gitee.sop.adminserver.api.service.param.RouteUpdateParam;
import com.gitee.sop.adminserver.api.service.result.RouteVO;
import com.gitee.sop.adminserver.bean.RouteConfigDto;
@@ -123,6 +124,26 @@ public class RouteApi {
this.updateRouteConfig(param);
}
@Api(name = "route.status.update")
@ApiDocMethod(description = "修改路由状态")
void updateRouteStatus(RouteStatusUpdateParam param) {
String routeId = param.getId();
ConfigRouteBase configRouteBase = configRouteBaseMapper.getByColumn("route_id", routeId);
boolean doSave = configRouteBase == null;
if (doSave) {
configRouteBase = new ConfigRouteBase();
configRouteBase.setRouteId(routeId);
}
configRouteBase.setStatus(param.getStatus());
int i = doSave ? configRouteBaseMapper.save(configRouteBase)
: configRouteBaseMapper.update(configRouteBase);
if (i > 0) {
this.sendMsg(configRouteBase);
}
}
@Api(name = "route.del")
@ApiDocMethod(description = "删除路由")
void delRoute(RouteDeleteParam param) {

View File

@@ -75,6 +75,7 @@ public class ServiceApi {
return serviceId.contains(param.getServiceId());
}
})
.sorted()
.collect(Collectors.toList());
}

View File

@@ -0,0 +1,32 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author tanghc
*/
@Getter
@Setter
public class RouteStatusUpdateParam {
/**
* 路由的Id
*/
@NotBlank(message = "id不能为空")
@ApiDocField(description = "路由id")
private String id;
/**
* 状态
*/
@NotNull
@ApiDocField(description = "状态0审核1启用2禁用")
private Byte status;
}

View File

@@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.c6dfb7ee.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],d=0,l=[];d<a.length;d++)c=a[d],u[c]&&l.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);h&&h(n);while(l.length)l.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"66819987","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d32e7":"213708f2","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-4bdcb5ea":"cf292569","chunk-4de1c2b6":"e74e3d03","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"52bc6b2c","chunk-9f479afe":"3e73ea9f","chunk-c3ce42fe":"9517b588"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-4bdcb5ea":1,"chunk-4de1c2b6":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d32e7":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-4bdcb5ea":"b23e7407","chunk-4de1c2b6":"a37cd815","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"3b12267b","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var l=document.getElementsByTagName("style");for(a=0;a<l.length;a++){i=l[a],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),t(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,f.nc&&d.setAttribute("nonce",f.nc),d.src=a(e),i=function(n){d.onerror=d.onload=null,clearTimeout(l);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var l=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var l=0;l<i.length;l++)n(i[l]);var h=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.2e027154.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.6095bfbf.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],d=0,l=[];d<a.length;d++)c=a[d],u[c]&&l.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);h&&h(n);while(l.length)l.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-25908fca":"02b977ea","chunk-2c1f2e8f":"f092c0a0","chunk-2d0d32e7":"e7c489be","chunk-2d2085ef":"91d75f3c","chunk-2d221c34":"20057287","chunk-30c6c34f":"b288bbf5","chunk-4de1c2b6":"e74e3d03","chunk-73b2dcec":"60c5d8e9","chunk-9b31c83a":"494fc338","chunk-9f479afe":"2093f9d0","chunk-c3ce42fe":"9517b588"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-25908fca":1,"chunk-2c1f2e8f":1,"chunk-30c6c34f":1,"chunk-4de1c2b6":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-c3ce42fe":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-25908fca":"a66354ec","chunk-2c1f2e8f":"0314067f","chunk-2d0d32e7":"31d6cfe0","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-30c6c34f":"3b12267b","chunk-4de1c2b6":"a37cd815","chunk-73b2dcec":"ed391cc5","chunk-9b31c83a":"c4612b4a","chunk-9f479afe":"31d6cfe0","chunk-c3ce42fe":"6b789903"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var l=document.getElementsByTagName("style");for(a=0;a<l.length;a++){i=l[a],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),t(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,f.nc&&d.setAttribute("nonce",f.nc),d.src=a(e),i=function(n){d.onerror=d.onload=null,clearTimeout(l);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var l=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var l=0;l<i.length;l++)n(i[l]);var h=d;t()})([]);</script><script src=static/js/chunk-elementUI.298ac98c.js></script><script src=static/js/chunk-libs.75deb05f.js></script><script src=static/js/app.f323bdd7.js></script></body></html>

View File

@@ -1 +1 @@
.custom-tree-node{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-size:14px;padding-right:8px}.el-input.is-disabled .el-input__inner,.el-radio__input.is-disabled+span.el-radio__label{color:#909399}.limit-tip[data-v-08125a7c]{cursor:pointer;margin-left:10px}
.custom-tree-node{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-size:14px;padding-right:8px}.el-input.is-disabled .el-input__inner,.el-radio__input.is-disabled+span.el-radio__label{color:#909399}.roles-content{cursor:pointer;color:#20a0ff}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0d32e7"],{"5c58":function(t,e,l){"use strict";l.r(e);var a=function(){var t=this,e=t.$createElement,l=t._self._c||e;return l("div",{staticClass:"app-container"},[l("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[l("el-form-item",{attrs:{label:"接口名"}},[l("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"输入接口名或版本号"},model:{value:t.searchFormData.routeId,callback:function(e){t.$set(t.searchFormData,"routeId",e)},expression:"searchFormData.routeId"}})],1),t._v(" "),l("el-form-item",[l("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.loadTable}},[t._v("搜索")])],1)],1),t._v(" "),l("el-alert",{staticStyle:{"margin-bottom":"10px"},attrs:{title:"监控数据保存在网关服务器,重启网关数据会清空。",type:"info",closable:!1}}),t._v(" "),l("el-table",{attrs:{data:t.tableData,border:"","default-expand-all":!1,"row-key":"id",height:"500","empty-text":"无数据"}},[l("el-table-column",{attrs:{fixed:"",prop:"instanceId",label:"网关实例",width:"200"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.children?t._e():l("span",[t._v(t._s(e.row.instanceId))])]}}])}),t._v(" "),l("el-table-column",{attrs:{fixed:"",prop:"name",label:"接口名 (版本号)",width:"280"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v("\n "+t._s(e.row.name+(e.row.version?" ("+e.row.version+")":""))+"\n ")]}}])}),t._v(" "),l("el-table-column",{attrs:{prop:"serviceId",label:"serviceId",width:"170"}}),t._v(" "),l("el-table-column",{attrs:{prop:"maxTime",label:"最大耗时(ms)",width:"125"}},[l("template",{slot:"header"},[t._v("\n 最大耗时(ms)\n "),l("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"},on:{click:function(e){return t.$alert("耗时计算:签名验证成功后开始,微服务返回结果后结束")}}})])],2),t._v(" "),l("el-table-column",{attrs:{prop:"minTime",label:"最小耗时(ms)",width:"120"}}),t._v(" "),l("el-table-column",{attrs:{prop:"avgTime",label:"平均耗时(ms)",width:"120"}}),t._v(" "),l("el-table-column",{attrs:{prop:"totalCount",label:"总调用次数",width:"100"}}),t._v(" "),l("el-table-column",{attrs:{prop:"successCount",label:"成功次数",width:"100"}}),t._v(" "),l("el-table-column",{attrs:{prop:"errorCount",label:"失败次数",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.errorCount>0?l("el-link",{staticStyle:{"text-decoration":"underline"},attrs:{underline:!1,type:"danger"},on:{click:function(l){return t.onShowErrorDetail(e.row)}}},[t._v("\n "+t._s(e.row.errorCount)+"\n ")]):t._e(),t._v(" "),0===e.row.errorCount?l("span",[t._v("0")]):t._e()]}}])},[l("template",{slot:"header"},[t._v("\n 失败次数\n "),l("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"},on:{click:function(e){return t.$alert("只统计微服务返回的未知错误JSR-303验证错误算作成功")}}})])],2)],1),t._v(" "),l("el-dialog",{attrs:{title:"错误详情",visible:t.logDetailVisible,width:"60%"},on:{"update:visible":function(e){t.logDetailVisible=e}}},[l("div",{staticStyle:{"overflow-x":"auto"},domProps:{innerHTML:t._s(t.errorMsgDetail)}}),t._v(" "),l("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[l("el-button",{attrs:{type:"primary"},on:{click:function(e){t.logDetailVisible=!1}}},[t._v("关 闭")])],1)])],1)},o=[],r={data:function(){return{searchFormData:{routeId:""},tableData:[],logDetailVisible:!1,errorMsgDetail:""}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("monitor.data.list",this.searchFormData,function(t){var e=t.data;this.tableData=e.monitorInfoData})},onShowErrorDetail:function(t){var e=t.errorMsgList;this.errorMsgDetail=e.length>0?e.join("<br>"):"无内容",this.logDetailVisible=!0}}},i=r,n=l("2877"),s=Object(n["a"])(i,a,o,!1,null,null,null);e["default"]=s.exports}}]);

View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0d32e7"],{"5c58":function(t,e,a){"use strict";a.r(e);var l=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"app-container"},[a("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[a("el-form-item",{attrs:{label:"接口名"}},[a("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"输入接口名或版本号"},model:{value:t.searchFormData.routeId,callback:function(e){t.$set(t.searchFormData,"routeId",e)},expression:"searchFormData.routeId"}})],1),t._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.loadTable}},[t._v("搜索")])],1)],1),t._v(" "),a("el-alert",{staticStyle:{"margin-bottom":"10px"},attrs:{title:"监控数据保存在网关服务器,重启网关数据会清空。",type:"info",closable:!1}}),t._v(" "),a("el-table",{attrs:{data:t.tableData,border:"","default-expand-all":!1,"row-key":"id",height:"500","empty-text":"无数据"}},[a("el-table-column",{attrs:{fixed:"",prop:"instanceId",label:"网关实例",width:"200"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.children?t._e():a("span",[t._v(t._s(e.row.instanceId))])]}}])}),t._v(" "),a("el-table-column",{attrs:{fixed:"",prop:"name",label:"接口名 (版本号)",width:"280"},scopedSlots:t._u([{key:"default",fn:function(e){return[t._v("\n "+t._s(e.row.name+(e.row.version?" ("+e.row.version+")":""))+"\n ")]}}])}),t._v(" "),a("el-table-column",{attrs:{prop:"serviceId",label:"serviceId",width:"170"}}),t._v(" "),a("el-table-column",{attrs:{prop:"maxTime",label:"最大耗时(ms)",width:"125"}},[a("template",{slot:"header"},[t._v("\n 最大耗时(ms)\n "),a("el-tooltip",{attrs:{effect:"dark",content:"耗时计算:签名验证成功后开始,微服务返回结果后结束",placement:"top"}},[a("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"}})])],1)],2),t._v(" "),a("el-table-column",{attrs:{prop:"minTime",label:"最小耗时(ms)",width:"120"}}),t._v(" "),a("el-table-column",{attrs:{prop:"avgTime",label:"平均耗时(ms)",width:"120"}}),t._v(" "),a("el-table-column",{attrs:{prop:"totalCount",label:"总调用次数",width:"100"}}),t._v(" "),a("el-table-column",{attrs:{prop:"successCount",label:"成功次数",width:"100"}}),t._v(" "),a("el-table-column",{attrs:{prop:"errorCount",label:"失败次数",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.errorCount>0?a("el-link",{staticStyle:{"text-decoration":"underline"},attrs:{underline:!1,type:"danger"},on:{click:function(a){return t.onShowErrorDetail(e.row)}}},[t._v("\n "+t._s(e.row.errorCount)+"\n ")]):t._e(),t._v(" "),0===e.row.errorCount?a("span",[t._v("0")]):t._e()]}}])},[a("template",{slot:"header"},[t._v("\n 失败次数\n "),a("el-tooltip",{attrs:{effect:"dark",content:"只统计微服务返回的未知错误JSR-303验证错误算作成功",placement:"top-end"}},[a("i",{staticClass:"el-icon-question",staticStyle:{cursor:"pointer"}})])],1)],2)],1),t._v(" "),a("el-dialog",{attrs:{title:"错误详情",visible:t.logDetailVisible,width:"60%"},on:{"update:visible":function(e){t.logDetailVisible=e}}},[a("div",{staticStyle:{"overflow-x":"auto"},domProps:{innerHTML:t._s(t.errorMsgDetail)}}),t._v(" "),a("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[a("el-button",{attrs:{type:"primary"},on:{click:function(e){t.logDetailVisible=!1}}},[t._v("关 闭")])],1)])],1)},o=[],r={data:function(){return{searchFormData:{routeId:""},tableData:[],logDetailVisible:!1,errorMsgDetail:""}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("monitor.data.list",this.searchFormData,function(t){var e=t.data;this.tableData=e.monitorInfoData})},onShowErrorDetail:function(t){var e=t.errorMsgList;this.errorMsgDetail=e.length>0?e.join("<br>"):"无内容",this.logDetailVisible=!0}}},i=r,n=a("2877"),s=Object(n["a"])(i,l,o,!1,null,null,null);e["default"]=s.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -63,3 +63,6 @@ div:focus {
.app-container {
padding: 20px;
}
.cell .el-button {padding: 0;}
span.tip {color: #909399;font-size: 12px;}

View File

@@ -94,6 +94,18 @@ Object.assign(Vue.prototype, {
}
}).catch(function() {})
},
downloadText(filename, text) {
const element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element);
},
/**
* 重置表单
* @param formName 表单元素的ref

View File

@@ -15,14 +15,9 @@
fit
highlight-current-row
>
<el-table-column
prop="id"
label="ID"
width="80"
/>
<el-table-column
prop="appKey"
label="appId"
label="AppId"
width="250"
/>
<el-table-column
@@ -37,11 +32,11 @@
<el-table-column
prop="roleList"
label="角色"
width="100"
width="150"
:show-overflow-tooltip="true"
>
<template slot-scope="scope">
<div v-html="roleRender(scope.row)"></div>
<span v-html="roleRender(scope.row)"></span>
</template>
</el-table-column>
<el-table-column
@@ -59,24 +54,20 @@
label="添加时间"
width="160"
/>
<el-table-column
prop="gmtModified"
label="修改时间"
width="160"
/>
<el-table-column
prop="remark"
label="备注"
width="120"
width="200"
:show-overflow-tooltip="true"
/>
<el-table-column
label="操作"
width="150"
width="200"
>
<template slot-scope="scope">
<el-button type="text" size="mini" @click="onTableUpdate(scope.row)">修改</el-button>
<el-button type="text" size="mini" @click="onKeysUpdate(scope.row)">秘钥管理</el-button>
<el-button type="text" size="mini" @click="onExportKeys(scope.row)">导出秘钥</el-button>
</template>
</el-table-column>
</el-table>
@@ -281,6 +272,20 @@ export default {
onKeysUpdate: function(row) {
this.$router.push({ path: `keys?appKey=${row.appKey}` })
},
onExportKeys: function(row) {
this.post('isv.keys.get', { appKey: row.appKey }, function(resp) {
const data = resp.data
const appId = data.appKey
const privateKeyIsv = data.privateKeyIsv
const publicKeyPlatform = data.publicKeyPlatform
let content = `AppId${appId}\n\n开发者私钥\n${privateKeyIsv}\n\n`
if (publicKeyPlatform) {
content = content + `平台公钥:\n${publicKeyPlatform}`
}
const filename = `${appId}.txt`
this.downloadText(filename, content)
})
},
onSizeChange: function(size) {
this.searchFormData.pageSize = size
this.loadTable()

View File

@@ -1,46 +1,12 @@
<template>
<div class="app-container">
<el-container>
<el-aside style="min-height: 300px;width: 250px;">
<el-input v-model="filterText" prefix-icon="el-icon-search" placeholder="搜索服务..." style="margin-bottom:20px;" size="mini" clearable />
<el-tree
ref="tree2"
:data="treeData"
:props="defaultProps"
:filter-node-method="filterNode"
:highlight-current="true"
:expand-on-click-node="false"
empty-text="无数据"
node-key="id"
class="filter-tree"
default-expand-all
@node-click="onNodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<div>
<el-tooltip v-show="data.custom" content="自定义服务" class="item" effect="light" placement="left">
<i class="el-icon-warning-outline"></i>
</el-tooltip>
<span v-if="data.label.length < serviceTextLimitSize">{{ data.label }}</span>
<span v-else>
<el-tooltip :content="data.label" class="item" effect="light" placement="right">
<span>{{ data.label.substring(0, serviceTextLimitSize) + '...' }}</span>
</el-tooltip>
</span>
<div v-if="tabsData.length === 0">
无服务
</div>
<span>
<el-button
v-if="data.custom === 1"
type="text"
size="mini"
icon="el-icon-delete"
title="删除服务"
@click.stop="() => onDelService(data)"/>
</span>
</span>
</el-tree>
</el-aside>
<el-main style="padding-top:0">
<div v-else>
<el-tabs v-model="tabsActive" type="card" @tab-click="selectTab">
<el-tab-pane v-for="tabName in tabsData" :key="tabName" :label="tabName" :name="tabName" />
</el-tabs>
<el-form :inline="true" :model="searchFormData" class="demo-form-inline" size="mini">
<el-form-item label="路由ID">
<el-input v-model="searchFormData.routeId" placeholder="接口名,支持模糊查询" clearable />
@@ -75,7 +41,19 @@
width="120"
>
<template slot="header" slot-scope>
限流策略 <i class="el-icon-question" style="cursor: pointer" @click="onLimitTypeTipClick"></i>
限流策略
<el-popover
ref="popover"
placement="top"
title="限流策略"
width="500"
trigger="hover">
<div>
<p>窗口策略每秒处理固定数量的请求超出请求数量返回错误信息</p>
<p>令牌桶策略每秒放置固定数量的令牌数每个请求进来后先去拿令牌拿到了令牌才能继续拿不到则等候令牌重新生成了再拿</p>
</div>
</el-popover>
<i v-popover:popover class="el-icon-question" style="cursor: pointer"></i>
</template>
<template slot-scope="scope">
<span v-if="scope.row.limitType === 1">窗口策略</span>
@@ -143,6 +121,7 @@
@size-change="onSizeChange"
@current-change="onPageIndexChange"
/>
</div>
<!-- dialog -->
<el-dialog
:title="dlgTitle"
@@ -188,7 +167,18 @@
<el-radio :label="1">窗口策略</el-radio>
<el-radio :label="2">令牌桶策略</el-radio>
</el-radio-group>
<i class="el-icon-question limit-tip" @click="onLimitTypeTipClick"></i>
<el-popover
ref="popover"
placement="top"
title="限流策略"
width="500"
trigger="hover">
<div>
<p>窗口策略每秒处理固定数量的请求超出请求数量返回错误信息</p>
<p>令牌桶策略每秒放置固定数量的令牌数每个请求进来后先去拿令牌拿到了令牌才能继续拿不到则等候令牌重新生成了再拿</p>
</div>
</el-popover>
<i v-popover:popover class="el-icon-question" style="cursor: pointer"></i>
</el-form-item>
<el-form-item label="开启状态">
<el-switch
@@ -202,9 +192,7 @@
</el-form-item>
<el-form-item label="排序" prop="orderIndex">
<el-input-number v-model="limitDialogFormData.orderIndex" controls-position="right" :min="0" />
<el-tooltip class="item" content="值小优先执行" placement="top">
<i class="el-icon-question limit-tip"></i>
</el-tooltip>
<span class="tip" style="margin-left: 10px">值小优先执行</span>
</el-form-item>
<el-form-item v-show="isWindowType()" label="请求数" prop="execCountPerSecond" :rules="isWindowType() ? rulesLimit.execCountPerSecond : []">
<el-input-number v-model="limitDialogFormData.durationSeconds" controls-position="right" :min="1" /> 秒可处理
@@ -222,8 +210,6 @@
<el-button type="primary" @click="onLimitDialogSave"> </el-button>
</div>
</el-dialog>
</el-main>
</el-container>
</div>
</template>
<style>
@@ -242,6 +228,8 @@
export default {
data() {
return {
tabsData: [],
tabsActive: '',
serviceTextLimitSize: 20,
filterText: '',
treeData: [],
@@ -320,9 +308,20 @@ export default {
}
},
created() {
this.loadTree()
this.loadTabs()
},
methods: {
loadTabs() {
this.post('registry.service.list', {}, function(resp) {
this.tabsData = resp.data
this.$nextTick(() => {
if (this.tabsData.length > 0) {
this.tabsActive = this.tabsData[0]
this.loadLimitData()
}
})
})
},
// 加载树
loadTree: function() {
this.post('registry.service.list', {}, function(resp) {
@@ -344,6 +343,15 @@ export default {
this.loadRouteList(this.serviceId)
}
},
selectTab() {
this.loadLimitData()
},
loadLimitData() {
this.serviceId = this.tabsActive
this.searchFormData.serviceId = this.serviceId
this.loadTable()
this.loadRouteList(this.serviceId)
},
/**
* 数组转成树状结构
* @param data 数据结构 [{
@@ -506,9 +514,3 @@ export default {
}
}
</script>
<style scoped>
.limit-tip {
cursor: pointer;
margin-left: 10px;
}
</style>

View File

@@ -54,11 +54,9 @@
>
<template slot="header">
最大耗时(ms)
<i
class="el-icon-question"
style="cursor: pointer"
@click="$alert('耗时计算:签名验证成功后开始,微服务返回结果后结束')"
></i>
<el-tooltip effect="dark" content="耗时计算:签名验证成功后开始,微服务返回结果后结束" placement="top">
<i class="el-icon-question" style="cursor: pointer"></i>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
@@ -88,11 +86,9 @@
>
<template slot="header">
失败次数
<i
class="el-icon-question"
style="cursor: pointer"
@click="$alert('只统计微服务返回的未知错误JSR-303验证错误算作成功')"
></i>
<el-tooltip effect="dark" content="只统计微服务返回的未知错误JSR-303验证错误算作成功" placement="top-end">
<i class="el-icon-question" style="cursor: pointer"></i>
</el-tooltip>
</template>
<template slot-scope="scope">
<el-link

View File

@@ -1,65 +1,13 @@
<template>
<div class="app-container">
<el-container>
<el-aside style="min-height: 300px;width: 250px;">
<el-button
type="primary"
plain
size="mini"
icon="el-icon-plus"
style="display: none;"
@click.stop="addService"
>
新建服务
</el-button>
<el-input
v-model="filterText"
prefix-icon="el-icon-search"
placeholder="搜索服务..."
style="margin-bottom:10px;margin-top:10px;"
size="mini"
clearable
/>
<el-tree
ref="serviceTree"
:data="treeData"
:props="defaultProps"
:filter-node-method="filterNode"
:highlight-current="true"
:expand-on-click-node="false"
empty-text="无数据"
node-key="serviceId"
class="filter-tree"
default-expand-all
@node-click="onNodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<div>
<el-tooltip v-show="data.custom" content="自定义服务" class="item" effect="light" placement="left">
<i class="el-icon-warning-outline"></i>
</el-tooltip>
<span v-if="data.label.length < serviceTextLimitSize">{{ data.label }}</span>
<span v-else>
<el-tooltip :content="data.label" class="item" effect="light" placement="right">
<span>{{ data.label.substring(0, serviceTextLimitSize) + '...' }}</span>
</el-tooltip>
</span>
<div v-if="tabsData.length === 0">
无服务
</div>
<span>
<el-button
v-if="data.custom === 1"
type="text"
size="mini"
icon="el-icon-delete"
title="删除服务"
@click.stop="() => onDelService(data)"
/>
</span>
</span>
</el-tree>
</el-aside>
<el-main style="padding-top:0">
<el-form :inline="true" :model="searchFormData" class="demo-form-inline" size="mini">
<div v-else>
<el-tabs v-model="tabsActive" type="card" @tab-click="selectTab">
<el-tab-pane v-for="tabName in tabsData" :key="tabName" :label="tabName" :name="tabName" />
</el-tabs>
<el-form :inline="true" :model="searchFormData" class="demo-form-inline" size="mini" @submit.native.prevent>
<el-form-item label="路由名称">
<el-input v-model="searchFormData.id" :clearable="true" placeholder="输入接口名或版本号" />
</el-form-item>
@@ -70,7 +18,7 @@
<el-checkbox v-model="searchFormData.needToken">需要token</el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="onSearchTable">查询</el-button>
<el-button type="primary" icon="el-icon-search" native-type="submit" @click="onSearchTable">查询</el-button>
</el-form-item>
</el-form>
<el-button
@@ -91,25 +39,28 @@
<el-table-column
prop="name"
label="接口名 (版本号)"
width="350"
>
<template slot-scope="scope">
{{ scope.row.name + (scope.row.version ? ' (' + scope.row.version + ')' : '') }}
{{ getNameVersion(scope.row) }}
</template>
</el-table-column>
<el-table-column
prop="roles"
label="访问权限"
width="150"
:show-overflow-tooltip="true"
>
<template slot-scope="scope">
<span v-html="roleRender(scope.row)"></span>
<span v-if="!scope.row.permission">
公开
</span>
<span v-else class="roles-content" @click="onTableAuth(scope.row)" v-html="roleRender(scope.row)"></span>
</template>
</el-table-column>
<el-table-column
prop="ignoreValidate"
label="签名校验"
width="80"
width="120"
>
<template slot-scope="scope">
<span v-if="scope.row.ignoreValidate === 0">校验</span>
@@ -129,7 +80,7 @@
<el-table-column
prop="needToken"
label="需要token"
width="100"
width="120"
>
<template slot-scope="scope">
<span v-if="scope.row.needToken === 1" style="font-weight: bold;color: #303133;"></span>
@@ -142,19 +93,14 @@
width="80"
>
<template slot-scope="scope">
<span v-if="scope.row.status === 0" style="color:#E6A23C">待审核</span>
<span v-if="scope.row.status === 1" style="color:#67C23A">已启用</span>
<span v-if="scope.row.status === 2" style="color:#F56C6C">已禁用</span>
</template>
</el-table-column>
<el-table-column
label="操作"
width="100"
>
<template slot-scope="scope">
<el-button type="text" size="mini" @click="onTableUpdate(scope.row)">修改</el-button>
<el-button v-if="scope.row.permission" type="text" size="mini" @click="onTableAuth(scope.row)">授权</el-button>
<el-button v-if="scope.row.custom" type="text" size="mini" @click="onTableDel(scope.row)">删除</el-button>
<el-switch
v-model="scope.row.status"
active-color="#13ce66"
inactive-color="#ff4949"
:active-value="1"
:inactive-value="2"
@change="onChangeStatus(scope.row)"
/>
</template>
</el-table-column>
</el-table>
@@ -169,8 +115,7 @@
@size-change="onSizeChange"
@current-change="onPageIndexChange"
/>
</el-main>
</el-container>
</div>
<!-- route dialog -->
<el-dialog
:title="routeDialogTitle"
@@ -270,11 +215,14 @@
}
.el-input.is-disabled .el-input__inner {color: #909399;}
.el-radio__input.is-disabled+span.el-radio__label {color: #909399;}
.roles-content { cursor: pointer;color: #20a0ff }
</style>
<script>
export default {
data() {
return {
tabsData: [],
tabsActive: '',
serviceTextLimitSize: 20,
filterText: '',
treeData: [],
@@ -352,10 +300,21 @@ export default {
}
},
created() {
this.loadTree()
this.loadTabs()
this.loadRouteRole()
},
methods: {
loadTabs() {
this.post('registry.service.list', {}, function(resp) {
this.tabsData = resp.data
this.$nextTick(() => {
if (this.tabsData.length > 0) {
this.tabsActive = this.tabsData[0]
this.loadRouteData()
}
})
})
},
// 加载树
loadTree: function() {
this.post('registry.service.list', {}, function(resp) {
@@ -383,6 +342,14 @@ export default {
this.loadTable()
}
},
selectTab() {
this.loadRouteData()
},
loadRouteData() {
this.serviceId = this.tabsActive
this.searchFormData.serviceId = this.serviceId
this.loadTable()
},
/**
* 数组转成树状结构
* @param data 数据结构 [{
@@ -421,6 +388,9 @@ export default {
result.push(root)
return result
},
getNameVersion(row) {
return row.name + (row.version ? ' (' + row.version + ')' : '')
},
// table
loadTable: function(param) {
if (!this.searchFormData.serviceId) {
@@ -469,6 +439,30 @@ export default {
})
})
},
// element-ui switch开关 点击按钮后,弹窗确认后再改变开关状态
// https://blog.csdn.net/Gomeer/article/details/103697593
onChangeStatus: function(row) {
const newStatus = row.status
const oldStatus = newStatus === 1 ? 2 : 1
// 先将状态改成原来的值
row.status = oldStatus
const nameVersion = this.getNameVersion(row)
const msg = oldStatus === 1 ? `确认要禁用 ${nameVersion} 吗?` : `确认要启用 ${nameVersion} 吗?`
this.confirm(msg, function(done) {
const data = {
id: row.id,
status: newStatus
}
// 'route.role.update', this.authDialogFormData
this.post('route.status.update', data, function() {
done()
row.status = newStatus
})
}, (done) => {
row.status = oldStatus
done()
})
},
onCloseRouteDialog: function() {
this.resetForm('routeDialogFormRef')
},
@@ -495,20 +489,17 @@ export default {
})
},
roleRender: function(row) {
if (!row.permission) {
return '(公开)'
}
const html = []
const roles = row.roles
for (let i = 0; i < roles.length; i++) {
html.push(roles[i].description)
}
return html.length > 0 ? html.join(', ') : '<span class="x-red">未授权</span>'
return html.length > 0 ? html.join(', ') : '点击授权'
},
onRouteDialogSave: function() {
this.$refs.routeDialogFormRef.validate((valid) => {
if (valid) {
const uri = this.routeDialogFormData.id ? 'route.update' : 'route.add'
const uri = this.routeDialogFormData.id ? 'route.status.update' : 'route.add'
this.routeDialogFormData.serviceId = this.serviceId
this.post(uri, this.routeDialogFormData, function() {
this.routeDialogVisible = false

View File

@@ -106,7 +106,7 @@
<el-tabs v-model="tabsActiveName" type="card">
<el-tab-pane label="灰度用户" name="first">
<el-alert
title="可以是appId或IP地址多个用英文逗号隔开"
title="可以是AppId或IP地址多个用英文逗号隔开"
type="info"
:closable="false"
style="margin-bottom: 20px;"
@@ -114,13 +114,18 @@
<el-form-item prop="userKeyContent">
<el-input
v-model="grayForm.userKeyContent"
placeholder="可以是appId或IP地址多个用英文逗号隔开"
placeholder="可以是AppId或IP地址多个用英文逗号隔开"
type="textarea"
:rows="6"
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="接口配置" name="second">
<el-alert
title="灰度接口:接口名相同,版本号不同"
type="info"
:closable="false"
/>
<el-form-item>
<el-button type="text" @click="addNameVersion">新增灰度接口</el-button>
</el-form-item>
@@ -138,7 +143,8 @@
老接口
<el-select
v-model="grayRouteConfig.oldRouteId"
style="margin-right: 10px;"
filterable
style="margin-right: 10px;width: 250px"
@change="onChangeOldRoute(grayRouteConfig)"
>
<el-option
@@ -159,7 +165,9 @@
灰度接口
<el-select
v-model="grayRouteConfig.newVersion"
filterable
no-data-text="无数据"
style="width: 250px"
>
<el-option
v-for="routeNew in getGraySelectData(grayRouteConfig.oldRouteId)"

View File

@@ -1,7 +1,9 @@
package com.gitee.sop.storyweb.controller;
import com.gitee.sop.servercommon.annotation.Open;
import com.gitee.sop.servercommon.bean.OpenContext;
import com.gitee.sop.servercommon.bean.ParamNames;
import com.gitee.sop.servercommon.bean.ServiceContext;
import com.gitee.sop.storyweb.controller.param.StoryParam;
import com.gitee.sop.storyweb.controller.result.StoryResult;
import io.swagger.annotations.Api;
@@ -24,9 +26,9 @@ public class Example1007_TokenController {
@Open(value = "story.get.token", needToken = true/* 设置true网关会校验token是否存在 */)
@RequestMapping("token")
public StoryResult token(StoryParam story, HttpServletRequest request) {
String appAuthToken = request.getParameter(ParamNames.APP_AUTH_TOKEN_NAME);
OpenContext openContext = ServiceContext.getCurrentContext().getOpenContext();
StoryResult result = new StoryResult();
result.setName("appAuthToken:" + appAuthToken);
result.setName("appAuthToken:" + openContext.getAppAuthToken());
return result;
}
}

View File

@@ -0,0 +1,23 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class MyConfig {
@PostConstruct
public void after() {
ApiConfig.getInstance().setTokenValidator(apiParam -> {
// 获取客户端传递过来的token
String token = apiParam.fetchAccessToken();
return !StringUtils.isBlank(token);
// TODO: 校验token有效性可以从redis中读取
// 返回true表示这个token真实、有效
});
}
}

View File

@@ -102,7 +102,7 @@ public class AllInOneTest extends TestBase {
.version("1.0")
.ignoreSign(true)
.bizContent(new BizContent().add("id", "222").add("name", "忽略222"))
.httpMethod(HttpTool.HTTPMethod.GET);
.httpMethod(HttpTool.HTTPMethod.POST);
client.execute(requestBuilder);
}