From be0adc0a8ead72088e042c9f3d6f5c59ed0266d7 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 26 Sep 2019 20:01:35 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8Deureka?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/service/IPBlacklistApi.java | 2 +- .../adminserver/api/service/LimitNewApi.java | 6 +- .../sop/adminserver/api/service/RouteApi.java | 105 ++++++++---- .../api/service/param/RouteSearchParam.java | 10 +- .../api/service/result/RouteVO.java | 47 +++++- .../sop/adminserver/bean/GatewayPushDTO.java | 22 +++ .../entity/ConfigServiceRoute.java | 69 ++++++++ .../sop/adminserver/entity/RouteRoleDTO.java | 18 ++ .../mapper/ConfigServiceRouteMapper.java | 11 ++ .../mapper/PermRolePermissionMapper.java | 5 + .../service/ConfigPushService.java | 58 ++++++- .../sop/adminserver/service/RouteService.java | 52 ------ .../main/resources/application-dev.properties | 5 + .../mapper/PermRolePermissionMapper.xml | 19 +++ sop-common/sop-gateway-common/pom.xml | 6 + .../sop/gatewaycommon/bean/ChannelMsg.java | 9 +- .../gatewaycommon/bean/GatewayPushDTO.java | 22 +++ .../manager/AbstractConfiguration.java | 25 ++- .../manager/ServiceRoutesLoader.java | 5 + .../route/BaseRoutesListener.java | 154 ++++++++++++++++++ .../route/EurekaRoutesListener.java | 34 ++++ .../route/NacosRoutesListener.java | 80 +++++++++ .../gatewaycommon/route/RegistryListener.java | 26 +++ .../gatewaycommon/route/RoutesProcessor.java | 24 +++ .../support/EurekaListenerConfiguration.java | 43 +++++ .../sop/gatewaycommon/util/RequestUtil.java | 12 ++ .../controller/ConfigChannelController.java | 68 ++++++++ .../gateway/entity/ConfigServiceRoute.java | 71 ++++++++ .../gateway/manager/ChannelMsgProcessor.java | 10 ++ .../sop/gateway/manager/DbEnvGrayManager.java | 39 +++-- .../gateway/manager/DbIPBlacklistManager.java | 38 +++-- .../sop/gateway/manager/DbIsvManager.java | 37 +++-- .../manager/DbIsvRoutePermissionManager.java | 61 +++---- .../gateway/manager/DbLimitConfigManager.java | 33 ++-- .../gateway/manager/DbRouteConfigManager.java | 32 ++-- .../gateway/manager/DbRoutesProcessor.java | 68 ++++++++ .../mapper/ConfigServiceRouteMapper.java | 11 ++ 37 files changed, 1119 insertions(+), 218 deletions(-) create mode 100644 sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayPushDTO.java create mode 100644 sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigServiceRoute.java create mode 100644 sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/RouteRoleDTO.java create mode 100644 sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigServiceRouteMapper.java delete mode 100644 sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java create mode 100644 sop-admin/sop-admin-server/src/main/resources/mybatis/mapper/PermRolePermissionMapper.xml create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/GatewayPushDTO.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRoutesListener.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRoutesListener.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosRoutesListener.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RegistryListener.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RoutesProcessor.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/support/EurekaListenerConfiguration.java create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/controller/ConfigChannelController.java create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigServiceRoute.java create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ChannelMsgProcessor.java create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRoutesProcessor.java create mode 100644 sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigServiceRouteMapper.java diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/IPBlacklistApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/IPBlacklistApi.java index 44b3de1d..cfdf7258 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/IPBlacklistApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/IPBlacklistApi.java @@ -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); } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitNewApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitNewApi.java index d67ee856..6dbf48ed 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitNewApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LimitNewApi.java @@ -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 listLimit(LimitNewParam param) throws Exception { + PageInfo listLimit(LimitNewParam param) { Query query = Query.build(param); query.orderby("route_id", Sort.ASC) .orderby("app_key", Sort.ASC) diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java index 409731e2..d56a62b3 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/RouteApi.java @@ -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; + @ApiDocMethod(description = "路由列表,分页") + @Api(name = "route.page") + PageEasyui page(RouteSearchParam form) { + Query query = Query.build(form); + query.orderby("id", Sort.ASC); + PageEasyui datagrid = MapperUtil.queryForEasyuiDatagrid(configServiceRouteMapper, query, RouteVO.class); + List routeIdList = datagrid.getRows() + .parallelStream() + .map(RouteVO::getId) + .collect(Collectors.toList()); - @Api(name = "route.list") - @ApiDocMethod(description = "路由列表") - List listRoute(RouteSearchParam param) throws Exception { - List routeDefinitionList = routeService.getRouteDefinitionList(param) + Map routeIdStatusMap = configRouteBaseMapper + .list(new Query().in("route_id", routeIdList)) .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; - }) - .collect(Collectors.toList()); + .collect(Collectors.toMap(ConfigRouteBase::getRouteId, ConfigRouteBase::getStatus)); + + Map> routeIdRoleMap = permRolePermissionMapper.listRouteRole(routeIdList) + .parallelStream() + .collect(Collectors.groupingBy(RouteRoleDTO::getRouteId)); + - return routeDefinitionList; + datagrid.getRows().forEach(vo -> { + String routeId = vo.getId(); + List 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 listRoute2(RouteSearchParam param) throws Exception { - List routeDefinitionList = routeService.getRouteDefinitionList(param) - .stream() - .map(gatewayRouteDefinition -> { - RouteVO vo = new RouteVO(); - BeanUtils.copyProperties(gatewayRouteDefinition, vo); - return vo; - }) - .collect(Collectors.toList()); - - return routeDefinitionList; + List 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 getRouteRole(List routeIdList) { + // key:routeId, value: roleCode + Map> 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 */ diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java index 61b9d7c2..46205320 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/RouteSearchParam.java @@ -1,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; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/RouteVO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/RouteVO.java index b6fb23ca..c189ab70 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/RouteVO.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/RouteVO.java @@ -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 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 roles; } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayPushDTO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayPushDTO.java new file mode 100644 index 00000000..22f40111 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/GatewayPushDTO.java @@ -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; + } +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigServiceRoute.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigServiceRoute.java new file mode 100644 index 00000000..369b2e42 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/ConfigServiceRoute.java @@ -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; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/RouteRoleDTO.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/RouteRoleDTO.java new file mode 100644 index 00000000..3a9f2ebf --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/entity/RouteRoleDTO.java @@ -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; +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigServiceRouteMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigServiceRouteMapper.java new file mode 100644 index 00000000..1365c93f --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/ConfigServiceRouteMapper.java @@ -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 { +} diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/PermRolePermissionMapper.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/PermRolePermissionMapper.java index c40777a3..b6d19eb3 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/PermRolePermissionMapper.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/mapper/PermRolePermissionMapper.java @@ -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 { + List listRouteRole(@Param("routeIdList") List routeIdList); } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigPushService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigPushService.java index 9b1109de..1dc06106 100644 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigPushService.java +++ b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/ConfigPushService.java @@ -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 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); } } diff --git a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java b/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java deleted file mode 100644 index 4fd510e0..00000000 --- a/sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RouteService.java +++ /dev/null @@ -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 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()); - } - -} diff --git a/sop-admin/sop-admin-server/src/main/resources/application-dev.properties b/sop-admin/sop-admin-server/src/main/resources/application-dev.properties index 5fc92919..8158468f 100644 --- a/sop-admin/sop-admin-server/src/main/resources/application-dev.properties +++ b/sop-admin/sop-admin-server/src/main/resources/application-dev.properties @@ -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 diff --git a/sop-admin/sop-admin-server/src/main/resources/mybatis/mapper/PermRolePermissionMapper.xml b/sop-admin/sop-admin-server/src/main/resources/mybatis/mapper/PermRolePermissionMapper.xml new file mode 100644 index 00000000..aa83a958 --- /dev/null +++ b/sop-admin/sop-admin-server/src/main/resources/mybatis/mapper/PermRolePermissionMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/sop-common/sop-gateway-common/pom.xml b/sop-common/sop-gateway-common/pom.xml index 667bae83..58acee0a 100644 --- a/sop-common/sop-gateway-common/pom.xml +++ b/sop-common/sop-gateway-common/pom.xml @@ -71,6 +71,12 @@ spring-boot-starter-webflux true + + org.springframework.cloud + spring-cloud-netflix-eureka-server + 2.1.0.RELEASE + true + diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ChannelMsg.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ChannelMsg.java index f43b0130..a321e10e 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ChannelMsg.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ChannelMsg.java @@ -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 toObject(Class clazz) { + return data.toJavaObject(clazz); + } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/GatewayPushDTO.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/GatewayPushDTO.java new file mode 100644 index 00000000..fc961de8 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/GatewayPushDTO.java @@ -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; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java index 5d49a949..c10a694f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java @@ -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 { +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 diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ServiceRoutesLoader.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ServiceRoutesLoader.java index 7b39b819..c80158fd 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ServiceRoutesLoader.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ServiceRoutesLoader.java @@ -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 { diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRoutesListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRoutesListener.java new file mode 100644 index 00000000..f73e8039 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/BaseRoutesListener.java @@ -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 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 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 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; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRoutesListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRoutesListener.java new file mode 100644 index 00000000..a7a23418 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/EurekaRoutesListener.java @@ -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()); + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosRoutesListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosRoutesListener.java new file mode 100644 index 00000000..58475ff6 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/NacosRoutesListener.java @@ -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 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 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) { + + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RegistryListener.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RegistryListener.java new file mode 100644 index 00000000..13df0741 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RegistryListener.java @@ -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); + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RoutesProcessor.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RoutesProcessor.java new file mode 100644 index 00000000..56758588 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/RoutesProcessor.java @@ -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); +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/support/EurekaListenerConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/support/EurekaListenerConfiguration.java new file mode 100644 index 00000000..fad894d3 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/support/EurekaListenerConfiguration.java @@ -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(); + } + +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java index 34b524e4..672316c5 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java @@ -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 uploadParams; diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/ConfigChannelController.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/ConfigChannelController.java new file mode 100644 index 00000000..3b2f2b90 --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/controller/ConfigChannelController.java @@ -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> 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 aClass = processorMap.get(key); + return SpringContext.getBean(aClass); + } + +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigServiceRoute.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigServiceRoute.java new file mode 100644 index 00000000..d063844b --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/entity/ConfigServiceRoute.java @@ -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; +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ChannelMsgProcessor.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ChannelMsgProcessor.java new file mode 100644 index 00000000..1747c03b --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/ChannelMsgProcessor.java @@ -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); +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java index 1927df86..03d41dec 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbEnvGrayManager.java @@ -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); } }); } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIPBlacklistManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIPBlacklistManager.java index 542e6f7e..b60aaf53 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIPBlacklistManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIPBlacklistManager.java @@ -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 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; } - } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java index f17fefa7..c5d0ec71 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvManager.java @@ -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 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); } }); } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java index edde6086..42f53528 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbIsvRoutePermissionManager.java @@ -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; + } } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java index 34fc168d..7aa0a4bb 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java @@ -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); } }); } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java index a96a8493..e826c252 100644 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRouteConfigManager.java @@ -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); } }); } diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRoutesProcessor.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRoutesProcessor.java new file mode 100644 index 00000000..beab446e --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRoutesProcessor.java @@ -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 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); + } +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigServiceRouteMapper.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigServiceRouteMapper.java new file mode 100644 index 00000000..94a6137c --- /dev/null +++ b/sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/ConfigServiceRouteMapper.java @@ -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 { +}