路由修改

1.x
tanghc 6 years ago
parent 2231fdece1
commit 48b0ed87a1
  1. 2
      sop-admin/sop-admin-front/assets/css/xadmin.css
  2. 15
      sop-admin/sop-admin-front/assets/js/ApiUtil.js
  3. 24
      sop-admin/sop-admin-front/assets/js/common.js
  4. 2
      sop-admin/sop-admin-front/assets/js/lib.js
  5. 30
      sop-admin/sop-admin-front/assets/js/profile.js
  6. 67
      sop-admin/sop-admin-front/pages/service/routeManager.html
  7. 150
      sop-admin/sop-admin-front/pages/service/routeManager.js
  8. 4
      sop-admin/sop-admin-front/pages/service/serviceList.html
  9. 13
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteListApi.java
  10. 57
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/UpdateRouteParam.java
  11. 39
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayRouteDefinition.java
  12. 13
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ZookeeperContext.java
  13. 6
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/BaseRouteDefinition.java
  14. 2
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayZookeeperRouteManager.java
  15. 4
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/SopRouteLocator.java
  16. 1
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulRouteDefinition.java
  17. 2
      sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/route/ZuulZookeeperRouteManager.java
  18. 17
      sop-service-common/src/main/java/com/gitee/sop/servercommon/manager/ServiceZookeeperApiMetaManager.java
  19. 34
      sop-service-common/src/main/java/com/gitee/sop/servercommon/route/GatewayRouteDefinition.java

