需求:

正常的提供一个网关服务,可以实现网关的管理(增删改查)

思路:

1、创建一个网关路由数据表来实现网关的配置管理
2、低版本Spring Cloud Gateway 框架要实现基于reids网关动态路由,有两步
(1)实现RouteDefinitionRepository接口,实现下面三个 方法即可分别对应路由的获取、保存和删除
Flux getRouteDefinitions();
Mono save(Mono route);
Mono delete(Mono routeId);
(2)创建spring事件发布器实现ApplicationEventPublisherAware,可以不重启服务就让spring框架的网关服务自动刷新网关配置

但是!!!
Spring Cloud Gateway 新版本,比如我们这次使用的3.1.1人家给你提供好了,不需要自己再创建(1)了,就是RedisRouteDefinitionRepository类,在配置文件启用下即可,下面步骤有展示

3、集群环境下,网关也可能部署多台服务器,上面步骤(2)中的发布器值针对当前服务生效,考虑用消息队列来通知集群的网关服务一起刷新路由,当然也可以使用zk或者nacos注册中心来实现

注意:

如果采用MQ来实现集群网关的刷新,尽量使用一个独立的MQ,基本省可以达到秒刷的效果,否则和业务公用一个MQ的话,一旦消息积压,那刷新的延时就很大了

不过生产环境还是用注册中心来实现更好(推荐),注册中心的实现方式下次有空再补

技术栈:

spring cloud gateway + redis + rocketmq +mysql

网关入门的老哥清先阅读最下面的参考文档,找到了几个不错哦的博客

实操:

1、创建网关路由表实现管理路由

CREATE TABLE `manage_gateway_route`  (
  `unid` bigint(20) NOT NULL COMMENT '主键',
  `gateway_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '网关Code',
  `route_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '路由名称',
  `route_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '路由Code',
  `route_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '路由URI',
  `route_paths` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '路由分发地址\",\"分隔',
  `route_sort` int(3) NOT NULL DEFAULT 0 COMMENT '路由排序',
  `limit_strategy_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '限流策略code',
  `limit_strategy` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '限流策略',
  `limit_replenish_rate` int(5) NULL DEFAULT NULL COMMENT '每秒并发量',
  `limit_burst_capacity` int(5) NULL DEFAULT NULL COMMENT '最大并发量',
  `enable_flag` tinyint(2) NOT NULL DEFAULT 1 COMMENT '是否启用:1-启用 0-禁用 ',
  `create_time` datetime(0) NOT NULL COMMENT '创建时间',
  `update_time` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',
  `creator_unid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人ID',
  `creator_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人名称',
  PRIMARY KEY (`unid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '网关路由管理表' ROW_FORMAT = Dynamic;

插入几条模拟数据,分别是用户服务、两个业务服务

INSERT INTO `manage_gateway_route` VALUES (10001, 'app2-service', '业务服务2', 'demo-app2', 'lb://demo-app2', '/app2/**', 5, '#{@ipKeyResolver}', 'IP限流', 10, 10, 1, '2022-03-24 17:22:29', '2022-04-06 09:16:40', '1111', 'test');
INSERT INTO `manage_gateway_route` VALUES (10002, 'app-service', '业务服务', 'demo-app', 'lb://demo-app', '/app/**', 4, '#{@ipKeyResolver}', 'IP限流', 10, 10, 1, '2022-03-24 15:49:42', '2022-04-06 09:16:46', '1111', 'test');
INSERT INTO `manage_gateway_route` VALUES (10003, 'user-service', '用户服务', 'demo-user', 'lb://demo-user', '/user/**,/account/**', 21, '#{@ipKeyResolver}', 'IP限流', 10, 10, 1, '2022-02-22 06:39:11', '2022-04-06 09:16:56', '1111', 'test');

2、引入pom依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.4</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gateway</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>Demo project for gateway</description>
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>2021.0.1</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jdbc</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.76</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-spring-boot-starter</artifactId>
        <version>2.2.1</version>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

3、application.yml配置文件

# 应用服务
server.port: 8099
# 应用名称
spring.application.name: gateway


# spring-cloud
spring:
  cloud:
    zookeeper.connect-string: 192.168.8.49:2181
#    启用redis存储路由,不加这个的话需要自己注册bean
    gateway:
      redis-route-definition-repository:
        enabled: true

# redis
spring.redis:
  database: 1
  host: 192.168.8.49
  password: 123456
  port: 6379
  timeout: 3000

# mysql
spring.datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/gateway?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false&allowMultiQueries=true
  username: root
  password: 123456

# mybatis
mybatis:
  mapper-locations: classpath:mapper/**/*Mapper.xml
  type-aliases-package: com.gateway.demo.*.entity

# rocketmq
rocketmq:
  name-server: 192.168.8.49:9876
  producer:
    send-message-timeout: 3000
    group: gateway
  topic:
    prefix: test
    # 网关刷新topic
    gateway-refresh-topic: ${rocketmq.topic.prefix}_gateway_refresh_topic

4、根据ip限流GatewayRateLimiterConfig

我们已最常用的IP限流进行配置,接口限流和用户限流也注册了bean,根据需要引用即可

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;
import java.util.Objects;

/**
* 限流配置
* @author pym
* @date 2022/4/1
*/
@Configuration
public class GatewayRateLimiterConfig {
    /**
     * Gateway通过内置的RequestRateLimiter过滤器实现限流,用的是令牌桶算法,借助Redis保存中间数据
     * 这里自定义一个KeyResolver
     * 作用是对来源ip进行限流
     */
    @Primary
    @Bean(value = "ipKeyResolver")
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress());
    }

    /**
     * 对接口进行限流
     */
    @Bean(value = "apiKeyResolver")
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

    /**
     * 对用户进行限流
     */
    @Bean(value = "userKeyResolver")
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getHeaders().getFirst("Authorization")));
    }

}

