服务列表查询、上下线

1.x
tanghc 6 years ago
parent 44f3c76c78
commit 340598ee66
  1. 5
      sop-admin/sop-admin-front/assets/css/xadmin.css
  2. 6
      sop-admin/sop-admin-front/assets/js/ApiUtil.js
  3. 5
      sop-admin/sop-admin-front/pages/service/routeManager.html
  4. 10
      sop-admin/sop-admin-front/pages/service/routeManager.js
  5. 6
      sop-admin/sop-admin-front/pages/service/serviceList.html
  6. 63
      sop-admin/sop-admin-front/pages/service/serviceList.js
  7. 45
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
  8. 2
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java
  9. 20
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceInstanceParam.java
  10. 6
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInfoVo.java
  11. 62
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/EurekaUri.java

@ -644,6 +644,11 @@ table th, table td {
padding: 0 10px;
}
.layui-table-cell .layui-btn {
height: 27px;
line-height: 28px;
}
.x-admin-sm .layui-btn-lg{
height: 38px;
line-height: 38px;

@ -55,11 +55,11 @@ var ApiUtil = (function () {
, getUrl: function () {
return url;
}
, createUrl: function (uri) {
, createUrl: function (uri, params) {
if (!uri) {
throw new Error('name不能为空');
throw new Error('uri不能为空');
}
return url + formatUri(uri);
return url + formatUri(uri) + (params ? '?data=' + encodeURIComponent(JSON.stringify(params)) : '');
}
, getParam: function (paramName) {
return params[paramName];

@ -43,7 +43,7 @@
</form>
</div>
<table class="layui-hide" id="routeTable" lay-filter="routeTable"></table>
<table class="layui-hide" id="routeTable" lay-filter="routeTableFilter"></table>
<script type="text/html" id="toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-ms layui-btn-normal" lay-event="add">
@ -51,9 +51,6 @@
</button>
</div>
</script>
<script type="text/html" id="optBar" >
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>
</script>
</div>
</div>

@ -128,12 +128,16 @@ lib.importJs('../../assets/js/profile.js').use(['element', 'table', 'tree', 'for
return ROUTE_STATUS[row.status + ''];
}
}
, {fixed: 'right', title: '操作', toolbar: '#optBar', width: 100}
, {
fixed: 'right', title: '操作', width: 100, templet: function (row) {
return '<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">修改</a>';
}
}
]]
});
//监听单元格事件
table.on('tool(routeTable)', function(obj) {
table.on('tool(routeTableFilter)', function(obj) {
var data = obj.data;
if(obj.event === 'edit'){
//表单初始赋值
@ -142,8 +146,6 @@ lib.importJs('../../assets/js/profile.js').use(['element', 'table', 'tree', 'for
updateForm.setData(data);
// form.val('updateWinFilter', data);
layer.open({
type: 1
,title: '修改路由' + smTitle

@ -32,11 +32,7 @@
</form>
</div>
<table class="layui-hide" id="treeTable"></table>
<script type="text/html" id="optCol">
<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>
<table class="layui-hide" id="treeTable" lay-filter="treeTableFilter"></table>
</div>
<script type="text/javascript" src="../../assets/js/lib.js"></script>

@ -3,23 +3,23 @@ lib.config({
}).extend({
treetable: 'treetable-lay/treetable'
}).use(['element', 'table', 'form', 'treetable'], function () {
var table = layui.table;
var layer = layui.layer;
var form = layui.form;
var treetable = layui.treetable;
var serverTable;
// 渲染表格
var renderTable = function () {
var renderTable = function (params) {
layer.load(2);
serverTable = treetable.render({
treetable.render({
elem: '#treeTable',
treeColIndex: 1,
treeSpid: 0,
treeIdName: 'id',
treePidName: 'parentId',
treeDefaultClose: true,
treeDefaultClose: false,
treeLinkage: false,
elem: '#treeTable',
url: ApiUtil.createUrl('service.instance.list'),
url: ApiUtil.createUrl('service.instance.list', params),
page: false,
cols: [[
{type: 'numbers'},
@ -29,24 +29,61 @@ lib.config({
{field: 'serverPort', title: '端口号', width: 100},
{field: 'status', title: 'status', width: 100},
{field: 'updateTime', title: '最后更新时间', width: 150},
{fixed: 'right', templet: '#optCol', title: '操作', width: 200}
{fixed: 'right', title: '操作', width: 200, templet: function (row) {
if (row.parentId > 0) {
var html = [];
if (row.status === 'UP') {
html.push('<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="offline">下线</a>');
}
if (row.status === 'OUT_OF_SERVICE') {
html.push('<a class="layui-btn layui-btn-xs" lay-event="online">上线</a>');
}
return html.join('');
}
return '';
}}
]],
done: function () {
layer.closeAll('loading');
}
});
//监听单元格事件
table.on('tool(treeTableFilter)', function(obj) {
if (obj.event === 'offline') {
var data = obj.data;
layer.confirm('确定要下线【'+data.name+'】吗?', {icon: 3, title:'提示'}, function(index){
var params = {
serviceId: data.name
, instanceId: data.instanceId
};
ApiUtil.post('service.instance.offline', params, function (resp) {
layer.alert('修改成功');
});
layer.close(index);
});
}
if (obj.event === 'online') {
var data = obj.data;
layer.confirm('确定要上线【'+data.name+'】吗?', {icon: 3, title:'提示'}, function(index){
var params = {
serviceId: data.name
, instanceId: data.instanceId
};
ApiUtil.post('service.instance.online', params, function (resp) {
layer.alert('修改成功');
});
layer.close(index);
});
}
});
};
renderTable();
form.on('submit(searchFilter)', function(data){
var param = data.field;
serverTable.reload({
where: {
data: JSON.stringify(param)
}
})
renderTable(param)
return false;
});

@ -6,6 +6,7 @@ import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.easyopen.exception.ApiException;
import com.gitee.sop.adminserver.api.service.param.ServiceInstanceParam;
import com.gitee.sop.adminserver.api.service.param.ServiceSearchParam;
import com.gitee.sop.adminserver.api.service.result.ServiceInfo;
import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo;
@ -50,12 +51,8 @@ public class ServiceApi {
// eureka.client.serviceUrl.defaultZone
@Api(name = "service.list")
@ApiDocMethod(description = "服务列表", elementClass = ServiceInfo.class)
@ApiDocMethod(description = "服务列表(旧)", elementClass = ServiceInfo.class)
List<ServiceInfo> listServiceInfo(ServiceSearchParam param) throws Exception {
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS);
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class);
String routeRootPath = ZookeeperContext.getSopRouteRootPath(param.getProfile());
List<ChildData> childDataList = ZookeeperContext.getChildrenData(routeRootPath);
List<ServiceInfo> serviceInfoList = childDataList.stream()
@ -78,7 +75,7 @@ public class ServiceApi {
}
@Api(name = "service.instance.list")
@ApiDocMethod(description = "服务列表", elementClass = ServiceInfo.class)
@ApiDocMethod(description = "服务列表", elementClass = ServiceInfoVo.class)
List<ServiceInfoVo> listService(ServiceSearchParam param) throws Exception {
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS);
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class);
@ -87,6 +84,12 @@ public class ServiceApi {
List<EurekaApplication> applicationList = eurekaApps.getApplications().getApplication();
AtomicInteger idGen = new AtomicInteger(1);
applicationList.stream()
.filter(eurekaApplication -> {
if (StringUtils.isBlank(param.getServiceId())) {
return true;
}
return StringUtils.containsIgnoreCase(eurekaApplication.getName(), param.getServiceId());
})
.forEach(eurekaApplication -> {
int pid = idGen.getAndIncrement();
String name = eurekaApplication.getName();
@ -107,29 +110,33 @@ public class ServiceApi {
serviceInfoVoList.add(vo);
}
});
return serviceInfoVoList;
}
private String requestEurekaServer(EurekaUri uri) throws IOException {
Request request = this.buildRequest(EurekaUri.QUERY_APPS);
@Api(name = "service.instance.offline")
@ApiDocMethod(description = "服务下线")
void serviceOffline(ServiceInstanceParam param) throws IOException {
this.requestEurekaServer(EurekaUri.OFFLINE_SERVICE, param.getServiceId(), param.getInstanceId());
}
@Api(name = "service.instance.online")
@ApiDocMethod(description = "服务上线")
void serviceOnline(ServiceInstanceParam param) throws IOException {
this.requestEurekaServer(EurekaUri.ONLINE_SERVICE, param.getServiceId(), param.getInstanceId());
}
private String requestEurekaServer(EurekaUri eurekaUri, String... args) throws IOException {
Request request = eurekaUri.getRequest(this.eurekaUrl, args);
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
return "{}";
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code());
throw new ApiException("操作失败", String.valueOf(response.code()));
}
}
private Request buildRequest(EurekaUri uri) {
String apiUrl = this.eurekaUrl + uri.getUri();
Request request = new Request.Builder()
.url(apiUrl)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.build();
return request;
}
@PostConstruct
protected void after() {
String eurekaUrls = environment.getProperty("eureka.client.serviceUrl.defaultZone");

@ -1,5 +1,6 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Getter;
import lombok.Setter;
@ -9,5 +10,6 @@ import lombok.Setter;
@Getter
@Setter
public class RouteSearchParam extends ServiceSearchParam {
@ApiDocField(description = "id")
private String id;
}

@ -0,0 +1,20 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author tanghc
*/
@Data
public class ServiceInstanceParam {
@ApiDocField(description = "serviceId")
@NotBlank(message = "serviceId不能为空")
private String serviceId;
@ApiDocField(description = "instanceId")
@NotBlank(message = "instanceId不能为空")
private String instanceId;
}

@ -15,7 +15,7 @@ public class ServiceInfoVo {
@ApiDocField(description = "id")
private Integer id;
@ApiDocField(description = "服务名称")
@ApiDocField(description = "服务名称(serviceId)")
private String name;
@ApiDocField(description = "instanceId")
@ -42,6 +42,10 @@ public class ServiceInfoVo {
@ApiDocField(description = "parentId")
private Integer parentId;
public String getServiceId() {
return this.name;
}
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
public Date getUpdateTime() {
if (StringUtils.isBlank(lastUpdatedTimestamp)) {

@ -1,20 +1,70 @@
package com.gitee.sop.adminserver.bean;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.internal.http.HttpMethod;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* https://github.com/Netflix/eureka/wiki/Eureka-REST-operations
*
* @author tanghc
*/
public enum EurekaUri {
/** Query for all instances */
QUERY_APPS("/apps"),
/**
* 查询所有实例 Query for all instances
*/
QUERY_APPS(RequestMethod.GET, "/apps"),
/**
* 下线 Take instance out of service
*/
OFFLINE_SERVICE(RequestMethod.PUT, "/apps/%s/%s/status?value=OUT_OF_SERVICE"),
/**
* 上线 Move instance back into service (remove override)
*/
ONLINE_SERVICE(RequestMethod.DELETE, "/apps/%s/%s/status?value=UP"),
;
public static final String URL_PREFIX = "/";
String uri;
RequestMethod requestMethod;
EurekaUri(String uri) {
EurekaUri(RequestMethod httpMethod, String uri) {
if (!uri.startsWith(URL_PREFIX)) {
uri = "/" + uri;
}
this.uri = uri;
this.requestMethod = httpMethod;
}
public String getUri(String... args) {
if (ArrayUtils.isEmpty(args)) {
return uri;
}
Object[] param = ArrayUtils.clone(args);
return String.format(uri, param);
}
public String getUri() {
return uri;
}}
public Request getRequest(String url, String... args) {
String requestUrl = url + getUri(args);
Request request = this.getBuilder()
.url(requestUrl)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.build();
return request;
}
public Request.Builder getBuilder() {
String method = requestMethod.name();
RequestBody requestBody = null;
if (HttpMethod.requiresRequestBody(method)) {
MediaType contentType = MediaType.parse(org.springframework.http.MediaType.APPLICATION_JSON_VALUE);
requestBody = RequestBody.create(contentType, "{}");
}
return new Request.Builder().method(requestMethod.name(), requestBody);
}
}

Loading…
Cancel
Save