使⽤⽹关对静态化微服务进⾏代理(添加在它的上游,相当于隐藏了具体微服务的信息,对外暴露的是⽹关)。
1.
右键⽗⼯程【
yx-parent
】选择【
New
】
-
【
Module
】选项,然后选择创建【
Maven
】类型项⽬(不勾选模 板),将项⽬名称设置为
,
注意这⾥不选择⽗⼯程
。
项⽬的pom.xml⽂件引⼊以下依赖。注意,Gateway不需要使⽤Web模块,使⽤的是 WebFlux(类似于Spring MVC)模块,因此不要引⼊starter-web模块,⽽引⼊的是starter-webflux模块。
<!-- Spring Boot父启动器依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 引入WebFlux -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- 日志依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Lombok工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<!-- 引入Jaxb开始 -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.10-b140310.1920</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 引入Jaxb结束 -->
<!-- Actuator可以帮助你监控和管理Spring Boot应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 链路追踪 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<!-- Spring Cloud依赖版本管理 -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!-- 打包插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
3.
如果导⼊
Maven
依赖后,提示
'parent.relativePath' of POM com.yx:yx-cloud-gateway:1.0-SNAPSHOT
问题,则 解决⽅案是在 <parent>
标签中加上
<relativePath />
标签,然后重新编译,解决问题
错误原因:
1.xxx
的
parent
⾥写的并不是
xxx
的上⼀级,⽽是继承了
Spring Boot
。
2.Maven
构建
jar
包的时候查找顺序:
relativePath
元素中的地址
->
本地仓库
->
远程仓库。
3.
<relativePath />
设定⼀个空值将始终从仓库中获取,不从本地路径获取。
.在项⽬的com.yx.gateway包下创建GatewayApplication启动类。
package com.qf.product;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //将当前的项目标记为注册中心的客户端,然后向注册信息
public class ProductApplication9001 {
public static void main(String[] args) {
SpringApplication.run(ProductApplication9001.class,args);
}
}
在项⽬的resources⽬录下创建application.yml配置⽂件并添加以下内容。
server:
port: 9300
eureka:
client:
serviceUrl: # Eureka Server的路径
defaultZone: http://YXCloudEurekaServerC:9200/eureka,http://YXCloudEurekaServerD:9201/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
spring:
application:
name: yx-cloud-gateway
# gateway⽹关配置
cloud:
gateway: # gateway⽹关配置
routes: # 配置路由
- id: service-page-router
# 动态路由:从(消费)注册中⼼获取对应服务的实例
#lb://表示从注册中心获取服务信息(//后更的是具体服务实例的具体名称)
uri: lb://yx-service-page
predicates: # 当断⾔匹配成功后,则将请求转发给某个微服务
- Path=/page/**
- id: service-product-router
uri: lb://yx-service-product
predicates:
# http://127.0.0.1:9300/product/query/1 - /query/1 - 商品微服务
- Path=/product/**
filters:
# 访问uri时,会过滤掉uri中Path取值匹配上的前⼀部分,uri中第⼆部分才是⽬标访问路径
- StripPrefix=1
⾃定义全局过滤器实现
IP
访问限制
y.filter
包下创建
BlackListGlobalFilter
全局过滤器
package com.qf.product.fifter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
/**
* 定义全局过滤器,会对所有路由⽣效
*/
@Slf4j
@Component
public class BlackListGlobalFilter implements GlobalFilter, Ordered {
// 模拟⿊名单(实际可以去数据库或者Redis中查询)
private static List<String> blackList = new ArrayList<>();
static {
// 模拟本机地址
blackList.add("127.0.0.1");
blackList.add("10.48.185.11");
}
/**
* 过滤器核⼼⽅法
*
* @param exchange 封装了request和response对象的上下⽂
* @param chain ⽹关过滤器链(包含全局过滤器和单路由过滤器)
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
/* 实现思路:获取客户端IP,判断是否在⿊名单中,在的话就拒绝访问,不在的话就放⾏ */
// 从上下⽂中取出request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 从request对象中获取客户端IP
String clientIP = request.getRemoteAddress().getHostString();
log.info("=====>IP: " + clientIP);
// 获取到客户端IP后去⿊名单中查询,存在的话就决绝访问
if (blackList.contains(clientIP)) {
// 状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
String data = "Request be denied!";
//响应的字符串转化成字节数组,将来输出返回客户端
DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());
// 决绝访问,直接返回指定结果数据
return response.writeWith(Mono.just(wrap));
}
// 合法请求,放⾏,执⾏后续的过滤器
return chain.filter(exchange);
}
/**
* 返回值表示当前过滤器的顺序(优先级),数值越⼩,优先级越⾼
*/
@Override
public int getOrder() {
return 0;
}
}