mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 02:08:15 +08:00
服务修改后 Redis 通知 Gateway 刷新路由信息
This commit is contained in:
parent
685fab4eed
commit
08a9a8534b
@ -1,16 +1,22 @@
|
|||||||
package com.ruoyi.gateway.config;
|
package com.ruoyi.gateway.config;
|
||||||
|
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import com.ruoyi.gateway.config.handler.GlobalErrorWebExceptionHandler;
|
import com.ruoyi.gateway.config.handler.GlobalErrorWebExceptionHandler;
|
||||||
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
||||||
import com.ruoyi.gateway.filter.CustomerGlobalFilter;
|
import com.ruoyi.gateway.filter.CustomerGlobalFilter;
|
||||||
import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter;
|
import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RTopic;
|
||||||
import org.redisson.api.RedissonClient;
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
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.GlobalFilter;
|
||||||
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
|
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
|
||||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||||
import org.springframework.cloud.gateway.support.ConfigurationService;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||||
@ -19,6 +25,7 @@ import org.springframework.data.redis.core.script.RedisScript;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gateway 配置文件
|
* Gateway 配置文件
|
||||||
@ -26,12 +33,19 @@ import java.util.List;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021-09-11
|
* @date 2021-09-11
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
public class GatewayConfig
|
public class GatewayConfig implements ApplicationEventPublisherAware
|
||||||
{
|
{
|
||||||
@Resource
|
private RedissonClient client = SpringUtil.getBean(RedissonClient.class);
|
||||||
private RedissonClient redissonClient;
|
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 路由仓库
|
* Redis 路由仓库
|
||||||
*
|
*
|
||||||
@ -40,7 +54,7 @@ public class GatewayConfig
|
|||||||
@Bean
|
@Bean
|
||||||
public RouteDefinitionRepository redisRouteDefinitionRepository()
|
public RouteDefinitionRepository redisRouteDefinitionRepository()
|
||||||
{
|
{
|
||||||
return new RedisRouteDefinitionRepository(redissonClient);
|
return new RedisRouteDefinitionRepository(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -60,4 +74,22 @@ public class GatewayConfig
|
|||||||
public ErrorWebExceptionHandler errorWebExceptionHandler() {
|
public ErrorWebExceptionHandler errorWebExceptionHandler() {
|
||||||
return new GlobalErrorWebExceptionHandler();
|
return new GlobalErrorWebExceptionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅通道接收消息
|
||||||
|
*
|
||||||
|
* @param channelKey 通道key
|
||||||
|
* @param clazz 消息类型
|
||||||
|
* @param consumer 自定义处理
|
||||||
|
*/
|
||||||
|
public <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
|
||||||
|
RTopic topic = client.getTopic(channelKey);
|
||||||
|
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationEventPublisher(ApplicationEventPublisher publisher)
|
||||||
|
{
|
||||||
|
this.publisher = publisher;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.ruoyi.isc.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.tree.Tree;
|
import cn.hutool.core.lang.tree.Tree;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
@ -119,7 +120,9 @@ public class IscServiceServiceImpl extends ServicePlusImpl<IscServiceMapper, Isc
|
|||||||
{
|
{
|
||||||
IscService update = BeanUtil.toBean(bo, IscService.class);
|
IscService update = BeanUtil.toBean(bo, IscService.class);
|
||||||
validEntityBeforeSave(update);
|
validEntityBeforeSave(update);
|
||||||
return updateById(update);
|
boolean result = updateById(update);
|
||||||
|
RouteUtils.updateRoute(RouteUtils.generateRoute(update));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,7 +142,9 @@ public class IscServiceServiceImpl extends ServicePlusImpl<IscServiceMapper, Isc
|
|||||||
{
|
{
|
||||||
//TODO 做一些业务上的校验,判断是否需要校验
|
//TODO 做一些业务上的校验,判断是否需要校验
|
||||||
}
|
}
|
||||||
return removeByIds(ids);
|
boolean result = removeByIds(ids);
|
||||||
|
RouteUtils.deleteRoute(ids.stream().map(String::valueOf).collect(Collectors.toSet()));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -176,6 +181,8 @@ public class IscServiceServiceImpl extends ServicePlusImpl<IscServiceMapper, Isc
|
|||||||
{
|
{
|
||||||
checkAuditBO(bo);
|
checkAuditBO(bo);
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
|
boolean pass = IscConstants.AUDIT_PASS.equals(bo.getStatus());
|
||||||
|
Collection<IscRouteDefinition> routes = pass ? ListUtil.list(false) : null;
|
||||||
for (Long id : bo.getIds())
|
for (Long id : bo.getIds())
|
||||||
{
|
{
|
||||||
IscService service = getOne(Wrappers.<IscService>lambdaQuery()
|
IscService service = getOne(Wrappers.<IscService>lambdaQuery()
|
||||||
@ -186,6 +193,14 @@ public class IscServiceServiceImpl extends ServicePlusImpl<IscServiceMapper, Isc
|
|||||||
}
|
}
|
||||||
result = updateById(new IscService().setServiceId(id).setStatus(bo.getStatus())
|
result = updateById(new IscService().setServiceId(id).setStatus(bo.getStatus())
|
||||||
.setAuditMind(bo.getRemark()));
|
.setAuditMind(bo.getRemark()));
|
||||||
|
if(pass) {
|
||||||
|
//生成路由
|
||||||
|
routes.add(RouteUtils.generateRoute(service));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(pass) {
|
||||||
|
//保存路由信息
|
||||||
|
RouteUtils.saveRoute(routes);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package com.ruoyi.isc.utils;
|
package com.ruoyi.isc.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import com.ruoyi.common.constant.IscConstants;
|
import com.ruoyi.common.constant.IscConstants;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.RedisUtils;
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||||
import com.ruoyi.isc.domain.IscAppService;
|
import com.ruoyi.isc.domain.IscAppService;
|
||||||
import com.ruoyi.isc.domain.IscService;
|
import com.ruoyi.isc.domain.IscService;
|
||||||
@ -9,6 +12,7 @@ import com.ruoyi.isc.utils.beans.IscFilterDefinition;
|
|||||||
import com.ruoyi.isc.utils.beans.IscPredicateDefinition;
|
import com.ruoyi.isc.utils.beans.IscPredicateDefinition;
|
||||||
import com.ruoyi.isc.utils.beans.IscRouteDefinition;
|
import com.ruoyi.isc.utils.beans.IscRouteDefinition;
|
||||||
import com.ruoyi.isc.utils.beans.IscRule;
|
import com.ruoyi.isc.utils.beans.IscRule;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RMap;
|
import org.redisson.api.RMap;
|
||||||
import org.redisson.api.RedissonClient;
|
import org.redisson.api.RedissonClient;
|
||||||
import org.redisson.client.codec.Codec;
|
import org.redisson.client.codec.Codec;
|
||||||
@ -16,10 +20,9 @@ import org.redisson.codec.TypedJsonJacksonCodec;
|
|||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.List;
|
import java.util.function.Consumer;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -27,10 +30,12 @@ import java.util.stream.Collectors;
|
|||||||
* @author Wenchao Gong
|
* @author Wenchao Gong
|
||||||
* @date 2021/9/10 14:46
|
* @date 2021/9/10 14:46
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class RouteUtils {
|
public class RouteUtils {
|
||||||
|
|
||||||
public static final Codec ROUTE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRouteDefinition.class);
|
public static final Codec ROUTE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRouteDefinition.class);
|
||||||
public static final Codec RULE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRule.class);
|
public static final Codec RULE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRule.class);
|
||||||
|
public static final String TOPIC_GATEWAY_REFRESH_ROUTE = "TOPIC_GATEWAY_REFRESH_ROUTE";
|
||||||
/**
|
/**
|
||||||
* Gateway 虚拟路径前缀
|
* Gateway 虚拟路径前缀
|
||||||
*/
|
*/
|
||||||
@ -68,8 +73,7 @@ public class RouteUtils {
|
|||||||
*/
|
*/
|
||||||
public static URI getURI(String uri)
|
public static URI getURI(String uri)
|
||||||
{
|
{
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
return new URI(uri);
|
return new URI(uri);
|
||||||
} catch (URISyntaxException e)
|
} catch (URISyntaxException e)
|
||||||
{
|
{
|
||||||
@ -77,6 +81,15 @@ public class RouteUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布路由刷新通知
|
||||||
|
* @param consumer
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static void sendRefreshRouteToGateway(Consumer<String> consumer) {
|
||||||
|
RedisUtils.publish(TOPIC_GATEWAY_REFRESH_ROUTE, DateUtil.now(), consumer);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新路由信息 先清空再批量新增
|
* 刷新路由信息 先清空再批量新增
|
||||||
*
|
*
|
||||||
@ -90,32 +103,53 @@ public class RouteUtils {
|
|||||||
final RMap<String, IscRouteDefinition> map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
final RMap<String, IscRouteDefinition> map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
||||||
map.clear();
|
map.clear();
|
||||||
map.putAll(routeMap);
|
map.putAll(routeMap);
|
||||||
|
sendRefreshRouteToGateway((time) -> log.info("路由刷新完成,通知网关刷新路由![{}]", time));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存路由信息
|
* 保存路由信息
|
||||||
*
|
*
|
||||||
* @param route 路由信息
|
* @param routes 路由信息
|
||||||
* @return 是否成功
|
* @return 是否成功
|
||||||
*/
|
*/
|
||||||
public static boolean saveRoute(IscRouteDefinition route)
|
public static boolean saveRoute(Collection<IscRouteDefinition> routes) {
|
||||||
|
return saveRoute(routes, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存路由信息
|
||||||
|
*
|
||||||
|
* @param routes 路由信息
|
||||||
|
* @param consumer 回调操作
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public static boolean saveRoute(Collection<IscRouteDefinition> routes, Consumer<String> consumer)
|
||||||
{
|
{
|
||||||
|
if(CollectionUtil.isEmpty(routes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
final RMap<String, IscRouteDefinition> map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
final RMap<String, IscRouteDefinition> map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
||||||
map.put(route.getId(), route);
|
Map<String, IscRouteDefinition> 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除路由信息
|
* 删除路由信息
|
||||||
*
|
*
|
||||||
* @param routeId 路由ID
|
* @param routeIds 路由ID
|
||||||
* @return 是否成功
|
* @return 是否成功
|
||||||
*/
|
*/
|
||||||
public static boolean deleteRoute(String routeId)
|
public static boolean deleteRoute(Collection<String> routeIds)
|
||||||
{
|
{
|
||||||
final RMap<String, IscRouteDefinition> map = client.getMap(IscConstants.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
final RMap<String, IscRouteDefinition> 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +161,9 @@ public class RouteUtils {
|
|||||||
*/
|
*/
|
||||||
public static boolean updateRoute(IscRouteDefinition route)
|
public static boolean updateRoute(IscRouteDefinition route)
|
||||||
{
|
{
|
||||||
return saveRoute(route);
|
boolean result = saveRoute(Collections.singletonList(route), (time) ->
|
||||||
|
log.info("更新路由[{}]完成,通知网关刷新路由![{}]", route.getId(), time));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user