5、controller类

import com.gateway.demo.service.IManageGatewayRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import java.util.List;
/**
* 路由控制Controller
* @author ppp
* @date 2022/3/31
*/
@RestController
@RequestMapping("/route")
public class Controller {

    @Autowired
    IManageGatewayRouteService gatewayRouteService;

    /**
     * 获取网关
     * @return 是否成功:true-成功,false-失败
     */
    @GetMapping("/getGateway")
    public Mono<List<RouteDefinition>> getGateway(){
    return gatewayRouteService.getGateway();
    }

    /**
     * 路由手动刷新
     * @return 是否成功:true-成功,false-失败
     */
    @GetMapping("/refresh")
    public Boolean refresh(){
        return gatewayRouteService.loadAndRefresh();
    }

}

6、(核心1)ManageGatewayRouteServiceImpl网关管理实现类

接口类:

/**
 * 网关路由管理表 服务类
 *
 * @author ppp
 * @since 2022-04-01
 */
public interface IManageGatewayRouteService {

    /**
     * 路由加载刷新
     * @return 是否成功:true-成功,false-失败
     */
    public boolean loadAndRefresh();

    /**
     * 获取网关
     * @return 是否成功:true-成功,false-失败
     */
    Mono<List<RouteDefinition>> getGateway();

}

接口实现类

import com.gateway.demo.entity.dto.ManageGatewayRouteDO;
import com.gateway.demo.entity.enums.MessageTagEnum;
import com.gateway.demo.mapper.ManageGatewayRouteMapper;
import com.gateway.demo.rocketmq.producer.GatewayRefreshProducer;
import com.gateway.demo.service.IManageGatewayRouteService;
import com.gateway.demo.service.IRoutePublishService;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RedisRouteDefinitionRepository;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 网关路由管理表 服务实现类
 *
 * @author ppp
 * @since 2022-04-01
 */
@Service
public class ManageGatewayRouteServiceImpl implements IManageGatewayRouteService {

	    @Resource
	    IRoutePublishService routePublishService;
	    @Resource
	    RedisRouteDefinitionRepository redisRouteDefinitionRepository;
	    @Resource
	    ManageGatewayRouteMapper manageGatewayRouteMapper;
	    @Resource
	    GatewayRefreshProducer gatewayRefreshProducer;
	
