springboot gateway 动态路由-01

SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty

 项目结构:

  • pom.xml
<?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.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.youxiu326</groupId>
    <artifactId>sb_gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sb_gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.7</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.53</version>
        </dependency>

        <!-- springcloud gateway网关依赖 start-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-gateway-webflux</artifactId>
        </dependency>
        <!-- springcloud gateway网关依赖 end-->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>

            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
            </plugin>
        </plugins>
    </build>

</project>
  • yml
spring:
  datasource:
    password: zz123456.ZZ
    url: jdbc:mysql://youxiu326.xin:3306/super_man?useUnicode=true&characterEncoding=utf8
    username: youxiu326
  redis:
    host: youxiu326.xin
  freemarker:
    settings:
      classic_compatible: true
      datetime_format: yyyy-MM-dd HH:mm:ss
      number_format: '#.##'
      template_exception_handler: debug
    suffix: .html

server:
  port: 8080

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:/mapper/*.xml

  

  

  • 定义gateway实体类
package com.youxiu326.gateway.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Gateway的路由定义模型
 *
 */
public class GatewayRouteDefinition {

    /**
     * 路由的Id
     */
    private String id;

    /**
     * 路由断言集合配置
     */
    private List<GatewayPredicateDefinition> predicates = new ArrayList<>();

    /**
     * 路由过滤器集合配置
     */
    private List<GatewayFilterDefinition> filters = new ArrayList<>();

    /**
     * 路由规则转发的目标uri
     */
    private String uri;

    /**
     * 路由执行的顺序
     */
    private int order = 0;

    /**
     * 断言集合json字符串
     */
    private String predicatesJson;

    /**
     * 路由过滤器json字符串
     */
    private String filtersJson;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<GatewayPredicateDefinition> getPredicates() {
        return predicates;
    }

    public void setPredicates(List<GatewayPredicateDefinition> predicates) {
        this.predicates = predicates;
    }

    public List<GatewayFilterDefinition> getFilters() {
        return filters;
    }

    public void setFilters(List<GatewayFilterDefinition> filters) {
        this.filters = filters;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public String getPredicatesJson() {
        return predicatesJson;
    }

    public void setPredicatesJson(String predicatesJson) {
        this.predicatesJson = predicatesJson == null ? null : predicatesJson.trim();
    }

    public String getFiltersJson() {
        return filtersJson;
    }

    public void setFiltersJson(String filtersJson) {
        this.filtersJson = filtersJson == null ? null : filtersJson.trim();
    }
}
GatewayRouteDefinition.java
package com.youxiu326.gateway.model;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 路由断言定义模型
 */
public class GatewayPredicateDefinition {

    /**
     * 断言对应的Name
     */
    private String name;

    /**
     * 配置的断言规则
     */
    private Map<String, String> args = new LinkedHashMap<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<String, String> getArgs() {
        return args;
    }

    public void setArgs(Map<String, String> args) {
        this.args = args;
    }

}
GatewayPredicateDefinition.java
package com.youxiu326.gateway.model;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 过滤器定义模型
 */
public class GatewayFilterDefinition {

    /**
     * Filter Name
     */
    private String name;

    /**
     * 对应的路由规则
     */
    private Map<String, String> args = new LinkedHashMap<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<String, String> getArgs() {
        return args;
    }

    public void setArgs(Map<String, String> args) {
        this.args = args;
    }

}
GatewayFilterDefinition.java
实体类设计,其实就是为了和原生路由对象对应

public class RouteDefinition {
@NotEmpty
private String id = UUID.randomUUID().toString();
@NotEmpty
@Valid
private List<PredicateDefinition> predicates = new ArrayList();
@Valid
private List<FilterDefinition> filters = new ArrayList();
@NotNull
private URI uri;
private int order = 0;
}
  • 实体类增删改查 dao service
package com.youxiu326.gateway.dao;

import com.youxiu326.gateway.model.GatewayRouteDefinition;

import java.util.List;

public interface GatewayRouteDefinitionMapper {
    int deleteByPrimaryKey(String id);

    int insert(GatewayRouteDefinition record);

    int insertSelective(GatewayRouteDefinition record);

    GatewayRouteDefinition selectByPrimaryKey(String id);

    int updateByPrimaryKeySelective(GatewayRouteDefinition record);

    int updateByPrimaryKey(GatewayRouteDefinition record);

    List<GatewayRouteDefinition> queryAllRoutes();
}
GatewayRouteDefinitionMapper.java
<?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.youxiu326.gateway.dao.GatewayRouteDefinitionMapper" >
  <resultMap id="BaseResultMap" type="com.youxiu326.gateway.model.GatewayRouteDefinition" >
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="uri" property="uri" jdbcType="VARCHAR" />
    <result column="order_" property="order" jdbcType="INTEGER" />
    <result column="predicates_json" property="predicatesJson" jdbcType="VARCHAR" />
    <result column="filters_json" property="filtersJson" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, uri, order_, predicates_json, filters_json
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from gateway_route_definition
    where id = #{id,jdbcType=VARCHAR}
  </select>

