mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
适配eureka
This commit is contained in:
@@ -86,7 +86,7 @@ public class IPBlacklistApi {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendIpBlacklistMsg(ConfigIpBlacklist configIpBlacklist, ChannelOperation channelOperation) throws Exception {
|
||||
public void sendIpBlacklistMsg(ConfigIpBlacklist configIpBlacklist, ChannelOperation channelOperation) {
|
||||
ChannelMsg channelMsg = new ChannelMsg(channelOperation, configIpBlacklist);
|
||||
configPushService.publishConfig(NacosConfigs.DATA_ID_IP_BLACKLIST, NacosConfigs.GROUP_CHANNEL, channelMsg);
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ import com.gitee.sop.adminserver.common.BizException;
|
||||
import com.gitee.sop.adminserver.entity.ConfigLimit;
|
||||
import com.gitee.sop.adminserver.mapper.ConfigLimitMapper;
|
||||
import com.gitee.sop.adminserver.service.RouteConfigService;
|
||||
import com.gitee.sop.adminserver.service.RouteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -33,9 +32,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Slf4j
|
||||
public class LimitNewApi {
|
||||
|
||||
@Autowired
|
||||
RouteService routeService;
|
||||
|
||||
@Autowired
|
||||
RouteConfigService routeConfigService;
|
||||
|
||||
@@ -44,7 +40,7 @@ public class LimitNewApi {
|
||||
|
||||
@Api(name = "config.limit.list")
|
||||
@ApiDocMethod(description = "限流列表(新)", elementClass = LimitNewVO.class)
|
||||
PageInfo<ConfigLimit> listLimit(LimitNewParam param) throws Exception {
|
||||
PageInfo<ConfigLimit> listLimit(LimitNewParam param) {
|
||||
Query query = Query.build(param);
|
||||
query.orderby("route_id", Sort.ASC)
|
||||
.orderby("app_key", Sort.ASC)
|
||||
|
@@ -4,6 +4,10 @@ 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.fastmybatis.core.query.Query;
|
||||
import com.gitee.fastmybatis.core.query.Sort;
|
||||
import com.gitee.fastmybatis.core.support.PageEasyui;
|
||||
import com.gitee.fastmybatis.core.util.MapperUtil;
|
||||
import com.gitee.sop.adminserver.api.isv.result.RoleVO;
|
||||
import com.gitee.sop.adminserver.api.service.param.RouteAddParam;
|
||||
import com.gitee.sop.adminserver.api.service.param.RouteDeleteParam;
|
||||
@@ -14,19 +18,24 @@ import com.gitee.sop.adminserver.api.service.result.RouteVO;
|
||||
import com.gitee.sop.adminserver.bean.RouteConfigDto;
|
||||
import com.gitee.sop.adminserver.common.BizException;
|
||||
import com.gitee.sop.adminserver.entity.ConfigRouteBase;
|
||||
import com.gitee.sop.adminserver.entity.ConfigServiceRoute;
|
||||
import com.gitee.sop.adminserver.entity.PermRole;
|
||||
import com.gitee.sop.adminserver.entity.PermRolePermission;
|
||||
import com.gitee.sop.adminserver.entity.RouteRoleDTO;
|
||||
import com.gitee.sop.adminserver.mapper.ConfigRouteBaseMapper;
|
||||
import com.gitee.sop.adminserver.mapper.ConfigServiceRouteMapper;
|
||||
import com.gitee.sop.adminserver.mapper.PermRoleMapper;
|
||||
import com.gitee.sop.adminserver.mapper.PermRolePermissionMapper;
|
||||
import com.gitee.sop.adminserver.service.RouteConfigService;
|
||||
import com.gitee.sop.adminserver.service.RoutePermissionService;
|
||||
import com.gitee.sop.adminserver.service.RouteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -46,48 +55,56 @@ public class RouteApi {
|
||||
@Autowired
|
||||
ConfigRouteBaseMapper configRouteBaseMapper;
|
||||
|
||||
@Autowired
|
||||
private ConfigServiceRouteMapper configServiceRouteMapper;
|
||||
|
||||
@Autowired
|
||||
RoutePermissionService routePermissionService;
|
||||
|
||||
@Autowired
|
||||
RouteConfigService routeConfigService;
|
||||
|
||||
@Autowired
|
||||
RouteService routeService;
|
||||
|
||||
@Api(name = "route.list")
|
||||
@ApiDocMethod(description = "路由列表")
|
||||
List<RouteVO> listRoute(RouteSearchParam param) throws Exception {
|
||||
List<RouteVO> routeDefinitionList = routeService.getRouteDefinitionList(param)
|
||||
.stream()
|
||||
.map(gatewayRouteDefinition -> {
|
||||
RouteVO vo = new RouteVO();
|
||||
BeanUtils.copyProperties(gatewayRouteDefinition, vo);
|
||||
vo.setRoles(this.getRouteRole(gatewayRouteDefinition.getId()));
|
||||
ConfigRouteBase configRouteBase = configRouteBaseMapper.getByColumn("route_id", gatewayRouteDefinition.getId());
|
||||
if (configRouteBase != null) {
|
||||
vo.setStatus(configRouteBase.getStatus());
|
||||
}
|
||||
return vo;
|
||||
})
|
||||
@ApiDocMethod(description = "路由列表,分页")
|
||||
@Api(name = "route.page")
|
||||
PageEasyui<RouteVO> page(RouteSearchParam form) {
|
||||
Query query = Query.build(form);
|
||||
query.orderby("id", Sort.ASC);
|
||||
PageEasyui<RouteVO> datagrid = MapperUtil.queryForEasyuiDatagrid(configServiceRouteMapper, query, RouteVO.class);
|
||||
List<String> routeIdList = datagrid.getRows()
|
||||
.parallelStream()
|
||||
.map(RouteVO::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return routeDefinitionList;
|
||||
Map<String, Byte> routeIdStatusMap = configRouteBaseMapper
|
||||
.list(new Query().in("route_id", routeIdList))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ConfigRouteBase::getRouteId, ConfigRouteBase::getStatus));
|
||||
|
||||
Map<String, List<RouteRoleDTO>> routeIdRoleMap = permRolePermissionMapper.listRouteRole(routeIdList)
|
||||
.parallelStream()
|
||||
.collect(Collectors.groupingBy(RouteRoleDTO::getRouteId));
|
||||
|
||||
|
||||
datagrid.getRows().forEach(vo -> {
|
||||
String routeId = vo.getId();
|
||||
List<RouteRoleDTO> routeRoleDTOS = routeIdRoleMap.getOrDefault(routeId, Collections.emptyList());
|
||||
vo.setRoles(routeRoleDTOS);
|
||||
Byte status = routeIdStatusMap.getOrDefault(routeId, vo.getStatus());
|
||||
vo.setStatus(status);
|
||||
});
|
||||
|
||||
return datagrid;
|
||||
}
|
||||
|
||||
@Api(name = "route.list", version = "1.2")
|
||||
@ApiDocMethod(description = "路由列表1.2")
|
||||
List<RouteVO> listRoute2(RouteSearchParam param) throws Exception {
|
||||
List<RouteVO> routeDefinitionList = routeService.getRouteDefinitionList(param)
|
||||
.stream()
|
||||
.map(gatewayRouteDefinition -> {
|
||||
RouteVO vo = new RouteVO();
|
||||
BeanUtils.copyProperties(gatewayRouteDefinition, vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return routeDefinitionList;
|
||||
List<ConfigServiceRoute> listRoute2(RouteSearchParam param) {
|
||||
String serviceId = param.getServiceId();
|
||||
if (StringUtils.isBlank(serviceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Query query = Query.build(param);
|
||||
return configServiceRouteMapper.list(query);
|
||||
}
|
||||
|
||||
@Api(name = "route.add")
|
||||
@@ -149,6 +166,34 @@ public class RouteApi {
|
||||
|
||||
/**
|
||||
* 获取路由对应的角色
|
||||
*
|
||||
* @param routeIdList routeIdList
|
||||
* @return
|
||||
*/
|
||||
private List<RoleVO> getRouteRole(List<String> routeIdList) {
|
||||
// key:routeId, value: roleCode
|
||||
Map<String, List<String>> routeIdRoleCodeMap = permRolePermissionMapper.list(new Query().in("route_id", routeIdList))
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(PermRolePermission::getRouteId,
|
||||
Collectors.mapping(PermRolePermission::getRoleCode, Collectors.toList())));
|
||||
|
||||
|
||||
|
||||
return permRolePermissionMapper.list(new Query().in("route_id", routeIdList))
|
||||
.stream()
|
||||
.map(permRolePermission -> {
|
||||
RoleVO vo = new RoleVO();
|
||||
String roleCode = permRolePermission.getRoleCode();
|
||||
PermRole permRole = permRoleMapper.getByColumn("role_code", roleCode);
|
||||
BeanUtils.copyProperties(permRole, vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取路由对应的角色
|
||||
*
|
||||
* @param id routeId
|
||||
* @return
|
||||
*/
|
||||
|
@@ -1,6 +1,9 @@
|
||||
package com.gitee.sop.adminserver.api.service.param;
|
||||
|
||||
import com.gitee.easyopen.doc.annotation.ApiDocField;
|
||||
import com.gitee.fastmybatis.core.query.Operator;
|
||||
import com.gitee.fastmybatis.core.query.annotation.Condition;
|
||||
import com.gitee.fastmybatis.core.query.param.PageParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -11,11 +14,16 @@ import javax.validation.constraints.NotBlank;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class RouteSearchParam {
|
||||
public class RouteSearchParam extends PageParam {
|
||||
@ApiDocField(description = "服务名serviceId")
|
||||
@NotBlank(message = "serviceId不能为空")
|
||||
private String serviceId;
|
||||
|
||||
@ApiDocField(description = "路由id")
|
||||
@Condition(column = "id", operator = Operator.like)
|
||||
private String id;
|
||||
|
||||
@ApiDocField(description = "是否授权接口,1:是")
|
||||
@Condition(ignoreValue = "0")
|
||||
private Integer permission;
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package com.gitee.sop.adminserver.api.service.result;
|
||||
|
||||
import com.gitee.sop.adminserver.api.isv.result.RoleVO;
|
||||
import com.gitee.sop.adminserver.bean.RouteDefinition;
|
||||
import com.gitee.sop.adminserver.entity.RouteRoleDTO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -12,6 +11,46 @@ import java.util.List;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class RouteVO extends RouteDefinition {
|
||||
private List<RoleVO> roles;
|
||||
public class RouteVO {
|
||||
|
||||
/** 数据库字段:id */
|
||||
private String id;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 接口名, 数据库字段:name */
|
||||
private String name;
|
||||
|
||||
/** 版本号, 数据库字段:version */
|
||||
private String version;
|
||||
|
||||
/** 路由断言(SpringCloudGateway专用), 数据库字段:predicates */
|
||||
private String predicates;
|
||||
|
||||
/** 路由过滤器(SpringCloudGateway专用), 数据库字段:filters */
|
||||
private String filters;
|
||||
|
||||
/** 路由规则转发的目标uri, 数据库字段:uri */
|
||||
private String uri;
|
||||
|
||||
/** uri后面跟的path, 数据库字段:path */
|
||||
private String path;
|
||||
|
||||
/** 路由执行的顺序, 数据库字段:order */
|
||||
private Integer order;
|
||||
|
||||
/** 是否忽略验证,业务参数验证除外, 数据库字段:ignore_validate */
|
||||
private Byte ignoreValidate;
|
||||
|
||||
/** 状态,0:待审核,1:启用,2:禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 是否合并结果, 数据库字段:merge_result */
|
||||
private Byte mergeResult;
|
||||
|
||||
/** 是否需要授权才能访问, 数据库字段:permission */
|
||||
private Byte permission;
|
||||
|
||||
private List<RouteRoleDTO> roles;
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package com.gitee.sop.adminserver.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class GatewayPushDTO {
|
||||
private String dataId;
|
||||
private String groupId;
|
||||
private ChannelMsg channelMsg;
|
||||
|
||||
public GatewayPushDTO() {
|
||||
}
|
||||
|
||||
public GatewayPushDTO(String dataId, String groupId, ChannelMsg channelMsg) {
|
||||
this.dataId = dataId;
|
||||
this.groupId = groupId;
|
||||
this.channelMsg = channelMsg;
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
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_service_route
|
||||
* 备注:路由配置
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Table(name = "config_service_route")
|
||||
@Data
|
||||
public class ConfigServiceRoute {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
/** 数据库字段:id */
|
||||
private String id;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 接口名, 数据库字段:name */
|
||||
private String name;
|
||||
|
||||
/** 版本号, 数据库字段:version */
|
||||
private String version;
|
||||
|
||||
/** 路由断言(SpringCloudGateway专用), 数据库字段:predicates */
|
||||
private String predicates;
|
||||
|
||||
/** 路由过滤器(SpringCloudGateway专用), 数据库字段:filters */
|
||||
private String filters;
|
||||
|
||||
/** 路由规则转发的目标uri, 数据库字段:uri */
|
||||
private String uri;
|
||||
|
||||
/** uri后面跟的path, 数据库字段:path */
|
||||
private String path;
|
||||
|
||||
/** 路由执行的顺序, 数据库字段:order */
|
||||
private Integer order;
|
||||
|
||||
/** 是否忽略验证,业务参数验证除外, 数据库字段:ignore_validate */
|
||||
private Byte ignoreValidate;
|
||||
|
||||
/** 状态,0:待审核,1:启用,2:禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 是否合并结果, 数据库字段:merge_result */
|
||||
private Byte mergeResult;
|
||||
|
||||
/** 是否需要授权才能访问, 数据库字段:permission */
|
||||
private Byte permission;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package com.gitee.sop.adminserver.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class RouteRoleDTO {
|
||||
/** routeId, 数据库字段:route_id */
|
||||
private String routeId;
|
||||
|
||||
/** 角色代码, 数据库字段:role_code */
|
||||
private String roleCode;
|
||||
|
||||
/** 角色描述, 数据库字段:description */
|
||||
private String description;
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.adminserver.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.adminserver.entity.ConfigServiceRoute;
|
||||
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, Long> {
|
||||
}
|
@@ -3,10 +3,15 @@ package com.gitee.sop.adminserver.mapper;
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
|
||||
import com.gitee.sop.adminserver.entity.PermRolePermission;
|
||||
import com.gitee.sop.adminserver.entity.RouteRoleDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface PermRolePermissionMapper extends CrudMapper<PermRolePermission, Long> {
|
||||
List<RouteRoleDTO> listRouteRole(@Param("routeIdList") List<String> routeIdList);
|
||||
}
|
||||
|
@@ -5,10 +5,20 @@ import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.gitee.sop.adminserver.bean.ChannelMsg;
|
||||
import com.gitee.sop.adminserver.bean.GatewayPushDTO;
|
||||
import com.gitee.sop.adminserver.bean.HttpTool;
|
||||
import com.gitee.sop.adminserver.common.BizException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@@ -16,17 +26,53 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class ConfigPushService {
|
||||
|
||||
private static final String GATEWAY_PUSH_URL = "http://%s/configChannelMsg";
|
||||
|
||||
private static HttpTool httpTool = new HttpTool();
|
||||
|
||||
@NacosInjected
|
||||
private ConfigService configService;
|
||||
|
||||
@Value("${gateway.host:}")
|
||||
private String gatewayHost;
|
||||
|
||||
@Value("${zuul.secret}")
|
||||
private String secret;
|
||||
|
||||
public void publishConfig(String dataId, String groupId, ChannelMsg channelMsg) {
|
||||
try {
|
||||
log.info("nacos配置, dataId={}, groupId={}, operation={}", dataId, groupId, channelMsg.getOperation());
|
||||
configService.publishConfig(dataId, groupId, JSON.toJSONString(channelMsg));
|
||||
} catch (NacosException e) {
|
||||
log.error("nacos配置失败, dataId={}, groupId={}, operation={}", dataId, groupId, channelMsg.getOperation(), e);
|
||||
throw new BizException("nacos配置失败");
|
||||
if (StringUtils.isNotBlank(gatewayHost)) {
|
||||
String[] hosts = gatewayHost.split(",");
|
||||
for (String host : hosts) {
|
||||
GatewayPushDTO gatewayPushDTO = new GatewayPushDTO(dataId, groupId, channelMsg);
|
||||
String url = String.format(GATEWAY_PUSH_URL, host);
|
||||
try {
|
||||
String requestBody = JSON.toJSONString(gatewayPushDTO);
|
||||
Map<String, String> header = new HashMap<>(8);
|
||||
header.put("sign", buildRequestBodySign(requestBody, secret));
|
||||
String resp = httpTool.requestJson(url, requestBody, header);
|
||||
if (!"ok".equals(resp)) {
|
||||
throw new IOException(resp);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("nacos配置失败, dataId={}, groupId={}, operation={}, url={}", dataId, groupId, channelMsg.getOperation(), url, e);
|
||||
throw new BizException("推送配置失败");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
log.info("nacos配置, dataId={}, groupId={}, operation={}", dataId, groupId, channelMsg.getOperation());
|
||||
configService.publishConfig(dataId, groupId, JSON.toJSONString(channelMsg));
|
||||
} catch (NacosException e) {
|
||||
log.error("nacos配置失败, dataId={}, groupId={}, operation={}", dataId, groupId, channelMsg.getOperation(), e);
|
||||
throw new BizException("nacos配置失败");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String buildRequestBodySign(String requestBody, String secret) {
|
||||
String signContent = secret + requestBody + secret;
|
||||
return DigestUtils.md5Hex(signContent);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,52 +0,0 @@
|
||||
package com.gitee.sop.adminserver.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.gitee.sop.adminserver.api.service.param.RouteSearchParam;
|
||||
import com.gitee.sop.adminserver.bean.RouteDefinition;
|
||||
import com.gitee.sop.adminserver.bean.NacosConfigs;
|
||||
import com.gitee.sop.adminserver.bean.ServiceRouteInfo;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Service
|
||||
public class RouteService {
|
||||
|
||||
@NacosInjected
|
||||
private ConfigService configService;
|
||||
|
||||
public List<RouteDefinition> getRouteDefinitionList(RouteSearchParam param) throws Exception {
|
||||
String serviceId = param.getServiceId();
|
||||
if (StringUtils.isBlank(serviceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String configData = configService.getConfig(NacosConfigs.getRouteDataId(serviceId), NacosConfigs.GROUP_ROUTE, 3000);
|
||||
if (StringUtils.isBlank(configData)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(configData, ServiceRouteInfo.class);
|
||||
|
||||
return serviceRouteInfo.getRouteDefinitionList()
|
||||
.stream()
|
||||
.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(toList());
|
||||
}
|
||||
|
||||
}
|
@@ -9,6 +9,10 @@ mysql.password=root
|
||||
|
||||
# nacos注册中心地址
|
||||
nacos.url=127.0.0.1:8848
|
||||
|
||||
# 网关地址,多个用逗号隔开
|
||||
# 此配置仅在使用eureka时有用,不用的话注释掉
|
||||
gateway.host=127.0.0.1:8081
|
||||
# ------- 需要改的配置end -------
|
||||
|
||||
# token过期时间,分钟
|
||||
@@ -27,6 +31,7 @@ spring.datasource.username=${mysql.username}
|
||||
spring.datasource.password=${mysql.password}
|
||||
|
||||
# 固定不用改
|
||||
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
|
||||
easyopen.show-doc=false
|
||||
easyopen.ignore-validate=true
|
||||
|
||||
|
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<!-- 注意:文件名必须跟Dao类名字一致,因为是根据文件名做关联。 -->
|
||||
<mapper namespace="com.gitee.sop.adminserver.mapper.PermRolePermissionMapper">
|
||||
|
||||
<select id="listRouteRole" resultType="com.gitee.sop.adminserver.entity.RouteRoleDTO">
|
||||
SELECT
|
||||
t.route_id as routeId,
|
||||
t.role_code as roleCode,
|
||||
t2.description
|
||||
FROM perm_role_permission t
|
||||
INNER JOIN perm_role t2 ON t.role_code=t2.role_code
|
||||
WHERE t.route_id in
|
||||
<foreach collection="routeIdList" item="routeId" open="(" separator="," close=")">
|
||||
#{routeId}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
</mapper>
|
@@ -71,6 +71,12 @@
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
<version>2.1.0.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -7,6 +8,10 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
public class ChannelMsg {
|
||||
private String operation = "_unknown_";
|
||||
private String data = "{}";
|
||||
private String operation;
|
||||
private JSONObject data;
|
||||
|
||||
public <T> T toObject(Class<T> clazz) {
|
||||
return data.toJavaObject(clazz);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class GatewayPushDTO {
|
||||
private String dataId;
|
||||
private String groupId;
|
||||
private ChannelMsg channelMsg;
|
||||
|
||||
public GatewayPushDTO() {
|
||||
}
|
||||
|
||||
public GatewayPushDTO(String dataId, String groupId, ChannelMsg channelMsg) {
|
||||
this.dataId = dataId;
|
||||
this.groupId = groupId;
|
||||
this.channelMsg = channelMsg;
|
||||
}
|
||||
}
|
@@ -7,6 +7,8 @@ import com.gitee.sop.gatewaycommon.bean.SpringContext;
|
||||
import com.gitee.sop.gatewaycommon.limit.LimitManager;
|
||||
import com.gitee.sop.gatewaycommon.message.ErrorFactory;
|
||||
import com.gitee.sop.gatewaycommon.param.ParameterFormatter;
|
||||
import com.gitee.sop.gatewaycommon.route.NacosRoutesListener;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener;
|
||||
import com.gitee.sop.gatewaycommon.secret.IsvManager;
|
||||
import com.gitee.sop.gatewaycommon.session.SessionManager;
|
||||
import com.gitee.sop.gatewaycommon.validate.Validator;
|
||||
@@ -16,8 +18,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
@@ -28,12 +31,13 @@ import javax.annotation.PostConstruct;
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public class AbstractConfiguration implements ApplicationContextAware, ApplicationListener<HeartbeatEvent> {
|
||||
public class AbstractConfiguration implements ApplicationContextAware {
|
||||
|
||||
@Autowired
|
||||
protected Environment environment;
|
||||
|
||||
@Autowired
|
||||
private ServiceRoutesLoader serviceRoutesLoader;
|
||||
private RegistryListener registryListener;
|
||||
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
@@ -44,12 +48,15 @@ public class AbstractConfiguration implements ApplicationContextAware, Applicati
|
||||
|
||||
/**
|
||||
* nacos事件监听
|
||||
* @see org.springframework.cloud.alibaba.nacos.discovery.NacosWatch NacosWatch
|
||||
*
|
||||
* @param heartbeatEvent
|
||||
*/
|
||||
@Override
|
||||
public void onApplicationEvent(HeartbeatEvent heartbeatEvent) {
|
||||
serviceRoutesLoader.load(heartbeatEvent);
|
||||
@EventListener(classes = HeartbeatEvent.class)
|
||||
public void listenNacosEvent(ApplicationEvent heartbeatEvent) {
|
||||
Object source = heartbeatEvent.getSource();
|
||||
if (source != null && source.getClass().getName().contains("NacosWatch")) {
|
||||
registryListener.onRegister(heartbeatEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +64,8 @@ public class AbstractConfiguration implements ApplicationContextAware, Applicati
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServiceRoutesLoader serviceRoutesLoader() {
|
||||
return new ServiceRoutesLoader();
|
||||
RegistryListener registryListener() {
|
||||
return new NacosRoutesListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@@ -10,6 +10,7 @@ import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.NacosConfigs;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.TargetRoute;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -31,7 +32,11 @@ import java.util.Objects;
|
||||
* 发现新服务,更新路由信息
|
||||
*
|
||||
* @author tanghc
|
||||
*
|
||||
* @deprecated
|
||||
* @see RegistryListener
|
||||
*/
|
||||
@Deprecated
|
||||
@Slf4j
|
||||
public class ServiceRoutesLoader<T extends TargetRoute> {
|
||||
|
||||
|
@@ -0,0 +1,154 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.manager.BaseRouteCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseRoutesListener implements RegistryListener {
|
||||
|
||||
private static final String SOP_ROUTES_PATH = "/sop/routes";
|
||||
|
||||
private static final String SECRET = "a3d9sf!1@odl90zd>fkASwq";
|
||||
|
||||
private static final int FIVE_SECONDS = 1000 * 5;
|
||||
|
||||
private static final String METADATA_SERVER_CONTEXT_PATH = "server.servlet.context-path";
|
||||
|
||||
private static final String METADATA_SOP_ROUTES_PATH = "sop.routes.path";
|
||||
|
||||
private static RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
static {
|
||||
// 解决statusCode不等于200,就抛异常问题
|
||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||
@Override
|
||||
protected boolean hasError(HttpStatus statusCode) {
|
||||
return statusCode == null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<String, Long> updateTimeMap = new ConcurrentHashMap<>(16);
|
||||
|
||||
@Autowired
|
||||
private BaseRouteCache<?> baseRouteCache;
|
||||
|
||||
@Autowired
|
||||
private RoutesProcessor routesProcessor;
|
||||
|
||||
/**
|
||||
* 移除路由信息
|
||||
*
|
||||
* @param serviceId serviceId
|
||||
*/
|
||||
public void removeRoutes(String serviceId) {
|
||||
doOperator(serviceId, () -> {
|
||||
log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
|
||||
baseRouteCache.remove(serviceId);
|
||||
routesProcessor.removeAllRoutes(serviceId);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由信息
|
||||
*
|
||||
* @param instance 服务实例
|
||||
*/
|
||||
public void pullRoutes(InstanceDefinition instance) {
|
||||
String serviceName = instance.getServiceId();
|
||||
doOperator(serviceName, () -> {
|
||||
String url = getRouteRequestUrl(instance);
|
||||
log.info("拉取路由配置,serviceId: {}, url: {}", serviceName, url);
|
||||
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
|
||||
baseRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
|
||||
} else {
|
||||
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void doOperator(String serviceId, Runnable runnable) {
|
||||
if (canOperator(serviceId)) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canOperator(String serviceId) {
|
||||
// nacos会不停的触发事件,这里做了一层拦截
|
||||
// 同一个serviceId5秒内允许访问一次
|
||||
Long lastUpdateTime = updateTimeMap.getOrDefault(serviceId, 0L);
|
||||
long now = System.currentTimeMillis();
|
||||
boolean can = now - lastUpdateTime > FIVE_SECONDS;
|
||||
if (can) {
|
||||
updateTimeMap.put(serviceId, now);
|
||||
}
|
||||
return can;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取路由请求url
|
||||
*
|
||||
* @param instance 服务实例
|
||||
* @return 返回最终url
|
||||
*/
|
||||
private static String getRouteRequestUrl(InstanceDefinition instance) {
|
||||
Map<String, String> metadata = instance.getMetadata();
|
||||
String customPath = metadata.get(METADATA_SOP_ROUTES_PATH);
|
||||
String homeUrl;
|
||||
String servletPath;
|
||||
// 如果metadata中指定了获取路由的url
|
||||
if (StringUtils.isNotBlank(customPath)) {
|
||||
// 自定义完整的url
|
||||
if (customPath.startsWith("http")) {
|
||||
homeUrl = customPath;
|
||||
servletPath = "";
|
||||
} else {
|
||||
homeUrl = getHomeUrl(instance);
|
||||
servletPath = customPath;
|
||||
}
|
||||
} else {
|
||||
// 默认处理
|
||||
homeUrl = getHomeUrl(instance);
|
||||
String contextPath = metadata.getOrDefault(METADATA_SERVER_CONTEXT_PATH, "");
|
||||
servletPath = contextPath + SOP_ROUTES_PATH;
|
||||
}
|
||||
if (StringUtils.isNotBlank(servletPath) && !servletPath.startsWith("/")) {
|
||||
servletPath = '/' + servletPath;
|
||||
}
|
||||
String query = buildQuery(SECRET);
|
||||
return homeUrl + servletPath + query;
|
||||
}
|
||||
|
||||
private static String getHomeUrl(InstanceDefinition instance) {
|
||||
return "http://" + instance.getIp() + ":" + instance.getPort();
|
||||
}
|
||||
|
||||
private static String buildQuery(String secret) {
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String source = secret + time + secret;
|
||||
String sign = DigestUtils.md5DigestAsHex(source.getBytes());
|
||||
return "?time=" + time + "&sign=" + sign;
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* 加载服务路由,eureka实现
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
public class EurekaRoutesListener extends BaseRoutesListener {
|
||||
|
||||
@Override
|
||||
public void onRegister(ApplicationEvent applicationEvent) {
|
||||
EurekaInstanceRegisteredEvent event = (EurekaInstanceRegisteredEvent)applicationEvent;
|
||||
InstanceInfo instanceInfo = event.getInstanceInfo();
|
||||
InstanceDefinition instanceDefinition = new InstanceDefinition();
|
||||
instanceDefinition.setInstanceId(instanceInfo.getInstanceId());
|
||||
instanceDefinition.setServiceId(instanceInfo.getAppName());
|
||||
instanceDefinition.setIp(instanceInfo.getIPAddr());
|
||||
instanceDefinition.setPort(instanceInfo.getPort());
|
||||
instanceDefinition.setMetadata(instanceInfo.getMetadata());
|
||||
pullRoutes(instanceDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeregister(ApplicationEvent applicationEvent) {
|
||||
EurekaInstanceCanceledEvent event = (EurekaInstanceCanceledEvent)applicationEvent;
|
||||
removeRoutes(event.getServerId());
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.alibaba.nacos.api.annotation.NacosInjected;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.api.naming.NamingService;
|
||||
import com.alibaba.nacos.api.naming.pojo.Instance;
|
||||
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 加载服务路由,nacos实现
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class NacosRoutesListener extends BaseRoutesListener {
|
||||
|
||||
@Autowired
|
||||
private NacosDiscoveryProperties nacosDiscoveryProperties;
|
||||
|
||||
@NacosInjected
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public void onRegister(ApplicationEvent applicationEvent) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
try {
|
||||
subscribes = namingService.getSubscribeServices();
|
||||
} catch (NacosException e) {
|
||||
log.error("namingService.getSubscribeServices()错误", e);
|
||||
}
|
||||
if (CollectionUtils.isEmpty(subscribes)) {
|
||||
return;
|
||||
}
|
||||
// subscribe
|
||||
String thisServiceId = nacosDiscoveryProperties.getService();
|
||||
for (ServiceInfo serviceInfo : subscribes) {
|
||||
String serviceName = serviceInfo.getName();
|
||||
// 如果是本机服务,跳过
|
||||
if (Objects.equals(thisServiceId, serviceName)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
List<Instance> allInstances = namingService.getAllInstances(serviceName);
|
||||
if (CollectionUtils.isEmpty(allInstances)) {
|
||||
// 如果没有服务列表,则删除所有路由信息
|
||||
removeRoutes(serviceName);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
InstanceDefinition instanceDefinition = new InstanceDefinition();
|
||||
instanceDefinition.setInstanceId(instance.getInstanceId());
|
||||
instanceDefinition.setServiceId(serviceName);
|
||||
instanceDefinition.setIp(instance.getIp());
|
||||
instanceDefinition.setPort(instance.getPort());
|
||||
instanceDefinition.setMetadata(instance.getMetadata());
|
||||
pullRoutes(instanceDefinition);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("选择服务实例失败,serviceName: {}", serviceName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeregister(ApplicationEvent applicationEvent) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* 发现新服务,更新路由信息
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface RegistryListener {
|
||||
|
||||
/**
|
||||
* 触发新服务注册
|
||||
*
|
||||
* @param applicationEvent 事件,可能是nacos事件,也可能是eureka事件
|
||||
*/
|
||||
void onRegister(ApplicationEvent applicationEvent);
|
||||
|
||||
/**
|
||||
* 注销服务
|
||||
*
|
||||
* @param applicationEvent
|
||||
*/
|
||||
void onDeregister(ApplicationEvent applicationEvent);
|
||||
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.gitee.sop.gatewaycommon.route;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface RoutesProcessor {
|
||||
/**
|
||||
* 删除serviceId下所有路由
|
||||
*
|
||||
* @param serviceId serviceId
|
||||
*/
|
||||
void removeAllRoutes(String serviceId);
|
||||
|
||||
/**
|
||||
* 保存路由
|
||||
*
|
||||
* @param serviceRouteInfo 路由信息
|
||||
* @param instance 服务实例
|
||||
*/
|
||||
void saveRoutes(ServiceRouteInfo serviceRouteInfo, InstanceDefinition instance);
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.gitee.sop.gatewaycommon.support;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.route.EurekaRoutesListener;
|
||||
import com.gitee.sop.gatewaycommon.route.RegistryListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
||||
/**
|
||||
* eureka注册中心事件监听
|
||||
* @author tanghc
|
||||
*/
|
||||
public class EurekaListenerConfiguration {
|
||||
|
||||
@Autowired
|
||||
private RegistryListener registryListener;
|
||||
|
||||
/**
|
||||
* 客户端注册触发
|
||||
* @param event
|
||||
*/
|
||||
@EventListener
|
||||
public void onEurekaInstanceRegisteredEvent(EurekaInstanceRegisteredEvent event) {
|
||||
registryListener.onRegister(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端下线触发
|
||||
* @param event
|
||||
*/
|
||||
@EventListener
|
||||
public void onEurekaInstanceCanceledEvent(EurekaInstanceCanceledEvent event) {
|
||||
registryListener.onDeregister(event);
|
||||
}
|
||||
|
||||
@Bean
|
||||
RegistryListener registryListener() {
|
||||
return new EurekaRoutesListener();
|
||||
}
|
||||
|
||||
}
|
@@ -6,6 +6,7 @@ import com.gitee.sop.gatewaycommon.param.ApiUploadContext;
|
||||
import com.gitee.sop.gatewaycommon.param.UploadContext;
|
||||
import com.netflix.zuul.http.HttpServletRequestWrapper;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
@@ -268,6 +269,17 @@ public class RequestUtil {
|
||||
return uploadInfo;
|
||||
}
|
||||
|
||||
public static void checkResponseBody(String responseBody, String sign, String secret) throws Exception {
|
||||
if (sign == null) {
|
||||
throw new Exception("签名不存在");
|
||||
}
|
||||
String signContent = secret + responseBody + secret;
|
||||
String clientSign = DigestUtils.md5Hex(signContent);
|
||||
if (!sign.equals(clientSign)) {
|
||||
throw new Exception("签名错误");
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class UploadInfo {
|
||||
private Map<String, String> uploadParams;
|
||||
|
@@ -0,0 +1,68 @@
|
||||
package com.gitee.sop.gateway.controller;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.sop.gateway.manager.ChannelMsgProcessor;
|
||||
import com.gitee.sop.gateway.manager.DbEnvGrayManager;
|
||||
import com.gitee.sop.gateway.manager.DbIPBlacklistManager;
|
||||
import com.gitee.sop.gateway.manager.DbIsvManager;
|
||||
import com.gitee.sop.gateway.manager.DbIsvRoutePermissionManager;
|
||||
import com.gitee.sop.gateway.manager.DbLimitConfigManager;
|
||||
import com.gitee.sop.gateway.manager.DbRouteConfigManager;
|
||||
import com.gitee.sop.gatewaycommon.bean.GatewayPushDTO;
|
||||
import com.gitee.sop.gatewaycommon.bean.NacosConfigs;
|
||||
import com.gitee.sop.gatewaycommon.bean.SpringContext;
|
||||
import com.gitee.sop.gatewaycommon.util.RequestUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class ConfigChannelController {
|
||||
|
||||
private static Map<String, Class<? extends ChannelMsgProcessor>> processorMap = new HashMap<>(16);
|
||||
|
||||
static {
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_GRAY, DbEnvGrayManager.class);
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_IP_BLACKLIST, DbIPBlacklistManager.class);
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ISV, DbIsvManager.class);
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ROUTE_PERMISSION, DbIsvRoutePermissionManager.class);
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_LIMIT_CONFIG, DbLimitConfigManager.class);
|
||||
processorMap.put(NacosConfigs.GROUP_CHANNEL + NacosConfigs.DATA_ID_ROUTE_CONFIG, DbRouteConfigManager.class);
|
||||
}
|
||||
|
||||
@Value("${zuul.secret}")
|
||||
private String secret;
|
||||
|
||||
@PostMapping("/configChannelMsg")
|
||||
public String configChannel(HttpServletRequest request) throws IOException {
|
||||
String requestJson = RequestUtil.getText(request);
|
||||
String sign = request.getHeader("sign");
|
||||
try {
|
||||
RequestUtil.checkResponseBody(requestJson, sign, secret);
|
||||
} catch (Exception e) {
|
||||
log.error("configChannelMsg错误", e);
|
||||
return e.getMessage();
|
||||
}
|
||||
GatewayPushDTO gatewayPushDTO = JSON.parseObject(requestJson, GatewayPushDTO.class);
|
||||
ChannelMsgProcessor channelMsgProcessor = getChannelMsgProcessor(gatewayPushDTO);
|
||||
channelMsgProcessor.process(gatewayPushDTO.getChannelMsg());
|
||||
return "ok";
|
||||
}
|
||||
|
||||
private ChannelMsgProcessor getChannelMsgProcessor(GatewayPushDTO gatewayPushDTO) {
|
||||
String key = gatewayPushDTO.getGroupId() + gatewayPushDTO.getDataId();
|
||||
Class<? extends ChannelMsgProcessor> aClass = processorMap.get(key);
|
||||
return SpringContext.getBean(aClass);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package com.gitee.sop.gateway.entity;
|
||||
|
||||
import com.gitee.fastmybatis.core.annotation.LogicDelete;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
|
||||
/**
|
||||
* 表名:config_service_route
|
||||
* 备注:路由配置
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Table(name = "config_service_route")
|
||||
@Data
|
||||
public class ConfigServiceRoute {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
/** 数据库字段:id */
|
||||
private String id;
|
||||
|
||||
/** 数据库字段:service_id */
|
||||
private String serviceId;
|
||||
|
||||
/** 接口名, 数据库字段:name */
|
||||
private String name;
|
||||
|
||||
/** 版本号, 数据库字段:version */
|
||||
private String version;
|
||||
|
||||
/** 路由断言(SpringCloudGateway专用), 数据库字段:predicates */
|
||||
private String predicates;
|
||||
|
||||
/** 路由过滤器(SpringCloudGateway专用), 数据库字段:filters */
|
||||
private String filters;
|
||||
|
||||
/** 路由规则转发的目标uri, 数据库字段:uri */
|
||||
private String uri;
|
||||
|
||||
/** uri后面跟的path, 数据库字段:path */
|
||||
private String path;
|
||||
|
||||
/** 路由执行的顺序, 数据库字段:order */
|
||||
private Integer order;
|
||||
|
||||
/** 是否忽略验证,业务参数验证除外, 数据库字段:ignore_validate */
|
||||
private Byte ignoreValidate;
|
||||
|
||||
/** 状态,0:待审核,1:启用,2:禁用, 数据库字段:status */
|
||||
private Byte status;
|
||||
|
||||
/** 是否合并结果, 数据库字段:merge_result */
|
||||
private Byte mergeResult;
|
||||
|
||||
/** 是否需要授权才能访问, 数据库字段:permission */
|
||||
private Byte permission;
|
||||
|
||||
/** 数据库字段:gmt_create */
|
||||
private Date gmtCreate;
|
||||
|
||||
/** 数据库字段:gmt_modified */
|
||||
private Date gmtModified;
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface ChannelMsgProcessor {
|
||||
void process(ChannelMsg channelMsg);
|
||||
}
|
@@ -36,7 +36,7 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbEnvGrayManager extends DefaultEnvGrayManager {
|
||||
public class DbEnvGrayManager extends DefaultEnvGrayManager implements ChannelMsgProcessor {
|
||||
|
||||
private static final int STATUS_ENABLE = 1;
|
||||
|
||||
@@ -97,29 +97,32 @@ public class DbEnvGrayManager extends DefaultEnvGrayManager {
|
||||
this.saveServiceGrayConfig(serviceGrayConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
ServiceGrayDefinition userKeyDefinition = channelMsg.toObject(ServiceGrayDefinition.class);
|
||||
String serviceId = userKeyDefinition.getServiceId();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "set":
|
||||
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
|
||||
setServiceGrayConfig(configGray);
|
||||
break;
|
||||
case "open":
|
||||
openGray(userKeyDefinition.getInstanceId(), serviceId);
|
||||
break;
|
||||
case "close":
|
||||
closeGray(userKeyDefinition.getInstanceId());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
configService.addListener(NacosConfigs.DATA_ID_GRAY, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
String data = channelMsg.getData();
|
||||
ServiceGrayDefinition userKeyDefinition = JSON.parseObject(data, ServiceGrayDefinition.class);
|
||||
String serviceId = userKeyDefinition.getServiceId();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "set":
|
||||
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
|
||||
setServiceGrayConfig(configGray);
|
||||
break;
|
||||
case "open":
|
||||
openGray(userKeyDefinition.getInstanceId(), serviceId);
|
||||
break;
|
||||
case "close":
|
||||
closeGray(userKeyDefinition.getInstanceId());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
|
||||
public class DbIPBlacklistManager extends DefaultIPBlacklistManager implements ChannelMsgProcessor {
|
||||
|
||||
@Autowired
|
||||
private IPBlacklistMapper ipBlacklistMapper;
|
||||
@@ -35,29 +35,34 @@ public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
|
||||
public void load() {
|
||||
List<String> ipList = ipBlacklistMapper.listAllIP();
|
||||
log.info("加载IP黑名单, size:{}", ipList.size());
|
||||
ipList.stream().forEach(this::add);
|
||||
ipList.forEach(this::add);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IPDto ipDto = channelMsg.toObject(IPDto.class);
|
||||
String ip = ipDto.getIp();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "add":
|
||||
log.info("添加IP黑名单,ip:{}", ip);
|
||||
add(ip);
|
||||
break;
|
||||
case "delete":
|
||||
log.info("移除IP黑名单,ip:{}", ip);
|
||||
remove(ip);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
configService.addListener(NacosConfigs.DATA_ID_IP_BLACKLIST, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
final IPDto ipDto = JSON.parseObject(channelMsg.getData(), IPDto.class);
|
||||
String ip = ipDto.getIp();
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "add":
|
||||
log.info("添加IP黑名单,ip:{}", ip);
|
||||
add(ip);
|
||||
break;
|
||||
case "delete":
|
||||
log.info("移除IP黑名单,ip:{}", ip);
|
||||
remove(ip);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -66,5 +71,4 @@ public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
|
||||
private static class IPDto {
|
||||
private String ip;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIsvManager extends CacheIsvManager {
|
||||
public class DbIsvManager extends CacheIsvManager implements ChannelMsgProcessor{
|
||||
|
||||
@Autowired
|
||||
private IsvInfoMapper isvInfoMapper;
|
||||
@@ -35,7 +35,7 @@ public class DbIsvManager extends CacheIsvManager {
|
||||
@Override
|
||||
public void load() {
|
||||
List<IsvDetailDTO> isvInfoList = isvInfoMapper.listIsvDetail();
|
||||
isvInfoList.stream()
|
||||
isvInfoList
|
||||
.forEach(isvInfo -> {
|
||||
IsvDefinition isvDefinition = new IsvDefinition();
|
||||
BeanUtils.copyProperties(isvInfo, isvDefinition);
|
||||
@@ -43,6 +43,23 @@ public class DbIsvManager extends CacheIsvManager {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IsvDefinition isvDefinition = channelMsg.toObject(IsvDefinition.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "update":
|
||||
log.info("更新ISV信息,isvDefinition:{}", isvDefinition);
|
||||
update(isvDefinition);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV,isvDefinition:{}", isvDefinition);
|
||||
remove(isvDefinition.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
ApiConfig.getInstance().setIsvManager(this);
|
||||
@@ -50,20 +67,8 @@ public class DbIsvManager extends CacheIsvManager {
|
||||
configService.addListener(NacosConfigs.DATA_ID_ISV, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
final IsvDefinition isvDefinition = JSON.parseObject(channelMsg.getData(), IsvDefinition.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "update":
|
||||
log.info("更新ISV信息,isvDefinition:{}", isvDefinition);
|
||||
update(isvDefinition);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV,isvDefinition:{}", isvDefinition);
|
||||
remove(isvDefinition.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ import static java.util.stream.Collectors.toList;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager {
|
||||
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager implements ChannelMsgProcessor {
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
@@ -122,41 +122,46 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Data
|
||||
static class IsvRole {
|
||||
private String appKey;
|
||||
private String roleCode;
|
||||
}
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final IsvRoutePermission isvRoutePermission = channelMsg.toObject(IsvRoutePermission.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
try {
|
||||
load();
|
||||
} catch (Exception e) {
|
||||
log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e);
|
||||
}
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
update(isvRoutePermission);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
remove(isvRoutePermission.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
configService.addListener(NacosConfigs.DATA_ID_ROUTE_PERMISSION, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
final IsvRoutePermission isvRoutePermission = JSON.parseObject(channelMsg.getData(), IsvRoutePermission.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
try {
|
||||
load();
|
||||
} catch (Exception e) {
|
||||
log.error("重新加载路由权限失败, channelMsg:{}", channelMsg, e);
|
||||
}
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
update(isvRoutePermission);
|
||||
break;
|
||||
case "remove":
|
||||
log.info("删除ISV路由权限信息,isvRoutePermission:{}", isvRoutePermission);
|
||||
remove(isvRoutePermission.getAppKey());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
static class IsvRole {
|
||||
private String appKey;
|
||||
private String roleCode;
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import javax.annotation.PostConstruct;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbLimitConfigManager extends DefaultLimitConfigManager {
|
||||
public class DbLimitConfigManager extends DefaultLimitConfigManager implements ChannelMsgProcessor {
|
||||
|
||||
@Autowired
|
||||
ConfigLimitMapper configLimitMapper;
|
||||
@@ -39,7 +39,6 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
|
||||
public void load() {
|
||||
Query query = new Query();
|
||||
configLimitMapper.list(query)
|
||||
.stream()
|
||||
.forEach(configLimit -> putVal(configLimit));
|
||||
|
||||
}
|
||||
@@ -50,25 +49,29 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
|
||||
this.update(configLimitDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final ConfigLimitDto configLimitDto = channelMsg.toObject(ConfigLimitDto.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
load();
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
update(configLimitDto);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
configService.addListener(NacosConfigs.DATA_ID_LIMIT_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
final ConfigLimitDto configLimitDto = JSON.parseObject(channelMsg.getData(), ConfigLimitDto.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
load();
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新限流配置信息,configLimitDto:{}", configLimitDto);
|
||||
update(configLimitDto);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ import java.util.Collection;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DbRouteConfigManager extends DefaultRouteConfigManager {
|
||||
public class DbRouteConfigManager extends DefaultRouteConfigManager implements ChannelMsgProcessor {
|
||||
|
||||
@Autowired
|
||||
ConfigRouteBaseMapper configRouteBaseMapper;
|
||||
@@ -72,25 +72,29 @@ public class DbRouteConfigManager extends DefaultRouteConfigManager {
|
||||
this.doUpdate(routeId, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(ChannelMsg channelMsg) {
|
||||
final RouteConfig routeConfig = channelMsg.toObject( RouteConfig.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
load();
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
update(routeConfig);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void after() throws Exception {
|
||||
configService.addListener(NacosConfigs.DATA_ID_ROUTE_CONFIG, NacosConfigs.GROUP_CHANNEL, new AbstractListener() {
|
||||
@Override
|
||||
public void receiveConfigInfo(String configInfo) {
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
final RouteConfig routeConfig = JSON.parseObject(channelMsg.getData(), RouteConfig.class);
|
||||
switch (channelMsg.getOperation()) {
|
||||
case "reload":
|
||||
log.info("重新加载路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
load();
|
||||
break;
|
||||
case "update":
|
||||
log.info("更新路由配置信息,routeConfigDto:{}", routeConfig);
|
||||
update(routeConfig);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
ChannelMsg channelMsg = JSON.parseObject(configInfo, ChannelMsg.class);
|
||||
process(channelMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -0,0 +1,68 @@
|
||||
package com.gitee.sop.gateway.manager;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.gitee.fastmybatis.core.query.Query;
|
||||
import com.gitee.sop.gateway.entity.ConfigServiceRoute;
|
||||
import com.gitee.sop.gateway.mapper.ConfigServiceRouteMapper;
|
||||
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
import com.gitee.sop.gatewaycommon.route.RoutesProcessor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DbRoutesProcessor implements RoutesProcessor {
|
||||
|
||||
@Autowired
|
||||
private ConfigServiceRouteMapper configServiceRouteMapper;
|
||||
|
||||
@Override
|
||||
public void removeAllRoutes(String serviceId) {
|
||||
// 删除serviceId下所有的路由
|
||||
Query delServiceQuery = new Query().eq("service_id", serviceId);
|
||||
configServiceRouteMapper.deleteByQuery(delServiceQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveRoutes(ServiceRouteInfo serviceRouteInfo, InstanceDefinition instance) {
|
||||
log.info("保存路由信息到数据库,instance: {}", instance);
|
||||
String serviceId = serviceRouteInfo.getServiceId();
|
||||
List<ConfigServiceRoute> configServiceRoutes = serviceRouteInfo
|
||||
.getRouteDefinitionList()
|
||||
.parallelStream()
|
||||
.map(routeDefinition -> {
|
||||
ConfigServiceRoute configServiceRoute = new ConfigServiceRoute();
|
||||
configServiceRoute.setId(routeDefinition.getId());
|
||||
configServiceRoute.setName(routeDefinition.getName());
|
||||
configServiceRoute.setVersion(routeDefinition.getVersion());
|
||||
configServiceRoute.setUri(routeDefinition.getUri());
|
||||
configServiceRoute.setPath(routeDefinition.getPath());
|
||||
configServiceRoute.setFilters(JSON.toJSONString(routeDefinition.getFilters()));
|
||||
configServiceRoute.setPredicates(JSON.toJSONString(routeDefinition.getPredicates()));
|
||||
configServiceRoute.setIgnoreValidate((byte) routeDefinition.getIgnoreValidate());
|
||||
configServiceRoute.setMergeResult((byte) routeDefinition.getMergeResult());
|
||||
configServiceRoute.setStatus((byte) routeDefinition.getStatus());
|
||||
configServiceRoute.setPermission((byte) routeDefinition.getPermission());
|
||||
configServiceRoute.setOrder(routeDefinition.getOrder());
|
||||
configServiceRoute.setServiceId(serviceId);
|
||||
return configServiceRoute;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 删除serviceId下所有的路由
|
||||
this.removeAllRoutes(serviceId);
|
||||
|
||||
// 批量保存
|
||||
configServiceRouteMapper.saveBatch(configServiceRoutes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gateway.mapper;
|
||||
|
||||
import com.gitee.fastmybatis.core.mapper.CrudMapper;
|
||||
import com.gitee.sop.gateway.entity.ConfigServiceRoute;
|
||||
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface ConfigServiceRouteMapper extends CrudMapper<ConfigServiceRoute, Long> {
|
||||
}
|
Reference in New Issue
Block a user