    @Override
    public boolean loadAndRefresh() {

        List<ManageGatewayRouteDO> gatewayRouteList = manageGatewayRouteMapper.getEnableList();
        for (ManageGatewayRouteDO gatewayRoute : gatewayRouteList) {
            RouteDefinition routeDefinition = new RouteDefinition();
            routeDefinition.setId(gatewayRoute.getRouteCode());
            URI routeUri = UriComponentsBuilder.fromUriString(gatewayRoute.getRouteUri()).build().toUri();
            routeDefinition.setUri(routeUri);
            routeDefinition.setOrder(gatewayRoute.getRouteSort());
            List<PredicateDefinition> predicates = getPredicates(gatewayRoute.getRoutePaths());
            if (!predicates.isEmpty()) {
                routeDefinition.setPredicates(predicates);
            }
            // 获取限流过滤器
            List<FilterDefinition> filters = new ArrayList();
            if(!ObjectUtils.isEmpty(gatewayRoute.getLimitStrategy())){
                Map<String, String> args = new LinkedHashMap();
                args.put("key-resolver", gatewayRoute.getLimitStrategyCode());
                args.put("redis-rate-limiter.replenishRate", String.valueOf(gatewayRoute.getLimitReplenishRate()));
                args.put("redis-rate-limiter.burstCapacity", String.valueOf(gatewayRoute.getLimitBurstCapacity()));
                FilterDefinition filterDefinition = new FilterDefinition();
                filterDefinition.setName("RequestRateLimiter");
                filterDefinition.setArgs(args);
                filters.add(filterDefinition);
            }
            routeDefinition.setFilters(filters);
            redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
        }
        // 集群模式下,用mq广播刷新路由消息,这样每个节点都能刷新
        gatewayRefreshProducer.sendMessage(MessageTagEnum.SUCCESS.getValue());
        // 单机部署直接用这个即可,不发消息,直接刷新
//        routePublishService.refreshRoutes();
        return Boolean.TRUE;
    }

    @Override
    public Mono<List<RouteDefinition>> getGateway() {
        return redisRouteDefinitionRepository.getRouteDefinitions().collectList();
    }

    /**
     * 获取地址断言
     *
     * @param routePaths 路由地址
     * @return java.util.List
     */
    private List<PredicateDefinition> getPredicates(String routePaths) {
        Map<String, String> args = new LinkedHashMap();
        String[] paths = routePaths.split(",");
        for (int i = 0; i < paths.length; i++) {
            args.put("_genkey_" + i, paths[i]);
        }
        PredicateDefinition predicate = new PredicateDefinition();
        predicate.setName("Path");
        predicate.setArgs(args);

        List<PredicateDefinition> predicates = new ArrayList();
        predicates.add(predicate);
        return predicates;
    }

}

7、(核心2)事件发布类

接口类

/**
* 路由发布服务
* @author ppp
* @date 2022/4/2
*/
public interface IRoutePublishService {
    /**
     * 发布路由
     */
    public void publishRoutes();

}

接口实现类

import com.gateway.demo.service.IRoutePublishService;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;

/**
* 路由发布服务
 * gateway在配置类GatewayAutoConfiguration中初始化了一个刷新路由的监听器RouteRefreshListener作为加载路由的入口,里面有一个重置方法reset()
 *     private void reset() {
 *         this.publisher.publishEvent(new RefreshRoutesEvent(this));
 *     }
 * 内容是通过Spring事件触发 发布RefreshRoutesEvent事件即可达到路由的刷新
* @author ppp
* @date 2022/3/23
*/
@Service
public class RoutePublishServiceImpl implements ApplicationEventPublisherAware, IRoutePublishService {
    /**
     * spring事件发布器
     */
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    @Override
    public void publishRoutes() {
        publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

8、消息生产者

import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

/**
* 网关刷新mq消息生产者
* @author ppp
* @date 2022/4/2
*/
@Component
public class GatewayRefreshProducer {
    private static final Logger logger = LoggerFactory.getLogger(GatewayRefreshProducer.class);

    @Value("${rocketmq.topic.gateway-refresh-topic}")
    String gatewayRefreshTopic;

    @Autowired
    RocketMQTemplate rocketMqTemplate;

    public void sendMessage(String tag){
        // 消息体没啥需要发送的内容对象,就搞个"-"字符串把
        Message<String> message = MessageBuilder.withPayload("-").build();
        rocketMqTemplate.asyncSend(gatewayRefreshTopic + ":" + tag, message, new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                logger.info("发送网关刷新消息成功");
            }

            @Override
            public void onException(Throwable throwable) {
                logger.info(throwable.getMessage(), throwable);
                logger.info("发送网关刷新消息失败");
            }
        });
    }

}

9、消息消费者

