从零搭建微服务项目Base(第7章——微服务网关模块基础实现)
前言:
在前面6章的学习中已经完成了服务间的调用实现,即各微服务通过nacos或eureka服务器完成服务的注册,并从nacos中拉取配置实现热更新。当某个服务接口需要调用其他服务时,通过feign定义接口,并通过注解配置服务名称,在nacos或eureka服务器中找到对应服务端口完成调用。
但实际应用中,用户不可能直接访问这些服务端口,因为每个服务对应一个端口,当服务拆分很多时,会有大量端口,前端开发人员不可能针对每次调用看文档找对应端口,因此引入网关模块,用户只需要访问网关模块端口,网关模块自动转发,且网关模块也能实现服务聚合、负载均衡、用户鉴权等功能。为此,本章实现基础的网关模块,包括网关服务模块创建、路由断言、过滤器配置。

本章代码基于第6章项目,前置源码可在第6章博客下载,博客链接如下:
从零搭建微服务项目(第6章——Feign性能优化以及模块抽取)-CSDN博客
https://blog.csdn.net/wlf2030/article/details/145649565简要介绍前置项目流程:order-service以及user-service两服务分别连接order-db以及user-db两数据库,order-db中仅有user-id,user-info存在user-db中,为提供完整order-info,order-service通过nacos发现user-service服务地址并使用Feign调用服务端口拿取user-info结合从order-db中拿取的信息返回给前端。同时项目自定义日志输出。
本项目源码链接如下:
wlf728050719/SpringCloudBase7
https://github.com/wlf728050719/SpringCloudBase7以及本专栏会持续更新微服务项目,每一章的项目都会基于前一章项目进行功能的完善,欢迎小伙伴们关注!同时如果只是对单章感兴趣也不用从头看,只需下载前一章项目即可,每一章都会有前置项目准备部分,跟着操作就能实现上一章的最终效果,当然如果是一直跟着做可以直接跳过这一部分。

一、前置项目准备
1.从github下载前一章的项目解压,重命名为Base7打开。
![]()
2.重命名模块为Base7.

3.父工程pom.xml中<name>改成Base7。

4.选择环境为dev,并重新加载maven

5.启动nacos(安装和启动见第三章)

6.进入nacos网页 配置管理->配置列表确认有这些yaml文件。
(如果不是一直跟着专栏做自然是没有的,需要看第四章的环境隔离和配置拉取,记得把父工程pom文件中namespace的值与nacos中命名空间生成的保持一致)


7.配置数据源,更换两服务的resources下yml文件的数据库配置,数据库sql见第一章数据库准备部分。

.测试数据库连接 属性->点击数据源->测试连接->输入用户名密码



8.添加运行配置 服务->加号->运行配置类型->spring boot。

启动服务,测试接口。

能够在日志文件中看到最新的日志记录。


二、网关服务模块创建以及配置
1.新建SpringBoot模块,配置如下。

2.不添加任何依赖

3.删除不必要文件和目录,最终结构如下。

4.将gateway模块的pom文件替换为下面内容。
<?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>cn.bit</groupId><artifactId>Base7</artifactId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><artifactId>gateway</artifactId><version>0.0.1-SNAPSHOT</version><name>gateway</name><description>gateway</description><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId><version>2.2.5.RELEASE</version></dependency><!-- nacos客户端依赖包 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
4.修改父文件pom,即将gateway模块声明为父模块的子模块,重新加载maven模块。

5.重新加载maven文件后,查看maven结构是否如下,如果不是见本专栏第0章第三节部分有对应解决方法。

6.在父文件pom中为gateway在各配置环境下设置端口。

7.在gateway的application中排除默认数据源,否则需要在application中配置数据源,后续动态路由时需要使用数据库时再恢复。

