diff --git a/pom.xml b/pom.xml
index 3a5000b82..f199256bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,6 +31,7 @@
5.7.11
29.0-jre
3.0.3
+ 3.0.3
11.6
4.9.1
2.5.1
@@ -155,6 +156,12 @@
${guava.version}
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+ ${gateway.version}
+
+
org.springframework.cloud
spring-cloud-starter-openfeign
diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml
index 2a348af4a..f4ea1559a 100644
--- a/ruoyi-extend/pom.xml
+++ b/ruoyi-extend/pom.xml
@@ -13,6 +13,7 @@
ruoyi-monitor-admin
+ ruoyi-isc-gateway
diff --git a/ruoyi-extend/ruoyi-isc-gateway/pom.xml b/ruoyi-extend/ruoyi-isc-gateway/pom.xml
new file mode 100644
index 000000000..d6fc777cf
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+ ruoyi-vue-plus
+ com.ruoyi
+ 3.1.0
+ ../../pom.xml
+
+ 4.0.0
+
+ ruoyi-isc-gateway
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
+ redis.clients
+ jedis
+
+
+
+
+ de.codecentric
+ spring-boot-admin-starter-client
+
+
+
+
\ No newline at end of file
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java
new file mode 100644
index 000000000..8fbc70508
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java
@@ -0,0 +1,20 @@
+package com.ruoyi.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * 启动程序
+ *
+ * @author Wenchao Gong
+ * @date 2021-09-11
+ */
+@SpringBootApplication
+public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ System.out.println("Gateway 启动成功" );
+ }
+
+}
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
new file mode 100644
index 000000000..cc0eec028
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java
@@ -0,0 +1,68 @@
+package com.ruoyi.gateway.config;
+
+import com.ruoyi.gateway.config.provider.ComplexRouteDefinitionRepository;
+import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
+import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository;
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import javax.annotation.Resource;
+
+/**
+ * Gateway 配置文件
+ *
+ * @author Wenchao Gong
+ * @date 2021-09-11
+ */
+@Configuration
+public class GatewayConfig {
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory)
+ {
+ final RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(redisConnectionFactory);
+ Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(RouteDefinition.class);
+ template.setValueSerializer(jackson2JsonRedisSerializer);
+ template.setHashValueSerializer(jackson2JsonRedisSerializer);
+ final StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+ template.setKeySerializer(stringRedisSerializer);
+ template.setHashKeySerializer(stringRedisSerializer);
+ return template;
+ }
+
+ @Bean
+ public RouteDefinitionRepository complexRouteDefinitionRepository()
+ {
+ return new ComplexRouteDefinitionRepository(inMemoryRouteDefinitionRepository(), redisRouteDefinitionRepository());
+ }
+
+ /**
+ * 内存 路由仓库
+ *
+ * @return 本地内存路由仓库
+ */
+ RouteDefinitionRepository inMemoryRouteDefinitionRepository()
+ {
+ return new InMemoryRouteDefinitionRepository();
+ }
+
+ /**
+ * Redis 路由仓库
+ *
+ * @return redis路由仓库
+ */
+ RouteDefinitionRepository redisRouteDefinitionRepository()
+ {
+ return new RedisRouteDefinitionRepository(redisTemplate);
+ }
+}
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/ComplexRouteDefinitionRepository.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/ComplexRouteDefinitionRepository.java
new file mode 100644
index 000000000..70af9a671
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/ComplexRouteDefinitionRepository.java
@@ -0,0 +1,65 @@
+package com.ruoyi.gateway.config.provider;
+
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 复合的路由存储器
+ *
+ * @author Wenchao Gong
+ * @date 2021-09-11
+ */
+public class ComplexRouteDefinitionRepository implements RouteDefinitionRepository {
+
+ private RouteDefinitionRepository localCache;
+ private RouteDefinitionRepository remoteReps;
+
+ public ComplexRouteDefinitionRepository(RouteDefinitionRepository localCache, RouteDefinitionRepository remoteReps)
+ {
+ this.localCache = localCache;
+ this.remoteReps = remoteReps;
+ }
+
+
+ @Override
+ public Flux getRouteDefinitions()
+ {
+ final Flux routeDefinitions = localCache.getRouteDefinitions();
+ return routeDefinitions.collectList().flatMapIterable(list -> {
+ if(list.isEmpty()) {
+ final Flux definitions = remoteReps.getRouteDefinitions();
+ definitions.collectList().flatMapIterable(routes -> {
+ if(!routes.isEmpty()) {
+ routes.stream().map(m -> {
+ routes.add(m);
+ return Mono.just(m);
+ }).forEach(m -> {
+ localCache.save(m);
+ });
+ }
+ return routes;
+ }).filter(l -> Objects.nonNull(l)).map(m -> list.add(m)).collectList();
+ }
+ return list;
+ });
+ }
+
+ @Override
+ public Mono save(Mono route)
+ {
+ remoteReps.save(route);
+ return localCache.save(route);
+ }
+
+ @Override
+ public Mono delete(Mono routeId)
+ {
+ remoteReps.delete(routeId);
+ return localCache.delete(routeId);
+ }
+}
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java
new file mode 100644
index 000000000..fd8fc1beb
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java
@@ -0,0 +1,50 @@
+package com.ruoyi.gateway.config.provider;
+
+import org.springframework.cloud.gateway.route.RouteDefinition;
+import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
+import org.springframework.data.redis.core.RedisTemplate;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+/**
+ * Redis 路由仓库
+ *
+ * @author Wenchao Gong
+ * @date 2021-09-11
+ */
+public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
+ public static final String KEY_ROUTES = "ROUTES::";
+ private final RedisTemplate redisTemplate;
+
+ public RedisRouteDefinitionRepository(RedisTemplate redisTemplate)
+ {
+ this.redisTemplate = redisTemplate;
+ }
+
+ @Override
+ public Flux getRouteDefinitions()
+ {
+ List values = redisTemplate.opsForHash().values(KEY_ROUTES);
+ return Flux.fromIterable(values);
+ }
+
+ @Override
+ public Mono save(Mono route)
+ {
+ return route.flatMap(definition -> {
+ redisTemplate.opsForHash().put(KEY_ROUTES, definition.getId(), definition);
+ return Mono.empty();
+ });
+ }
+
+ @Override
+ public Mono delete(Mono routeId)
+ {
+ return routeId.flatMap(id -> {
+ redisTemplate.opsForHash().delete(KEY_ROUTES, id);
+ return Mono.empty();
+ });
+ }
+}
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml
new file mode 100644
index 000000000..c94a3d34f
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml
@@ -0,0 +1,44 @@
+--- # 监控配置
+spring:
+ boot:
+ admin:
+ # Spring Boot Admin Client 客户端的相关配置
+ client:
+ # 增加客户端开关
+ enabled: true
+ # 设置 Spring Boot Admin Server 地址
+ url: http://localhost:9090/admin
+ instance:
+ prefer-ip: true # 注册实例时,优先使用 IP
+ username: ruoyi
+ password: 123456
+
+--- # redis 配置
+spring:
+ redis:
+ # 地址
+ host: 192.168.64.128
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # 密码
+ password:
+ # 连接超时时间
+ timeout: 10s
+ # 是否开启ssl
+ ssl: false
+
+--- # Actuator 监控端点的配置项
+management:
+ endpoints:
+ web:
+ # Actuator 提供的 API 接口的根目录。默认为 /actuator
+ base-path: /actuator
+ exposure:
+ # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
+ # 生产环境不建议放开所有 根据项目需求放开即可
+ include: @endpoints.include@
+ endpoint:
+ logfile:
+ external-file: ./logs/sys-console.log
\ No newline at end of file
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml
new file mode 100644
index 000000000..9e1aa773c
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml
@@ -0,0 +1,8 @@
+server:
+ port: 8090
+# Spring配置
+spring:
+ application:
+ name: RuoYi-Gateway
+ profiles:
+ active: @profiles.active@
diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml
new file mode 100644
index 000000000..663eef0c5
--- /dev/null
+++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+ ${console.log.pattern}
+ utf-8
+
+
+
+
+
+ ${log.path}/sys-console.log
+
+
+ ${log.path}/sys-console.%d{yyyy-MM-dd}.log
+
+ 1
+
+
+ ${log.pattern}
+ utf-8
+
+
+
+ INFO
+
+
+
+
+
+ ${log.path}/sys-info.log
+
+
+
+ ${log.path}/sys-info.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ INFO
+
+ ACCEPT
+
+ DENY
+
+
+
+
+ ${log.path}/sys-error.log
+
+
+
+ ${log.path}/sys-error.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+ ERROR
+
+ ACCEPT
+
+ DENY
+
+
+
+
+
+ ${log.path}/sys-user.log
+
+
+ ${log.path}/sys-user.%d{yyyy-MM-dd}.log
+
+ 60
+
+
+ ${log.pattern}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+