import com.gateway.demo.entity.enums.MessageTagEnum;
import com.gateway.demo.service.IRoutePublishService;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
* 网关刷新mq消息消费者
* @author ppp
* @date 2022/4/2
*/
@Component
public class GatewayRefreshConsumer implements ApplicationRunner {
    private static final Logger logger = LoggerFactory.getLogger(GatewayRefreshConsumer.class);

    @Value("${rocketmq.topic.gateway-refresh-topic}")
    String gatewayRefreshTopic;

    @Value("${rocketmq.name-server}")
    private String rocketMqNameServer;

    @Autowired
    IRoutePublishService routePublishService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(gatewayRefreshTopic + "_group");
        consumer.setNamesrvAddr(rocketMqNameServer);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.setConsumeThreadMin(4);
        consumer.setConsumeThreadMax(20);
        // 设置为广播消息消费
        consumer.setMessageModel(MessageModel.BROADCASTING);
        consumer.subscribe(gatewayRefreshTopic, MessageTagEnum.SUCCESS.getValue());
        consumer.registerMessageListener((MessageListenerConcurrently) (messageExts, consumeconcurrentlycontext) -> {
            for (MessageExt message : messageExts) {
                logger.info("接收【网关刷新】消息,msg:{}", message);
                routePublishService.publishRoutes();
                logger.info("刷新路由成功");
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        consumer.start();
        logger.info("GatewayRefreshConsumer Listener Start Success");
    }

}

10、表entity、mapper、xml

表实体类

import com.fasterxml.jackson.annotation.JsonInclude;

import java.io.Serializable;
import java.util.Date;

/**
 * 网关路由管理表
 *
 * @author ppp
 * @since 2022-04-01
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ManageGatewayRouteDO implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    private Long unid;

    /**
     * 网关Code
     */
    private String gatewayCode;

    /**
     * 路由名称
     */
    private String routeName;

    /**
     * 路由Code
     */
    private String routeCode;

    /**
     * 路由URI
     */
    private String routeUri;

    /**
     * 路由分发地址","分隔
     */
    private String routePaths;

    /**
     * 路由排序
     */
    private Integer routeSort;

    /**
     * 限流策略code
     */
    private String limitStrategyCode;

    /**
     * 限流策略
     */
    private String limitStrategy;

    /**
     * 每秒并发量
     */
    private Integer limitReplenishRate;

    /**
     * 最大并发量
     */
    private Integer limitBurstCapacity;

    /**
     * 是否启用:1-启用 0-禁用
     */
    private Integer enableFlag;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 创建人ID
     */
    private String creatorUnid;

    /**
     * 创建人名称
     */
    private String creatorName;


    public Long getUnid() {
        return unid;
    }

    public void setUnid(Long unid) {
        this.unid = unid;
    }

    public String getGatewayCode() {
        return gatewayCode;
    }

    public void setGatewayCode(String gatewayCode) {
        this.gatewayCode = gatewayCode;
    }

    public String getRouteName() {
        return routeName;
    }

    public void setRouteName(String routeName) {
        this.routeName = routeName;
    }

    public String getRouteCode() {
        return routeCode;
    }

    public void setRouteCode(String routeCode) {
        this.routeCode = routeCode;
    }

    public String getRouteUri() {
        return routeUri;
    }

    public void setRouteUri(String routeUri) {
        this.routeUri = routeUri;
    }

    public String getRoutePaths() {
        return routePaths;
    }

    public void setRoutePaths(String routePaths) {
        this.routePaths = routePaths;
    }

    public Integer getRouteSort() {
        return routeSort;
    }

    public void setRouteSort(Integer routeSort) {
        this.routeSort = routeSort;
    }

    public String getLimitStrategyCode() {
        return limitStrategyCode;
    }

    public void setLimitStrategyCode(String limitStrategyCode) {
        this.limitStrategyCode = limitStrategyCode;
    }

    public String getLimitStrategy() {
        return limitStrategy;
    }

    public void setLimitStrategy(String limitStrategy) {
        this.limitStrategy = limitStrategy;
    }

    public Integer getLimitReplenishRate() {
        return limitReplenishRate;
    }

    public void setLimitReplenishRate(Integer limitReplenishRate) {
        this.limitReplenishRate = limitReplenishRate;
    }

    public Integer getLimitBurstCapacity() {
        return limitBurstCapacity;
    }

    public void setLimitBurstCapacity(Integer limitBurstCapacity) {
        this.limitBurstCapacity = limitBurstCapacity;
    }

    public Integer getEnableFlag() {
        return enableFlag;
    }

    public void setEnableFlag(Integer enableFlag) {
        this.enableFlag = enableFlag;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public String getCreatorUnid() {
        return creatorUnid;
    }

    public void setCreatorUnid(String creatorUnid) {
        this.creatorUnid = creatorUnid;
    }

    public String getCreatorName() {
        return creatorName;
    }

    public void setCreatorName(String creatorName) {
        this.creatorName = creatorName;
    }

    @Override
    public String toString() {
        return "ManageGatewayRouteDO{" +
        "unid=" + unid +
        ", gatewayCode=" + gatewayCode +
        ", routeName=" + routeName +
        ", routeCode=" + routeCode +
        ", routeUri=" + routeUri +
        ", routePaths=" + routePaths +
        ", routeSort=" + routeSort +
        ", limitStrategyCode=" + limitStrategyCode +
        ", limitStrategy=" + limitStrategy +
        ", limitReplenishRate=" + limitReplenishRate +
        ", limitBurstCapacity=" + limitBurstCapacity +
        ", enableFlag=" + enableFlag +
        ", createTime=" + createTime +
        ", updateTime=" + updateTime +
        ", creatorUnid=" + creatorUnid +
        ", creatorName=" + creatorName +
        "}";
    }
}

消息枚举

/**
* 消息枚举
* @author ppp
* @date 2022/4/2
*/
public enum  MessageTagEnum {
    /**
     * 消息Tag枚举
     */
    SUCCESS("success", "成功"),
    FAILURE("failure", "失败");

    MessageTagEnum(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    private final String value;
    private final String desc;

    public String getValue() {
        return value;
    }

    public String getDesc() {
        return desc;
    }
}

mapper接口

import com.gateway.demo.entity.dto.ManageGatewayRouteDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

/**
 * 网关路由管理表 Mapper 接口
 *
 * @author ppp
 * @since 2022-04-01
 */
@Mapper
public interface ManageGatewayRouteMapper {


    /**
     * 获取启用的路由列表
     * @return  List<ManageGatewayRouteDO>
     */
    List<ManageGatewayRouteDO> getEnableList();
    /**
     * 根据unid查询网关路由管理表
     * @param unid 网关路由管理表ID
     * @return 网关路由管理表数据对象
     */
    ManageGatewayRouteDO selectByUnid(Long unid);

    /**
     * 新增
     * @param record 网关路由管理表数据对象
     * @return 影响行数
     */
    int insert(ManageGatewayRouteDO record);

    /**
     * 根据unid更新
     * @param record 网关路由管理表数据对象
     * @return 影响行数
     */
    int updateByUnid(ManageGatewayRouteDO record);

    /**
     * 根据unid删除
     * @param unid 网关路由管理表ID
     * @return 影响行数
     */
    int deleteByUnid(Long unid);

}

mapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gateway.demo.mapper.ManageGatewayRouteMapper">

    <!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.gateway.demo.entity.dto.ManageGatewayRouteDO">
    <id column="unid" jdbcType="BIGINT" property="unid" />
    <result column="gateway_code" jdbcType="VARCHAR" property="gatewayCode" />
    <result column="route_name" jdbcType="VARCHAR" property="routeName" />
    <result column="route_code" jdbcType="VARCHAR" property="routeCode" />
    <result column="route_uri" jdbcType="VARCHAR" property="routeUri" />
    <result column="route_paths" jdbcType="VARCHAR" property="routePaths" />
    <result column="route_sort" jdbcType="INTEGER" property="routeSort" />
    <result column="limit_strategy_code" jdbcType="VARCHAR" property="limitStrategyCode" />
    <result column="limit_strategy" jdbcType="VARCHAR" property="limitStrategy" />
    <result column="limit_replenish_rate" jdbcType="INTEGER" property="limitReplenishRate" />
    <result column="limit_burst_capacity" jdbcType="INTEGER" property="limitBurstCapacity" />
    <result column="enable_flag" jdbcType="TINYINT" property="enableFlag" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
    <result column="creator_unid" jdbcType="VARCHAR" property="creatorUnid" />
    <result column="creator_name" jdbcType="VARCHAR" property="creatorName" />
</resultMap>

<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
    unid, gateway_code, route_name, route_code, route_uri,
    route_paths, route_sort, limit_strategy_code, limit_strategy, limit_replenish_rate,
    limit_burst_capacity, enable_flag, create_time, update_time, creator_unid,
    creator_name
</sql>

<!--根据unid查询-->
<select id="selectByUnid" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select <include refid="Base_Column_List" />
    from manage_gateway_route
    where unid = #{unid,jdbcType=BIGINT}
</select>

<select id="getEnableList" resultMap="BaseResultMap">
    select <include refid="Base_Column_List" />
    from manage_gateway_route
    where enable_flag = 1
</select>

<!--新增-->
<insert id="insert" parameterType="com.gateway.demo.entity.dto.ManageGatewayRouteDO">
    insert into manage_gateway_route ( unid, gateway_code, route_name, route_code, route_uri,
        route_paths, route_sort, limit_strategy_code, limit_strategy, limit_replenish_rate,
        limit_burst_capacity, enable_flag, create_time, update_time, creator_unid,
        creator_name )
    values ( #{unid,jdbcType=BIGINT}, #{gatewayCode,jdbcType=VARCHAR}, #{routeName,jdbcType=VARCHAR},
        #{routeCode,jdbcType=VARCHAR}, #{routeUri,jdbcType=VARCHAR}, #{routePaths,jdbcType=VARCHAR},
        #{routeSort,jdbcType=INTEGER}, #{limitStrategyCode,jdbcType=VARCHAR}, #{limitStrategy,jdbcType=VARCHAR},
        #{limitReplenishRate,jdbcType=INTEGER}, #{limitBurstCapacity,jdbcType=INTEGER}, #{enableFlag,jdbcType=TINYINT},
        #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}, #{creatorUnid,jdbcType=VARCHAR},
        #{creatorName,jdbcType=VARCHAR} )
</insert>

<!--根据unid更新-->
<update id="updateByUnid" parameterType="com.gateway.demo.entity.dto.ManageGatewayRouteDO">
    update manage_gateway_route
    <set>
        <if test="gatewayCode != null and gatewayCode != ''">
            gateway_code = #{gatewayCode,jdbcType=VARCHAR},
        </if>
        <if test="routeName != null and routeName != ''">
            route_name = #{routeName,jdbcType=VARCHAR},
        </if>
        <if test="routeCode != null and routeCode != ''">
            route_code = #{routeCode,jdbcType=VARCHAR},
        </if>
        <if test="routeUri != null and routeUri != ''">
            route_uri = #{routeUri,jdbcType=VARCHAR},
        </if>
        <if test="routePaths != null and routePaths != ''">
            route_paths = #{routePaths,jdbcType=VARCHAR},
        </if>
        <if test="routeSort != null">
            route_sort = #{routeSort,jdbcType=INTEGER},
        </if>
        <if test="limitStrategyCode != null and limitStrategyCode != ''">
            limit_strategy_code = #{limitStrategyCode,jdbcType=VARCHAR},
        </if>
        <if test="limitStrategy != null and limitStrategy != ''">
            limit_strategy = #{limitStrategy,jdbcType=VARCHAR},
        </if>
        <if test="limitReplenishRate != null">
            limit_replenish_rate = #{limitReplenishRate,jdbcType=INTEGER},
        </if>
        <if test="limitBurstCapacity != null">
            limit_burst_capacity = #{limitBurstCapacity,jdbcType=INTEGER},
        </if>
        <if test="enableFlag != null">
            enable_flag = #{enableFlag,jdbcType=TINYINT},
        </if>
        <if test="createTime != null">
            create_time = #{createTime,jdbcType=TIMESTAMP},
        </if>
        <if test="updateTime != null">
            update_time = #{updateTime,jdbcType=TIMESTAMP},
        </if>
        <if test="creatorUnid != null and creatorUnid != ''">
            creator_unid = #{creatorUnid,jdbcType=VARCHAR},
        </if>
        <if test="creatorName != null and creatorName != ''">
            creator_name = #{creatorName,jdbcType=VARCHAR},
        </if>
    </set>
    where unid = #{unid,jdbcType=BIGINT}
</update>

<!--根据unid删除-->
<delete id="deleteByUnid" parameterType="java.lang.Long">
    delete from manage_gateway_route
    where unid = #{unid,jdbcType=BIGINT}
</delete>

参考文档:

(这几篇都写的不错)
Gateway网关简介及使用:


Gateway 源码解析 :


详解动态路由的两种方式:


基于Redis实现Spring Cloud Gateway的动态管理: