diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java index ca4a9f4ba..f56ea21e5 100644 --- a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java @@ -1,16 +1,22 @@ package com.ruoyi.gateway.config; +import cn.hutool.extra.spring.SpringUtil; import com.ruoyi.gateway.config.handler.GlobalErrorWebExceptionHandler; import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository; import com.ruoyi.gateway.filter.CustomerGlobalFilter; import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RTopic; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.cloud.gateway.event.RefreshRoutesEvent; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; import org.springframework.cloud.gateway.route.RouteDefinitionRepository; import org.springframework.cloud.gateway.support.ConfigurationService; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.ReactiveStringRedisTemplate; @@ -19,6 +25,7 @@ import org.springframework.data.redis.core.script.RedisScript; import javax.annotation.Resource; import java.util.List; +import java.util.function.Consumer; /** * Gateway 配置文件 @@ -26,12 +33,19 @@ import java.util.List; * @author Wenchao Gong * @date 2021-09-11 */ +@Slf4j @Configuration -public class GatewayConfig +public class GatewayConfig implements ApplicationEventPublisherAware { - @Resource - private RedissonClient redissonClient; - + private RedissonClient client = SpringUtil.getBean(RedissonClient.class); + public ApplicationEventPublisher publisher; + public static final String TOPIC_GATEWAY_REFRESH_ROUTE = "TOPIC_GATEWAY_REFRESH_ROUTE"; + { + subscribe(TOPIC_GATEWAY_REFRESH_ROUTE, String.class, msg -> { + publisher.publishEvent(new RefreshRoutesEvent(this)); + log.info("网关接收通知[{}]刷新本地路由!", msg); + }); + } /** * Redis 路由仓库 * @@ -40,7 +54,7 @@ public class GatewayConfig @Bean public RouteDefinitionRepository redisRouteDefinitionRepository() { - return new RedisRouteDefinitionRepository(redissonClient); + return new RedisRouteDefinitionRepository(client); } @Bean @@ -60,4 +74,22 @@ public class GatewayConfig public ErrorWebExceptionHandler errorWebExceptionHandler() { return new GlobalErrorWebExceptionHandler(); } + + /** + * 订阅通道接收消息 + * + * @param channelKey 通道key + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public void subscribe(String channelKey, Class clazz, Consumer consumer) { + RTopic topic = client.getTopic(channelKey); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher publisher) + { + this.publisher = publisher; + } } diff --git a/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java b/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java index afda1230b..5f83c32fc 100644 --- a/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java +++ b/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java @@ -2,6 +2,7 @@ package com.ruoyi.isc.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.map.MapUtil; @@ -119,7 +120,9 @@ public class IscServiceServiceImpl extends ServicePlusImpl routes = pass ? ListUtil.list(false) : null; for (Long id : bo.getIds()) { IscService service = getOne(Wrappers.lambdaQuery() @@ -186,6 +193,14 @@ public class IscServiceServiceImpl extends ServicePlusImpl consumer) { + RedisUtils.publish(TOPIC_GATEWAY_REFRESH_ROUTE, DateUtil.now(), consumer); + } + /** * 刷新路由信息 先清空再批量新增 * @@ -90,32 +103,53 @@ public class RouteUtils { final RMap map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE); map.clear(); map.putAll(routeMap); + sendRefreshRouteToGateway((time) -> log.info("路由刷新完成,通知网关刷新路由![{}]", time)); return true; } /** * 保存路由信息 * - * @param route 路由信息 + * @param routes 路由信息 * @return 是否成功 */ - public static boolean saveRoute(IscRouteDefinition route) + public static boolean saveRoute(Collection routes) { + return saveRoute(routes, null); + } + + /** + * 保存路由信息 + * + * @param routes 路由信息 + * @param consumer 回调操作 + * @return 是否成功 + */ + public static boolean saveRoute(Collection routes, Consumer consumer) { + if(CollectionUtil.isEmpty(routes)) { + return true; + } final RMap map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE); - map.put(route.getId(), route); + Map collect = routes.stream().collect(Collectors.toMap(IscRouteDefinition::getId, Function.identity())); + map.putAll(collect); + if(Objects.isNull(consumer)) { + consumer = (time) -> log.info("保存路由[{}]完成,通知网关刷新路由![{}]", map.keySet(), time); + } + sendRefreshRouteToGateway(consumer); return true; } /** * 删除路由信息 * - * @param routeId 路由ID + * @param routeIds 路由ID * @return 是否成功 */ - public static boolean deleteRoute(String routeId) + public static boolean deleteRoute(Collection routeIds) { final RMap map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE); - map.remove(routeId); + map.fastRemove(routeIds.toArray(new String[0])); + sendRefreshRouteToGateway((time) -> log.info("删除路由[{}]完成,通知网关刷新路由![{}]", routeIds, time)); return true; } @@ -127,7 +161,9 @@ public class RouteUtils { */ public static boolean updateRoute(IscRouteDefinition route) { - return saveRoute(route); + boolean result = saveRoute(Collections.singletonList(route), (time) -> + log.info("更新路由[{}]完成,通知网关刷新路由![{}]", route.getId(), time)); + return result; } /**