重学SpringBoot3-WebClient配置与使用详解
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍
重学SpringBoot3-WebClient配置与使用详解
- 1. 简介
- 2. 环境准备
- 2.1 依赖配置
- 3. WebClient配置
- 3.1 基础配置
- 3.2 高级配置
- 3.3 retrieve()和exchange()区别
- 4. 使用示例
- 4.1 基本请求操作
- 4.2 处理复杂响应
- 4.3 高级用法
- 5. 最佳实践
- 6. 注意事项
- 7. 与RestTemplate对比
- 8. 总结
- 参考资料
1. 简介
WebClient是Spring 5引入的响应式Web客户端,用于执行HTTP请求。相比传统的RestTemplate,WebClient提供了非阻塞、响应式的方式来处理HTTP请求,是Spring推荐的新一代HTTP客户端工具。本文将详细介绍如何在SpringBoot 3.x中配置和使用WebClient。
2. 环境准备
2.1 依赖配置
在 pom.xml
中添加必要的依赖:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.10</version><relativePath/> <!-- lookup parent from repository --></parent><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
3. WebClient配置
3.1 基础配置
@Configuration
public class WebClientConfig {@Beanpublic WebClient webClient() {return WebClient.builder().baseUrl("https://echo.apifox.com").defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).build();}
}
3.2 高级配置
package com.coderjia.boot3webflux.config;import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;import java.time.Duration;/*** @author CoderJia* @create 2024/12/3 下午 09:42* @Description**/
@Slf4j
@Configuration
public class WebClientConfig {@Beanpublic WebClient webClient() {// 配置HTTP连接池ConnectionProvider provider = ConnectionProvider.builder("custom").maxConnections(500).maxIdleTime(Duration.ofSeconds(20)).build();// 配置HTTP客户端HttpClient httpClient = HttpClient.create(provider).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000).responseTimeout(Duration.ofSeconds(5)).doOnConnected(conn ->conn.addHandlerLast(new ReadTimeoutHandler(5)).addHandlerLast(new WriteTimeoutHandler(5)));// 构建WebClient实例return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).baseUrl("https://echo.apifox.com").defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)// 添加请求日志记录功能.filter(ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {log.debug("Request: {} {}",clientRequest.method(),clientRequest.url());return Mono.just(clientRequest);}))// 添加响应日志记录功能.filter(ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {log.debug("Response status: {}",clientResponse.statusCode());return Mono.just(clientResponse);})).build();}
}
3.3 retrieve()和exchange()区别
在使用 WebClient 进行 HTTP 请求时,retrieve() 和 exchange() 方法都可以用来处理响应,但它们有不同的用途和行为。以下是它们的主要区别:
retrieve()
- 用途:retrieve() 方法用于简化响应处理,特别是当你只需要响应体时。
- 自动错误处理:retrieve() 会自动处理 HTTP 错误状态码(例如 4xx 和 5xx),并抛出 WebClientResponseException 及其子类。
- 返回值:通常用于直接获取响应体,例如 bodyToMono(String.class) 或 bodyToFlux(String.class)。
- 适用场景:适用于大多数常见的请求处理场景,特别是当你不需要手动处理响应状态码时。
exchange()
- 用途:exchange() 方法提供了更底层的控制,允许你手动处理响应,包括响应状态码和响应头。
- 手动错误处理:exchange() 不会自动处理 HTTP 错误状态码,你需要手动检查响应状态码并进行相应的处理。
- 返回值:返回 ClientResponse 对象,你可以从中提取响应状态码、响应头和响应体。
- 适用场景:适用于需要手动处理响应状态码或响应头的复杂场景。
示例对比
retrieve()
public Mono<JSONObject> get(String q1) {return webClient.get().uri(uriBuilder -> uriBuilder.path("/get").queryParam("q1", q1).build()).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(JSONObject.class);
}
exchange()
public Mono<JSONObject> get(String q1) {return webClient.get().uri(uriBuilder -> uriBuilder.path("/get").queryParam("q1", q1).build()).accept(MediaType.APPLICATION_JSON).exchangeToMono(response -> {if (response.statusCode().is2xxSuccessful()) {return response.bodyToMono(JSONObject.class);} else {return Mono.error(new RuntimeException("Request failed with status code: " + response.statusCode()));}});
}
4. 使用示例
4.1 基本请求操作
package com.coderjia.boot3webflux.service;import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;/*** @author CoderJia* @create 2024/12/3 下午 10:22* @Description**/
@Service
public class ApiService {@Resourceprivate WebClient webClient;// GET请求public Mono<JSONObject> get(String q1) {return webClient.get().uri(uriBuilder -> uriBuilder.path("/get").queryParam("q1", q1).build()).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(JSONObject.class);}// POST请求public Mono<JSONObject> post(JSONObject body) {return webClient.post().uri("/post").bodyValue(body).retrieve().bodyToMono(JSONObject.class);}// PUT请求public Mono<JSONObject> put(String q1, JSONObject JSONObject) {return webClient.put().uri(uriBuilder -> uriBuilder.path("/put").queryParam("q1", q1).build()).bodyValue(JSONObject).retrieve().bodyToMono(JSONObject.class);}// DELETE请求public Mono<JSONObject> delete(String q1) {return webClient.delete().uri(uriBuilder -> uriBuilder.path("/delete").queryParam("q1", q1).build()).retrieve().bodyToMono(JSONObject.class);}
}
效果展示
4.2 处理复杂响应
@Service
public class ApiService {// 获取列表数据public Flux<JSONObject> getAllUsers() {return webClient.get().uri("/users").retrieve().bodyToFlux(JSONObject.class);}// 处理错误响应public Mono<JSONObject> getUserWithErrorHandling(Long id) {return webClient.get().uri("/users/{id}", id).retrieve().onStatus(HttpStatusCode::is4xxClientError, clientResponse -> Mono.error(new RuntimeException("客户端错误"))).onStatus(HttpStatusCode::is5xxServerError, clientResponse -> Mono.error(new RuntimeException("服务器错误"))).bodyToMono(JSONObject.class);}// 使用exchange()方法获取完整响应public Mono<ResponseEntity<JSONObject>> getUserWithFullResponse(Long id) {return webClient.get().uri("/users/{id}", id).accept(MediaType.APPLICATION_JSON).exchange().flatMap(response -> response.toEntity(JSONObject.class));}
}
4.3 高级用法
@Service
public class ApiService {// 带请求头的请求public Mono<JSONObject> getUserWithHeaders(Long id, String token) {return webClient.get().uri("/users/{id}", id).header("Authorization", "Bearer " + token).retrieve().bodyToMono(JSONObject.class);}// 带查询参数的请求public Flux<JSONObject> searchUsers(String name, int age) {return webClient.get().uri(uriBuilder -> uriBuilder.path("/users/search").queryParam("name", name).queryParam("age", age).build()).retrieve().bodyToFlux(JSONObject.class);}// 文件上传public Mono<String> uploadFile(FilePart filePart) {return webClient.post().uri("/upload").contentType(MediaType.MULTIPART_FORM_DATA).body(BodyInserters.fromMultipartData("file", filePart)).retrieve().bodyToMono(String.class);}
}
5. 最佳实践
-
合理使用响应式类型
- 使用 Mono 用于单个对象
- 使用 Flux 用于集合数据
- 注意背压处理
-
错误处理
public Mono<JSONObject> getUserWithRetry(Long id) {return webClient.get().uri("/users/{id}", id).retrieve().bodyToMono(JSONObject.class).retryWhen(Retry.backoff(3, Duration.ofSeconds(1))).timeout(Duration.ofSeconds(5)).onErrorResume(TimeoutException.class,e -> Mono.error(new RuntimeException("请求超时")));}
-
资源管理
- 使用连接池
- 设置适当的超时时间
- 实现优雅关闭
6. 注意事项
- WebClient 是非阻塞的,需要注意响应式编程的特性
- 合理配置连接池和超时参数
- 在生产环境中实现适当的错误处理和重试机制
- 注意内存使用,特别是处理大量数据时
7. 与RestTemplate对比
特性 | WebClient | RestTemplate |
---|---|---|
编程模型 | 响应式、非阻塞 | 同步、阻塞 |
性能 | 更好 | 一般 |
资源利用 | 更高效 | 一般 |
学习曲线 | 较陡 | 平缓 |
适用场景 | 高并发、响应式系统 | 简单应用、传统系统 |
8. 总结
WebClient 作为 Spring 推荐的新一代 HTTP 客户端,提供了强大的响应式编程能力和更好的性能。虽然相比 RestTemplate 有一定的学习曲线,但在现代微服务架构中,其带来的好处远超过学习成本。建议在新项目中优先考虑使用WebClient,特别是在需要处理高并发请求的场景下。
参考资料
- Spring WebClient官方文档
- Spring Boot官方文档
- Project Reactor文档
相关文章:

重学SpringBoot3-WebClient配置与使用详解
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-WebClient配置与使用详解 1. 简介2. 环境准备2.1 依赖配置 3. WebClient配置3.1 基础配置3.2 高级配置3.3 retrieve()和exchange()区别 4. 使用示例4.1 …...
springBoot中的日志级别在哪里配置
在Spring Boot中,日志级别的配置可以通过多种方式来实现,主要包括在配置文件中设置、使用自定义的logback配置文件,以及在代码中动态配置等。以下是一些具体的配置方法: 一、在配置文件中设置日志级别 Spring Boot默认使用appli…...

统一身份安全管理体系的业务协同能力
随着集团企业数字化组织转型深化,各组织机构间业务协同程度提升。研发业务协同、数据驱动生产决策等数字化生产协作工作体系得以展开,企业内数据流转加快。企业对统一身份安全管理体系的业务协同管理和支撑能力要求提升: 统一身份管理流程需…...
JAVA课堂笔记23(IO流 (java.io包中))
第五章:IO流 (java.io包中) 三、字符流 1. 字符流的父类(抽象类): Reader:字符输入流 对应的操作为读操作 功能方法:read方法 Writer:字符输出流 对应的操作为写操作 功能方法:write方法 …...

C# DLT645 97/07数据采集工具
电表模拟器 97协议测试 07协议测试 private void btnSend_Click(object sender, EventArgs e) {string addr txtAddr.Text.Trim();string data txtDataFlg.Text.Trim();byte control 0x01;switch (cmbControl.SelectedIndex){case 0: control (byte)0x01; break;// 97协议c…...

中后台管理信息系统:Axure12套高效原型设计框架模板全解析
中后台管理信息系统作为企业内部管理的核心支撑,其设计与实现对于提升企业的运营效率与决策能力具有至关重要的作用。为了满足多样化的中后台管理系统开发需求,一套全面、灵活的原型设计方案显得尤为重要。本文将深入探讨中后台管理信息系统通用原型方案…...

Reactor 响应式编程(第四篇:Spring Security Reactive)
系列文章目录 Reactor 响应式编程(第一篇:Reactor核心) Reactor 响应式编程(第二篇:Spring Webflux) Reactor 响应式编程(第三篇:R2DBC) Reactor 响应式编程(…...

JVM 双亲委派模型以及垃圾回收机制
目录 1. JVM 内存区域划分 2. JVM 中类加载的过程 1) 类加载的基本流程 2) 双亲委派模型 3. JVM 中垃圾回收机制 1) 找到垃圾 a) 引用计数 b) 可达性分析 2) 释放垃圾 1. JVM 内存区域划分 一个运行起来的 Java 进程,其实就是一个 JVM 虚拟机。 而进程是…...
Delphi编写涂鸦桌面的小程序
用Delphi编写涂鸦桌面的小程序,类似于腾讯会议中的画板功能的实现。这里用Delphi实现代码给大家提供一些思路; 首先,新建一个Application,将Form1的WindowState设为wsMaximized,BorderStyle设为bsNone。这样做的目的就…...
智星云技术文档:GPU测速教程
安装gpu burn git clone https://github.com/wilicc/gpu-burn cd gpu-burn/ make测试 ./gpu_burn 60100.0% procd: 14280 (7373 Gflop/s) - 13390 (6997 Gflop/s) - 15912 (7110 Gflop/s) - 13184 (7055 Gflop/s) - 13464 (7369 Gflop/s) - 13974 (7351 Gflop/s) - 16626 (7…...
《Kali Linux 软件源更换攻略:优化软件获取与系统更新》
KALI为什么要换源 速度提升 Kali Linux 默认的软件源服务器通常位于国外。在从这些国外源下载软件包、更新系统时,会受到网络带宽、网络延迟等因素的限制。例如,在中国,连接到国外服务器的网络速度可能较慢,尤其是在下载大型软件…...
C# 在dataview可以直接增删改查mysql数据库
C# 在dataview可以直接增删改查mysql数据库 首先,确保你的项目中已经安装了MySql.Data。你可以通过NuGet包管理器安装它: Install-Package MySql.Data -Version 8.0.28using System; using System.Data; using MySql.Data.MySqlClient;public class My…...
C#—泛型约束
C#—泛型约束 概念: 泛型约束就是告知编译器类型参数必须具备的功能。 在没有任何约束的情况下,类型参数可以是任何类型。 编译器只能假定 System.Object 的成员,它是任何 .NET 类型的最终基类。当分配给泛型的类型参数不满足约束的类型时&…...
MeiliSearch:一款轻量级开源搜索引擎
Meilisearch 是由 Meili (一家总部位于法国的软件开发公司)创建的搜索引擎,目前在 Github 上有 47.9k stars。 Meillisearch 具备以下特色功能(ChatGPT-4o 翻译): 混合搜索:结合语义搜索和全文…...