8.为gateway在resources目录下创建application.yml配置文件,内容如下:
server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- Path=/user/**- id: order-serviceuri:lb://order-servicepredicates:- Path=/order/**
9.启动服务

通过在网关端口输入路径即可通过断言调取对应服务的接口。
三、路由断言

目前是通过application.yml配置路由工厂。但使用动态路由需要重写实现路由工厂类,以及使用统一的格式便于规范数据库中路由信息,即使用args+name,为方便后续章节理解,使用args+name替换gateway的application.yml,内容如下:
server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- name: Pathargs:_genkey_0: /user/**- id: order-serviceuri:lb://order-servicepredicates:- name: Pathargs:_genkey_0: /order/**
测试通过

四、路由过滤器

后续鉴权模块需要配合网关的过滤器一起搭配使用才能实现不同角色不同权限访问对应服务/端口,需要手写代码实现 AbstractGatewayFilterFactory,目前先通过yml配置文件为网关添加过滤器方便后续理解。
修改网关模块的yml文件如下:(现在的yml其实就已经很长了,后续必然需要使用代码结合数据库代替配置文件)
server:port: @gateway.port@
spring:application:name: gatewaycloud:nacos:server-addr: localhost:8848discovery:namespace: @namespace@gateway:routes:- id: user-serviceuri:lb://user-servicepredicates:- name: Pathargs:_genkey_0: /user/**filters:- name: AddRequestHeaderargs:name: sourcevalue: request user from gateway- id: order-serviceuri:lb://order-servicepredicates:- name: Pathargs:_genkey_0: /order/**filters:- name: AddRequestHeaderargs:name: sourcevalue: request order from gateway
为了获取请求头内容,对OrderController和UserController进行修改。直接替换成下面内容即可。
package cn.bit.orderservice.controller;import cn.bit.common.pojo.vo.OrderInfoVO;
import cn.bit.common.pojo.vo.R;
import cn.bit.orderservice.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("/test/{id}")public String test(@PathVariable Integer id) {System.out.println(id);return id.toString();}@GetMapping("/info/{id}")public R getOrderInfoById(@PathVariable Integer id, @RequestHeader(value = "source",required = false) String source) {log.debug("debug");log.info("info");log.warn("warning");System.out.println(source);OrderInfoVO orderInfoVO = orderService.getOrderInfoById(id);if (orderInfoVO == null) {return R.failed("订单不存在");}elsereturn R.ok(orderInfoVO);}
}
package cn.bit.userservice.controller;import cn.bit.common.pojo.dto.UserBaseInfoDTO;
import cn.bit.common.pojo.vo.R;
import cn.bit.common.pojo.vo.UserFavorVO;
import cn.bit.userservice.config.PatternProperties;
import cn.bit.userservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate PatternProperties patternProperties;@GetMapping("/test/{id}")public String test(@PathVariable Integer id) {System.out.println(id);return id.toString()+" "+LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));}@GetMapping("/favor/{id}")public R getUserFavorById(@PathVariable Integer id) {UserFavorVO vo = userService.getUserFavorById(id);if(vo != null) {return R.ok(vo);}elsereturn R.failed("用户不存在");}@GetMapping("/baseInfo/{id}")public R getUserBaseInfoById(@PathVariable Integer id, @RequestHeader(value = "source",required = false) String source) {System.out.println("get request");System.out.println(source);UserBaseInfoDTO dto = userService.getUserBaseInfoById(id);if(dto != null) {return R.ok(dto);}elsereturn R.failed("用户不存在");}
}
启动服务

先访问user接口即localhost:1233/user/baseInfo/1

能够验证确实添加了请求头

再访问order接口即localhost:1233/order/info/1

发现order-service获取到请求头,user-service为null,因为网关只对访问order-service的request添加了请求头,order-service之后使用feign访问的user-service,自然没有请求头。


为了实现调用朔源可以修改UserClient的接口方法

以及其调用

再次启动服务调用

五、全局过滤器
之前的过滤器为每个路由的过滤器,而全局过滤器无论使用哪条路由均需要使用。配置如下:
在网关模块创建filter包以及AuthorizeFilter类,内容如下:
package cn.bit.gateway.filter;import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();MultiValueMap<String, String> queryParams = request.getQueryParams();String token = queryParams.getFirst("token");if("admin".equals(token)) {return chain.filter(exchange);}exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}
}
重启后发现只有请求参数包含token字段且值为token才能访问对应服务。


六、过滤器执行顺序


最后:
黑马课程关于网关模块讲解还是比较浅显,和企业实际应用有较大出入,后续会研究动态路由实现以及鉴权模块,这两模块比较复杂所以后续更新会慢些。
相关文章:
从零搭建微服务项目Base(第7章——微服务网关模块基础实现)
前言: 在前面6章的学习中已经完成了服务间的调用实现,即各微服务通过nacos或eureka服务器完成服务的注册,并从nacos中拉取配置实现热更新。当某个服务接口需要调用其他服务时,通过feign定义接口,并通过注解配置服务名…...
pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原
pdf转换成word在线 简单好用 支持批量转换 效率高 100%还原 在数字化办公的浪潮中,文档格式转换常常让人头疼不已,尤其是 PDF 转 Word 的需求极为常见。PDF 格式虽然方便阅读和传输,但难以编辑,而 Word 格式却能灵活地进行内容修…...
嵌入式音视频开发(二)ffmpeg音视频同步
系列文章目录 嵌入式音视频开发(零)移植ffmpeg及推流测试 嵌入式音视频开发(一)ffmpeg框架及内核解析 嵌入式音视频开发(二)ffmpeg音视频同步 嵌入式音视频开发(三)直播协议及编码器…...
SpringBoot速成概括
视频:黑马程序员SpringBoot3Vue3全套视频教程,springbootvue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili 图示:...
微信小程序image组件mode属性详解
今天学习微信小程序开发的image组件,mode属性的属性值不少,一开始有点整不明白。后来从网上下载了一张图片,把每个属性都试验了一番,总算明白了。现总结归纳如下: 1.使用scaleToFill。这是mode的默认值,sc…...
Matlab写入点云数据到Rosbag
最近有需要读取一个点云并做处理后,重新写回rosbag。网上有很多读取的教程,但没有写入。自己写入时也遇到了很多麻烦,踩了一堆坑进行记录。 1. rosbag中一个lidar的msg有哪些信息? 通过如下代码,先读取一个rosbag的l…...
数据分析--数据清洗
一、数据清洗的重要性:数据质量决定分析成败 1.1 真实案例警示 电商平台事故:2019年某电商大促期间,因价格数据未清洗导致错误标价,产生3000万元损失医疗数据分析:未清洗的异常血压值(如300mmHgÿ…...
iNeuOS工业互联网操作系统,民爆远程运维平台案例
iNeuOS工业互联网操作系统,民爆远程运维平台案例 目 录 1. 概述... 2 2. iNeuOS在民爆生产厂区和北京运维中心配置... 3 1.1 生产厂区配置... 3 1.2 运维中心配置... 7 1. 概述 针对本项目进行初步调研,项目的总体需求为满足新建…...
用命令模式设计一个JSBridge用于JavaScript与Android交互通信
用命令模式设计一个JSBridge用于JavaScript与Android交互通信 在开发APP的过程中,通常会遇到Android需要与H5页面互相传递数据的情况,而Android与H5交互的容器就是WebView。 因此要想设计一个高可用的 J S B r i d g e JSBridge JSBridge,不…...
Vue 3最新组件解析与实践指南:提升开发效率的利器
目录 引言 一、Vue 3核心组件特性解析 1. Composition API与组件逻辑复用 2. 内置组件与生命周期优化 3. 新一代UI组件库推荐 二、高级组件开发技巧 1. 插件化架构设计 2. 跨层级组件通信 三、性能优化实战 1. 惰性计算与缓存策略 2. 虚拟滚动与列表优化 3. Tree S…...
计算机网络(涵盖OSI,TCP/IP,交换机,路由器,局域网)
一、网络通信基础 (一)网络通信的概念 网络通信是指终端设备之间通过计算机网络进行的信息传递与交流。它类似于现实生活中的物品传递过程:数据(物品)被封装成报文(包裹),通过网络…...
JVM-Java程序的运行环境
Java Virtual Machine Java程序的运行环境 JVM组成 程序计数器 线程私有的,内部保存的字节码的行号。用于记录正在执行的字节码指令的地址。 Java堆 线程共享的区域: 主要用来保存对象实例, 数组等, 当堆中没有内存空间可分配给实例也无法再扩展时, 则抛出OutOfMe…...
什么是网关,网关的作用是什么?网络安全零基础入门到精通实战教程!
1. 什么是网关 网关又称网间连接器、协议转换器,也就是网段(局域网、广域网)关卡,不同网段中的主机不能直接通信,需要通过关卡才能进行互访,比如IP地址为192.168.31.9(子网掩码:255.255.255.0)和192.168.7.13(子网掩码…...
makefile+LSF
LSF LSF(Load Sharing Facility)是一种常用的集群作业调度系统,bsub 命令用于提交作业到 LSF 集群,而若要关闭(终止)一个正在运行的作业,需要使用 bkill 命令,下面为你详细介绍相关…...
《千恋万花》无广版手游安卓苹果免费下载直装版
自取https://pan.xunlei.com/s/VOJS77k8NDrVawqcOerQln2lA1?pwdn6k8 《千恋万花》:柚子社的和风恋爱杰作 《千恋万花》(Senren * Banka)是由日本知名美少女游戏品牌柚子社(Yuzusoft)于2016年推出的一款和风恋爱题材…...
javaEE-14.spring MVC练习
目录 1.加法计算器 需求分析: 前端页面代码: 后端代码实现功能: 调整前端页面代码: 进行测试: 2.用户登录 需求分析: 定义接口: 1.登录数据校验接口: 2.查询登录用户接口: 前端代码: 后端代码: 调整前端代码: 测试/查错因 后端: 前端: lombok工具 1.引入依赖…...
rabbitmq五种模式的实现——springboot
rabbitmq五种模式的实现——springboot 基础知识和javase的实现形式可以看我之前的博客 代码地址:https://github.com/9lucifer/rabbitmq4j-learning 一、进行集成 (一)Spring Boot 集成 RabbitMQ 概述 Spring Boot 提供了对 RabbitMQ 的自…...
23. AI-大语言模型-DeepSeek赋能开发-Spring AI集成
文章目录 前言一、Spring AI 集成 DeepSeek1. 开发AI程序2. DeepSeek 大模型3. 集成 DeepSeek 大模型1. 接入前准备2. 引入依赖3. 工程配置4. 调用示例5. 小结 4. 集成第三方平台(已集成 DeepSeek 大模型)1. 接入前准备2. POM依赖3. 工程配置4. 调用示例…...
Educational Codeforces Round 174 (Rated for Div. 2)(ABCD)
A. Was there an Array? 翻译: 对于整数数组 ,我们将其相等特征定义为数组 ,其中,如果数组 a 的第 i 个元素等于其两个相邻元素,则 ;如果数组 a 的第 i 个元素不等于其至少一个相邻元素,则 …...
如何在本机上模拟IP地址
如何在本机上模拟IP地址 前言 在某些开发或测试场景中,我们可能需要在本机上模拟一个指定的 IP 地址,并让局域网内的其他设备能够通过该 IP 访问本机提供的服务(如 Web 服务)。 本文将详细介绍如何在 Windows 和 macOS 系统上实…...
C++二叉树:数据的“家族树”与高效检索的奥秘
C二叉树:数据的“家族树”与高效检索的奥秘 开篇小故事:图书馆的“智能目录” 想象一座古老的图书馆,藏书百万,却能在几秒内找到任意一本书。 秘密在于它的“智能目录系统”——一本巨大的家族树状手册: 每本书按主题…...
深入解析 Vue 项目中的缓存刷新机制:原理与实战
目录 前言1. Demo2. 知识拓展 前言 在 Vue 项目中,缓存通常用于存储用户信息、角色权限、系统设置等,以提高页面加载速度并减少 API 请求 这里使用 web-storage-cache 作为封装的本地存储工具,支持 localStorage 和 sessionStorage 方式存储…...
【嵌入式Linux应用开发基础】进程间通信(1):管道
目录 一、管道的基本概念 二、管道的工作原理 三、管道的类型 3.1. 匿名管道(Anonymous Pipe) 3.2. 命名管道(Named Pipe,FIFO) 四、管道的读写规则 4.1. 匿名管道的读写规则 4.2. 命名管道的读写规则 五、管…...
【DeepSeek】Mac m1电脑部署DeepSeek
一、电脑配置 个人电脑配置 二、安装ollama 简介:Ollama 是一个强大的开源框架,是一个为本地运行大型语言模型而设计的工具,它帮助用户快速在本地运行大模型,通过简单的安装指令,可以让用户执行一条命令就在本地运…...
DHCP详解,网络安全零基础入门到精通实战教程!
一、DHCP简介 DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。 DHCP前身是BOOTP&am…...
蓝桥杯篇---IAP15F2K61S2中断
文章目录 前言简介中断源1.外部中断2.定时器中断3.串口中断4.ADC中断5.PCA中断6.SPI中断7.PWM中断 中断优先级中断相关寄存器1.IE2.IP3.TCON4.SCON 中断使用步骤1.配置中断源2.使能中断3.设置优先级4.编写中断服务程序5.清除中断标志 示例代码:外部中断使用示例代码…...
【Prometheus】prometheus结合pushgateway实现脚本运行状态监控
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
立创实战派ESP32-S3烧录小智AI指南
小智 AI 聊天机器人-开源项目介绍 本项目是一个开源项目,主要用于教学目的。我们希望通过这个项目,能够帮助更多人入门 AI 硬件开发,了解如何将当下飞速发展的大语言模型应用到实际的硬件设备中。无论你是对 AI 感兴趣的学生,还是…...
深度学习的集装箱箱号OCR识别技术,识别率99.9%
集装箱箱号OCR识别技术是一项结合计算机视觉和规则校验的复杂任务,以下是其关键要点及实现思路的总结: 1、集装箱号结构:11位字符,格式为公司代码(3字母)和序列号(6数字)以及校验码(1数字)和尺寸/类型代码(可选),例如…...
使用 PyTorch 实现标准卷积神经网络(CNN)
卷积神经网络(CNN)是深度学习中的重要组成部分,广泛应用于图像处理、语音识别、视频分析等任务。在这篇博客中,我们将使用 PyTorch 实现一个标准的卷积神经网络(CNN),并介绍各个部分的作用。 什…...
