学透Spring Boot — 013. Spring Web-Flux 函数式风格的控制器
这是我的学透Spring Boot的第13篇文章,更多文章请移步我的专栏
学透 Spring Boot_postnull咖啡的博客-CSDN博客
目录
传统风格的Spring MVC
函数式编程风格的Spring MVC
引入WebFlux依赖
定义Handler类
定义Router类
WebFlux不生效
灵魂拷问
Spring Web MVC框架,简称Spring MVC,是一种MVC的Web框架
- model:模型
- view:视图
- controller:控制器
传统风格的Spring MVC
一般情况,我们都是通过@Controller或者@RestController标注一个类,用来绑定进来的HTTP请求。方法中使用@RequestMapping注解来映射HTTP请求。
@RestController
@RequestMapping("/test")
public class TestUserController {private final TypiUserRestService typiUserRestService;public TestUserController(TypiUserRestService typiUserRestService) {this.typiUserRestService = typiUserRestService;}@GetMapping("/user/{id}")public TypiUser getById(@PathVariable Integer id) {return typiUserRestService.getUser(id);}
}
http://localhost:8080/test/user/1
函数式编程风格的Spring MVC
上面的传统风格的好处是简单,我们把业务代码和路由配置都写在一个类里面。我们也可以把它们分离开。
引入WebFlux依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
特别注意,如果我们项目中已经引入Spring-web,webflux会被自动忽略!!!
所以我们需要去掉pom.xml中spring-boot-starter-web
定义Handler类
类似于Controller,只是这里没有HTTP的绑定和路径的映射
@Component
public class MyUserHandler {final private TypiUserRestService typiUserRestService;public MyUserHandler(TypiUserRestService typiUserRestService) {this.typiUserRestService = typiUserRestService;}public Mono<ServerResponse> getUser(ServerRequest request){TypiUser user = typiUserRestService.getUser(Integer.valueOf(request.pathVariable("id")));return ServerResponse.ok().bodyValue(user);}
}
定义Router类
然后我们定义路由,再路由中绑定HTTP请求和handler
@Configuration
public class MyRoutingConfiguration {private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);@Beanpublic RouterFunction<ServerResponse> routerFunction(MyUserHandler myUserHandler) {return route().GET("/testabc/user/{id}", ACCEPT_JSON, myUserHandler::getUser).build();}
}
说明:
- 路由通过 RouterFunctions.route() 构建,不再使用注解。
- 请求处理逻辑集中在 Handler 类中,实现更清晰的职责划分。
- 处理方法返回的是 Mono<ServerResponse>,这是 WebFlux 的响应式风格。
WebFlux不生效
用了函数式路由后,启动项目,但是访问一直提示404 怎么回事呢
原来是因为WebFlux和Web冲突了,如果项目中同时存在两种环境(Spring MVC和Spring WebFlux),则会优先使用Spring MVC。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
我们来一探究竟。
毫无疑问,肯定是Spring Boot的自动配置搞的鬼。
我们在自动配置的包下,找到自动配置类
看看自动配置类的
@AutoConfiguration(after = { ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,ReactiveMultipartAutoConfiguration.class, ValidationAutoConfiguration.class,WebSessionIdResolverAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@ImportRuntimeHints(WebResourcesRuntimeHints.class)
public class WebFluxAutoConfiguration {
我们来看看其中一个生效条件
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
仅当应用是响应式 Web 应用时才生效(判断条件是有没有 WebFlux 类、是否排除了 Servlet 环境等)
如果你用了 spring-boot-starter-web 就不会满足这个条件 → 不生效
我们可以把debug日志打开 application.properties
debug=true
启动应用后,我们可以看到配置类的情况
Did not match: 告诉我们Spring Boot 判断我们的项目不是一个响应式 Web 应用(WebFlux),所以它 没有启用 WebFluxAutoConfiguration 自动配置类。
Matched是告诉我们,找到了WebFlux的类,因为我们的pom中引入了依赖!
是不是WebFlux环境,我们可以看这个类
可以看到是一个Servlet容器
综上所述,我们引入了Web-flux就需要移除Spring MVC
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
灵魂拷问
Spring MVC提供的Controller模式,已经非常简便了,大部分开发也是熟知这种模式,那为什么还要搞另外一套呢?
一句话,Router和Handler分离,可以实现更灵活的控制。
有时候,像Spring Cloud Gateway 一样,只是做简单的转发
.route(POST("/api/merge"), handler::mergeApis)
.route(GET("/health"), handler::probe)
另外,Handler和Router分离后,类的职责更单一了。
所以,我们也不是非要用函数式路由,对大部分场景,直接使用注解路由更简单!
相关文章:
学透Spring Boot — 013. Spring Web-Flux 函数式风格的控制器
这是我的学透Spring Boot的第13篇文章,更多文章请移步我的专栏 学透 Spring Boot_postnull咖啡的博客-CSDN博客 目录 传统风格的Spring MVC 函数式编程风格的Spring MVC 引入WebFlux依赖 定义Handler类 定义Router类 WebFlux不生效 灵魂拷问 Spring Web MVC…...
L33.【LeetCode题解】快乐数(双指针思想)
目录 1.题目 2.分析 3.代码 4.提交结果 5.题外话 证明:一定是循环的 前置知识:鸽巢原理 不严格证明 1.题目 https://leetcode.cn/problems/happy-number/ 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将…...
gltf unity-Unity中Gltf模型的使用与优化技巧
在现代游戏开发和3D应用领域,高质量模型是提升用户体验的关键因素之一。GLTF(GL Transmission Format)作为一款开放标准的3D模型交换格式,已经被越来越多的开发者所认可。Unity引擎,作为全球领先的3D游戏开发平台&…...
Oracle数据库指南
目录 一、前言 二、Oracle数据库基础入门篇 1. Oracle体系结构概述 2. 安装与配置 3. SQL语言入门 三、PL/SQL编程与高级特性 1. PL/SQL基础语法 2. 触发器与任务调度 3. 高级特性 四、日常维护与监控 1. 备份与恢复策略 2. 日志管理与故障排查 3. 自动化运维 五…...
Qt -信号与槽
博客主页:【夜泉_ly】 本文专栏:【暂无】 欢迎点赞👍收藏⭐关注❤️ 目录 前言引入connect调用链模板类型的connectQObject::connectImplQObjectPrivate::connectImpl qobject_p_p.hconnect作用总结ai对信号与槽的模拟实现 前言 面向对象&am…...
macos 魔搭 模型下载 Wan-AI ComfyUI
环境安装 ➜ ~ sw_vers ProductName: macOS ProductVersion: 15.3.2 ➜ ~ pip --version pip 24.3.1 from /opt/homebrew/lib/python3.11/site-packages/pip (python 3.11)安装ModelScope SDK pip install modelscope➜ ~ modelscope download --help Traceback (most r…...
Xshell Plus 6下载与安装
文章目录 Xshell Plus 6 简介(一)网络连接与协议支持(二)会话管理(三)安全特性(四)文件传输功能(因集成Xftp 6 )(五)个性化与便捷功能…...
Kubernetes 集群搭建(一):从环境准备到 Calico 网络插件部署
(一)虚拟环境准备 名称ip备注m1192.168.101.131mastern1192.168.101.132workern2192.168.101.133worker (二)集群统一配置 2.1 关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld sed -i s/enforcin…...
【国产突围!致远电子ZXDoc如何打破Vector垄断,成为新能源车研发“神器”?】
摘要:在汽车“新四化”浪潮下,国产汽车总线工具链软件正迎来高光时刻!广州致远电子推出的ZXDoc以全栈自主化技术硬核国产芯片生态,斩获2024金辑奖“最佳技术实践应用奖”,成为新能源车企研发工程师的“效率倍增器”。本…...
3-Visual Studio 2022打包NET开发项目为安装包
引言 本文将上一期博文>>>门店管理系统开发<<<开发的项目打包为Windows安装包 一,安装扩展 安装此扩展:installer Projects 二,创建安装程序项目 创建项目 右键解决方案-添加-新建项目 选择setup Project项目 填写项目名…...
Cookie、Session、Token、JWT的区别和使用场景
Cookie、Session和Token的区别 存储位置数据容量安全性生命周期性能Cookie客户端(通常是浏览器)4KB、Cookie数量也有限制不安全、XSS(跨站脚本攻击)、CSRF(跨站请求伪造)可以设置过期时间,过期后…...
P1883 【模板】三分 | 函数
题目描述 给定 n 个二次函数 f1(x),f2(x),…,fn(x)(均形如 ax2bxc),设 F(x)max{f1(x),f2(x),...,fn(x)},求 F(x) 在区间 [0,1000] 上的最小值。 输入格式 输入第一行为正整数 T,表示有 T 组数据。 每组…...
Ruoyi-vue plus 5.2.2 flowble设计流程点击开始流程图错误
网关设置条件或者是事件删除后出现,点击网关节点无法找到下面的事件节点。 配置页面事件错误,点背景配置进去了事件,发现再次加载,或者删除的时候VUE页面无法加载。 解决方式:查看XML文件,这个节点是否存在…...
MySQL学习笔记(三)——图形化界面工具DataGrip
目录 1. 图形化界面工具 2.下载 3. 安装 3.1 安装步骤 3.2 激活说明 4. 使用 4.1 汉化教程 4.2 使用 1. 图形化界面工具 上述,我们已经讲解了通过 DDL 语句,如何操作数据库、操作表、操作表中的字段,而通过 DDL 语句执行在命令进行操…...
keil软件仿真
设置 选择软件仿真。 修改参数。 获取参数 找到自己的芯片信号。这里用的是F103ZET6 复制下来,并对其进行修改。 接下来进入仿真即可...
每日一题(小白)模拟娱乐篇14
直接理解题意,一分钟扩散一次,那么2020分钟也就是需要循环2020次,然后加入扩散后的条件,每一个次扩散使方格子的总量1(只要有一个点扩散就无需看其他的点),若干次循环过后总数之和即所有黑色格子…...
(二)使用Android Studio开发基于Java+xml的安卓app之环境搭建
以下是使用Android Studio搭建基于Java和XML的Android应用开发环境的详细步骤: 一、系统要求 操作系统:Windows 7/8/10/11(64位)内存:建议8GB及以上磁盘空间:至少5GB空闲(建议预留10GB以上&…...
STM32定时器通道1-4(CH1-CH4)的引脚映射关系
以下是 STM32定时器通道1-4(CH1-CH4)的引脚映射关系的详细说明,以常见型号为例。由于不同系列/型号差异较大,请务必结合具体芯片的参考手册确认。 一、STM32F1系列(如STM32F103C8T6) 1. TIM1(高级定时器) 通道默认引脚重映射引脚(部分/完全)备注CH1PA8无互补输出CH1…...
看爬山虎学本领 软爬机器人来创新 各种场景能适应
*本文只做阅读笔记分享* 一、灵感来源:向植物取经 大家好!今天来聊一款超酷的软爬机器人,它的灵感来自会攀爬的植物——爬山虎。 大家都知道,爬墙高手爬山虎能在各种复杂墙面轻松生长攀爬,可现有的攀爬机器人在复杂…...
Spring AI Alibaba示例项目深度解析:dashscope-audio子模块详解
Spring AI Alibaba示例项目深度解析:dashscope-audio子模块详解 一、模块定位与核心价值 1.1 功能定位 • 音频处理核心组件:基于阿里云DashScope平台实现STT(语音识别)和TTS(文生语音)双模态能力 • 企业级解决方案:提供同步/异步/流式三种调用范式,适配不同业务场景…...
Linux 下 日志系统搭建全攻略
目录 一、引言 二、日志系统基础 日志级别 日志输出格式 三、创建日志所需函数 认识可变参数 编辑 获取时间的函数 小结 四、创建日志 一、引言 在 Linux 环境中开发 C/C 程序时,日志系统是不可或缺的一部分。它不仅有助于调试程序、排查问题ÿ…...
前端布局难题:父元素padding导致子元素无法全屏?3种解决方案
大家好,我是一诺。今天要跟大家分享一个我在实际项目中经常用到的CSS技巧——如何让子元素突破父元素的padding限制,实现真正的全屏宽度效果。 为什么会有这个需求? 记得我刚入行的时候,接到一个需求:要在内容区插入…...
写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码?
VB.NET 写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码? 分享 1. 在 VB.NET 中指定运行 Sub Main 在 VB.NET 里,你能够指定 Sub Main 作为程序的入口点。下面为你介绍两种实现方式: 方式一:在项目属性…...
蓝桥杯单片机频率
long int Freq; unsigned int Timer_1000Ms; 加上 TMOD | 0x05; void Timer0Init(void) //0毫秒12.000MHz {AUXR & 0x7F; //定时器时钟12T模式TMOD & 0xF0; //设置定时器模式TMOD | 0x05;TL0 0x00; //设置定时初值TH0 0x00; //设置定时初值TF0 0; //清除TF0标…...
word导出PDF老是目录格式变化的问题
这里是写给和我一样的笨蛋的经验帖,适合试了很多网上的经验,结果都用不成的傻瓜蛋,先说好,我是傻瓜蛋,我不是在攻击谁,我们只是客观的,缺根弦罢了。 这些帖子里讲的最多的应该是:“…...
P1577 切绳子(二分)
题目描述 有 N 条绳子,它们的长度分别为 Li。如果从它们中切割出 K 条长度相同的绳子,这 K 条绳子每条最长能有多长?答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。 输入格式 第一行两个整数 N 和 K,接下来 N 行…...
高级:分布式系统面试题精讲
一、引言 分布式系统在现代软件开发中占据重要地位,其设计和实现需要考虑多个关键因素。面试官通过相关问题,考察候选人对分布式系统核心概念的理解、实际应用能力以及在复杂场景下的问题解决能力。本文将深入分析分布式系统的CAP定理、一致性协议、分布…...
【速写】SFT案例实操(以Qwen2.5-instruct-0.5B)
参考资料: https://openbayes.com/console/bbruceyuan/containers/OPg9Oo99ET6https://www.bilibili.com/video/BV1NM1tY3Eu5 LoRA微调案例 首先还是要安装: !pip install -q accelerate peft bitsandbytes transformers sentencepiece !pip install…...
springboot457-库存管理系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
Node.js中间件的分类
目录 Node.js 中间件的分类与详细介绍 1. 目录结构 2. Express 中间件的主要分类 3. 代码实现 1. 应用级中间件(作用于整个应用) 示例:日志记录中间件 2. 路由级中间件(仅作用于特定路由) 示例:身份…...
棒球规则快速入门·棒球1号位
棒球规则快速入门: 得分方式 进攻方击球后,依次跑过一、二、三垒并返回本垒得1分。若击球直接飞出外场围栏(全垒打),击球员和已上垒的跑垒员均可得分。 比赛结构 共9局,每局分上下半场,双方各…...
【深度学习】通过colab将本地的数据集上传到drive
本地数据集上传到colab很慢,而且断开后就没了,因此通过colab将本地的数据集上传到drive,即使断开连接,第二次连接后挂载drive后即可直接使用数据集。 步骤一、将本地数据集上传到colab的临时文件夹中,由于将文件夹上传…...
MYSQL 存储引擎 和 日志
存储引擎 InnoDB 支持行级别的锁粒度,MyISAM 不支持,只支持表级别的锁粒度。MyISAM 不提供事务支持。InnoDB 提供事务支持,实现了 SQL 标准定义了四个隔离级别。MyISAM 不支持外键,而 InnoDB 支持。MyISAM 不支持 MVCC,…...
【2022】【论文笔记】太赫兹量子阱——
前言 类型 太赫兹 + 量子阱 太赫兹 + 量子阱 太赫兹+量子阱 期刊 红外与毫米波学报 红外与毫米波学报 红外与毫米波学报 作者 张真真 ,...
【NLP 面经 7、常见transformer面试题】
目录 1. 为何使用多头注意力机制? 2. Q和K使用不同权重矩阵的原因 3. 选择点乘而非加法的原因 4. Attention进行scaled的原因 5. 对padding做mask操作 6. 多头注意力降维原因 7. Transformer Encoder模块简介 8. 乘以embedding size的开方的意义 9. 位置编码 10. 其…...
在js中数组相关用法讲解
数组 uniqueArray 简单数组去重 /*** 简单数组去重* param arr* returns*/ export const uniqueArray <T>(arr: T[]) > [...new Set(arr)];const arr1 [1,1,1,1 2, 3];uniqueArray(arr); // [1,2,3]uniqueArrayByKey 根据 key 数组去重 /*** 根据key数组去重* …...
第四章 react-redux,@reduxjs/toolkit依赖,学习
redux系列文章目录 第一章 简单学习redux,单个reducer 第二章 简单学习redux,多个reducer 第三章 redux和react-redux,reduxjs/toolkit依赖结合使用 第五章 两张图告诉你redux常使用的api有哪些 前言 本章将使用react-redux,reduxjs/toolkit依赖创…...
雅思7分听说读写专项书籍推荐
对于目标 7分以上的雅思考生(中高级水平),选对资料真的事半功倍。 下面按照 听力、阅读、写作、口语、综合书籍 五大类来分别列举高分推荐书籍,每本书包括:适合人群、核心内容、推荐理由,并贴合7分目标。 …...
C++容器使用说明
C标准库提供了多种容器,分为序列容器、关联容器、无序关联容器、容器适配器及其他相关类型。以下是所有标准容器的分类及简要说明: 1. 序列容器(Sequence Containers) 按线性顺序存储元素,支持随机或顺序访问。 vecto…...
Python-函数
1. 函数基础 1.1 定义函数 在Python中,使用def关键字来定义函数: def greet():"""简单的问候函数"""print("Hello, World!")1.2 调用函数 定义函数后,可以通过函数名加括号来调用: …...
【Redis】数据的淘汰策略
目录 淘汰策略方案(8种) LRU和LFU策略的区别 使用建议 手搓LRU算法 方式一 方式二 大家好,我是jstart千语。今天和大家回来聊一下redis,这次要讲的是它的淘汰策略。为什么需要淘汰策略呢,就是当redis里面的内存占…...
第七章:从类库到服务的分布式基石_《凤凰架构:构建可靠的大型分布式系统》
第七章:从类库到服务的分布式基石 一、服务发现(Service Discovery) 核心目标:解决分布式系统中服务实例动态变化时如何定位可用服务的问题。 1. 服务发现的意义 动态环境挑战: 微服务架构中,服务实例的…...
spring-ai-alibaba第九章使用Milvus构建大模型RAG应用
1、pom文件 <dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>${spring-ai-alibaba.version}</version></dependency><dependency&g…...
手撕LLM(一):从源码出发,探索LLM推理全流程
2025年,大模型爆发元年,各种各样的大模型、框架、工具层出不穷,不断刷新人们应用大模型的门槛,短短10行代码,就能完成“加载模型加载数据集推理强化学习”的全流程训练,但其底层的运行机制也被高度抽象的接…...
讯飞语音听写(流式版)开发指南
语音交互大模型的功能越来越受到重视。讯飞语音听写(流式版)为开发者提供了一种高效、准确的语音识别解决方案。本文将基于 Home.vue、iat_xfyun.js 和 sparkChat.js 这三个文档,详细阐述讯飞语音听写(流式版)的开发逻…...
P3654 First Step (ファーストステップ)
题目描述 可是……这个篮球场,好像很久没有使用过的样子啊…… 里面堆满了学校的各种杂物呢…… 我们 Aqours 的成员要怎么在里面列队站下呢? 我们浦之星女子学院的篮球场是一个 R 行 C 列的矩阵,其中堆满了各种学校的杂物 (用 # 表示)&a…...
MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略
MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略 MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略一、引言二、为什么需要分库分表2.1 性能瓶颈2.2 存储瓶颈2.3 高并发压力 三、分库分表的方…...
SonarQube 配置SQL Server 数据库遇到的问题
之前本机跑了一套SonarQube的社区版,默认使用的是H2数据库,那么我把它练到我机器上的SQL Server数据库了,期间遇到以下两个问题,并在配置过程中解决掉,特将这个过程记录下来。 一、JDBC连接SQL Server问题 1. 问题出…...
23种设计模式-行为型模式-备忘录
文章目录 简介问题解决代码关键实现要点功能扩展方向 总结 简介 备忘录是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 问题 假如你正在开发一款文字编辑器应用。你想加入撤销功能。你可以采用直接的方式来实现: 程序在执行任…...
IDEA/WebStrom操作之commit前批量清除console.log()与debugger
前言: 在前端开发过程中,往往需要频繁用到console.log()与debugger,来观察数据具体情况以及断点调试。在经历了水生火热的开发动作后,往往会残留一地console.log()和debugger,若开发者还得手动在多个文件中一个个去除…...