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

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM