重学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++ 面向对象的三个特征 封装是把数据和操作数据的函数捆绑在一起,并且对数据的访问进行限制。这样做的好处是可以隐藏对象的内部实现细节,只暴露必要的接口给外部。例如,在一个银行账户类中,账户余额这个数据成员是被封装起来的,外部不能直接访问和修改,而是通过存款、取…...
深度与视差的关系及其转换
深度与视差的关系及其转换 在计算机视觉和立体视觉中,深度和视差是两个重要的概念。理解这两者之间的关系对于实现立体图像处理、三维重建以及深度估计至关重要。在这篇博客中,我们将深入探讨深度和视差的概念,并介绍它们之间的转换关系。 …...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
