介绍:API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与 管理、静态响应处理。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

在这里插入图片描述

具体实现流程图:

在这里插入图片描述

第一步:pom新增需要包

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

第二步:application.yml文件配置

server:
   port: 9090
 eureka:
   client:
     service-url:
       defaultZone: http://admin:admin@127.0.0.1:8761/eureka/
   instance:
     prefer-ip-address: true
 spring:
   application:
     name: microservice-gateway
   redis:
     host: 192.168.0.116
     port: 6379
   profiles:
     active: dev
 management:
   endpoint:
     refresh:
       enabled: true
   endpoints:
     web:
       exposure:
         include: refresh,health,info

第三步:加载网关配置

网关配置类
import com.example.constant.GatewayEnum;
import com.example.pojo.vo.RouteVo;
import com.example.tools.RedisTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * @Author: 胡成
 * @Version: 0.0.1V
 * @Date: 2018/11/19
 * @Description: 网关路由初始化
 **/
@Slf4j
@Configuration
public class GatewayConfig {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Bean
    @RefreshScope
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        StripPrefixGatewayFilterFactory.Config config = new StripPrefixGatewayFilterFactory.Config();
        config.setParts(1);

        RouteLocatorBuilder.Builder routeLocator = builder.routes();

        List<RouteVo> lists = RedisTools.hget(stringRedisTemplate, GatewayEnum.ROUTE_LIST.getKey(),RouteVo.class);

        log.info("加载网关路由配置 --> {}",lists);

        lists.forEach(routeVo -> routeLocator.route(routeVo.getId(),
                r -> r.path(routeVo.getPath()).and().weight(routeVo.getGroup(),
                        routeVo.getWeight()).filters(f -> f.stripPrefix(1)).uri(routeVo.getUri())));

        return routeLocator.build();
    }
}

路由参数
import lombok.Data;

import java.io.Serializable;

/**
 * @Author: 胡成
 * @Version: 0.0.1V
 * @Date: 2018/11/20
 * @Description: 网关路由bean
 **/
@Data
public class RouteVo implements Serializable {

    private static final long serialVersionUID = 1L;

    /**唯一*/
    private String id;
    /**转发识别  eg:/path/**  */
    private String path;
    /**分组,如果需要双机负载均衡,就把两个路由group填写一致*/
    private String group;
    /**权重,配合分组使用,如果分组填写了,就可以调节权重0-100*/
    private Integer weight;
    /**转发目标的地址*/
    private String uri;

}
网关路由枚举
import lombok.Getter;
import lombok.Setter;

/**
 * @Author: 胡成
 * @Version: 0.0.1V
 * @Date: 2018/11/20
 * @Description: 网关路由枚举类
 **/
public enum GatewayEnum {
    /**
     * 路由枚举
     */
    ROUTE_LIST("route:list");

    @Setter
    @Getter
    private String key;

    GatewayEnum(String key) {
        this.key = key;
    }

    public static GatewayEnum get(String key) {
        for (GatewayEnum c : GatewayEnum.values()) {
            if (c.key == key) {
                return c;
            }
        }
        return null;
    }
}

第四步:修改新增路由方法

@PostMapping("saveGateway")
public String saveGateway(RouteVo routeVo) throws UnsupportedEncodingException {
    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
    routeVo.setId(uuid);
    RedisTools.hset(stringRedisTemplate, GatewayEnum.ROUTE_LIST.getKey(), uuid, JSON.toJSONString(routeVo));
    //刷新路由配置bean
    restTemplate.getForObject(http://网关服务:9090/actuator/refresh , String.class);
    return "success";
}

@PostMapping("updateGateway")
public String updateGateway(RouteVo routeVo) throws UnsupportedEncodingException {
    //判断key是否存在
    if (!RedisTools.existsHash(stringRedisTemplate, GatewayEnum.ROUTE_LIST.getKey(), routeVo.getId())) {
        log.info("网关路由key不存在直接返回");
        return "fail";
    }
    RedisTools.hset(stringRedisTemplate, GatewayEnum.ROUTE_LIST.getKey(), routeVo.getId(), JSON.toJSONString(routeVo));
    //刷新路由配置bean 
    restTemplate.getForObject(http://网关服务:9090/actuator/refresh , String.class);
    return "success";
}

第五步:修改路由或者新增路由只需要刷新customRouteLocator bean就行,请求http://网关服务:9090/actuator/refresh,新增或修改路由,操作redis数据,然后刷新路由

项目下载

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