Ansible playbook 详解与实战操作
一、概述 playbook 与 ad-hoc 相比,是一种完全不同的运用 ansible 的方式,类似与 saltstack 的 state 状态文件。ad-hoc 无法持久使用,playbook 可以持久使用。 playbook 是由一个或多个 play 组成的列表,play 的主要功能在于将事先归并为一…...

青少年夏令营管理系统的设计与开发(社团管理)(springboot+vue)+文档
💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...
加速合并,音频与字幕的探讨
因上一节。合并时速度太慢了。显卡没用上。所以想快一点。1分钟的视频用了5分钟。 在合并视频时,进度条中的 now=None 通常表示当前处理的时间点没有被正确记录或显示。这可能是由于 moviepy 的内部实现细节或配置问题。为了加快视频合并速度并利用 GPU 加速,可以采取以下措…...
Uniapp插件如何通过NFC读取多种证卡信息?
nfc读卡uniapp插件,由中软高科进行开发,主要是通过NFC读取居民身份证、港澳台居住证、外国人居住证、护照等证卡的信息。经过多个版本的升级更新,目前性能已趋于稳定,并且读卡速度较之最初版本有了大的提升。 注意事项 测试使用的…...
米哈游C++开发精选60道面试题及参考答案
C++ 面向对象的三个特征 封装是把数据和操作数据的函数捆绑在一起,并且对数据的访问进行限制。这样做的好处是可以隐藏对象的内部实现细节,只暴露必要的接口给外部。例如,在一个银行账户类中,账户余额这个数据成员是被封装起来的,外部不能直接访问和修改,而是通过存款、取…...
深度与视差的关系及其转换
深度与视差的关系及其转换 在计算机视觉和立体视觉中,深度和视差是两个重要的概念。理解这两者之间的关系对于实现立体图像处理、三维重建以及深度估计至关重要。在这篇博客中,我们将深入探讨深度和视差的概念,并介绍它们之间的转换关系。 …...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...