mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 12:56:28 +08:00
路由管理优化
This commit is contained in:
@@ -101,7 +101,7 @@ body{
|
|||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
.login hr {
|
.login hr {
|
||||||
background: #fff url() 0 0 no-repeat;
|
background: #fff 0 0 no-repeat;
|
||||||
}
|
}
|
||||||
.login hr.hr15 {
|
.login hr.hr15 {
|
||||||
height: 15px;
|
height: 15px;
|
||||||
@@ -126,7 +126,7 @@ body{
|
|||||||
z-index: 99;
|
z-index: 99;
|
||||||
border-bottom: 1px solid #e5e5e5;
|
border-bottom: 1px solid #e5e5e5;
|
||||||
line-height: 39px;
|
line-height: 39px;
|
||||||
height: 39px;
|
height: 37px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
xblock{
|
xblock{
|
||||||
@@ -158,6 +158,9 @@ xblock{
|
|||||||
.x-red{
|
.x-red{
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
.x-green{
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
.x-a{
|
.x-a{
|
||||||
color: #1AA093;
|
color: #1AA093;
|
||||||
}
|
}
|
||||||
@@ -184,7 +187,7 @@ xblock{
|
|||||||
}
|
}
|
||||||
.page a{
|
.page a{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #fff url() 0 0 no-repeat;
|
background: #fff 0 0 no-repeat;
|
||||||
color: #888;
|
color: #888;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-width: 15px;
|
min-width: 15px;
|
||||||
@@ -199,7 +202,7 @@ xblock{
|
|||||||
}
|
}
|
||||||
.page span.current{
|
.page span.current{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #009688 url() 0 0 no-repeat;
|
background: #009688 0 0 no-repeat;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-width: 15px;
|
min-width: 15px;
|
||||||
@@ -211,7 +214,7 @@ xblock{
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.page .pagination li.active span{
|
.page .pagination li.active span{
|
||||||
background: #009688 url() 0 0 no-repeat;
|
background: #009688 0 0 no-repeat;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: 1px solid #009688;
|
border: 1px solid #009688;
|
||||||
|
|
||||||
@@ -244,7 +247,7 @@ xblock{
|
|||||||
}
|
}
|
||||||
.container .left_open i{
|
.container .left_open i{
|
||||||
display: block;
|
display: block;
|
||||||
background: rgba(255,255,255,0.1) url() 0 0 no-repeat;
|
background: rgba(255,255,255,0.1) 0 0 no-repeat;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@@ -255,7 +258,7 @@ xblock{
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.container .left_open i:hover{
|
.container .left_open i:hover{
|
||||||
background: rgba(255,255,255,0.3) url() 0 0 no-repeat;
|
background: rgba(255,255,255,0.3) 0 0 no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container .left{
|
.container .left{
|
||||||
@@ -289,7 +292,7 @@ xblock{
|
|||||||
bottom: 42px;
|
bottom: 42px;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
padding-top: 10px;
|
/*padding-top: 1px;*/
|
||||||
background-color: #EEEEEE;
|
background-color: #EEEEEE;
|
||||||
width: 220px;
|
width: 220px;
|
||||||
max-width: 220px;
|
max-width: 220px;
|
||||||
@@ -347,19 +350,26 @@ xblock{
|
|||||||
}
|
}
|
||||||
.left-nav #nav li .sub-menu li a i{
|
.left-nav #nav li .sub-menu li a i{
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
.left-nav #nav li a i{
|
.left-nav #nav li a i{
|
||||||
padding-right: 10px;
|
/*padding-right: 10px;*/
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
}
|
}
|
||||||
.left-nav #nav li .nav_right{
|
.left-nav #nav li .nav_right{
|
||||||
float: right;
|
float: right;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
.left-nav #nav li.active {
|
||||||
|
background: #ddd;
|
||||||
|
}
|
||||||
|
.left-nav #nav li.active a {
|
||||||
|
color: #148cf1;
|
||||||
|
}
|
||||||
|
|
||||||
.x-slide_left {
|
.x-slide_left {
|
||||||
width: 17px;
|
width: 17px;
|
||||||
height: 61px;
|
height: 61px;
|
||||||
background: url(../images/icon.png) 0 0 no-repeat;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 200px;
|
top: 200px;
|
||||||
left: 221px;
|
left: 221px;
|
||||||
@@ -390,13 +400,13 @@ xblock{
|
|||||||
.page-content .tab{
|
.page-content .tab{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #EFEEF0 url() 0 0 no-repeat;
|
background: #EFEEF0 0 0 no-repeat;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
.page-content .layui-tab-title{
|
.page-content .layui-tab-title{
|
||||||
/*padding-top: 5px;*/
|
/*padding-top: 5px;*/
|
||||||
height: 35px;
|
height: 35px;
|
||||||
background: #EFEEF0 url() 0 0 no-repeat;
|
background: #EFEEF0 0 0 no-repeat;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
@@ -416,7 +426,7 @@ xblock{
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
.page-content .layui-tab-title .layui-this{
|
.page-content .layui-tab-title .layui-this{
|
||||||
background: #fff url() 0 0 no-repeat;
|
background: #fff 0 0 no-repeat;
|
||||||
}
|
}
|
||||||
.page-content .layui-tab-bar{
|
.page-content .layui-tab-bar{
|
||||||
height:34px;
|
height:34px;
|
||||||
@@ -427,7 +437,7 @@ xblock{
|
|||||||
top: 36px;
|
top: 36px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #fff url() 0 0 no-repeat;
|
background: #fff 0 0 no-repeat;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -531,7 +541,7 @@ table th, table td {
|
|||||||
top: 36px;
|
top: 36px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background:rgb(255, 255, 255,0);
|
background:rgb(255, 255, 255);
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: none;
|
display: none;
|
||||||
|
@@ -23,9 +23,31 @@ var ApiUtil = (function () {
|
|||||||
url: url + uri
|
url: url + uri
|
||||||
, data: params // 请求参数
|
, data: params // 请求参数
|
||||||
, callback: function (resp) { // 成功回调
|
, callback: function (resp) { // 成功回调
|
||||||
callback(resp);
|
var code = resp.code
|
||||||
|
if (!code || code === '-9') {
|
||||||
|
layer.alert('系统错误');
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (code === '-100' || code === '18' || code === '21') { // 未登录
|
||||||
|
ApiUtil.logout()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (code === '0') { // 成功
|
||||||
|
callback(resp)
|
||||||
|
} else {
|
||||||
|
layer.alert(resp.msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
, getUrl: function () {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
, createUrl: function (uri) {
|
||||||
|
if (!uri) {
|
||||||
|
throw new Error('name不能为空');
|
||||||
|
}
|
||||||
|
return url + formatUri(uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
24
sop-admin/sop-admin-front/assets/js/common.js
Normal file
24
sop-admin/sop-admin-front/assets/js/common.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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 {}
|
||||||
|
})();
|
32
sop-admin/sop-admin-front/assets/js/index.js
Normal file
32
sop-admin/sop-admin-front/assets/js/index.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
layui.use('jquery', function () {
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var $pageFrame = $('#pageFrame');
|
||||||
|
var $selectLi = null;
|
||||||
|
$('.left-nav').on('click', 'li', function (event) {
|
||||||
|
var $tagLi = $(this);
|
||||||
|
var $tagA = $tagLi.find('a').eq(0);
|
||||||
|
var href = $tagA.prop('href');
|
||||||
|
if (href) {
|
||||||
|
$pageFrame.prop('src', href + '?q=' + new Date().getTime());
|
||||||
|
if ($selectLi) {
|
||||||
|
$selectLi.removeClass('active')
|
||||||
|
}
|
||||||
|
$selectLi = $tagLi.addClass('active');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.container .left_open i').click(function(event) {
|
||||||
|
if($('.left-nav').css('left')=='0px'){
|
||||||
|
$('.left-nav').animate({left: '-221px'}, 100);
|
||||||
|
$('.page-content').animate({left: '0px'}, 100);
|
||||||
|
$('.page-content-bg').hide();
|
||||||
|
}else{
|
||||||
|
$('.left-nav').animate({left: '0px'}, 100);
|
||||||
|
$('.page-content').animate({left: '221px'}, 100);
|
||||||
|
if($(window).width()<768){
|
||||||
|
$('.page-content-bg').show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
76
sop-admin/sop-admin-front/assets/js/lib.js
Normal file
76
sop-admin/sop-admin-front/assets/js/lib.js
Normal file
File diff suppressed because one or more lines are too long
@@ -342,6 +342,7 @@ $(function () {
|
|||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
var cateIds = [];
|
var cateIds = [];
|
||||||
function getCateId(cateId) {
|
function getCateId(cateId) {
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -2,32 +2,30 @@
|
|||||||
<html class="x-admin-sm">
|
<html class="x-admin-sm">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>后台登录-X-admin2.1</title>
|
<title>SOP Admin</title>
|
||||||
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
<meta name="renderer" content="webkit|ie-comp|ie-stand">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
|
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8"/>
|
||||||
<meta http-equiv="Cache-Control" content="no-siteapp"/>
|
<meta http-equiv="Cache-Control" content="no-siteapp"/>
|
||||||
<link rel="stylesheet" href="assets/css/font.css">
|
<link rel="stylesheet" href="assets/css/font.css">
|
||||||
<link rel="stylesheet" href="assets/css/xadmin.css">
|
<link rel="stylesheet" href="assets/css/xadmin.css">
|
||||||
<script type="text/javascript" src="assets/lib/jquery/3.2.1/jquery.min.js"></script>
|
<script type="text/javascript" src="assets/lib/layui/layui.js" charset="utf-8"></script>
|
||||||
<script src="assets/lib/layui/layui.js" charset="utf-8"></script>
|
<script type="text/javascript" src="assets/js/index.js"></script>
|
||||||
<script type="text/javascript" src="assets/js/xadmin.js"></script>
|
|
||||||
<script type="text/javascript" src="assets/js/cookie.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
// 是否开启刷新记忆tab功能
|
// 是否开启刷新记忆tab功能
|
||||||
// var is_remember = false;
|
// var is_remember = false;
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
.sub-menu cite {
|
.sub-menu cite {
|
||||||
margin-left: 30px;
|
margin-left: 0px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- 顶部开始 -->
|
<!-- 顶部开始 -->
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="logo"><a href="./index.html">X-admin v2.1</a></div>
|
<div class="logo"><a>SOP Admin</a></div>
|
||||||
<div class="left_open">
|
<div class="left_open">
|
||||||
<i title="展开左侧栏" class="iconfont"></i>
|
<i title="展开左侧栏" class="iconfont"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,32 +45,42 @@
|
|||||||
<div class="left-nav">
|
<div class="left-nav">
|
||||||
<div id="side-nav">
|
<div id="side-nav">
|
||||||
<ul id="nav">
|
<ul id="nav">
|
||||||
|
<li date-refresh="1">
|
||||||
|
<a href="pages/welcome.html">
|
||||||
|
<i class="layui-icon layui-icon-home"></i>
|
||||||
|
<cite>首页</cite>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="open">
|
<li class="open">
|
||||||
<a href="javascript:;">
|
<a>
|
||||||
<i class="iconfont"></i>
|
<i class="layui-icon layui-icon-template-1"></i>
|
||||||
<cite>配置管理</cite>
|
<cite>配置管理</cite>
|
||||||
<i class="iconfont nav_right"></i>
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="sub-menu">
|
<ul class="sub-menu">
|
||||||
<li date-refresh="1">
|
<li date-refresh="1">
|
||||||
<a _href="member-list.html">
|
<a href="pages/todo.html">
|
||||||
|
<i class="layui-icon layui-icon-table"></i>
|
||||||
<cite>配置列表</cite>
|
<cite>配置列表</cite>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="open">
|
<li class="open">
|
||||||
<a href="javascript:;">
|
<a>
|
||||||
<i class="iconfont"></i>
|
<i class="layui-icon layui-icon-app"></i>
|
||||||
<cite>服务管理</cite>
|
<cite>服务管理</cite>
|
||||||
<i class="iconfont nav_right"></i>
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="sub-menu">
|
<ul class="sub-menu">
|
||||||
<li date-refresh="1">
|
<li date-refresh="1">
|
||||||
<a _href="member-list.html">
|
<a href="pages/service/serviceList.html">
|
||||||
|
<i class="layui-icon layui-icon-table"></i>
|
||||||
<cite>服务列表</cite>
|
<cite>服务列表</cite>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li date-refresh="1">
|
||||||
|
<a href="pages/service/routeManager.html">
|
||||||
|
<i class="layui-icon layui-icon-component"></i>
|
||||||
|
<cite>路由管理</cite>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -84,24 +92,7 @@
|
|||||||
<!-- 左侧菜单结束 -->
|
<!-- 左侧菜单结束 -->
|
||||||
<!-- 右侧主体开始 -->
|
<!-- 右侧主体开始 -->
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<div class="layui-tab tab" lay-filter="xbs_tab" lay-allowclose="false">
|
<iframe id="pageFrame" src='pages/welcome.html' frameborder="0" scrolling="yes" class="x-iframe" width="100%" height="100%"></iframe>
|
||||||
<ul class="layui-tab-title">
|
|
||||||
<li class="home"><i class="layui-icon"></i>我的桌面</li>
|
|
||||||
</ul>
|
|
||||||
<div class="layui-unselect layui-form-select layui-form-selected" id="tab_right">
|
|
||||||
<dl>
|
|
||||||
<dd data-type="this">关闭当前</dd>
|
|
||||||
<dd data-type="other">关闭其它</dd>
|
|
||||||
<dd data-type="all">关闭全部</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<div class="layui-tab-content">
|
|
||||||
<div class="layui-tab-item layui-show">
|
|
||||||
<iframe src='pages/welcome.html' frameborder="0" scrolling="yes" class="x-iframe"></iframe>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="tab_show"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="page-content-bg"></div>
|
<div class="page-content-bg"></div>
|
||||||
<!-- 右侧主体结束 -->
|
<!-- 右侧主体结束 -->
|
||||||
|
55
sop-admin/sop-admin-front/pages/service/routeManager.html
Normal file
55
sop-admin/sop-admin-front/pages/service/routeManager.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="x-admin-sm">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>SOP Admin</title>
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8"/>
|
||||||
|
<link rel="stylesheet" href="../../assets/css/font.css">
|
||||||
|
<link rel="stylesheet" href="../../assets/css/xadmin.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="x-nav">
|
||||||
|
<span class="layui-breadcrumb">
|
||||||
|
<a href="../welcome.html">首页</a>
|
||||||
|
<a><cite>服务管理</cite></a>
|
||||||
|
<a><cite>路由管理</cite></a>
|
||||||
|
</span>
|
||||||
|
<a class="layui-btn layui-btn-small layui-btn-normal" style="line-height:1.6em;margin-top:4px;float:right"
|
||||||
|
href="javascript:location.replace(location.href);" title="刷新">
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<div class="layui-btn-group demoTable">
|
||||||
|
<button class="layui-btn layui-btn-ms layui-btn-normal" lay-event="addRoute">添加路由</button>
|
||||||
|
</div>
|
||||||
|
<table class="layui-hide" id="table"></table>
|
||||||
|
<script type="text/html" id="optBar">
|
||||||
|
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="../../assets/js/lib.js"></script>
|
||||||
|
<script type="text/javascript" src="routeManager.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
95
sop-admin/sop-admin-front/pages/service/routeManager.js
Normal file
95
sop-admin/sop-admin-front/pages/service/routeManager.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
lib.use(['element', 'table', 'tree', 'form'], function () {
|
||||||
|
var form = layui.form;
|
||||||
|
var table = layui.table;
|
||||||
|
var currentServiceId;
|
||||||
|
|
||||||
|
var serverTable = table.render({
|
||||||
|
elem: '#table'
|
||||||
|
, 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}
|
||||||
|
]]
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#profileList').find('li').on('click', function () {
|
||||||
|
initTree($(this).text());
|
||||||
|
})
|
||||||
|
|
||||||
|
function initTree(profile) {
|
||||||
|
ApiUtil.post('service.list', {profile: profile}, function (resp) {
|
||||||
|
var serviceList = resp.data;
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < serviceList.length; i++) {
|
||||||
|
var serviceInfo = serviceList[i];
|
||||||
|
children.push({
|
||||||
|
id: i + 1,
|
||||||
|
name: serviceInfo.serviceId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 清空表格
|
||||||
|
reloadRightPart({name: ''})
|
||||||
|
// 清空树
|
||||||
|
$('#leftTree').text('');
|
||||||
|
layui.tree({
|
||||||
|
elem: '#leftTree' //传入元素选择器
|
||||||
|
, nodes: [{ //节点
|
||||||
|
name: '服务列表(' + profile + ')'
|
||||||
|
, spread: true // 展开
|
||||||
|
, children: children
|
||||||
|
}]
|
||||||
|
, click: function (node) {
|
||||||
|
if (node.id) {
|
||||||
|
reloadRightPart(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新右边部分
|
||||||
|
* @param node 树节点
|
||||||
|
*/
|
||||||
|
function reloadRightPart(node) {
|
||||||
|
var serviceId = node.name;
|
||||||
|
currentServiceId = serviceId;
|
||||||
|
searchTable({
|
||||||
|
serviceId: serviceId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
form.on('submit(searchFilter)', function (data) {
|
||||||
|
var param = data.field;
|
||||||
|
param.serviceId = currentServiceId;
|
||||||
|
searchTable(param)
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchTable(param) {
|
||||||
|
serverTable.reload({
|
||||||
|
where: {
|
||||||
|
data: JSON.stringify(param)
|
||||||
|
, profile: window.profile
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
initTree('default');
|
||||||
|
});
|
78
sop-admin/sop-admin-front/pages/service/serviceList.html
Normal file
78
sop-admin/sop-admin-front/pages/service/serviceList.html
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="x-admin-sm">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>SOP Admin</title>
|
||||||
|
<meta name="renderer" content="webkit">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8"/>
|
||||||
|
<link rel="stylesheet" href="../../assets/css/font.css">
|
||||||
|
<link rel="stylesheet" href="../../assets/css/xadmin.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="x-nav">
|
||||||
|
<span class="layui-breadcrumb">
|
||||||
|
<a href="../welcome.html">首页</a>
|
||||||
|
<a><cite>服务管理</cite></a>
|
||||||
|
<a><cite>服务列表</cite></a>
|
||||||
|
</span>
|
||||||
|
<a class="layui-btn layui-btn-small layui-btn-normal" style="line-height:1.6em;margin-top:4px;float:right"
|
||||||
|
href="javascript:location.replace(location.href);" title="刷新">
|
||||||
|
<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">
|
||||||
|
服务名称:
|
||||||
|
<input name="serviceId" class="layui-input" style="width: 200px;" placeholder="输入服务名称(serviceId)">
|
||||||
|
<button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="searchFilter">
|
||||||
|
<i class="layui-icon layui-icon-search"></i>搜索
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="layui-hide" id="table"></table>
|
||||||
|
<script type="text/html" id="optBar">
|
||||||
|
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>
|
||||||
|
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">下线</a>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="../../assets/js/lib.js"></script>
|
||||||
|
<script>
|
||||||
|
lib.use(['element', 'table', 'form'], function () {
|
||||||
|
var table = layui.table;
|
||||||
|
var form = layui.form;
|
||||||
|
|
||||||
|
var serverTable = table.render({
|
||||||
|
elem: '#table'
|
||||||
|
, url: ApiUtil.createUrl('service.list')
|
||||||
|
, cellMinWidth: 80 //全局定义常规单元格的最小宽度,layui 2.2.1 新增
|
||||||
|
, cols: [[
|
||||||
|
{field: 'serviceId', title: '服务名称', sort: true}
|
||||||
|
, {field: 'description', title: '描述'}
|
||||||
|
, {field: 'createTime', title: '添加时间', sort: true}
|
||||||
|
, {field: 'updateTime', title: '修改时间', sort: true}
|
||||||
|
, {fixed: 'right', title:'操作', toolbar: '#optBar', width:150}
|
||||||
|
]]
|
||||||
|
});
|
||||||
|
|
||||||
|
form.on('submit(searchFilter)', function(data){
|
||||||
|
var param = data.field;
|
||||||
|
serverTable.reload({
|
||||||
|
where: {
|
||||||
|
data: JSON.stringify(param)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
sop-admin/sop-admin-front/pages/todo.html
Normal file
10
sop-admin/sop-admin-front/pages/todo.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>todo</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
待实现...
|
||||||
|
</body>
|
||||||
|
</html>
|
@@ -1,165 +1,35 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="x-admin-sm">
|
<html class="x-admin-sm">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>欢迎页面-X-admin2.1</title>
|
<title>SOP Admin</title>
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
|
<meta name="viewport"
|
||||||
<link rel="stylesheet" href="../assets/css/font.css">
|
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8"/>
|
||||||
<link rel="stylesheet" href="../assets/css/xadmin.css">
|
<link rel="stylesheet" href="../assets/css/font.css">
|
||||||
</head>
|
<link rel="stylesheet" href="../assets/css/xadmin.css">
|
||||||
<body>
|
|
||||||
<div class="x-body">
|
</head>
|
||||||
<blockquote class="layui-elem-quote">欢迎管理员:
|
<body>
|
||||||
<span class="x-red">test</span>!当前时间:2018-04-25 20:50:53</blockquote>
|
<div class="x-nav">
|
||||||
<fieldset class="layui-elem-field">
|
<span class="layui-breadcrumb">
|
||||||
<legend>数据统计</legend>
|
<a><cite>首页</cite></a>
|
||||||
<div class="layui-field-box">
|
</span>
|
||||||
<div class="layui-col-md12">
|
<a class="layui-btn layui-btn-small layui-btn-normal" style="line-height:1.6em;margin-top:4px;float:right"
|
||||||
<div class="layui-card">
|
href="javascript:location.replace(location.href);" title="刷新">
|
||||||
<div class="layui-card-body">
|
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
|
||||||
<div class="layui-carousel x-admin-carousel x-admin-backlog" lay-anim="" lay-indicator="inside" lay-arrow="none" style="width: 100%; height: 90px;">
|
</div>
|
||||||
<div carousel-item="">
|
<div class="x-body">
|
||||||
<ul class="layui-row layui-col-space10 layui-this">
|
<blockquote class="layui-elem-quote">欢迎管理员:
|
||||||
<li class="layui-col-xs2">
|
<span class="x-red">admin</span>!
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
</blockquote>
|
||||||
<h3>文章数</h3>
|
</div>
|
||||||
<p>
|
|
||||||
<cite>66</cite></p>
|
<script type="text/javascript" src="../assets/lib/layui/layui.js" charset="utf-8"></script>
|
||||||
</a>
|
<script>
|
||||||
</li>
|
layui.use('element', function () {
|
||||||
<li class="layui-col-xs2">
|
});
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
</script>
|
||||||
<h3>会员数</h3>
|
</body>
|
||||||
<p>
|
|
||||||
<cite>12</cite></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="layui-col-xs2">
|
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
|
||||||
<h3>回复数</h3>
|
|
||||||
<p>
|
|
||||||
<cite>99</cite></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="layui-col-xs2">
|
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
|
||||||
<h3>商品数</h3>
|
|
||||||
<p>
|
|
||||||
<cite>67</cite></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="layui-col-xs2">
|
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
|
||||||
<h3>文章数</h3>
|
|
||||||
<p>
|
|
||||||
<cite>67</cite></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="layui-col-xs2">
|
|
||||||
<a href="javascript:;" class="x-admin-backlog-body">
|
|
||||||
<h3>文章数</h3>
|
|
||||||
<p>
|
|
||||||
<cite>6766</cite></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset class="layui-elem-field">
|
|
||||||
<legend>系统通知</legend>
|
|
||||||
<div class="layui-field-box">
|
|
||||||
<table class="layui-table" lay-skin="line">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td >
|
|
||||||
<a class="x-a" href="/" target="_blank">新版x-admin 2.0上线了</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td >
|
|
||||||
<a class="x-a" href="/" target="_blank">交流qq群:(519492808)</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset class="layui-elem-field">
|
|
||||||
<legend>系统信息</legend>
|
|
||||||
<div class="layui-field-box">
|
|
||||||
<table class="layui-table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>xxx版本</th>
|
|
||||||
<td>1.0.180420</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>服务器地址</th>
|
|
||||||
<td>x.xuebingsi.com</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>操作系统</th>
|
|
||||||
<td>WINNT</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>运行环境</th>
|
|
||||||
<td>Apache/2.4.23 (Win32) OpenSSL/1.0.2j mod_fcgid/2.3.9</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>PHP版本</th>
|
|
||||||
<td>5.6.27</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>PHP运行方式</th>
|
|
||||||
<td>cgi-fcgi</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>MYSQL版本</th>
|
|
||||||
<td>5.5.53</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>ThinkPHP</th>
|
|
||||||
<td>5.0.18</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>上传附件限制</th>
|
|
||||||
<td>2M</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>执行时间限制</th>
|
|
||||||
<td>30s</td></tr>
|
|
||||||
<tr>
|
|
||||||
<th>剩余空间</th>
|
|
||||||
<td>86015.2M</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<fieldset class="layui-elem-field">
|
|
||||||
<legend>开发团队</legend>
|
|
||||||
<div class="layui-field-box">
|
|
||||||
<table class="layui-table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>版权所有</th>
|
|
||||||
<td>xuebingsi(xuebingsi)
|
|
||||||
<a href="http://x.xuebingsi.com/" class='x-a' target="_blank">访问官网</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>开发者</th>
|
|
||||||
<td>马志斌(113664000@qq.com)</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<blockquote class="layui-elem-quote layui-quote-nm">感谢layui,百度Echarts,jquery,本系统由x-admin提供技术支持。</blockquote>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
var _hmt = _hmt || [];
|
|
||||||
(function() {
|
|
||||||
var hm = document.createElement("script");
|
|
||||||
hm.src = "https://hm.baidu.com/hm.js?b393d153aeb26b46e9431fabaf0f6190";
|
|
||||||
var s = document.getElementsByTagName("script")[0];
|
|
||||||
s.parentNode.insertBefore(hm, s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
@@ -40,7 +40,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.curator</groupId>
|
<groupId>org.apache.curator</groupId>
|
||||||
<artifactId>curator-framework</artifactId>
|
<artifactId>curator-framework</artifactId>
|
||||||
<version>4.2.0</version>
|
<version>2.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-recipes</artifactId>
|
||||||
|
<version>2.13.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -62,7 +67,14 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.4</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
package com.gitee.sop.adminserver.api;
|
|
||||||
|
|
||||||
import com.gitee.easyopen.annotation.ApiService;
|
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author tanghc
|
|
||||||
*/
|
|
||||||
@ApiService
|
|
||||||
@ApiDoc("路由列表")
|
|
||||||
public class RouteListApi {
|
|
||||||
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
package com.gitee.sop.adminserver.api;
|
package com.gitee.sop.adminserver.api.config;
|
||||||
|
|
||||||
import com.gitee.easyopen.annotation.ApiService;
|
import com.gitee.easyopen.annotation.ApiService;
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
@@ -1,12 +1,12 @@
|
|||||||
package com.gitee.sop.adminserver.api;
|
package com.gitee.sop.adminserver.api.demo;
|
||||||
|
|
||||||
import com.gitee.easyopen.annotation.Api;
|
import com.gitee.easyopen.annotation.Api;
|
||||||
import com.gitee.easyopen.annotation.ApiService;
|
import com.gitee.easyopen.annotation.ApiService;
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
|
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
|
||||||
import com.gitee.sop.adminserver.api.param.GoodsParam;
|
import com.gitee.sop.adminserver.api.demo.param.GoodsParam;
|
||||||
import com.gitee.sop.adminserver.api.result.Goods;
|
import com.gitee.sop.adminserver.api.demo.result.Goods;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
@@ -1,4 +1,4 @@
|
|||||||
package com.gitee.sop.adminserver.api.param;
|
package com.gitee.sop.adminserver.api.demo.param;
|
||||||
|
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||||
import org.hibernate.validator.constraints.Length;
|
import org.hibernate.validator.constraints.Length;
|
@@ -1,4 +1,4 @@
|
|||||||
package com.gitee.sop.adminserver.api.result;
|
package com.gitee.sop.adminserver.api.demo.result;
|
||||||
|
|
||||||
import com.gitee.easyopen.doc.DataType;
|
import com.gitee.easyopen.doc.DataType;
|
||||||
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
@@ -0,0 +1,57 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.gitee.easyopen.annotation.Api;
|
||||||
|
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.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 java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@ApiService
|
||||||
|
@ApiDoc("服务管理")
|
||||||
|
public class RouteListApi {
|
||||||
|
|
||||||
|
@Api(name = "route.list")
|
||||||
|
@ApiDocMethod(description = "路由列表", elementClass = GatewayRouteDefinition.class)
|
||||||
|
List<GatewayRouteDefinition> listRoute(RouteSearchParam param) throws Exception {
|
||||||
|
if (StringUtils.isBlank(param.getServiceId())) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String searchPath = ZookeeperContext.getSopRouteRootPath(param.getProfile()) + "/" + param.getServiceId();
|
||||||
|
|
||||||
|
List<ChildData> childDataList = ZookeeperContext.getChildrenData(searchPath);
|
||||||
|
|
||||||
|
List<GatewayRouteDefinition> routeDefinitionList = childDataList.stream()
|
||||||
|
.map(childData -> {
|
||||||
|
String serviceNodeData = new String(childData.getData());
|
||||||
|
GatewayRouteDefinition routeDefinition = JSON.parseObject(serviceNodeData, GatewayRouteDefinition.class);
|
||||||
|
return routeDefinition;
|
||||||
|
})
|
||||||
|
.filter(gatewayRouteDefinition -> {
|
||||||
|
boolean isRoute = gatewayRouteDefinition.getOrder() != Integer.MIN_VALUE;
|
||||||
|
String id = param.getId();
|
||||||
|
if (StringUtils.isBlank(id)) {
|
||||||
|
return isRoute;
|
||||||
|
}else {
|
||||||
|
return isRoute && gatewayRouteDefinition.getId().contains(id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return routeDefinitionList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,57 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.gitee.easyopen.annotation.Api;
|
||||||
|
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.ServiceSearchParam;
|
||||||
|
import com.gitee.sop.adminserver.api.service.result.ServiceInfo;
|
||||||
|
import com.gitee.sop.adminserver.bean.ZookeeperContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.curator.framework.recipes.cache.ChildData;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.gitee.sop.adminserver.bean.SopAdminConstants.SOP_SERVICE_ROUTE_PATH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@ApiService
|
||||||
|
@ApiDoc("服务管理")
|
||||||
|
@Slf4j
|
||||||
|
public class ServiceApi {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
@Api(name = "service.list")
|
||||||
|
@ApiDocMethod(description = "服务列表", elementClass = ServiceInfo.class)
|
||||||
|
List<ServiceInfo> listServiceInfo(ServiceSearchParam param) throws Exception {
|
||||||
|
String routeRootPath = ZookeeperContext.getSopRouteRootPath(param.getProfile());
|
||||||
|
List<ChildData> childDataList = ZookeeperContext.getChildrenData(routeRootPath);
|
||||||
|
List<ServiceInfo> serviceInfoList = childDataList.stream()
|
||||||
|
.map(childData -> {
|
||||||
|
String serviceNodeData = new String(childData.getData());
|
||||||
|
ServiceInfo serviceInfo = JSON.parseObject(serviceNodeData, ServiceInfo.class);
|
||||||
|
return serviceInfo;
|
||||||
|
})
|
||||||
|
.filter(serviceInfo -> {
|
||||||
|
if (StringUtils.isBlank(param.getServiceId())) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return serviceInfo.getServiceId().contains(param.getServiceId());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return serviceInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.service.param;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RouteSearchParam extends ServiceSearchParam {
|
||||||
|
private String id;
|
||||||
|
}
|
@@ -0,0 +1,17 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.service.param;
|
||||||
|
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ServiceSearchParam {
|
||||||
|
|
||||||
|
@ApiDocField(description = "profile")
|
||||||
|
private String profile;
|
||||||
|
|
||||||
|
@ApiDocField(description = "serviceId")
|
||||||
|
private String serviceId;
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.service.result;
|
||||||
|
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ServiceInfo {
|
||||||
|
@ApiDocField(description = "serviceId")
|
||||||
|
private String serviceId;
|
||||||
|
|
||||||
|
@ApiDocField(description = "创建时间")
|
||||||
|
private String createTime;
|
||||||
|
|
||||||
|
@ApiDocField(description = "修改时间")
|
||||||
|
private String updateTime;
|
||||||
|
|
||||||
|
@ApiDocField(description = "描述")
|
||||||
|
private String description;
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
package com.gitee.sop.adminserver.api.system;
|
||||||
|
|
||||||
|
import com.gitee.easyopen.annotation.Api;
|
||||||
|
import com.gitee.easyopen.annotation.ApiService;
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDoc;
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@ApiService
|
||||||
|
@ApiDoc("系统接口")
|
||||||
|
public class SystemApi {
|
||||||
|
|
||||||
|
@Value("${sop-admin.profiles}")
|
||||||
|
private String profiles;
|
||||||
|
|
||||||
|
private List<String> profileList;
|
||||||
|
|
||||||
|
@ApiDocMethod(description = "获取profile列表")
|
||||||
|
@Api(name = "system.profile.list")
|
||||||
|
public List<String> listProfiles() {
|
||||||
|
if (profileList == null) {
|
||||||
|
String[] arr = profiles.split("\\,");
|
||||||
|
profileList = Stream.of(arr).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return profileList;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,17 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GatewayFilterDefinition {
|
||||||
|
/** Filter Name */
|
||||||
|
private String name;
|
||||||
|
/** 对应的路由规则 */
|
||||||
|
private Map<String, String> args = new LinkedHashMap<>();
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.validation.ValidationException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author thc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GatewayPredicateDefinition {
|
||||||
|
public static final String GEN_KEY = "_genkey_";
|
||||||
|
/** 断言对应的Name */
|
||||||
|
private String name;
|
||||||
|
/** 配置的断言规则 */
|
||||||
|
private Map<String, String> args = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public GatewayPredicateDefinition() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatewayPredicateDefinition(String text) {
|
||||||
|
int eqIdx = text.indexOf(61);
|
||||||
|
if (eqIdx <= 0) {
|
||||||
|
throw new ValidationException("Unable to parse GatewayPredicateDefinition text '" + text + "', must be of the form name=value");
|
||||||
|
} else {
|
||||||
|
this.setName(text.substring(0, eqIdx));
|
||||||
|
String[] args = StringUtils.tokenizeToStringArray(text.substring(eqIdx + 1), ",");
|
||||||
|
|
||||||
|
for(int i = 0; i < args.length; ++i) {
|
||||||
|
this.args.put(generateName(i), args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String generateName(int i) {
|
||||||
|
return GEN_KEY + i;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class GatewayRouteDefinition {
|
||||||
|
/** 路由的Id */
|
||||||
|
private String id = "";
|
||||||
|
/** 路由断言集合配置 */
|
||||||
|
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
|
||||||
|
/** 路由过滤器集合配置 */
|
||||||
|
private List<GatewayFilterDefinition> filters = new ArrayList<>();
|
||||||
|
/** 路由规则转发的目标uri */
|
||||||
|
private String uri;
|
||||||
|
/** 路由执行的顺序 */
|
||||||
|
private int order = 0;
|
||||||
|
/** 是否忽略验证,业务参数验证除外 */
|
||||||
|
private boolean ignoreValidate;
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author thc
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ServiceRouteInfo {
|
||||||
|
/** 服务名称,对应spring.application.name */
|
||||||
|
private String serviceId;
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime = new Date();
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime = new Date();
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@JSONField(serialize = false)
|
||||||
|
private List<GatewayRouteDefinition> routeDefinitionList;
|
||||||
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
public class SopAdminConstants {
|
||||||
|
/**
|
||||||
|
* zookeeper存放接口路由信息的根目录
|
||||||
|
*/
|
||||||
|
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,97 @@
|
|||||||
|
package com.gitee.sop.adminserver.bean;
|
||||||
|
|
||||||
|
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.retry.ExponentialBackoffRetry;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ZookeeperContext {
|
||||||
|
|
||||||
|
public static final String SOP_ROUTE_ROOT_PATH = SopAdminConstants.SOP_SERVICE_ROUTE_PATH + "-%s";
|
||||||
|
|
||||||
|
private static CuratorFramework client;
|
||||||
|
|
||||||
|
@Value("${spring.cloud.zookeeper.connect-string}")
|
||||||
|
private String zookeeperServerAddr;
|
||||||
|
|
||||||
|
@Value("${spring.cloud.zookeeper.baseSleepTimeMs}")
|
||||||
|
private String baseSleepTimeMs;
|
||||||
|
|
||||||
|
@Value("${spring.cloud.zookeeper.maxRetries}")
|
||||||
|
private String maxRetries;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
protected void after() {
|
||||||
|
CuratorFramework client = CuratorFrameworkFactory.builder()
|
||||||
|
.connectString(zookeeperServerAddr)
|
||||||
|
.retryPolicy(new ExponentialBackoffRetry(NumberUtils.toInt(baseSleepTimeMs, 3000), NumberUtils.toInt(maxRetries, 3)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
client.start();
|
||||||
|
|
||||||
|
setClient(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSopRouteRootPath(String profile) {
|
||||||
|
if (StringUtils.isBlank(profile)) {
|
||||||
|
profile = "default";
|
||||||
|
}
|
||||||
|
return String.format(SOP_ROUTE_ROOT_PATH, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CuratorFramework getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setClient(CuratorFramework client) {
|
||||||
|
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 List<ChildData> getChildrenData(String parentPath) throws Exception {
|
||||||
|
PathChildrenCache pathChildrenCache = buildPathChildrenCache(parentPath);
|
||||||
|
if (pathChildrenCache == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return pathChildrenCache.getCurrentData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PathChildrenCache buildPathChildrenCache(String path) throws Exception {
|
||||||
|
if (!isPathExist(path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
||||||
|
// 且第三个参数要设置为true,不然ChildData对象中的getData返回null
|
||||||
|
PathChildrenCache childrenCache = new PathChildrenCache(client, path, true);
|
||||||
|
// 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的
|
||||||
|
childrenCache.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
|
||||||
|
return childrenCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,14 +1,26 @@
|
|||||||
package com.gitee.sop.adminserver.config;
|
package com.gitee.sop.adminserver.config;
|
||||||
|
|
||||||
|
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.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author thc
|
||||||
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class WebConfig extends WebMvcConfigurerAdapter {
|
public class WebConfig extends WebMvcConfigurerAdapter {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
//配置映射关系
|
//配置映射关系
|
||||||
|
@@ -1,38 +0,0 @@
|
|||||||
server.port=8082
|
|
||||||
|
|
||||||
#################easyopen基础配置#################
|
|
||||||
# 显示文档
|
|
||||||
easyopen.show-doc=true
|
|
||||||
# 本地秘钥
|
|
||||||
easyopen.app-secret.test=123456
|
|
||||||
|
|
||||||
# 关闭跨域,默认开启
|
|
||||||
#easyopen.cors=false
|
|
||||||
|
|
||||||
# 开启webflux
|
|
||||||
easyopen.mono=false
|
|
||||||
|
|
||||||
## 拦截器
|
|
||||||
#easyopen.interceptors[0]=com.gitee.easyopen.support.LimitInterceptor
|
|
||||||
#easyopen.interceptors[1]=com.gitee.easyopen.support.PermissionInterceptor
|
|
||||||
|
|
||||||
# 配置中心,config-server-port对应easyopen-config中的netty.server.port
|
|
||||||
#easyopen.app-name=app-normal
|
|
||||||
#easyopen.config-server-ip=127.0.0.1
|
|
||||||
#easyopen.config-server-port=8071
|
|
||||||
#easyopen.doc-url=http://127.0.0.1:8081/api/doc
|
|
||||||
|
|
||||||
|
|
||||||
#################redis基础配置#################
|
|
||||||
spring.redis.database=1
|
|
||||||
spring.redis.host=10.1.11.48
|
|
||||||
spring.redis.password=0987654321rfvujmtgbyhn
|
|
||||||
spring.redis.port=6379
|
|
||||||
# 连接超时时间 单位 ms(毫秒)
|
|
||||||
spring.redis.timeout=3000
|
|
||||||
|
|
||||||
|
|
||||||
logging.file=D:/logs/server/server
|
|
||||||
logging.level.com.gitee=debug
|
|
||||||
|
|
||||||
|
|
@@ -0,0 +1,27 @@
|
|||||||
|
server:
|
||||||
|
port: 8082
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: sop-admin
|
||||||
|
|
||||||
|
cloud:
|
||||||
|
zookeeper:
|
||||||
|
connect-string: localhost:2181
|
||||||
|
baseSleepTimeMs: 3000
|
||||||
|
maxRetries: 3
|
||||||
|
|
||||||
|
easyopen:
|
||||||
|
show-doc: true
|
||||||
|
mono: false
|
||||||
|
ignore-validate: true
|
||||||
|
|
||||||
|
sop-admin:
|
||||||
|
profiles: default,prod,dev,test
|
||||||
|
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
com:
|
||||||
|
gitee: debug
|
||||||
|
|
@@ -1 +0,0 @@
|
|||||||
spring.profiles.active=dev
|
|
@@ -0,0 +1,3 @@
|
|||||||
|
spring:
|
||||||
|
profiles:
|
||||||
|
active: dev
|
@@ -26,4 +26,9 @@ public class BaseRouteDefinition {
|
|||||||
* 是否忽略验证,业务参数验证除外
|
* 是否忽略验证,业务参数验证除外
|
||||||
*/
|
*/
|
||||||
private boolean ignoreValidate;
|
private boolean ignoreValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否禁用
|
||||||
|
*/
|
||||||
|
private boolean disabled;
|
||||||
}
|
}
|
||||||
|
@@ -34,5 +34,5 @@ public class SopConstants {
|
|||||||
/**
|
/**
|
||||||
* zookeeper存放接口路由信息的根目录
|
* zookeeper存放接口路由信息的根目录
|
||||||
*/
|
*/
|
||||||
public static final String SOP_SERVICE_ROUTE_PATH = "/sop-service-route";
|
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package com.gitee.sop.gatewaycommon.gateway.route;
|
package com.gitee.sop.gatewaycommon.gateway.route;
|
||||||
|
|
||||||
import com.gitee.sop.gatewaycommon.bean.SopConstants;
|
import com.gitee.sop.gatewaycommon.bean.SopConstants;
|
||||||
|
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||||
|
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
|
||||||
import com.gitee.sop.gatewaycommon.param.ParamNames;
|
import com.gitee.sop.gatewaycommon.param.ParamNames;
|
||||||
import com.gitee.sop.gatewaycommon.util.RequestUtil;
|
import com.gitee.sop.gatewaycommon.util.RequestUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -59,7 +61,14 @@ public class NameVersionRoutePredicateFactory extends AbstractRoutePredicateFact
|
|||||||
String nameVersion = config.param;
|
String nameVersion = config.param;
|
||||||
String name = params.getOrDefault(ParamNames.API_NAME, "");
|
String name = params.getOrDefault(ParamNames.API_NAME, "");
|
||||||
String version = params.getOrDefault(ParamNames.VERSION_NAME, "");
|
String version = params.getOrDefault(ParamNames.VERSION_NAME, "");
|
||||||
return (name + version).equals(nameVersion);
|
boolean match = (name + version).equals(nameVersion);
|
||||||
|
if (match) {
|
||||||
|
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(nameVersion);
|
||||||
|
if (targetRoute != null && targetRoute.getRouteDefinition().isDisabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_ROUTE_PA
|
|||||||
/**
|
/**
|
||||||
* 路由管理,采用zookeeper实现,监听路由的增删改,并适时更新到本地。路由的存储格式为:
|
* 路由管理,采用zookeeper实现,监听路由的增删改,并适时更新到本地。路由的存储格式为:
|
||||||
* <pre>
|
* <pre>
|
||||||
* /sop-service-route 根节点
|
* /com.gitee.sop.route 根节点
|
||||||
* /serviceId 服务节点,名字为服务名
|
* /serviceId 服务节点,名字为服务名
|
||||||
* /route1 路由节点,名字为:name+version,存放路由信息
|
* /route1 路由节点,名字为:name+version,存放路由信息
|
||||||
* /route2
|
* /route2
|
||||||
@@ -38,12 +38,12 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.SOP_SERVICE_ROUTE_PA
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E extends BaseRouteDefinition, T extends TargetRoute> implements RouteManager {
|
public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E extends BaseRouteDefinition, T extends TargetRoute> implements RouteManager {
|
||||||
|
|
||||||
protected String sopRouteRootPath = SOP_SERVICE_ROUTE_PATH;
|
|
||||||
|
|
||||||
protected Environment environment;
|
protected Environment environment;
|
||||||
|
|
||||||
protected RouteRepository<T> routeRepository;
|
protected RouteRepository<T> routeRepository;
|
||||||
|
|
||||||
|
protected String routeRootPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回路由根对象class
|
* 返回路由根对象class
|
||||||
*
|
*
|
||||||
@@ -70,12 +70,15 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
|||||||
public BaseRouteManager(Environment environment, RouteRepository<T> routeRepository) {
|
public BaseRouteManager(Environment environment, RouteRepository<T> routeRepository) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.routeRepository = routeRepository;
|
this.routeRepository = routeRepository;
|
||||||
|
String profile = environment.getProperty("spring.profiles.active", "default");
|
||||||
|
this.routeRootPath = SOP_SERVICE_ROUTE_PATH + "-" + profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refresh() {
|
public void refresh() {
|
||||||
try {
|
try {
|
||||||
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
|
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
|
||||||
|
String profile = environment.getProperty("spring.profiles.active", "default");
|
||||||
if (StringUtils.isEmpty(zookeeperServerAddr)) {
|
if (StringUtils.isEmpty(zookeeperServerAddr)) {
|
||||||
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
|
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
|
||||||
}
|
}
|
||||||
@@ -91,9 +94,9 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
|||||||
.orSetData()
|
.orSetData()
|
||||||
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
// 如果指定节点的父节点不存在,则Curator将会自动级联创建父节点
|
||||||
.creatingParentContainersIfNeeded()
|
.creatingParentContainersIfNeeded()
|
||||||
.forPath(sopRouteRootPath, "".getBytes());
|
.forPath(routeRootPath, "".getBytes());
|
||||||
|
|
||||||
this.watchServiceChange(client, sopRouteRootPath);
|
this.watchServiceChange(client, routeRootPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -103,13 +106,13 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
|||||||
* 监听微服务更改
|
* 监听微服务更改
|
||||||
*
|
*
|
||||||
* @param client
|
* @param client
|
||||||
* @param sopRouteRootPath
|
* @param rootPath
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected void watchServiceChange(CuratorFramework client, String sopRouteRootPath) throws Exception {
|
protected void watchServiceChange(CuratorFramework client, String rootPath) throws Exception {
|
||||||
// 为子节点添加watcher
|
// 为子节点添加watcher
|
||||||
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
// PathChildrenCache: 监听数据节点的增删改,可以设置触发的事件
|
||||||
PathChildrenCache childrenCache = new PathChildrenCache(client, sopRouteRootPath, true);
|
PathChildrenCache childrenCache = new PathChildrenCache(client, rootPath, true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StartMode: 初始化方式
|
* StartMode: 初始化方式
|
||||||
@@ -122,7 +125,7 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
|||||||
// 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的
|
// 列出子节点数据列表,需要使用BUILD_INITIAL_CACHE同步初始化模式才能获得,异步是获取不到的
|
||||||
List<ChildData> childDataList = childrenCache.getCurrentData();
|
List<ChildData> childDataList = childrenCache.getCurrentData();
|
||||||
log.info("========== 加载路由信息 ==========");
|
log.info("========== 加载路由信息 ==========");
|
||||||
log.info("{} # 根节点", this.sopRouteRootPath);
|
log.info("{} # 根节点", rootPath);
|
||||||
for (ChildData childData : childDataList) {
|
for (ChildData childData : childDataList) {
|
||||||
String serviceNodeData = new String(childData.getData());
|
String serviceNodeData = new String(childData.getData());
|
||||||
R serviceRouteInfo = JSON.parseObject(serviceNodeData, getServiceRouteInfoClass());
|
R serviceRouteInfo = JSON.parseObject(serviceNodeData, getServiceRouteInfoClass());
|
||||||
@@ -130,7 +133,7 @@ public abstract class BaseRouteManager<R extends BaseServiceRouteInfo<E>, E exte
|
|||||||
log.info("\t{} # service节点,节点数据:{}", servicePath, serviceNodeData);
|
log.info("\t{} # service节点,节点数据:{}", servicePath, serviceNodeData);
|
||||||
this.loadServiceRouteItem(client, serviceRouteInfo, servicePath);
|
this.loadServiceRouteItem(client, serviceRouteInfo, servicePath);
|
||||||
}
|
}
|
||||||
log.info("监听服务节点增删改,rootPath:{}", this.sopRouteRootPath);
|
log.info("监听服务节点增删改,rootPath:{}", rootPath);
|
||||||
// 监听根节点下面的子节点
|
// 监听根节点下面的子节点
|
||||||
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
|
childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@@ -49,6 +49,9 @@ public class SopRouteLocator implements RouteLocator, Ordered {
|
|||||||
if (zuulTargetRoute == null) {
|
if (zuulTargetRoute == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (zuulTargetRoute.getRouteDefinition().isDisabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return zuulTargetRoute.getTargetRouteDefinition();
|
return zuulTargetRoute.getTargetRouteDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@ public class CuratorTest extends TestCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归删除节点,只能在测试环境用。
|
* 递归删除节点,只能在测试环境用。
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void testDel() throws Exception {
|
public void testDel() throws Exception {
|
||||||
@@ -26,6 +27,21 @@ public class CuratorTest extends TestCase {
|
|||||||
|
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH);
|
try {
|
||||||
|
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH + "-default");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH + "-dev");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
client.delete().deletingChildrenIfNeeded().forPath(SopConstants.SOP_SERVICE_ROUTE_PATH + "-test");
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
/**
|
/**
|
||||||
* zookeeper存放接口路由信息的根目录
|
* zookeeper存放接口路由信息的根目录
|
||||||
*/
|
*/
|
||||||
public static final String SOP_SERVICE_ROUTE_PATH = "/sop-service-route";
|
public static final String SOP_SERVICE_ROUTE_PATH = "/com.gitee.sop.route";
|
||||||
public static final String PATH_START_CHAR = "/";
|
public static final String PATH_START_CHAR = "/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,10 +42,14 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
|
|
||||||
private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_first.route_", "/", "v_000");
|
private static ServiceApiInfo.ApiMeta FIRST_API_META = new ServiceApiInfo.ApiMeta("_first.route_", "/", "v_000");
|
||||||
|
|
||||||
|
private final String routeRootPath;
|
||||||
|
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
public ServiceZookeeperApiMetaManager(Environment environment) {
|
public ServiceZookeeperApiMetaManager(Environment environment) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
String profile = environment.getProperty("spring.profiles.active", "default");
|
||||||
|
this.routeRootPath = SOP_SERVICE_ROUTE_PATH + "-" + profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,6 +74,8 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
}
|
}
|
||||||
ServiceRouteInfo serviceRouteInfo = new ServiceRouteInfo();
|
ServiceRouteInfo serviceRouteInfo = new ServiceRouteInfo();
|
||||||
serviceRouteInfo.setServiceId(serviceApiInfo.getServiceId());
|
serviceRouteInfo.setServiceId(serviceApiInfo.getServiceId());
|
||||||
|
String description = environment.getProperty("spring.application.description");
|
||||||
|
serviceRouteInfo.setDescription(description);
|
||||||
serviceRouteInfo.setRouteDefinitionList(routeDefinitionList);
|
serviceRouteInfo.setRouteDefinitionList(routeDefinitionList);
|
||||||
return serviceRouteInfo;
|
return serviceRouteInfo;
|
||||||
}
|
}
|
||||||
@@ -133,13 +139,14 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
*/
|
*/
|
||||||
protected void uploadServiceRouteInfoToZookeeper(ServiceRouteInfo serviceRouteInfo) {
|
protected void uploadServiceRouteInfoToZookeeper(ServiceRouteInfo serviceRouteInfo) {
|
||||||
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
|
String zookeeperServerAddr = environment.getProperty("spring.cloud.zookeeper.connect-string");
|
||||||
|
String profile = environment.getProperty("spring.profiles.active", "default");
|
||||||
if (StringUtils.isEmpty(zookeeperServerAddr)) {
|
if (StringUtils.isEmpty(zookeeperServerAddr)) {
|
||||||
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
|
throw new RuntimeException("未指定spring.cloud.zookeeper.connect-string参数");
|
||||||
}
|
}
|
||||||
CuratorFramework client = null;
|
CuratorFramework client = null;
|
||||||
try {
|
try {
|
||||||
// 保存路径
|
// 保存路径
|
||||||
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getServiceId();
|
String savePath = routeRootPath + "/" + serviceRouteInfo.getServiceId();
|
||||||
|
|
||||||
client = CuratorFrameworkFactory.builder()
|
client = CuratorFrameworkFactory.builder()
|
||||||
.connectString(zookeeperServerAddr)
|
.connectString(zookeeperServerAddr)
|
||||||
@@ -172,7 +179,7 @@ public class ServiceZookeeperApiMetaManager implements ApiMetaManager {
|
|||||||
*/
|
*/
|
||||||
protected String uploadFolder(CuratorFramework client, ServiceRouteInfo serviceRouteInfo) throws Exception {
|
protected String uploadFolder(CuratorFramework client, ServiceRouteInfo serviceRouteInfo) throws Exception {
|
||||||
// 保存路径
|
// 保存路径
|
||||||
String savePath = SOP_SERVICE_ROUTE_PATH + "/" + serviceRouteInfo.getServiceId();
|
String savePath = routeRootPath + "/" + serviceRouteInfo.getServiceId();
|
||||||
String serviceRouteInfoJson = JSON.toJSONString(serviceRouteInfo);
|
String serviceRouteInfoJson = JSON.toJSONString(serviceRouteInfo);
|
||||||
log.info("上传service目录到zookeeper,路径:{},内容:{}", savePath, serviceRouteInfoJson);
|
log.info("上传service目录到zookeeper,路径:{},内容:{}", savePath, serviceRouteInfoJson);
|
||||||
this.saveNode(client, savePath, serviceRouteInfoJson.getBytes());
|
this.saveNode(client, savePath, serviceRouteInfoJson.getBytes());
|
||||||
|
@@ -22,4 +22,9 @@ public class GatewayRouteDefinition {
|
|||||||
private int order = 0;
|
private int order = 0;
|
||||||
/** 是否忽略验证,业务参数验证除外 */
|
/** 是否忽略验证,业务参数验证除外 */
|
||||||
private boolean ignoreValidate;
|
private boolean ignoreValidate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否禁用
|
||||||
|
*/
|
||||||
|
private boolean disabled;
|
||||||
}
|
}
|
@@ -1,8 +1,10 @@
|
|||||||
package com.gitee.sop.servercommon.route;
|
package com.gitee.sop.servercommon.route;
|
||||||
|
|
||||||
import com.alibaba.fastjson.annotation.JSONField;
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,6 +14,15 @@ import java.util.List;
|
|||||||
public class ServiceRouteInfo {
|
public class ServiceRouteInfo {
|
||||||
/** 服务名称,对应spring.application.name */
|
/** 服务名称,对应spring.application.name */
|
||||||
private String serviceId;
|
private String serviceId;
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date createTime = new Date();
|
||||||
|
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date updateTime = new Date();
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
@JSONField(serialize = false)
|
@JSONField(serialize = false)
|
||||||
private List<GatewayRouteDefinition> routeDefinitionList;
|
private List<GatewayRouteDefinition> routeDefinitionList;
|
||||||
}
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: story-service
|
name: story-service
|
||||||
|
description: story服务
|
||||||
|
|
||||||
cloud:
|
cloud:
|
||||||
zookeeper:
|
zookeeper:
|
||||||
|
Reference in New Issue
Block a user