  <select id="queryAllRoutes" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from gateway_route_definition order by order_
  </select>

  <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
    delete from gateway_route_definition
    where id = #{id,jdbcType=VARCHAR}
  </delete>
  <insert id="insert" parameterType="com.youxiu326.gateway.model.GatewayRouteDefinition" >
    insert into gateway_route_definition (id, uri, order_,
      predicates_json, filters_json)
    values (#{id,jdbcType=VARCHAR}, #{uri,jdbcType=VARCHAR}, #{order,jdbcType=INTEGER}, 
      #{predicatesJson,jdbcType=VARCHAR}, #{filtersJson,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.youxiu326.gateway.model.GatewayRouteDefinition" >
    insert into gateway_route_definition
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="uri != null" >
        uri,
      </if>
      <if test="order != null" >
        order_,
      </if>
      <if test="predicatesJson != null" >
        predicates_json,
      </if>
      <if test="filtersJson != null" >
        filters_json,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=VARCHAR},
      </if>
      <if test="uri != null" >
        #{uri,jdbcType=VARCHAR},
      </if>
      <if test="order != null" >
        #{order,jdbcType=INTEGER},
      </if>
      <if test="predicatesJson != null" >
        #{predicatesJson,jdbcType=VARCHAR},
      </if>
      <if test="filtersJson != null" >
        #{filtersJson,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.youxiu326.gateway.model.GatewayRouteDefinition" >
    update gateway_route_definition
    <set >
      <if test="uri != null" >
        uri = #{uri,jdbcType=VARCHAR},
      </if>
      <if test="order != null" >
        order_ = #{order,jdbcType=INTEGER},
      </if>
      <if test="predicatesJson != null" >
        predicates_json = #{predicatesJson,jdbcType=VARCHAR},
      </if>
      <if test="filtersJson != null" >
        filters_json = #{filtersJson,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=VARCHAR}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.youxiu326.gateway.model.GatewayRouteDefinition" >
    update gateway_route_definition
    set uri = #{uri,jdbcType=VARCHAR},
      order_ = #{order,jdbcType=INTEGER},
      predicates_json = #{predicatesJson,jdbcType=VARCHAR},
      filters_json = #{filtersJson,jdbcType=VARCHAR}
    where id = #{id,jdbcType=VARCHAR}
  </update>
</mapper>
GatewayRouteDefinitionMapper.xml
package com.youxiu326.gateway.service;

import com.youxiu326.gateway.model.GatewayRouteDefinition;

import java.util.List;

public interface GatewayRouteService{

    public Integer add(GatewayRouteDefinition gatewayRouteDefinition);

    public Integer update(GatewayRouteDefinition gatewayRouteDefinition);

    public Integer delete(String id);

    public List<GatewayRouteDefinition> queryAllRoutes();

}
GatewayRouteService.java
package com.youxiu326.gateway.service.impl;

import com.youxiu326.gateway.dao.GatewayRouteDefinitionMapper;
import com.youxiu326.gateway.model.GatewayRouteDefinition;
import com.youxiu326.gateway.service.GatewayRouteService;
import com.youxiu326.gateway.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 *  自定义service层,增、删、改、查数据库路由配置信息
 */
@Service
public class GatewayRouteServiceImpl implements GatewayRouteService {

    @Autowired
    private GatewayRouteDefinitionMapper gatewayRouteMapper;

    public Integer add(GatewayRouteDefinition gatewayRouteDefinition) {

        if (!gatewayRouteDefinition.getPredicates().isEmpty())
            gatewayRouteDefinition.setPredicatesJson(
                    JsonUtils.parseString(gatewayRouteDefinition.getPredicates()));

        if (!gatewayRouteDefinition.getFilters().isEmpty())
            gatewayRouteDefinition.setFiltersJson(
                    JsonUtils.parseString(gatewayRouteDefinition.getFilters()));

//        if (gatewayRouteDefinition.getId()!=null)
//            return gatewayRouteMapper.updateByPrimaryKeySelective(gatewayRouteDefinition);

        return gatewayRouteMapper.insertSelective(gatewayRouteDefinition);
    }

    public Integer update(GatewayRouteDefinition gatewayRouteDefinition) {

        if (!gatewayRouteDefinition.getPredicates().isEmpty())
            gatewayRouteDefinition.setPredicatesJson(
                    JsonUtils.parseString(gatewayRouteDefinition.getPredicates()));

        if (!gatewayRouteDefinition.getFilters().isEmpty())
            gatewayRouteDefinition.setFiltersJson(
                    JsonUtils.parseString(gatewayRouteDefinition.getFilters()));

        return gatewayRouteMapper.updateByPrimaryKeySelective(gatewayRouteDefinition);
    }

