Merge branch 'develop'

# Conflicts:
#	changelog.md
#	sop-admin/sop-admin-server/pom.xml
#	sop-common/pom.xml
#	sop-common/sop-gateway-common/pom.xml
#	sop-common/sop-registry-api/pom.xml
#	sop-common/sop-service-common/pom.xml
#	sop-example/sop-auth/pom.xml
#	sop-example/sop-book/sop-book-web/pom.xml
#	sop-example/sop-easyopen/pom.xml
#	sop-example/sop-springmvc/pom.xml
#	sop-example/sop-story/sop-story-web/pom.xml
#	sop-gateway/pom.xml
#	sop-website/website-server/pom.xml
This commit is contained in:
tanghc
2019-08-07 15:15:54 +08:00
108 changed files with 2065 additions and 293 deletions

View File

@@ -26,6 +26,7 @@ import com.gitee.sop.adminserver.api.isv.result.RoleVO;
import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.common.ChannelOperation;
import com.gitee.sop.adminserver.common.IdGen;
import com.gitee.sop.adminserver.common.RSATool;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
@@ -229,7 +230,7 @@ public class IsvApi {
if (isvDetail == null) {
return;
}
ChannelMsg channelMsg = new ChannelMsg("update", isvDetail);
ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ISV_INFO_UPDATE, isvDetail);
String path = ZookeeperContext.getIsvInfoChannelPath();
String data = JSON.toJSONString(channelMsg);
try {

View File

@@ -16,6 +16,7 @@ import com.gitee.sop.adminserver.api.service.result.ConfigIpBlacklistVO;
import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.common.ChannelOperation;
import com.gitee.sop.adminserver.entity.ConfigIpBlacklist;
import com.gitee.sop.adminserver.mapper.ConfigIpBlacklistMapper;
import lombok.extern.slf4j.Slf4j;
@@ -51,7 +52,7 @@ public class IPBlacklistApi {
CopyUtil.copyPropertiesIgnoreNull(form, rec);
configIpBlacklistMapper.saveIgnoreNull(rec);
try {
this.sendIpBlacklistMsg(rec, BlacklistMsgType.ADD);
this.sendIpBlacklistMsg(rec, ChannelOperation.BLACKLIST_ADD);
} catch (Exception e) {
log.error("推送IP黑名单失败, rec:{}",rec, e);
throw new BizException("推送IP黑名单失败");
@@ -75,19 +76,18 @@ public class IPBlacklistApi {
}
configIpBlacklistMapper.deleteById(id);
try {
this.sendIpBlacklistMsg(rec, BlacklistMsgType.DELETE);
this.sendIpBlacklistMsg(rec, ChannelOperation.BLACKLIST_DELETE);
} catch (Exception e) {
log.error("推送IP黑名单失败, rec:{}",rec, e);
throw new BizException("推送IP黑名单失败");
}
}
public void sendIpBlacklistMsg(ConfigIpBlacklist configIpBlacklist, BlacklistMsgType blacklistMsgType) throws Exception {
String configData = JSON.toJSONString(configIpBlacklist);
ChannelMsg channelMsg = new ChannelMsg(blacklistMsgType.name().toLowerCase(), configData);
public void sendIpBlacklistMsg(ConfigIpBlacklist configIpBlacklist, ChannelOperation channelOperation) throws Exception {
ChannelMsg channelMsg = new ChannelMsg(channelOperation, configIpBlacklist);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getIpBlacklistChannelPath();
log.info("消息推送--IP黑名单设置({}), path:{}, data:{}",blacklistMsgType.name(), path, jsonData);
log.info("消息推送--IP黑名单设置({}), path:{}, data:{}",channelOperation.getOperation(), path, jsonData);
ZookeeperContext.createOrUpdateData(path, jsonData);
}

View File

@@ -6,15 +6,29 @@ 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.ServiceAddParam;
import com.gitee.sop.adminserver.api.service.param.ServiceGrayConfigParam;
import com.gitee.sop.adminserver.api.service.param.ServiceIdParam;
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.RouteServiceInfo;
import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo;
import com.gitee.sop.adminserver.api.service.result.ServiceInstanceVO;
import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.MetadataEnum;
import com.gitee.sop.adminserver.bean.ServiceGrayDefinition;
import com.gitee.sop.adminserver.bean.ServiceRouteInfo;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.common.ChannelOperation;
import com.gitee.sop.adminserver.common.StatusEnum;
import com.gitee.sop.adminserver.common.ZookeeperPathExistException;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
import com.gitee.sop.adminserver.entity.ConfigGray;
import com.gitee.sop.adminserver.entity.ConfigGrayInstance;
import com.gitee.sop.adminserver.entity.ConfigGrayUserkey;
import com.gitee.sop.adminserver.mapper.ConfigGrayInstanceMapper;
import com.gitee.sop.adminserver.mapper.ConfigGrayMapper;
import com.gitee.sop.adminserver.mapper.ConfigGrayUserkeyMapper;
import com.gitee.sop.registryapi.bean.ServiceInfo;
import com.gitee.sop.registryapi.bean.ServiceInstance;
import com.gitee.sop.registryapi.service.RegistryService;
@@ -41,9 +55,19 @@ import java.util.stream.Collectors;
@Slf4j
public class ServiceApi {
@Autowired
private RegistryService registryService;
@Autowired
private ConfigGrayUserkeyMapper configGrayUserkeyMapper;
@Autowired
private ConfigGrayMapper configGrayMapper;
@Autowired
private ConfigGrayInstanceMapper configGrayInstanceMapper;
@Api(name = "zookeeper.service.list")
@ApiDocMethod(description = "zk中的服务列表", elementClass = RouteServiceInfo.class)
List<RouteServiceInfo> listServiceInfo(ServiceSearchParam param) {
@@ -144,6 +168,9 @@ public class ServiceApi {
int id = idGen.getAndIncrement();
instanceVO.setId(id);
instanceVO.setParentId(pid);
if (instanceVO.getMetadata() == null) {
instanceVO.setMetadata(Collections.emptyMap());
}
serviceInfoVoList.add(instanceVO);
}
});
@@ -152,25 +179,138 @@ public class ServiceApi {
}
@Api(name = "service.instance.offline")
@ApiDocMethod(description = "服务下线")
void serviceOffline(ServiceInstance param) {
@ApiDocMethod(description = "服务禁用")
void serviceOffline(ServiceInstanceParam param) {
try {
registryService.offlineInstance(param);
registryService.offlineInstance(param.buildServiceInstance());
} catch (Exception e) {
log.error("下线失败param:{}", param, e);
throw new BizException("下线失败,请查看日志");
log.error("服务禁用失败param:{}", param, e);
throw new BizException("服务禁用失败,请查看日志");
}
}
@Api(name = "service.instance.online")
@ApiDocMethod(description = "服务上线")
void serviceOnline(ServiceInstance param) throws IOException {
@ApiDocMethod(description = "服务启用")
void serviceOnline(ServiceInstanceParam param) throws IOException {
try {
registryService.onlineInstance(param);
registryService.onlineInstance(param.buildServiceInstance());
} catch (Exception e) {
log.error("服务启用失败param:{}", param, e);
throw new BizException("服务启用失败,请查看日志");
}
}
@Api(name = "service.instance.env.pre.open")
@ApiDocMethod(description = "预发布")
void serviceEnvPre(ServiceInstanceParam param) throws IOException {
try {
MetadataEnum envPre = MetadataEnum.ENV_PRE;
registryService.setMetadata(param.buildServiceInstance(), envPre.getKey(), envPre.getValue());
} catch (Exception e) {
log.error("预发布失败param:{}", param, e);
throw new BizException("预发布失败,请查看日志");
}
}
@Api(name = "service.gray.config.get")
@ApiDocMethod(description = "灰度配置--获取")
ConfigGray serviceEnvGrayConfigGet(ServiceIdParam param) throws IOException {
return this.getConfigGray(param.getServiceId());
}
@Api(name = "service.gray.config.save")
@ApiDocMethod(description = "灰度配置--保存")
void serviceEnvGrayConfigSave(ServiceGrayConfigParam param) throws IOException {
String serviceId = param.getServiceId().toLowerCase();
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
if (configGray == null) {
configGray = new ConfigGray();
configGray.setServiceId(serviceId);
configGray.setNameVersionContent(param.getNameVersionContent());
configGray.setUserKeyContent(param.getUserKeyContent());
configGrayMapper.save(configGray);
} else {
configGray.setNameVersionContent(param.getNameVersionContent());
configGray.setUserKeyContent(param.getUserKeyContent());
configGrayMapper.update(configGray);
}
this.sendServiceGrayMsg(serviceId, ChannelOperation.GRAY_USER_KEY_SET);
}
@Api(name = "service.instance.env.gray.open")
@ApiDocMethod(description = "开启灰度发布")
void serviceEnvGray(ServiceInstanceParam param) throws IOException {
try {
String serviceId = param.getServiceId().toLowerCase();
ConfigGray configGray = this.getConfigGray(serviceId);
if (configGray == null) {
throw new BizException("请先设置灰度参数");
}
MetadataEnum envPre = MetadataEnum.ENV_GRAY;
registryService.setMetadata(param.buildServiceInstance(), envPre.getKey(), envPre.getValue());
String instanceId = param.getInstanceId();
ConfigGrayInstance configGrayInstance = configGrayInstanceMapper.getByColumn("instance_id", instanceId);
if (configGrayInstance == null) {
configGrayInstance = new ConfigGrayInstance();
configGrayInstance.setServiceId(serviceId);
configGrayInstance.setInstanceId(instanceId);
configGrayInstance.setStatus(StatusEnum.STATUS_ENABLE.getStatus());
configGrayInstanceMapper.save(configGrayInstance);
} else {
configGrayInstance.setStatus(StatusEnum.STATUS_ENABLE.getStatus());
configGrayInstance.setServiceId(serviceId);
configGrayInstanceMapper.update(configGrayInstance);
}
this.sendServiceGrayMsg(instanceId, serviceId, ChannelOperation.GRAY_USER_KEY_OPEN);
} catch (Exception e) {
log.error("灰度发布失败param:{}", param, e);
throw new BizException("灰度发布失败,请查看日志");
}
}
@Api(name = "service.instance.env.online")
@ApiDocMethod(description = "上线")
void serviceEnvOnline(ServiceInstance param) throws IOException {
try {
MetadataEnum envPre = MetadataEnum.ENV_ONLINE;
registryService.setMetadata(param, envPre.getKey(), envPre.getValue());
ConfigGrayInstance configGrayInstance = configGrayInstanceMapper.getByColumn("instance_id", param.getInstanceId());
if (configGrayInstance != null) {
configGrayInstance.setStatus(StatusEnum.STATUS_DISABLE.getStatus());
configGrayInstanceMapper.update(configGrayInstance);
this.sendServiceGrayMsg(param.getInstanceId(), param.getServiceId().toLowerCase(), ChannelOperation.GRAY_USER_KEY_CLOSE);
}
} catch (Exception e) {
log.error("上线失败param:{}", param, e);
throw new BizException("上线失败,请查看日志");
}
}
@Api(name = "service.instance.gray.userkey.get")
ConfigGrayUserkey getGrayUserkey(ServiceSearchParam param) {
return configGrayUserkeyMapper.getByColumn("instance_id", param.getInstanceId());
}
private void sendServiceGrayMsg(String serviceId, ChannelOperation channelOperation) {
this.sendServiceGrayMsg(null, serviceId, channelOperation);
}
private void sendServiceGrayMsg(String instanceId, String serviceId, ChannelOperation channelOperation) {
ServiceGrayDefinition serviceGrayDefinition = new ServiceGrayDefinition();
serviceGrayDefinition.setInstanceId(instanceId);
serviceGrayDefinition.setServiceId(serviceId);
ChannelMsg channelMsg = new ChannelMsg(channelOperation, serviceGrayDefinition);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getServiceGrayChannelPath();
log.info("消息推送--灰度发布({}), path:{}, data:{}",channelOperation.getOperation(), path, jsonData);
ZookeeperContext.createOrUpdateData(path, jsonData);
}
private ConfigGray getConfigGray(String serviceId) {
return configGrayMapper.getByColumn("service_id", serviceId);
}
}

View File

@@ -0,0 +1,25 @@
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 ServiceGrayConfigParam {
@ApiDocField(description = "服务名serviceId")
@NotBlank(message = "serviceId不能为空")
private String serviceId;
@ApiDocField(description = "灰度发布用户,多个用英文逗号隔开")
@NotBlank(message = "灰度发布用户不能为空")
private String userKeyContent;
@ApiDocField(description = "灰度发布接口名版本号如order.get1.0=1.2,多个用英文逗号隔开")
@NotBlank(message = "灰度发布接口名版本号不能为空")
private String nameVersionContent;
}

View File

@@ -0,0 +1,16 @@
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 ServiceIdParam {
@ApiDocField(description = "serviceId")
@NotBlank(message = "serviceId不能为空")
private String serviceId;
}

View File

@@ -0,0 +1,26 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
/**
* @author tanghc
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ServiceInstanceGrayParam extends ServiceInstanceParam {
@ApiDocField(description = "灰度发布用户,多个用英文逗号隔开")
@NotBlank(message = "灰度发布用户不能为空")
private String userKeyContent;
@ApiDocField(description = "灰度发布接口名版本号如order.get1.0=1.2,多个用英文逗号隔开")
@NotBlank(message = "灰度发布接口名版本号不能为空")
private String nameVersionContent;
@ApiDocField(description = "是否仅更新灰度用户")
private Boolean onlyUpdateGrayUserkey;
}

View File

@@ -1,6 +1,8 @@
package com.gitee.sop.adminserver.api.service.param;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import com.gitee.easyopen.util.CopyUtil;
import com.gitee.sop.registryapi.bean.ServiceInstance;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@@ -17,4 +19,29 @@ public class ServiceInstanceParam {
@ApiDocField(description = "instanceId")
@NotBlank(message = "instanceId不能为空")
private String instanceId;
/**
* ip
*/
@ApiDocField(description = "ip")
private String ip;
/**
* port
*/
@ApiDocField(description = "port")
private int port;
/**
* 服务状态UP已上线OUT_OF_SERVICE已下线
*/
@ApiDocField(description = "status")
private String status;
public ServiceInstance buildServiceInstance() {
ServiceInstance serviceInstance = new ServiceInstance();
CopyUtil.copyPropertiesIgnoreNull(this, serviceInstance);
return serviceInstance;
}
}

View File

@@ -4,8 +4,6 @@ import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author tanghc
*/
@@ -15,4 +13,7 @@ public class ServiceSearchParam {
@ApiDocField(description = "服务名serviceId")
private String serviceId;
@ApiDocField(description = "instanceId")
private String instanceId;
}

View File

@@ -3,6 +3,8 @@ package com.gitee.sop.adminserver.api.service.result;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Data;
import java.util.Map;
/**
* @author tanghc
*/
@@ -35,6 +37,9 @@ public class ServiceInstanceVO {
@ApiDocField(description = "parentId")
private Integer parentId;
@ApiDocField(description = "metadata")
private Map<String, String> metadata;
public String getIpPort() {
return ip != null && port > 0 ? ip + ":" + port : "";
}

View File

@@ -1,5 +1,6 @@
package com.gitee.sop.adminserver.bean;
import com.gitee.sop.adminserver.common.ChannelOperation;
import lombok.Data;
/**
@@ -8,8 +9,8 @@ import lombok.Data;
@Data
public class ChannelMsg {
public ChannelMsg(String operation, Object data) {
this.operation = operation;
public ChannelMsg(ChannelOperation channelOperation, Object data) {
this.operation = channelOperation.getOperation();
this.data = data;
}

View File

@@ -0,0 +1,37 @@
package com.gitee.sop.adminserver.bean;
/**
* @author tanghc
*/
public enum MetadataEnum {
/**
* 预发布环境
*/
ENV_PRE("env", "pre"),
/**
* 上线环境
*/
ENV_ONLINE("env", ""),
/**
* 灰度环境
*/
ENV_GRAY("env", "gray"),
;
private String key,value;
MetadataEnum(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}

View File

@@ -0,0 +1,13 @@
package com.gitee.sop.adminserver.bean;
import lombok.Data;
/**
* @author tanghc
*/
@Data
public class ServiceGrayDefinition {
private String serviceId;
private String instanceId;
private String data;
}

View File

@@ -89,6 +89,10 @@ public class ZookeeperContext {
return serviceIdPath + "/" + routeId;
}
public static String getServiceGrayChannelPath() {
return SOP_MSG_CHANNEL_PATH + "/gray";
}
public static String getIsvInfoChannelPath() {
return SOP_MSG_CHANNEL_PATH + "/isvinfo";
}

View File

@@ -0,0 +1,64 @@
package com.gitee.sop.adminserver.common;
/**
* @author tanghc
*/
public enum ChannelOperation {
/**
* 限流推送路由配置-修改
*/
LIMIT_CONFIG_UPDATE("update"),
/**
* 路由信息更新
*/
ROUTE_CONFIG_UPDATE("update"),
/**
* isv信息修改
*/
ISV_INFO_UPDATE("update"),
/**
* 黑名单消息类型:添加
*/
BLACKLIST_ADD("add"),
/**
* 黑名单消息类型:删除
*/
BLACKLIST_DELETE("delete"),
/**
* 路由权限配置更新
*/
ROUTE_PERMISSION_UPDATE("update"),
/**
* 路由权限加载
*/
ROUTE_PERMISSION_RELOAD("reload"),
/**
* 灰度发布设置
*/
GRAY_USER_KEY_SET("set"),
/**
* 灰度发布-开启
*/
GRAY_USER_KEY_OPEN("open"),
/**
* 灰度发布-关闭
*/
GRAY_USER_KEY_CLOSE("close"),
;
private String operation;
ChannelOperation(String operation) {
this.operation = operation;
}
public String getOperation() {
return operation;
}
}

View File

@@ -0,0 +1,26 @@
package com.gitee.sop.adminserver.common;
import lombok.Getter;
/**
* 通用状态枚举
*
* @author tanghc
*/
@Getter
public enum StatusEnum {
/**
* 启用
*/
STATUS_ENABLE((byte)1),
/**
* 禁用
*/
STATUS_DISABLE((byte)0),
;
private byte status;
StatusEnum(byte status) {
this.status = status;
}
}

View File

@@ -0,0 +1,42 @@
package com.gitee.sop.adminserver.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名config_gray
* 备注:服务灰度配置
*
* @author tanghc
*/
@Table(name = "config_gray")
@Data
public class ConfigGray {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** 数据库字段service_id */
private String serviceId;
/** 用户key多个用引文逗号隔开, 数据库字段user_key_content */
private String userKeyContent;
/** 需要灰度的接口goods.get1.0=1.2,多个用英文逗号隔开, 数据库字段name_version_content */
private String nameVersionContent;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,41 @@
package com.gitee.sop.adminserver.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名config_gray_instance
*
* @author tanghc
*/
@Table(name = "config_gray_instance")
@Data
public class ConfigGrayInstance {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** instance_id, 数据库字段instance_id */
private String instanceId;
/** service_id, 数据库字段service_id */
private String serviceId;
/** 0禁用1启用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,12 @@
package com.gitee.sop.adminserver.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.adminserver.entity.ConfigGrayInstance;
/**
* @author tanghc
*/
public interface ConfigGrayInstanceMapper extends CrudMapper<ConfigGrayInstance, Long> {
}

View File

@@ -0,0 +1,12 @@
package com.gitee.sop.adminserver.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.adminserver.entity.ConfigGray;
/**
* @author tanghc
*/
public interface ConfigGrayMapper extends CrudMapper<ConfigGray, Long> {
}

View File

@@ -5,6 +5,7 @@ import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.ConfigLimitDto;
import com.gitee.sop.adminserver.bean.RouteConfigDto;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.ChannelOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -21,8 +22,7 @@ public class RouteConfigService {
* @throws Exception
*/
public void sendRouteConfigMsg(RouteConfigDto routeConfigDto) {
String configData = JSON.toJSONString(routeConfigDto);
ChannelMsg channelMsg = new ChannelMsg("update", configData);
ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ROUTE_CONFIG_UPDATE, routeConfigDto);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getRouteConfigChannelPath();
log.info("消息推送--路由配置(update), path:{}, data:{}", path, jsonData);
@@ -35,8 +35,7 @@ public class RouteConfigService {
* @throws Exception
*/
public void sendLimitConfigMsg(ConfigLimitDto routeConfigDto) throws Exception {
String configData = JSON.toJSONString(routeConfigDto);
ChannelMsg channelMsg = new ChannelMsg("update", configData);
ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.LIMIT_CONFIG_UPDATE, routeConfigDto);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getLimitConfigChannelPath();
log.info("消息推送--限流配置(update), path:{}, data:{}", path, jsonData);

View File

@@ -7,6 +7,7 @@ import com.gitee.sop.adminserver.bean.ChannelMsg;
import com.gitee.sop.adminserver.bean.IsvRoutePermission;
import com.gitee.sop.adminserver.bean.SopAdminConstants;
import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.ChannelOperation;
import com.gitee.sop.adminserver.entity.PermIsvRole;
import com.gitee.sop.adminserver.entity.PermRolePermission;
import com.gitee.sop.adminserver.mapper.IsvInfoMapper;
@@ -68,7 +69,7 @@ public class RoutePermissionService {
isvRoutePermission.setAppKey(appKey);
isvRoutePermission.setRouteIdList(routeIdList);
isvRoutePermission.setRouteIdListMd5(roleCodeListMd5);
ChannelMsg channelMsg = new ChannelMsg("update", isvRoutePermission);
ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ROUTE_PERMISSION_UPDATE, isvRoutePermission);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getIsvRoutePermissionChannelPath();
log.info("消息推送--路由权限(update), path:{}, data:{}", path, jsonData);
@@ -105,7 +106,7 @@ public class RoutePermissionService {
});
IsvRoutePermission isvRoutePermission = new IsvRoutePermission();
isvRoutePermission.setListenPath(listenPath);
ChannelMsg channelMsg = new ChannelMsg("reload", isvRoutePermission);
ChannelMsg channelMsg = new ChannelMsg(ChannelOperation.ROUTE_PERMISSION_RELOAD, isvRoutePermission);
String jsonData = JSON.toJSONString(channelMsg);
String path = ZookeeperContext.getIsvRoutePermissionChannelPath();
log.info("消息推送--路由权限(reload), path:{}, data:{}", path, jsonData);

View File

@@ -45,8 +45,8 @@ registry.name=eureka
logging.level.com.gitee=debug
# 不用改
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillInsert=gmt_create
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillUpdate=gmt_modified
mybatis.ignore-update-columns[0]=gmt_create
mybatis.ignore-update-columns[1]=gmt_modified
# 不用改,如果要改,请全局替换修改
zuul.secret=MZZOUSTua6LzApIWXCwEgbBmxSzpzC

View File

@@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],l=0,d=[];l<a.length;l++)c=a[l],u[c]&&d.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);h&&h(n);while(d.length)d.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-238a81e9":"5955f13d","chunk-25908fca":"ca176fa6","chunk-29e7142c":"994a3ac0","chunk-2d2085ef":"7c741493","chunk-2d208c3a":"93f165b2","chunk-2d221c34":"8f017357","chunk-34c76be7":"98e1e7e5","chunk-37401378":"4e39ec9b","chunk-6f78c9fe":"f1ed64fa","chunk-73b2dcec":"14f248eb","chunk-9b31c83a":"2758df30"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-29e7142c":1,"chunk-34c76be7":1,"chunk-37401378":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-29e7142c":"d10599db","chunk-2d2085ef":"31d6cfe0","chunk-2d208c3a":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-34c76be7":"f531fb07","chunk-37401378":"a43114f3","chunk-6f78c9fe":"31d6cfe0","chunk-73b2dcec":"99cf6327","chunk-9b31c83a":"3b12267b"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],l=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(l===r||l===u))return n()}var d=document.getElementsByTagName("style");for(a=0;a<d.length;a++){i=d[a],l=i.getAttribute("data-href");if(l===r||l===u)return n()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=n,h.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),t(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,l=document.createElement("script");l.charset="utf-8",l.timeout=120,f.nc&&l.setAttribute("nonce",f.nc),l.src=a(e),i=function(n){l.onerror=l.onload=null,clearTimeout(d);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var d=setTimeout(function(){i({type:"timeout",target:l})},12e4);l.onerror=l.onload=i,document.head.appendChild(l)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],l=i.push.bind(i);i.push=n,i=i.slice();for(var d=0;d<i.length;d++)n(i[d]);var h=l;t()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.4a507d5e.js></script></body></html>
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],f=n[1],i=n[2],l=0,h=[];l<a.length;l++)c=a[l],u[c]&&h.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);d&&d(n);while(h.length)h.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-238a81e9":"5955f13d","chunk-25908fca":"ca176fa6","chunk-2d2085ef":"7c741493","chunk-2d221c34":"c8ef105a","chunk-34c76be7":"98e1e7e5","chunk-37401378":"4e39ec9b","chunk-6f78c9fe":"f1ed64fa","chunk-73b2dcec":"14f248eb","chunk-9b31c83a":"2758df30","chunk-9f479afe":"1204bc29","chunk-ea2e58a4":"f3f85b0e"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-34c76be7":1,"chunk-37401378":1,"chunk-73b2dcec":1,"chunk-9b31c83a":1,"chunk-ea2e58a4":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-2d2085ef":"31d6cfe0","chunk-2d221c34":"31d6cfe0","chunk-34c76be7":"f531fb07","chunk-37401378":"a43114f3","chunk-6f78c9fe":"31d6cfe0","chunk-73b2dcec":"99cf6327","chunk-9b31c83a":"3b12267b","chunk-9f479afe":"31d6cfe0","chunk-ea2e58a4":"d10599db"}[e]+".css",u=f.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var i=o[a],l=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(l===r||l===u))return n()}var h=document.getElementsByTagName("style");for(a=0;a<h.length;a++){i=h[a],l=i.getAttribute("data-href");if(l===r||l===u)return n()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=n,d.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],d.parentNode.removeChild(d),t(o)},d.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(d)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,l=document.createElement("script");l.charset="utf-8",l.timeout=120,f.nc&&l.setAttribute("nonce",f.nc),l.src=a(e),i=function(n){l.onerror=l.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var h=setTimeout(function(){i({type:"timeout",target:l})},12e4);l.onerror=l.onload=i,document.head.appendChild(l)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],l=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var d=l;t()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.8145abe4.js></script></body></html>

