diff --git a/sop-admin/sop-admin-front/assets/css/xadmin.css b/sop-admin/sop-admin-front/assets/css/xadmin.css
index d3baaa9c..2228b48a 100644
--- a/sop-admin/sop-admin-front/assets/css/xadmin.css
+++ b/sop-admin/sop-admin-front/assets/css/xadmin.css
@@ -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;
diff --git a/sop-admin/sop-admin-front/assets/js/ApiUtil.js b/sop-admin/sop-admin-front/assets/js/ApiUtil.js
index 3c7033dd..bce95141 100644
--- a/sop-admin/sop-admin-front/assets/js/ApiUtil.js
+++ b/sop-admin/sop-admin-front/assets/js/ApiUtil.js
@@ -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];
diff --git a/sop-admin/sop-admin-front/pages/service/routeManager.html b/sop-admin/sop-admin-front/pages/service/routeManager.html
index b061b9e6..e826bb6d 100644
--- a/sop-admin/sop-admin-front/pages/service/routeManager.html
+++ b/sop-admin/sop-admin-front/pages/service/routeManager.html
@@ -43,7 +43,7 @@
-
+
-
diff --git a/sop-admin/sop-admin-front/pages/service/routeManager.js b/sop-admin/sop-admin-front/pages/service/routeManager.js
index 353895c3..4cc02e52 100644
--- a/sop-admin/sop-admin-front/pages/service/routeManager.js
+++ b/sop-admin/sop-admin-front/pages/service/routeManager.js
@@ -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 '修改';
+ }
+ }
]]
});
//监听单元格事件
- 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
diff --git a/sop-admin/sop-admin-front/pages/service/serviceList.html b/sop-admin/sop-admin-front/pages/service/serviceList.html
index fc8ab65a..50c44e90 100644
--- a/sop-admin/sop-admin-front/pages/service/serviceList.html
+++ b/sop-admin/sop-admin-front/pages/service/serviceList.html
@@ -32,11 +32,7 @@
-
-
+
diff --git a/sop-admin/sop-admin-front/pages/service/serviceList.js b/sop-admin/sop-admin-front/pages/service/serviceList.js
index 7dadee53..fe45c9ea 100644
--- a/sop-admin/sop-admin-front/pages/service/serviceList.js
+++ b/sop-admin/sop-admin-front/pages/service/serviceList.js
@@ -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('下线');
+ }
+ if (row.status === 'OUT_OF_SERVICE') {
+ html.push('上线');
+ }
+ 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;
});
diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
index 9e7a5595..cf16b8fc 100644
--- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
+++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
@@ -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 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 childDataList = ZookeeperContext.getChildrenData(routeRootPath);
List 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 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 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");
diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java
index e5fd5d88..39904ef6 100644
--- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java
+++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java
@@ -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;
}
diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceInstanceParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceInstanceParam.java
new file mode 100644
index 00000000..7dfe26fc
--- /dev/null
+++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/ServiceInstanceParam.java
@@ -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;
+}
diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInfoVo.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInfoVo.java
index 68cf73a6..e1065cd9 100644
--- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInfoVo.java
+++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInfoVo.java
@@ -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)) {
diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/EurekaUri.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/EurekaUri.java
index 8f345a82..5f70f86b 100644
--- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/EurekaUri.java
+++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/EurekaUri.java
@@ -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);
+ }
+}