    public Integer delete(String id) {
        return gatewayRouteMapper.deleteByPrimaryKey(id);
    }

    public List<GatewayRouteDefinition> queryAllRoutes(){
        return gatewayRouteMapper.queryAllRoutes();
    }

}
GatewayRouteServiceImpl.java
  • 一个配置类(解决redis乱码) , 一个工具类(json转对象)
package com.youxiu326.gateway.utils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;

public class JsonUtils {
    
    private static Logger log = LoggerFactory.getLogger(JsonUtils.class);
    private static JsonFactory jsonfactory = new JsonFactory(); 
    private static ObjectMapper mapper = new ObjectMapper(jsonfactory);
    
    public static <T> T parseObject(String json,Class<T> clzz) {
        //设置JSON时间格式    
        SimpleDateFormat myDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   
        mapper.setDateFormat(myDateFormat);
        try {
            return mapper.readValue(json, clzz);
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
        return null;
    }
    
    /**
     * json转map
     * 
     * @param json
     * @return
     */
    public static Map<String,Object> parseMap(String json){
        TypeReference<HashMap<String,Object>> typeRef = new TypeReference<HashMap<String,Object>>() {}; 
        try {
            return mapper.readValue(json, typeRef);
        } catch (JsonParseException e) {
            log.error("字符串转json出错!"+json, e);
        } catch (JsonMappingException e) {
            log.error("json映射map出错!"+json, e);
        } catch (IOException e) {
            log.error("json转map流错误!"+json, e);
        }
        return null;
    }
    
    
    public static <T> List<T> parseList(String json,Class<?> clazz){
        TypeFactory t = TypeFactory.defaultInstance(); 
        try {
            List<T> list = mapper.readValue(json,t.constructCollectionType(ArrayList.class,clazz));
            return list;
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 对像转json字符串
     * 
     * @param obj
     * @return
     */
    public static String parseString(Object obj){
        String result = null;
        try {
            SimpleDateFormat myDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   
            mapper.setDateFormat(myDateFormat);
            result = mapper.writeValueAsString(obj);
        } catch (JsonParseException e) {
            log.error("字符串转json出错!", e);
        } catch (JsonMappingException e) {
            log.error("json映射map出错!", e);
        } catch (IOException e) {
            log.error("json转map流错误!", e);
        }
        return result;
    }
}
JsonUtils.java
package com.youxiu326.gateway.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.PostConstruct;


/**
 * 防止redis  中文乱码
 */
@Configuration
public class RedisConfig {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @PostConstruct
    public void initRedisTemplate() {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
    }

}
RedisConfig.java

以下是核心代码,自定义路由关键代码:

1.实现了RouteDefinitionRepository接口的RedisRouteDefinitionRepository扩展类,我们可以通过它来新增路由,删除路由。

即调用它的save方法与delete方法

2.实现了CommandLineRunner接口后可通过run方法在项目启动后调用loadRouteConfig()方法从而实现从数据库中加载路由

3.实现了ApplicationEventPublisherAware接口获得了ApplicationEventPublisher对象,通过它可发送更新路由的事件,从而实现刷新路由

// 发送更新路由事件
this.publisher.publishEvent(new RefreshRoutesEvent(this));
package com.youxiu326.gateway.configuration;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * Spring Cloud Gateway 扩展接口RouteDefinitionRepository,实现该接口实现自定义路由
 *
 *  重写以下三个方法
 *  Flux<RouteDefinition> getRouteDefinitions();
 *  Mono<Void> save(Mono<RouteDefinition> route);
 *  Mono<Void> delete(Mono<String> routeId);
 *
 *
 * 核心配置类,加载数据库的路由配置信息到redis,将定义好的路由表信息通过此类读写到redis中
 */
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {

    public static final String GATEWAY_ROUTES = "youxiu326:gateway";

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = new ArrayList<>();
        redisTemplate.opsForHash().values(GATEWAY_ROUTES).stream().forEach(routeDefinition -> {
            routeDefinitions.add(JSON.parseObject(routeDefinition.toString(), RouteDefinition.class));
        });
        return Flux.fromIterable(routeDefinitions);
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route
                .flatMap(routeDefinition -> {
                    redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),
                            JSON.toJSONString(routeDefinition));
                    return Mono.empty();
                });
    }

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

  

package com.youxiu326.gateway.configuration;

import com.alibaba.fastjson.JSON;
import com.youxiu326.gateway.dao.GatewayRouteDefinitionMapper;
import com.youxiu326.gateway.model.GatewayFilterDefinition;
import com.youxiu326.gateway.model.GatewayPredicateDefinition;
import com.youxiu326.gateway.model.GatewayRouteDefinition;
import com.youxiu326.gateway.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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 java.net.URI;
import java.util.*;


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

