一、表结构

二、导入依赖pom

我这里使用到了nacos,数据库操作使用的是jpa,如果不用的包请自行忽略或更改。

   <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

配置文件

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.254.128:8848
  application:
    name: gateway
  datasource:
    url: jdbc:mysql://localhost:3306/gateway?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root


  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

核心配置类

GatewayServiceHandler

package au.com.koalaclass.config;

import au.com.koalaclass.dao.GatewayRouteDao;
import au.com.koalaclass.entity.GatewayRouteEntity;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 *
 * 核心配置类,项目初始化加载数据库的路由配置
 *
 */
@Service
@Slf4j
public class GatewayServiceHandler implements ApplicationEventPublisherAware, CommandLineRunner {

    @Resource
    private RedisRouteDefinitionRepository routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

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

    //自己的获取数据dao
    @Resource
    private GatewayRouteDao gatewayRouteDao;
    // springboot启动后执行
    @Override
    public void run(String... args){
        this.loadRouteConfig();
    }

    public String loadRouteConfig() {
        //从数据库拿到路由配置
        List<GatewayRouteEntity> gatewayRouteList = gatewayRouteDao.findAll();

        log.info("网关配置信息:=====>"+  JSON.toJSONString(gatewayRouteList));

        gatewayRouteList.forEach(gatewayRoute -> {
            RouteDefinition definition = new RouteDefinition();

            Map<String, String> predicateParams = new HashMap<>(8);
            PredicateDefinition predicate = new PredicateDefinition();

            FilterDefinition filter = new FilterDefinition();
            Map<String, String> filterParams = new HashMap<>(8);

            URI uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();

            definition.setId(gatewayRoute.getId().toString());
            // 名称是固定的,spring gateway会根据名称找对应的PredicateFactory
            predicate.setName("Path");
            predicateParams.put("pattern",gatewayRoute.getPredicates());
            predicate.setArgs(predicateParams);

            // 名称是固定的, 路径去前缀(从前面截取一个,实际上就是截取url,后面的部分才是转发的url)
            filter.setName("StripPrefix");
            filterParams.put("_genkey_0", gatewayRoute.getFilters().toString());
            filter.setArgs(filterParams);

            definition.setPredicates(Arrays.asList(predicate));
            definition.setFilters(Arrays.asList(filter));
            definition.setUri(uri);

            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        });

        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

    public void deleteRoute(String routeId){
        routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

RedisRouteDefinitionRepository

package au.com.koalaclass.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 核心配置类,加载数据库的路由配置信息到redis
 * 将定义好的路由表信息通过此类读写到redis中
 */
@Component
@Slf4j
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {

    private Map<Object,RouteDefinition> routeDefinitionMap=new HashMap<>();

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        routeDefinitionMap.forEach((k,v) ->{
            routeDefinitions.add(v);
        });
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route
                .flatMap(routeDefinition -> {
                    log.info("routeDefinition:"+routeDefinition);
                    routeDefinitionMap.put(routeDefinition.getId(),routeDefinition);
                    return Mono.empty();
                });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            if (routeDefinitionMap.containsKey(id)) {
                routeDefinitionMap.remove(id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(new NotFoundException("路由文件没有找到: " + routeId)));
        });
    }
}

实体类GatewayRouteEntity

package au.com.koalaclass.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;

import javax.persistence.*;
import java.util.Date;

/**
 * 实体
 */
@Table(name = "gateway_route")
@Entity
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class GatewayRouteEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", columnDefinition = "int(11)")
    private Long id;

    @Column(name = "service_id")
    private String serviceId;

    @Column(name = "uri")
    private String uri;

    @Column(name = "predicates")
    private String predicates;

    @Column(name = "filters")
    private String filters;

    @Column(name = "order_")
    private String order;

    @Column(name = "creator_id")
    private String creatorId;

    @Column(name = "create_date")
    private Date createDate;

    @Column(name = "update_Id")
    private String updateId;

    @Column(name = "update_date")
    private Date updateDate;

    @Column(name = "remarks")
    private String remarks;

    @Column(name = "del_flag")
    private String delFlag;


}

Dao层

package au.com.koalaclass.dao;


import au.com.koalaclass.entity.GatewayRouteEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GatewayRouteDao extends JpaRepository<GatewayRouteEntity, Long> {
}

controller层

package au.com.koalaclass.controller;

import au.com.koalaclass.config.GatewayServiceHandler;
import au.com.koalaclass.dao.GatewayRouteDao;
import au.com.koalaclass.entity.GatewayRouteEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Superlu
 * @version 1.0.0
 * @ClassName RouteController
 * @Description TODO
 * @createTime 2021/11/15 11:18
 */
@RestController
@RequestMapping("/router")
public class RouteController {

    @Resource
    private GatewayServiceHandler gatewayServiceHandler;

    @Resource
    private GatewayRouteDao gatewayDao;

    @GetMapping("/refresh")
    public String refresh(){
        return gatewayServiceHandler.loadRouteConfig();
    }
    @GetMapping("/findAll")
    public List<GatewayRouteEntity> findAll(){
        return gatewayDao.findAll();
    }

    @PostMapping("/add")
    public GatewayRouteEntity add(@RequestBody GatewayRouteEntity gateway){
        GatewayRouteEntity save = gatewayDao.save(gateway);
        gatewayServiceHandler.loadRouteConfig();
        return save;
    }
}

请求示例

访问localhost/api-taobao
在这里插入图片描述

参考连接

动态路由实现参考博客https://blog.csdn.net/qq_42714869/article/details/92794911?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

动态路由实现参考代码
https://gitee.com/evoup/sb_cloud_gateway

这里没有使用redis。若要使用redis请参考以上内容

本文代码示例:https://gitee.com/luzhiyong_erfou/gateway-dynamic-routing
仓库代码根据业务略有修改。如有出入请自行根据自己业务修改。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