View File

@@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d208c3a"],{a5d4:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"app-container"},[n("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[n("el-form-item",{attrs:{label:"serviceId"}},[n("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"serviceId"},model:{value:t.searchFormData.serviceId,callback:function(e){t.$set(t.searchFormData,"serviceId",e)},expression:"searchFormData.serviceId"}})],1),t._v(" "),n("el-form-item",[n("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.onSearchTable}},[t._v("查询")])],1)],1),t._v(" "),n("el-table",{staticStyle:{width:"100%","margin-bottom":"20px"},attrs:{data:t.tableData,border:"","row-key":"id"}},[n("el-table-column",{attrs:{prop:"serviceId",label:"服务名称",width:"200"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",{domProps:{innerHTML:t._s(t.renderServiceName(e.row))}})]}}])}),t._v(" "),n("el-table-column",{attrs:{prop:"ipPort",label:"IP端口",width:"250"}}),t._v(" "),n("el-table-column",{attrs:{prop:"status",label:"服务状态",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?n("el-tag",{attrs:{type:"success"}},[t._v("已上线")]):t._e(),t._v(" "),e.row.parentId>0&&"STARTING"===e.row.status?n("el-tag",{attrs:{type:"info"}},[t._v("正在启动")]):t._e(),t._v(" "),e.row.parentId>0&&"UNKNOWN"===e.row.status?n("el-tag",[t._v("未知")]):t._e(),t._v(" "),e.row.parentId>0&&("OUT_OF_SERVICE"===e.row.status||"DOWN"===e.row.status)?n("el-tag",{attrs:{type:"danger"}},[t._v("已下线")]):t._e()]}}])}),t._v(" "),n("el-table-column",{attrs:{prop:"updateTime",label:"最后更新时间",width:"160"}}),t._v(" "),n("el-table-column",{attrs:{label:"操作",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return t.onOffline(e.row)}}},[t._v("下线")]):t._e(),t._v(" "),e.row.parentId>0&&"OUT_OF_SERVICE"===e.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return t.onOnline(e.row)}}},[t._v("上线")]):t._e()]}}])})],1)],1)},r=[],i=(n("ac6a"),{data:function(){return{searchFormData:{serviceId:""},tableData:[]}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("service.instance.list",this.searchFormData,function(t){this.tableData=this.buildTreeData(t.data)})},buildTreeData:function(t){return t.forEach(function(e){var n=e.parentId;0===n||t.forEach(function(t){if(t.id===n){var a=t.children;a||(a=[]),a.push(e),t.children=a}})}),t=t.filter(function(t){return 0===t.parentId}),t},onSearchTable:function(){this.loadTable()},onOffline:function(t){this.confirm("确定要下线【"+t.serviceId+"】吗?",function(e){this.post("service.instance.offline",t,function(){this.tip("下线成功"),e()})})},onOnline:function(t){this.confirm("确定要上线【"+t.serviceId+"】吗?",function(e){this.post("service.instance.online",t,function(){this.tip("上线成功"),e()})})},renderServiceName:function(t){var e="";if(t.children&&t.children.length>0){var n=t.children.filter(function(t){return"UP"===t.status}).length;e=" (".concat(n,"/").concat(t.children.length,")")}return t.serviceId+e}}}),o=i,s=n("2877"),l=Object(s["a"])(o,a,r,!1,null,null,null);e["default"]=l.exports}}]);

View File

@@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d221c34"],{cc75:function(a,t,e){"use strict";e.r(t);var i=function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("div",{staticClass:"app-container"},[e("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:a.searchFormData,size:"mini"}},[e("el-form-item",{attrs:{label:"IP"}},[e("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"输入IP"},model:{value:a.searchFormData.ip,callback:function(t){a.$set(a.searchFormData,"ip",t)},expression:"searchFormData.ip"}})],1),a._v(" "),e("el-form-item",[e("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:a.loadTable}},[a._v("查询")])],1)],1),a._v(" "),e("el-button",{staticStyle:{"margin-bottom":"10px"},attrs:{type:"primary",size:"mini",icon:"el-icon-plus"},on:{click:a.onAdd}},[a._v("新增IP")]),a._v(" "),e("el-table",{attrs:{data:a.pageInfo.rows,border:"","highlight-current-row":""}},[e("el-table-column",{attrs:{prop:"ip",label:"IP",width:"200"}}),a._v(" "),e("el-table-column",{attrs:{prop:"remark",label:"备注",width:"300"}}),a._v(" "),e("el-table-column",{attrs:{prop:"gmtCreate",label:"添加时间",width:"160"}}),a._v(" "),e("el-table-column",{attrs:{prop:"gmtModified",label:"修改时间",width:"160"}}),a._v(" "),e("el-table-column",{attrs:{label:"操作",width:"150"},scopedSlots:a._u([{key:"default",fn:function(t){return[e("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(e){return a.onTableUpdate(t.row)}}},[a._v("修改")]),a._v(" "),e("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(e){return a.onTableDelete(t.row)}}},[a._v("删除")])]}}])})],1),a._v(" "),e("el-pagination",{staticStyle:{"margin-top":"5px"},attrs:{background:"","current-page":a.searchFormData.pageIndex,"page-size":a.searchFormData.pageSize,"page-sizes":[5,10,20,40],total:a.pageInfo.total,layout:"total, sizes, prev, pager, next"},on:{"size-change":a.onSizeChange,"current-change":a.onPageIndexChange}}),a._v(" "),e("el-dialog",{attrs:{title:a.dialogTitle,visible:a.dialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){a.dialogVisible=t},close:function(t){return a.resetForm("dialogForm")}}},[e("el-form",{ref:"dialogForm",attrs:{rules:a.dialogFormRules,model:a.dialogFormData,"label-width":"120px",size:"mini"}},[e("el-form-item",{attrs:{prop:"ip",label:"IP"}},[e("el-input",{directives:[{name:"show",rawName:"v-show",value:0===a.dialogFormData.id,expression:"dialogFormData.id === 0"}],model:{value:a.dialogFormData.ip,callback:function(t){a.$set(a.dialogFormData,"ip",t)},expression:"dialogFormData.ip"}}),a._v(" "),e("span",{directives:[{name:"show",rawName:"v-show",value:a.dialogFormData.id>0,expression:"dialogFormData.id > 0"}]},[a._v(a._s(a.dialogFormData.ip))])],1),a._v(" "),e("el-form-item",{attrs:{prop:"remark",label:"备注"}},[e("el-input",{model:{value:a.dialogFormData.remark,callback:function(t){a.$set(a.dialogFormData,"remark",t)},expression:"dialogFormData.remark"}})],1)],1),a._v(" "),e("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[e("el-button",{on:{click:function(t){a.dialogVisible=!1}}},[a._v("取 消")]),a._v(" "),e("el-button",{attrs:{type:"primary"},on:{click:a.onDialogSave}},[a._v("保 存")])],1)],1)],1)},o=[],l={data:function(){var a=function(a,t,e){if(""===t)e(new Error("请输入IP"));else{var i=/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;i.test(t)||e(new Error("IP格式不正确")),e()}};return{searchFormData:{ip:"",pageIndex:1,pageSize:10},pageInfo:{rows:[],total:0},dialogVisible:!1,dialogTitle:"",dialogFormData:{id:0,ip:"",remark:""},dialogFormRules:{ip:[{validator:a,trigger:"blur"},{min:1,max:64,message:"长度在 1 到 64 个字符",trigger:"blur"}],remark:[{max:100,message:"不能超过 100 个字符",trigger:"blur"}]}}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("ip.blacklist.page",this.searchFormData,function(a){this.pageInfo=a.data})},onTableUpdate:function(a){var t=this;this.dialogTitle="修改IP",this.dialogVisible=!0,this.$nextTick(function(){Object.assign(t.dialogFormData,a)})},onTableDelete:function(a){this.confirm("确认要移除IP【".concat(a.ip,"】吗?"),function(t){var e={id:a.id};this.post("ip.blacklist.del",e,function(){t(),this.tip("删除成功"),this.loadTable()})})},onDialogSave:function(){var a=this;this.$refs.dialogForm.validate(function(t){if(t){var e=a.dialogFormData.id?"ip.blacklist.update":"ip.blacklist.add";a.post(e,a.dialogFormData,function(){this.dialogVisible=!1,this.loadTable()})}})},onSizeChange:function(a){this.searchFormData.pageSize=a,this.loadTable()},onAdd:function(){this.dialogTitle="新增IP",this.dialogVisible=!0,this.dialogFormData.id=0},onPageIndexChange:function(a){this.searchFormData.pageIndex=a,this.loadTable()}}},r=l,n=e("2877"),s=Object(n["a"])(r,i,o,!1,null,null,null);t["default"]=s.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d221c34"],{cc75:function(a,t,e){"use strict";e.r(t);var i=function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("div",{staticClass:"app-container"},[e("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:a.searchFormData,size:"mini"}},[e("el-form-item",{attrs:{label:"IP"}},[e("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"输入IP"},model:{value:a.searchFormData.ip,callback:function(t){a.$set(a.searchFormData,"ip",t)},expression:"searchFormData.ip"}})],1),a._v(" "),e("el-form-item",[e("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:a.loadTable}},[a._v("查询")])],1)],1),a._v(" "),e("el-button",{staticStyle:{"margin-bottom":"10px"},attrs:{type:"primary",size:"mini",icon:"el-icon-plus"},on:{click:a.onAdd}},[a._v("新增IP")]),a._v(" "),e("el-table",{attrs:{data:a.pageInfo.rows,border:"","highlight-current-row":""}},[e("el-table-column",{attrs:{prop:"ip",label:"IP",width:"200"}}),a._v(" "),e("el-table-column",{attrs:{prop:"remark",label:"备注",width:"300"}}),a._v(" "),e("el-table-column",{attrs:{prop:"gmtCreate",label:"添加时间",width:"160"}}),a._v(" "),e("el-table-column",{attrs:{prop:"gmtModified",label:"修改时间",width:"160"}}),a._v(" "),e("el-table-column",{attrs:{label:"操作",width:"150"},scopedSlots:a._u([{key:"default",fn:function(t){return[e("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(e){return a.onTableUpdate(t.row)}}},[a._v("修改")]),a._v(" "),e("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(e){return a.onTableDelete(t.row)}}},[a._v("删除")])]}}])})],1),a._v(" "),e("el-pagination",{staticStyle:{"margin-top":"5px"},attrs:{background:"","current-page":a.searchFormData.pageIndex,"page-size":a.searchFormData.pageSize,"page-sizes":[5,10,20,40],total:a.pageInfo.total,layout:"total, sizes, prev, pager, next"},on:{"size-change":a.onSizeChange,"current-change":a.onPageIndexChange}}),a._v(" "),e("el-dialog",{attrs:{title:a.dialogTitle,visible:a.dialogVisible,"close-on-click-modal":!1},on:{"update:visible":function(t){a.dialogVisible=t},close:function(t){return a.resetForm("dialogForm")}}},[e("el-form",{ref:"dialogForm",attrs:{rules:a.dialogFormRules,model:a.dialogFormData,"label-width":"120px",size:"mini"}},[e("el-form-item",{attrs:{prop:"ip",label:"IP"}},[e("el-input",{directives:[{name:"show",rawName:"v-show",value:0===a.dialogFormData.id,expression:"dialogFormData.id === 0"}],model:{value:a.dialogFormData.ip,callback:function(t){a.$set(a.dialogFormData,"ip",t)},expression:"dialogFormData.ip"}}),a._v(" "),e("span",{directives:[{name:"show",rawName:"v-show",value:a.dialogFormData.id>0,expression:"dialogFormData.id > 0"}]},[a._v(a._s(a.dialogFormData.ip))])],1),a._v(" "),e("el-form-item",{attrs:{prop:"remark",label:"备注"}},[e("el-input",{model:{value:a.dialogFormData.remark,callback:function(t){a.$set(a.dialogFormData,"remark",t)},expression:"dialogFormData.remark"}})],1)],1),a._v(" "),e("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[e("el-button",{on:{click:function(t){a.dialogVisible=!1}}},[a._v("取 消")]),a._v(" "),e("el-button",{attrs:{type:"primary"},on:{click:a.onDialogSave}},[a._v("保 存")])],1)],1)],1)},o=[],l={data:function(){var a=/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,t=function(t,e,i){""===e?i(new Error("请输入IP")):(a.test(e)||i(new Error("IP格式不正确")),i())};return{searchFormData:{ip:"",pageIndex:1,pageSize:10},pageInfo:{rows:[],total:0},dialogVisible:!1,dialogTitle:"",dialogFormData:{id:0,ip:"",remark:""},dialogFormRules:{ip:[{validator:t,trigger:"blur"},{min:1,max:64,message:"长度在 1 到 64 个字符",trigger:"blur"}],remark:[{max:100,message:"不能超过 100 个字符",trigger:"blur"}]}}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("ip.blacklist.page",this.searchFormData,function(a){this.pageInfo=a.data})},onTableUpdate:function(a){var t=this;this.dialogTitle="修改IP",this.dialogVisible=!0,this.$nextTick(function(){Object.assign(t.dialogFormData,a)})},onTableDelete:function(a){this.confirm("确认要移除IP【".concat(a.ip,"】吗?"),function(t){var e={id:a.id};this.post("ip.blacklist.del",e,function(){t(),this.tip("删除成功"),this.loadTable()})})},onDialogSave:function(){var a=this;this.$refs.dialogForm.validate(function(t){if(t){var e=a.dialogFormData.id?"ip.blacklist.update":"ip.blacklist.add";a.post(e,a.dialogFormData,function(){this.dialogVisible=!1,this.loadTable()})}})},onSizeChange:function(a){this.searchFormData.pageSize=a,this.loadTable()},onAdd:function(){this.dialogTitle="新增IP",this.dialogVisible=!0,this.dialogFormData.id=0},onPageIndexChange:function(a){this.searchFormData.pageIndex=a,this.loadTable()}}},r=l,n=e("2877"),s=Object(n["a"])(r,i,o,!1,null,null,null);t["default"]=s.exports}}]);

File diff suppressed because one or more lines are too long

View File

@@ -88,11 +88,11 @@
<script>
export default {
data() {
const regexIP = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
const ipValidator = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入IP'))
} else {
const regexIP = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
if (!regexIP.test(value)) {
callback(new Error('IP格式不正确'))
}

View File

@@ -28,16 +28,36 @@
label="IP端口"
width="250"
/>
<el-table-column
prop="metadata"
label="当前环境"
width="100"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.parentId > 0 && scope.row.metadata.env === 'pre'" type="warning">预发布</el-tag>
<el-tag v-if="scope.row.parentId > 0 && scope.row.metadata.env === 'gray'" type="info">灰度</el-tag>
<el-tag v-if="scope.row.parentId > 0 && !scope.row.metadata.env" type="success">线上</el-tag>
</template>
</el-table-column>
<el-table-column
prop="metadata"
label="metadata"
width="250"
>
<template slot-scope="scope">
<span v-if="scope.row.parentId > 0">{{ JSON.stringify(scope.row.metadata) }}</span>
</template>
</el-table-column>
<el-table-column
prop="status"
label="服务状态"
width="100"
>
<template slot-scope="scope">
<el-tag v-if="scope.row.parentId > 0 && scope.row.status === 'UP'" type="success">已上线</el-tag>
<el-tag v-if="scope.row.parentId > 0 && scope.row.status === 'UP'" type="success">正常</el-tag>
<el-tag v-if="scope.row.parentId > 0 && scope.row.status === 'STARTING'" type="info">正在启动</el-tag>
<el-tag v-if="scope.row.parentId > 0 && scope.row.status === 'UNKNOWN'">未知</el-tag>
<el-tag v-if="scope.row.parentId > 0 && (scope.row.status === 'OUT_OF_SERVICE' || scope.row.status === 'DOWN')" type="danger">下线</el-tag>
<el-tag v-if="scope.row.parentId > 0 && (scope.row.status === 'OUT_OF_SERVICE' || scope.row.status === 'DOWN')" type="danger">禁用</el-tag>
</template>
</el-table-column>
<el-table-column
@@ -47,24 +67,152 @@
/>
<el-table-column
label="操作"
width="100"
width="250"
>
<template slot-scope="scope">
<el-button v-if="scope.row.parentId > 0 && scope.row.status === 'UP'" type="text" size="mini" @click="onOffline(scope.row)">下线</el-button>
<el-button v-if="scope.row.parentId > 0 && scope.row.status === 'OUT_OF_SERVICE'" type="text" size="mini" @click="onOnline(scope.row)">上线</el-button>
<el-button v-if="scope.row.parentId > 0 && scope.row.metadata.env === 'pre'" type="text" size="mini" @click="onEnvPreClose(scope.row)">结束预发布</el-button>
<el-button v-if="scope.row.parentId > 0 && scope.row.metadata.env === 'gray'" type="text" size="mini" @click="onEnvGrayClose(scope.row)">结束灰度</el-button>
<el-button v-if="scope.row.parentId > 0 && !scope.row.metadata.env" type="text" size="mini" @click="onEnvPreOpen(scope.row)">开启预发布</el-button>
<el-button v-if="scope.row.parentId > 0 && !scope.row.metadata.env" type="text" size="mini" @click="onEnvGrayOpen(scope.row)">开启灰度</el-button>
<el-button v-if="scope.row.parentId === 0" type="text" size="mini" @click="onGrayConfigUpdate(scope.row)">设置灰度参数</el-button>
<el-button v-if="scope.row.parentId > 0 && scope.row.status === 'UP'" type="text" size="mini" @click="onDisable(scope.row)">禁用</el-button>
<el-button v-if="scope.row.parentId > 0 && scope.row.status === 'OUT_OF_SERVICE'" type="text" size="mini" @click="onEnable(scope.row)">启用</el-button>
</template>
</el-table-column>
</el-table>
<!-- dialog -->
<el-dialog
title="灰度设置"
:visible.sync="grayDialogVisible"
:close-on-click-modal="false"
@close="resetForm('grayForm')"
>
<el-form
ref="grayForm"
:model="grayForm"
:rules="grayFormRules"
size="mini"
>
<el-form-item label="serviceId">
{{ grayForm.serviceId }}
</el-form-item>
<el-tabs v-model="tabsActiveName" type="card">
<el-tab-pane label="灰度用户" name="first">
<el-alert
title="可以是appId或userId多个用英文逗号隔开"
type="info"
:closable="false"
style="margin-bottom: 20px;"
/>
<el-form-item prop="userKeyContent">
<el-input
v-model="grayForm.userKeyContent"
placeholder="可以是appId或userId多个用英文逗号隔开"
type="textarea"
:rows="6"
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="接口配置" name="second">
<el-form-item>
<el-button type="text" @click="addNameVersion">新增灰度接口</el-button>
</el-form-item>
<table cellpadding="0" cellspacing="0">
<tr
v-for="(grayRouteConfig, index) in grayForm.grayRouteConfigList"
:key="grayRouteConfig.key"
>
<td>
<el-form-item
:key="grayRouteConfig.key"
:prop="'grayRouteConfigList.' + index + '.oldRouteId'"
:rules="{required: true, message: '不能为空', trigger: ['blur', 'change']}"
>
老接口
<el-select
v-model="grayRouteConfig.oldRouteId"
style="margin-right: 10px;"
@change="onChangeOldRoute(grayRouteConfig)"
>
<el-option
v-for="route in routeList"
:key="route.id"
:label="route.name + '(' + route.version + ')'"
:value="route.id"
/>
</el-select>
</el-form-item>
</td>
<td>
<el-form-item
:key="grayRouteConfig.key + 1"
:prop="'grayRouteConfigList.' + index + '.newVersion'"
:rules="{required: true, message: '不能为空', trigger: ['blur', 'change']}"
>
灰度接口
<el-select
v-model="grayRouteConfig.newVersion"
no-data-text="无数据"
>
<el-option
v-for="routeNew in getGraySelectData(grayRouteConfig.oldRouteId)"
:key="routeNew.id"
:label="routeNew.name + '(' + routeNew.version + ')'"
:value="routeNew.version"
/>
</el-select>
</el-form-item>
</td>
<td style="vertical-align: baseline;">
<el-button v-show="grayForm.grayRouteConfigList.length > 1" type="text" @click.prevent="removeNameVersion(grayRouteConfig)">删除</el-button>
</td>
</tr>
</table>
</el-tab-pane>
</el-tabs>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="grayDialogVisible = false"> </el-button>
<el-button type="primary" @click="onGrayConfigSave"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
const regex = /^\w+(,\w+)*$/
const userKeyContentValidator = (rule, value, callback) => {
if (value === '') {
callback(new Error('不能为空'))
} else {
if (!regex.test(value)) {
callback(new Error('格式不正确'))
}
callback()
}
}
return {
searchFormData: {
serviceId: ''
},
grayDialogVisible: false,
grayForm: {
serviceId: '',
userKeyContent: '',
onlyUpdateGrayUserkey: false,
grayRouteConfigList: []
},
tabsActiveName: 'first',
routeList: [],
selectNameVersion: [],
grayFormRules: {
userKeyContent: [
{ required: true, message: '不能为空', trigger: 'blur' },
{ validator: userKeyContentValidator, trigger: 'blur' }
]
},
tableData: []
}
},
@@ -77,6 +225,18 @@ export default {
this.tableData = this.buildTreeData(resp.data)
})
},
loadRouteList: function(serviceId) {
if (this.routeList.length === 0) {
this.post('route.list/1.2', { serviceId: serviceId.toLowerCase() }, function(resp) {
this.routeList = resp.data
})
}
},
getGraySelectData: function(oldRouteId) {
return this.routeList.filter(routeNew => {
return oldRouteId !== routeNew.id && oldRouteId.indexOf(routeNew.name) > -1
})
},
buildTreeData: function(data) {
data.forEach(ele => {
const parentId = ele.parentId
@@ -103,22 +263,126 @@ export default {
onSearchTable: function() {
this.loadTable()
},
onOffline: function(row) {
this.confirm('确定要下线【' + row.serviceId + '】吗?', function(done) {
onDisable: function(row) {
this.confirm('确定要禁用【' + row.serviceId + '】吗?', function(done) {
this.post('service.instance.offline', row, function() {
this.tip('下线成功')
done()
})
})
},
onOnline: function(row) {
this.confirm('确定要上线【' + row.serviceId + '】吗?', function(done) {
onEnable: function(row) {
this.confirm('确定要启用【' + row.serviceId + '】吗?', function(done) {
this.post('service.instance.online', row, function() {
this.tip('上线成功')
done()
})
})
},
doEnvOnline: function(row, callback) {
this.post('service.instance.env.online', row, function() {
callback && callback.call(this)
})
},
onEnvPreOpen: function(row) {
this.confirm(`确定要开启 ${row.instanceId} 预发布吗?`, function(done) {
this.post('service.instance.env.pre.open', row, function() {
this.tip('预发布成功')
done()
})
})
},
onEnvPreClose: function(row) {
this.confirm(`确定要结束 ${row.instanceId} 预发布吗?`, function(done) {
this.doEnvOnline(row, function() {
this.tip('操作成功')
done()
})
})
},
onEnvGrayOpen: function(row) {
this.confirm(`确定要开启 ${row.instanceId} 灰度吗?`, function(done) {
this.post('service.instance.env.gray.open', row, function() {
this.tip('开启成功')
done()
})
})
},
onEnvGrayClose: function(row) {
this.confirm(`确定要结束 ${row.instanceId} 灰度吗?`, function(done) {
this.doEnvOnline(row, function() {
this.tip('操作成功')
done()
})
})
},
onGrayConfigUpdate: function(row) {
const serviceId = row.serviceId
this.loadRouteList(serviceId)
this.post('service.gray.config.get', { serviceId: serviceId }, function(resp) {
this.grayDialogVisible = true
const data = resp.data
Object.assign(this.grayForm, {
serviceId: serviceId,
userKeyContent: data.userKeyContent || '',
grayRouteConfigList: this.createGrayRouteConfigList(data.nameVersionContent)
})
})
},
onGrayConfigSave: function() {
this.$refs.grayForm.validate((valid) => {
if (valid) {
const nameVersionContents = []
const grayRouteConfigList = this.grayForm.grayRouteConfigList
for (let i = 0; i < grayRouteConfigList.length; i++) {
const config = grayRouteConfigList[i]
nameVersionContents.push(config.oldRouteId + '=' + config.newVersion)
}
this.grayForm.nameVersionContent = nameVersionContents.join(',')
this.post('service.gray.config.save', this.grayForm, function() {
this.grayDialogVisible = false
this.tip('保存成功')
})
}
})
},
createGrayRouteConfigList: function(nameVersionContent) {
if (!nameVersionContent) {
return [{
oldRouteId: '',
newVersion: '',
key: Date.now()
}]
}
const list = []
const arr = nameVersionContent.split(',')
for (let i = 0; i < arr.length; i++) {
const el = arr[i]
const elArr = el.split('=')
list.push({
oldRouteId: elArr[0],
newVersion: elArr[1],
key: Date.now()
})
}
return list
},
onChangeOldRoute: function(config) {
config.newVersion = ''
},
addNameVersion: function() {
this.grayForm.grayRouteConfigList.push({
oldRouteId: '',
newVersion: '',
key: Date.now()
})
},
removeNameVersion: function(item) {
const index = this.grayForm.grayRouteConfigList.indexOf(item)
if (index !== -1) {
this.grayForm.grayRouteConfigList.splice(index, 1)
}
},
renderServiceName: function(row) {
let instanceCount = ''
if (row.children && row.children.length > 0) {