    private final static Logger log = LoggerFactory.getLogger(GatewayServiceHandler.class);

    @Autowired
    private RedisRouteDefinitionRepository routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

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

    // 获取数据dao
    @Autowired
    private GatewayRouteDefinitionMapper gatewayRouteMapper;

    // springboot启动后执行
    @Override
    public void run(String... args){
        this.loadRouteConfig();
    }

    /**
     * 更新路由
     * @return
     */
    public String loadRouteConfig() {

        //从数据库拿到路由配置
        List<GatewayRouteDefinition> gatewayRouteList = gatewayRouteMapper.queryAllRoutes();

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

        gatewayRouteList.forEach(gatewayRoute -> {

            // 创建路由对象
            RouteDefinition definition = new RouteDefinition();

            definition.setId(gatewayRoute.getId());

            // 设置路由执行顺序
            definition.setOrder(gatewayRoute.getOrder());

            // 设置路由规则转发的目标uri
            URI uri = UriComponentsBuilder.fromHttpUrl(gatewayRoute.getUri()).build().toUri();
            definition.setUri(uri);


            // 设置路由断言
            String predicatesJson = gatewayRoute.getPredicatesJson();
            List<PredicateDefinition> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(predicatesJson)){
                List<GatewayPredicateDefinition> predicateDefinitions = JsonUtils.parseList(predicatesJson, GatewayPredicateDefinition.class);
                predicateDefinitions.stream().forEach(it->{
                    PredicateDefinition p = new PredicateDefinition();
                    p.setName(it.getName());
                    p.setArgs(it.getArgs());
                    predicates.add(p);
                });
            }
            definition.setPredicates(predicates);

            // 设置过滤器
            String filtersJson = gatewayRoute.getFiltersJson();
            List<FilterDefinition> filters = new ArrayList<>();
            if (StringUtils.isNotBlank(filtersJson)){
                List<GatewayFilterDefinition> filterDefinitions = JsonUtils.parseList(filtersJson, GatewayFilterDefinition.class);
                filterDefinitions.stream().forEach(it->{
                    FilterDefinition f = new FilterDefinition();
                    f.setName(it.getName());
                    f.setArgs(it.getArgs());
                    filters.add(f);
                });
            }
            definition.setFilters(filters);

            // 保存路由
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        });

        // 发送更新路由事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }


    /**
     * 删除路由
     * @param routeId
     */
    public void deleteRoute(String routeId){
        routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();

        // 发送更新路由事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }
}

  

  • Controller
package com.youxiu326.gateway.controller;

import com.youxiu326.gateway.configuration.GatewayServiceHandler;
import com.youxiu326.gateway.model.GatewayRouteDefinition;
import com.youxiu326.gateway.service.GatewayRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;


/**
 *  1.直接在数据库添加路由配置信息,手动刷新,使配置信息立即生效;
 *
 *  2.前端页面增、删、改路由配置信息,并使配置信息立即生效;
 *
 */
@RestController
@RequestMapping("/route")
public class RouteController {

    @Autowired
    private GatewayServiceHandler gatewayServiceHandler;

    @Autowired
    private GatewayRouteService gatewayRouteService;

    /**
     * 刷新路由配置
     * @return
     */
    @GetMapping("/refresh")
    public String refresh() throws Exception {
        return this.gatewayServiceHandler.loadRouteConfig();
    }

    /**
     * 增加路由记录
     *
     * @return
     */
    @PostMapping("/add")
    public String add(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) throws Exception {
        gatewayRouteService.add(gatewayRouteDefinition);
        // 刷新路由
        gatewayServiceHandler.loadRouteConfig();
        return "success";
    }

    @PostMapping("/update")
    public String update(@RequestBody GatewayRouteDefinition gatewayRouteDefinition) throws Exception {
        gatewayRouteService.update(gatewayRouteDefinition);
        // 刷新路由
        gatewayServiceHandler.loadRouteConfig();
        return "success";
    }

    @GetMapping("/delete/{id}")
    public String delete(@PathVariable String id) throws Exception {
        gatewayRouteService.delete(id);
        // 删除路由并刷新路由
        gatewayServiceHandler.deleteRoute(id);
        return "success";
    }

    @GetMapping("/routes")
    public List<GatewayRouteDefinition> routes() throws Exception {
        return gatewayRouteService.queryAllRoutes();
    }

}

  

新增路由对象:

访问 http://localhost:8080/pinduoduo 可以看见跳转到了官网

代码地址:https://github.com/youxiu326/sb_gateway

原文地址:https://www.cnblogs.com/youxiu326/p/cloud_gateway.html