添加 网关模块

This commit is contained in:
Wenchao Gong 2021-09-13 13:06:45 +08:00
parent ff1c729385
commit 7da40951e7
10 changed files with 422 additions and 0 deletions

View File

@ -31,6 +31,7 @@
<hutool.version>5.7.11</hutool.version>
<guava.version>29.0-jre</guava.version>
<feign.version>3.0.3</feign.version>
<gateway.version>3.0.3</gateway.version>
<feign-okhttp.version>11.6</feign-okhttp.version>
<okhttp.version>4.9.1</okhttp.version>
<spring-boot-admin.version>2.5.1</spring-boot-admin.version>
@ -155,6 +156,12 @@
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>${gateway.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>

View File

@ -13,6 +13,7 @@
<modules>
<module>ruoyi-monitor-admin</module>
<module>ruoyi-isc-gateway</module>
</modules>
</project>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.1.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-isc-gateway</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- pool 对象池 -->
<!--<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -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 启动成功" );
}
}

View File

@ -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<String, RouteDefinition> redisTemplate;
@Bean
public RedisTemplate<String, RouteDefinition> redisTemplate(RedisConnectionFactory redisConnectionFactory)
{
final RedisTemplate<String, RouteDefinition> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<RouteDefinition> 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);
}
}

View File

@ -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<RouteDefinition> getRouteDefinitions()
{
final Flux<RouteDefinition> routeDefinitions = localCache.getRouteDefinitions();
return routeDefinitions.collectList().flatMapIterable(list -> {
if(list.isEmpty()) {
final Flux<RouteDefinition> 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<Void> save(Mono<RouteDefinition> route)
{
remoteReps.save(route);
return localCache.save(route);
}
@Override
public Mono<Void> delete(Mono<String> routeId)
{
remoteReps.delete(routeId);
return localCache.delete(routeId);
}
}

View File

@ -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<String, RouteDefinition> redisTemplate;
public RedisRouteDefinitionRepository(RedisTemplate<String, RouteDefinition> redisTemplate)
{
this.redisTemplate = redisTemplate;
}
@Override
public Flux<RouteDefinition> getRouteDefinitions()
{
List<RouteDefinition> values = redisTemplate.<String,RouteDefinition>opsForHash().values(KEY_ROUTES);
return Flux.fromIterable(values);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route)
{
return route.flatMap(definition -> {
redisTemplate.opsForHash().put(KEY_ROUTES, definition.getId(), definition);
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId)
{
return routeId.flatMap(id -> {
redisTemplate.opsForHash().delete(KEY_ROUTES, id);
return Mono.empty();
});
}
}

View File

@ -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

View File

@ -0,0 +1,8 @@
server:
port: 8090
# Spring配置
spring:
application:
name: RuoYi-Gateway
profiles:
active: @profiles.active@

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log.path" value="./logs"/>
<property name="console.log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %green([%thread]) %boldMagenta(%logger{36}) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${console.log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 控制台输出 -->
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-console.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大 1天 -->
<maxHistory>1</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
<charset>utf-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.ruoyi" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
<appender-ref ref="file_console" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>