spring gateway 使用mysql

SpringCloud Gateway 使用 Mysql(R2DBC) 存储路由信息

表结构

1
2
3
4
5
6
7
CREATE TABLE `sys_route` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键自动增加',
`proxy_address` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '要代理的地址',
`location` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '请求前缀',
`strip_prefix` tinyint(4) NOT NULL COMMENT 'strip_prefix',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

代码配置

application.properties 配置文件

1
2
3
4
5
6
server.port=80
#database
spring.r2dbc.url=r2dbc:mysql://127.0.0.1:3306/gateway-sample
spring.r2dbc.username=root
spring.r2dbc.password=147258369
#logging.level.dev.miku.r2dbc.mysql.client.ReactorNettyClient=TRACE

DBRouteDomain 实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package net.wchar.code.sample.gateway.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(DBRouteDomain.TABLE_NAME)
public class DBRouteDomain {

public static final String TABLE_NAME = "sys_route";

//主键自动增加
@Id
private Long id;

//要代理的地址
@Column(value = "proxy_address")
private String proxyAddress;


//请求前缀
@Column(value = "location")
private String location;

//strip_prefix
@Column(value = "strip_prefix")
private Integer stripPrefix;
}

DBRouteRepository 访问数据库类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package net.wchar.code.sample.gateway.repository;

import net.wchar.code.sample.gateway.domain.DBRouteDomain;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.stereotype.Repository;

/**
* @author wchar.net
*/
@Repository
public interface DBRouteRepository extends ReactiveCrudRepository<DBRouteDomain, Long> {

}

DBRouteConfiguration 配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package net.wchar.code.sample.gateway.config;

import lombok.AllArgsConstructor;
import net.wchar.code.sample.gateway.domain.DBRouteDomain;
import net.wchar.code.sample.gateway.repository.DBRouteRepository;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.Buildable;
import org.springframework.cloud.gateway.route.builder.PredicateSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import reactor.core.publisher.Flux;

/**
* @author wchar.net
*/
@Configuration
public class DBRouteConfiguration {
@Bean
public RouteLocator routeLocator(DBRouteRepository dbRouteRepository,
RouteLocatorBuilder routeLocatorBuilder) {
return new DBRouteLocatorImpl(dbRouteRepository, routeLocatorBuilder);
}

@AllArgsConstructor
private static class DBRouteLocatorImpl implements RouteLocator {

private final DBRouteRepository dbRouteRepository;
private final RouteLocatorBuilder routeLocatorBuilder;

@Override
public Flux<Route> getRoutes() {
RouteLocatorBuilder.Builder routesBuilder = routeLocatorBuilder.routes();
return dbRouteRepository.findAll()
.map(route -> routesBuilder.route(String.valueOf(route.getId()),
predicateSpec -> setPredicateSpec(route, predicateSpec)))
.collectList()
.flatMapMany(builders -> routesBuilder.build()
.getRoutes());
}

private Buildable<Route> setPredicateSpec(DBRouteDomain dbRouteDomain, PredicateSpec predicateSpec) {
return predicateSpec.path(dbRouteDomain.getLocation()).and().method(
HttpMethod.GET,
HttpMethod.POST,
HttpMethod.PUT,
HttpMethod.DELETE,
HttpMethod.PATCH,
HttpMethod.HEAD,
HttpMethod.OPTIONS,
HttpMethod.TRACE
).filters(f -> f.stripPrefix(dbRouteDomain.getStripPrefix())).uri(dbRouteDomain.getProxyAddress());
}
}
}

运行测试

在表中添加一条数据

1
2
id     |    proxy_address       |  location     |  strip_prefix
1 | https://www.baidu.com | /baidu | 1

访问 http://localhost/baidu

到这一步就算是成功了,那要是在数据库添加一条数据,该怎么刷新路由呢?
哈哈,只需发射一个事件即可让gateway重新加载即可

1
//( @Autowired ApplicationEventPublisher)   applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));

完整代码: https://github.com/wchar-net/gateway-use-mysql-sample