@ -118,7 +118,7 @@ body{
width: 100%;
}
.x-body{
padding: 20px;
padding: 10px;
}
.x-nav{
padding: 0 20px;

@ -5,6 +5,18 @@ var ApiUtil = (function () {
// 接口URL,更改此处即可
var url = 'http://localhost:8082/api';
var URI_CHAR = '/';
var params = {};
(function () {
var aPairs, aTmp;
var queryString = window.location.search.toString();
queryString = queryString.substring(1, queryString.length); //remove "?"
aPairs = queryString.split("&");
for (var i = 0; i < aPairs.length; i++) {
aTmp = aPairs[i].split("=");
params[aTmp[0]] = decodeURIComponent(aTmp[1]);
}
})();
function formatUri(uri) {
if (uri.substring(0, 1) !== URI_CHAR) {
@ -49,5 +61,8 @@ var ApiUtil = (function () {
}
return url + formatUri(uri);
}
, getParam: function (paramName) {
return params[paramName];
}
}
})();

@ -1,24 +0,0 @@
var Common = (function () {
function initProfiles() {
var $profileList = $('#profileList');
if ($profileList.length > 0) {
ApiUtil.post('system.profile.list', {}, function (resp) {
var list = resp.data;
var html = [];
for (var i = 0; i < list.length; i++) {
html.push('<li' + (i == 0 ? ' class="layui-this"' : '') + '>' + list[i] + '</li>');
}
$profileList.html(html.join(''))
$profileList.find('li').on('click', function () {
window.profile = $(this).text();
});
});
}
}
initProfiles();
return {}
})();

@ -14,7 +14,7 @@ var lib = (function () {
,'../../assets/lib/layui/layui.js'
,'../../assets/lib/easyopen/sdk.js'
,'../../assets/js/ApiUtil.js'
,'../../assets/js/common.js'
,'../../assets/js/profile.js'
]
var jsArr = [];

@ -0,0 +1,30 @@
;(function () {
var currentProfile = ApiUtil.getParam('profile') || 'default';
ApiUtil.post('system.profile.list', {}, function (resp) {
var profileList = resp.data;
var html = ['<div class="layui-tab layui-tab-brief" style="margin-top: 0px;">'];
html.push('<ul id="profileList" class="layui-tab-title">')
for (var i = 0; i < profileList.length; i++) {
var profile = profileList[i];
var cls = currentProfile == profile ? 'layui-this' : '';
html.push('<li><a class="' + cls + '" href="' + getCurrentPage(profile) + '">' + profile + '</a></li>');
}
html.push('</ul>')
html.push('</div>')
$('.x-body').prepend(html.join(''));
});
function getCurrentPage(profile) {
var currentUrl = location.href.toString();
var indexStart = currentUrl.lastIndexOf('/') + 1;
var indexEnd = currentUrl.lastIndexOf('?');
var page = indexEnd > -1
? currentUrl.substring(indexStart, indexEnd)
: currentUrl.substring(indexStart);
return page + '?q=' + new Date().getTime() + '&profile=' + profile;
}
window.profile = currentProfile;
})();

@ -22,37 +22,46 @@
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>
<div class="x-body">
<div class="layui-tab" style="margin-top: 0px;" lay-filter="docDemoTabBrief">
<ul id="profileList" class="layui-tab-title">
</ul>
</div>
<div class="layui-col-md2">
<ul id="leftTree"></ul>
<div class="layui-row">
</div>
<div class="layui-col-md10">
<div class="layui-row">
<form class="layui-form layui-col-md12 x-so" action="" lay-filter="searchFrm">
路由名称:
<input name="id" class="layui-input" style="width: 200px;" placeholder="输入接口名或版本号">
<button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="searchFilter">
<i class="layui-icon layui-icon-search"></i>搜索
</button>
</form>
<div class="layui-row">
<div class="layui-col-md2">
<ul id="leftTree"></ul>
</div>
<div id="optTip" class="layui-col-md2" style="margin-top: 20px;">
<i class="layui-icon layui-icon-return"></i>点击树节点查看
</div>
<div id="rightPart" class="layui-col-md10" style="display: none;">
<div class="layui-row">
<form class="layui-form layui-col-md12 x-so" action="" lay-filter="searchFrm">
路由名称:
<input name="id" class="layui-input" style="width: 200px;" placeholder="输入接口名或版本号">
<button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="searchFilter">
<i class="layui-icon layui-icon-search"></i>搜索
</button>
</form>
</div>
<div class="layui-btn-group demoTable">
<button class="layui-btn layui-btn-ms layui-btn-normal" lay-event="addRoute">添加路由</button>
<div class="layui-btn-group demoTable">
<button class="layui-btn layui-btn-ms layui-btn-normal" lay-event="addRoute">
<i class="layui-icon layui-icon-add-circle-fine"></i>添加路由
</button>
</div>
<table class="layui-hide" id="routeTable" lay-filter="routeTable"></table>
<script type="text/html" id="optBar" >
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>
</script>
</div>
<table class="layui-hide" id="routeTable" lay-filter="routeTable"></table>
<script type="text/html" id="optBar" >
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>
</script>
</div>
</div>
<div id="updateWin" style="display: none;padding: 20px;">
<form class="layui-form" action="" lay-filter="updateWinFilter">
<input type="hidden" name="serviceId" />
<input type="hidden" name="profile" />
<div class="layui-form-item">
<label class="layui-form-label">id</label>
<div class="layui-input-block">
@ -65,6 +74,12 @@
<input type="text" name="uri" lay-verify="required" class="layui-input"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">path</label>
<div class="layui-input-block">
<input type="text" name="path" class="layui-input"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">忽略验证</label>
<div class="layui-input-block">
@ -75,8 +90,14 @@
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<input type="radio" name="disabled" value="true" title="启用">
<input type="radio" name="disabled" value="false" title="<span class='x-red'>禁用</span>">
<input type="radio" name="disabled" value="false" title="启用">
<input type="radio" name="disabled" value="true" title="<span class='x-red'>禁用</span>">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="updateWinSubmitFilter">保存</button>
<button type="button" class="layui-btn layui-btn-primary" onclick="layer.closeAll()">取消</button>
</div>
</div>
</form>

@ -2,62 +2,26 @@ lib.use(['element', 'table', 'tree', 'form'], function () {
var form = layui.form;
var table = layui.table;
var currentServiceId;
var routeTable;
var profile = window.profile;
var routeTable = table.render({
elem: '#routeTable'
, url: ApiUtil.createUrl('route.list')
, cellMinWidth: 80 //全局定义常规单元格的最小宽度,layui 2.2.1 新增
, cols: [[
{field: 'id', title: 'id(接口名+版本号)'}
, {field: 'uri', title: 'uri'}
, {
field: 'ignoreValidate', width: 80, title: '忽略验证', templet: function (row) {
return row.ignoreValidate
? '<span class="x-red">是</span>'
: '<span>否</span>';
}
}
, {
field: 'disabled', title: '状态', width: 80, templet: function (row) {
return row.disabled
? '<span class="x-red">禁用</span>'
: '<span class="x-green">启用</span>';
}
}
, {fixed: 'right', title: '操作', toolbar: '#optBar', width: 100}
]]
form.on('submit(searchFilter)', function (data) {
var param = data.field;
param.serviceId = currentServiceId;
searchTable(param)
return false;
});
//监听单元格事件
table.on('tool(routeTable)', function(obj){
var data = obj.data;
if(obj.event === 'edit'){
//表单初始赋值
data.disabled = !data.disabled + '';
data.ignoreValidate = data.ignoreValidate + '';
form.val('updateWinFilter', data)
layer.open({
type: 1
,title: '修改路由'
,area: ['490px', '360px']
,content: $('#updateWin') //这里content是一个DOM,注意:最好该元素要存放在body最外层,否则可能被其它的相对元素所影响
,btn: ['保存', '取消']
,yes: function(index, layero){
}
,btn2: function(index, layero){
layer.close(index);
}
});
}
//监听提交
form.on('submit(updateWinSubmitFilter)', function(data) {
ApiUtil.post('route.update', data.field, function (resp) {
layer.closeAll();
routeTable.reload();
})
return false;
});
$('#profileList').find('li').on('click', function () {
initTree($(this).text());
})
function initTree(profile) {
function initTree() {
ApiUtil.post('service.list', {profile: profile}, function (resp) {
var serviceList = resp.data;
var children = [];
@ -68,10 +32,7 @@ lib.use(['element', 'table', 'tree', 'form'], function () {
name: serviceInfo.serviceId
})
}
// 清空表格
reloadRightPart({name: ''})
// 清空树
$('#leftTree').text('');
layui.tree({
elem: '#leftTree' //传入元素选择器
, nodes: [{ //节点
@ -93,6 +54,8 @@ lib.use(['element', 'table', 'tree', 'form'], function () {
* @param node 树节点
*/
function reloadRightPart(node) {
$('#optTip').hide();
$('#rightPart').show();
var serviceId = node.name;
currentServiceId = serviceId;
searchTable({
@ -100,21 +63,70 @@ lib.use(['element', 'table', 'tree', 'form'], function () {
});
}
form.on('submit(searchFilter)', function (data) {
var param = data.field;
param.serviceId = currentServiceId;
searchTable(param)
return false;
});
/**
* 查询表格
* @param params
*/
function searchTable(params) {
var postData = {
data: JSON.stringify(params)
, profile: profile
};
function searchTable(param) {
routeTable.reload({
where: {
data: JSON.stringify(param)
, profile: window.profile
}
})
if (!routeTable) {
routeTable = table.render({
elem: '#routeTable'
, url: ApiUtil.createUrl('route.list')
, where: postData
, cellMinWidth: 80 //全局定义常规单元格的最小宽度,layui 2.2.1 新增
, cols: [[
{field: 'id', title: 'id(接口名+版本号)', width: 250}
, {field: 'uri', title: 'uri', width: 200}
, {field: 'path', title: 'path', width: 200}
, {
field: 'ignoreValidate', width: 80, title: '忽略验证', templet: function (row) {
return row.ignoreValidate
? '<span class="x-red">是</span>'
: '<span>否</span>';
}
}
, {
field: 'disabled', title: '状态', width: 80, templet: function (row) {
return row.disabled
? '<span class="x-red">禁用</span>'
: '<span class="x-green">启用</span>';
}
}
, {fixed: 'right', title: '操作', toolbar: '#optBar', width: 100}
]]
});
//监听单元格事件
table.on('tool(routeTable)', function(obj) {
var data = obj.data;
if(obj.event === 'edit'){
//表单初始赋值
data.disabled = data.disabled + '';
data.ignoreValidate = data.ignoreValidate + '';
data.serviceId = currentServiceId;
data.profile = profile;
form.val('updateWinFilter', data)
layer.open({
type: 1
,title: '修改路由'
,area: ['500px', '400px']
,content: $('#updateWin') //这里content是一个DOM,注意:最好该元素要存放在body最外层,否则可能被其它的相对元素所影响
});
}
});
} else {
routeTable.reload({
where: postData
})
}
}
initTree('default');
initTree();
});

@ -22,10 +22,6 @@
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>
<div class="x-body">
<div class="layui-tab" style="margin-top: 0px;" lay-filter="docDemoTabBrief">
<ul id="profileList" class="layui-tab-title">
</ul>
</div>
<div class="layui-row">
<form class="layui-form layui-col-md12 x-so" action="" lay-filter="searchFrm">
服务名称:

@ -6,11 +6,13 @@ import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.sop.adminserver.api.service.param.RouteSearchParam;
import com.gitee.sop.adminserver.api.service.param.UpdateRouteParam;
import com.gitee.sop.adminserver.bean.GatewayRouteDefinition;
import com.gitee.sop.adminserver.bean.SopAdminConstants;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.springframework.beans.BeanUtils;
import java.util.Collections;
import java.util.List;
@ -54,4 +56,15 @@ public class RouteListApi {
return routeDefinitionList;
}
@Api(name = "route.update")
@ApiDocMethod(description = "修改路由")
void updateRoute(UpdateRouteParam param) throws Exception {
String serviceIdPath = ZookeeperContext.getSopRouteRootPath(param.getProfile()) + "/" + param.getServiceId();
String zookeeperRoutePath = serviceIdPath + "/" + param.getId();
String data = ZookeeperContext.getData(zookeeperRoutePath);
GatewayRouteDefinition routeDefinition = JSON.parseObject(data, GatewayRouteDefinition.class);
BeanUtils.copyProperties(param, routeDefinition);
ZookeeperContext.setData(zookeeperRoutePath, JSON.toJSONString(routeDefinition));
}
}

@ -0,0 +1,57 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author tanghc
*/
@Data
public class UpdateRouteParam {
@NotBlank(message = "profile不能为空")
@ApiDocField(description = "profile")
private String profile;
@NotBlank(message = "serviceId不能为空")
@ApiDocField(description = "serviceId")
private String serviceId;
/**
* 路由的Id
*/
@NotBlank(message = "id不能为空")
@ApiDocField(description = "路由id")
private String id = "";
/**
* 路由规则转发的目标uri
*/
@NotBlank(message = "uri不能为空")
@ApiDocField(description = "路由uri")
private String uri;
/**
* uri后面跟的path
*/
@ApiDocField(description = "路由path")
private String path;
/**
* 是否忽略验证业务参数验证除外
*/
@NotNull
@ApiDocField(description = "是否忽略验证")
private Boolean ignoreValidate;
/**
* 是否禁用
*/
@NotNull
@ApiDocField(description = "是否禁用")
private Boolean disabled;
}

@ -10,16 +10,43 @@ import java.util.List;
*/
@Data
public class GatewayRouteDefinition {
/** 路由的Id */
/**
* 路由的Id
*/
private String id = "";
/** 路由断言集合配置 */
/**
* 路由断言集合配置
*/
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
/** 路由过滤器集合配置 */
/**
* 路由过滤器集合配置
*/
private List<GatewayFilterDefinition> filters = new ArrayList<>();
/** 路由规则转发的目标uri */
/**
* 路由规则转发的目标uri
*/
private String uri;
/** 路由执行的顺序 */
/**
* uri后面跟的path
*/
private String path;
/**
* 路由执行的顺序
*/
private int order = 0;
/** 是否忽略验证,业务参数验证除外 */
/**
* 是否忽略验证业务参数验证除外
*/
private boolean ignoreValidate;
/**
* 是否禁用
*/
private boolean disabled;
}

@ -7,6 +7,7 @@ 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.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@ -68,6 +69,18 @@ public class ZookeeperContext {
}
}
public static Stat setData(String path, String data) throws Exception {
return getClient().setData().forPath(path, data.getBytes());
}
public static String getData(String path) throws Exception {
if (!isPathExist(path)) {
return null;
}
byte[] data = getClient().getData().forPath(path);
return new String(data);
}
/**
* 获取子节点数据
* @param parentPath 父节点

@ -17,6 +17,12 @@ public class BaseRouteDefinition {
* 路由规则转发的目标uri
*/
private String uri;
/**
* uri后面跟的path
*/
private String path;
/**
* 路由执行的顺序
*/

@ -41,7 +41,7 @@ public class GatewayZookeeperRouteManager extends BaseRouteManager<GatewayServic
protected GatewayTargetRoute buildRouteDefinition(GatewayServiceRouteInfo serviceRouteInfo, GatewayRouteDefinition gatewayRouteDefinition) {
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(gatewayRouteDefinition.getId());
routeDefinition.setUri(URI.create(gatewayRouteDefinition.getUri()));
routeDefinition.setUri(URI.create(gatewayRouteDefinition.getUri() + "#" + gatewayRouteDefinition.getPath()));
routeDefinition.setOrder(gatewayRouteDefinition.getOrder());
List<FilterDefinition> filterDefinitionList = new ArrayList<>(gatewayRouteDefinition.getFilters().size());
List<PredicateDefinition> predicateDefinitionList = new ArrayList<>(gatewayRouteDefinition.getPredicates().size());

@ -1,5 +1,6 @@
package com.gitee.sop.gatewaycommon.zuul.route;
import com.gitee.sop.gatewaycommon.message.ErrorEnum;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import org.springframework.cloud.netflix.zuul.filters.Route;
@ -49,8 +50,9 @@ public class SopRouteLocator implements RouteLocator, Ordered {
if (zuulTargetRoute == null) {
return null;
}
// 路由被禁用
if (zuulTargetRoute.getRouteDefinition().isDisabled()) {
return null;
throw ErrorEnum.ISV_INVALID_METHOD.getErrorMeta().getException();
}
return zuulTargetRoute.getTargetRouteDefinition();
}

@ -10,5 +10,4 @@ import lombok.Setter;
@Getter
@Setter
public class ZuulRouteDefinition extends BaseRouteDefinition {
private String path;
}

@ -31,7 +31,7 @@ public class ZuulZookeeperRouteManager extends BaseRouteManager<ZuulServiceRoute
@Override
protected ZuulTargetRoute buildRouteDefinition(ZuulServiceRouteInfo serviceRouteInfo, ZuulRouteDefinition routeDefinition) {
Route route = new Route(routeDefinition.getId(), RoutePathUtil.findPath(routeDefinition.getUri()), serviceRouteInfo.getServiceId(), null, false, null);
Route route = new Route(routeDefinition.getId(), routeDefinition.getPath(), serviceRouteInfo.getServiceId(), null, false, null);
return new ZuulTargetRoute(serviceRouteInfo, routeDefinition, route);
}
}

@ -106,26 +106,27 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
gatewayRouteDefinition.setOrder(0);
List<GatewayPredicateDefinition> predicates = Arrays.asList(this.buildNameVersionPredicateDefinition(apiMeta));
gatewayRouteDefinition.setPredicates(predicates);
// lb://story-service#/alipay.story.get/
String uri = this.buildUri(serviceApiInfo, apiMeta);
String path = this.buildServletPath(serviceApiInfo, apiMeta);
gatewayRouteDefinition.setUri(uri);
gatewayRouteDefinition.setPath(path);
gatewayRouteDefinition.setIgnoreValidate(apiMeta.isIgnoreValidate());
return gatewayRouteDefinition;
}
protected String buildUri(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
String servletPath = getServletPath(serviceApiInfo, apiMeta);
return "lb://" + serviceApiInfo.getServiceId();
}
protected String buildServletPath(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
String servletPath = apiMeta.getPath();
if (servletPath == null) {
servletPath = PATH_START_CHAR;
servletPath = "";
}
if (!servletPath.startsWith(PATH_START_CHAR)) {
servletPath = PATH_START_CHAR + servletPath;
}
return "lb://" + serviceApiInfo.getServiceId() + "#" + servletPath;
}
protected String getServletPath(ServiceApiInfo serviceApiInfo, ServiceApiInfo.ApiMeta apiMeta) {
return apiMeta.getPath();
return servletPath;
}
protected GatewayPredicateDefinition buildNameVersionPredicateDefinition(ServiceApiInfo.ApiMeta apiMeta) {

@ -10,17 +10,39 @@ import java.util.List;
*/
@Data
public class GatewayRouteDefinition {
/** 路由的Id */
/**
* 路由的Id
*/
private String id;
/** 路由断言集合配置 */
/**
* 路由断言集合配置
*/
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
/** 路由过滤器集合配置 */
/**
* 路由过滤器集合配置
*/
private List<GatewayFilterDefinition> filters = new ArrayList<>();
/** 路由规则转发的目标uri */
/**
* 路由规则转发的目标uri
*/
private String uri;
/** 路由执行的顺序 */
/**
* uri后面跟的path
*/
private String path;
/**
* 路由执行的顺序
*/
private int order = 0;
/** 是否忽略验证,业务参数验证除外 */
/**
* 是否忽略验证业务参数验证除外
*/
private boolean ignoreValidate;
/**

Loading…
Cancel
Save