为什么使用httpClient发送x-www-form-urlencoded类型的请求时,必须要使用MultiValueMap来传参

大家好,我是G探险者。

今天主要介绍一下MultiValueMap和HashMap的区别。

事情起因是这样的,在我们项目code review的时候,客户方提了一个问题,说,你们在用restTemplate进行远程调用的时候,为啥使用MultiValueMap来传递参数,而不用HashMap。
这有啥区别么?

当时没有给出专业的解答。事后我就好好查询了一番。

从以下几个方面来阐述。

1. MultiValueMap 和 HashMap的区别?

MultiValueMapHashMap在数据结构上有一些差异,这导致了它们对待键值对的方式不同,从而使得MultiValueMap可以支持一个键对应多个值,而HashMap则不支持。

MultiValueMap:

MultiValueMap是Spring Framework中的接口,它的实现类通常是LinkedMultiValueMap。它的实现方式是每个键可以映射到一个值的列表,而不是单个值。这样就允许一个键拥有多个值。

HashMap:

HashMap在jdk<=1.7是基于数组+链表 在jdk>=1.8是数据+链表+红黑树,每个键值对映射到一个唯一的键上。因此,当你向HashMap中添加一个已经存在的键时,新值会覆盖旧值,而不是追加在旧值的后面。这就是为什么HashMap不支持一个键对应多个值的原因。

对比:

  • 存储方式MultiValueMap采用列表来存储值,一个键可以对应多个值;而HashMap每个键只能对应一个值,不支持多值。
  • 数据结构MultiValueMap内部使用了链表或者类似结构,以便存储多个值;HashMap内部使用数组+链表(或者红黑树),每个键对应一个唯一的哈希值。
  • 使用场景MultiValueMap适用于需要存储多个值的情况,比如HTTP请求参数;HashMap适用于需要唯一键值对的情况,比如建立字典。

下面是一个对比MultiValueMapHashMap的区别的表格:

特性MultiValueMapHashMap
数据结构键对应值的列表哈希表
是否支持多值
用途表单数据、HTTP请求参数通用键值对存储
处理重复键支持,每个键可以对应多个值后添加的值会覆盖之前的值
参数编码无需手动编码,自动处理需要手动进行URL编码
框架集成Spring框架中常用通用
示例代码MultiValueMap<String, List<String>>HashMap<String, String>

通过这个表格,可以清晰地了解到MultiValueMapHashMap在数据结构、支持多值、参数编码、框架集成等方面的区别。MultiValueMap更适用于处理需要支持多值的情况,特别是在Spring框架中;而HashMap适用于一般的键值对存储。

综上所述,虽然MultiValueMapHashMap都用于存储键值对,但它们的底层数据结构和对键值对的处理方式不同,导致了它们在支持一个键对应多个值这个特性上的差异。

了解了以上、MultiValueMap 和 HashMap在数据结构上的差异,我们再来讨论下面的问题

2. form表单提交的请求类型x-www-form-urlencoded为啥使用MultiValueMap来传递参数更合适?

在使用HttpClient发送x-www-form-urlencoded类型的请求时,通常需要使用MultiValueMap来传递参数,这是因为x-www-form-urlencoded格式要求参数以键值对的形式进行传递,而且在同一个键名下可能存在多个值。MultiValueMap是Spring Framework中的一种数据结构,用于表示键值对,并且支持一个键对应多个值的情况。

总结起来,主要有以下几个原因:

  • 多值支持: x-www-form-urlencoded格式要求同一个参数名可以对应多个值,而MultiValueMap正是为了支持这种情况而设计的。在HashMap中,相同的键只能对应一个值,如果需要传递多个值,你可能需要自己手动处理这种情况,而使用MultiValueMap则可以直接支持多值。

  • 参数编码: x-www-form-urlencoded格式要求参数需要进行URL编码,以确保特殊字符正确传输。Spring框架中的MultiValueMap会自动处理这种编码,确保参数在传输过程中不会出现问题。如果使用HashMap,你需要自己编写代码来手动进行参数的编码,这样就增加了额外的工作量和复杂度。

  • 框架集成: 在Spring框架中,很多API都会接受MultiValueMap类型的参数,因此使用MultiValueMap能够更好地与Spring的其他功能集成。例如,Spring提供了RestTemplate类来发送HTTP请求,该类的一些方法接受MultiValueMap类型的参数,这样你可以直接传递参数而无需进行额外的转换。

综上所述,虽然你可以使用HashMap来传递参数,但是为了更好地符合x-www-form-urlencoded格式的要求,以及在Spring框架中更好地与其他功能集成,推荐使用MultiValueMap来传递参数。

使用MultiValueMap能够更方便地构建这种参数形式,确保参数按照x-www-form-urlencoded格式正确编码。另外,Spring框架提供了一些便捷的方法来构建和处理MultiValueMap,使得参数的处理更加简单和灵活。

下面我分别从代码层面来阐述一下,使用MultiValueMap和使用HashMap进行传值的区别

2.1 使用 MultiValueMap:

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;// 创建 MultiValueMap 对象
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();// 添加参数到 MultiValueMap
params.add("key1", "value1");
params.add("key2", "value2");
params.add("key2", "value3"); // 添加同名参数,支持多值// 使用 MultiValueMap 发送请求
// 假设 HttpClient 已经实例化为 httpClient
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<String> response = httpClient.exchange(url, HttpMethod.POST, requestEntity, String.class);

2.2 使用 HashMap:

import java.util.HashMap;
import java.util.Map;// 创建 HashMap 对象
Map<String, String> params = new HashMap<>();// 添加参数到 HashMap
params.put("key1", "value1");
params.put("key2", "value2");
params.put("key2", "value3"); // 重复的键会覆盖之前的值// 构建 x-www-form-urlencoded 格式的参数字符串
StringBuilder requestBody = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {if (requestBody.length() > 0) {requestBody.append("&");}requestBody.append(URLEncoder.encode(entry.getKey(), "UTF-8"));requestBody.append("=");requestBody.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}// 发送请求
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> requestEntity = new HttpEntity<>(requestBody.toString(), headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);

从以上两个示例代码我们可以清楚的看到如下区别:

2.3 区别:

  1. 多值支持MultiValueMap支持一个键对应多个值,而HashMap不支持,需要手动处理。

  2. 编码处理MultiValueMap会自动处理参数值的URL编码,而HashMap需要手动编码。

  3. 代码复杂度:使用MultiValueMap更简洁,不需要手动构建参数字符串。

总的来说,使用MultiValueMap更方便、更符合Spring框架的习惯,而使用HashMap则需要手动处理更多的细节。

如果喜欢的话,请点个关注哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/8026.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-线性表-应用题-2.2-7

将两个有序顺序表合并为一个新的有序顺序表&#xff0c;并由函数返回结果顺序表 使用了归并排序的思想 按顺序将两个顺序表表头较小的节点存入新的顺序表中&#xff0c;若一个表用完了&#xff0c;就把另一个表的剩下的部分加到新表中去 bool Merge(SeqList A,SeqList B,Seq…

docker部署elasticsearch7.7.0级拼音(pinyin)插件和分词(ik)插件

拉取并启动es docker run -d --namees -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" elasticsearch:7.7.0安装pinyin插件 下载pinyin插件 下载ik插件 上传插件到服务器 docker cp /path/to/elasticsearch-analysis-pinyin-7.7.0.zip elasticsearch…

免费分享一套微信小程序在线订餐(点餐)配送系统(SpringBoot+Vue),帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序在线订餐(点餐)配送系统(SpringBootVue)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序在线订餐(点餐)配送系统(SpringBootVue) Java毕业设计_哔哩哔哩_bilibili【免费】微信小程序在…

Django中如何实现单元测试覆盖率报告?

在 Django 中可以使用 coverage 模块来实现单元测试覆盖率报告。下面是一个实现的步骤&#xff1a; 首先&#xff0c;在项目的根目录下&#xff0c;安装 coverage 模块&#xff1a; pip install coverage创建一个 .coveragerc 文件&#xff0c;用于配置 coverage 的一些参数。在…

91、动态规划-不同的路径

思路&#xff1a; 首先我们可以使用暴力递归解法&#xff0c;无非就是每次向下或者向右看看是否有解法&#xff0c;代码如下&#xff1a; public class Solution {public int uniquePaths(int m, int n) {return findPaths(0, 0, m, n);}private int findPaths(int i, int j,…

企业防泄露如何做到安全有效

随着信息时代的急速演进&#xff0c;企业的重要商业机密越来越多地以电子文档的形式存在。常见的CAD图纸、Office文档承载着公司的核心价值和竞争优势&#xff0c;同时也面临着前所未有的数据安全威胁。确保这些重要信息的文档安全已经成为每个企业必须直面的挑战。在这样的背景…

绝地求生:新型小队对决系统或将择日上线?

就在刚才&#xff0c;PUBG官博发布了一则短视频&#xff0c;视频内容为两只小队通过竞争积分排名产生不断地变化。 原文官博 视频内容 在这里我猜测为之前官方在2024工作计划视频中介绍过的新型小队对决系统&#xff1a; 据当时的介绍称&#xff1a;这个系统中&#xff0c;己方…

【牛客】【模板】差分

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 差分模板。 b[0]a[0]; b[1]a[1]-a[0]; b[2]a[2]-a[1]; ...... b[n-1]a[n-1]-a[n-2]; b[n]a[n]-a[n-1]; 差分标记&#xff1a;b[l]k,b…

【DevOps】深入剖析Elasticsearch的分片与副本对性能的影响

目录 一、分片 (Shards) 1、什么是分片&#xff1f; 2、分片的类型 3、分片对性能的影响 二、副本 (Replicas) 1、什么是副本&#xff1f; 2、副本对性能的影响 三、最佳实践 1、主分片数量的选择 2、副本分片的设置 3、监控和调整 4、考虑使用 Shrink 和 Split AP…

vue3中用 let a= b赋值会改变b的值

注意b是reactive const paramreactive({ pageSize:12, }) 在JavaScript中&#xff0c;基本类型&#xff08;比如String&#xff0c;Number&#xff0c;Boolean&#xff0c;undefined&#xff0c;null&#xff09;是按值传递的&#xff0c;这意味着当你将一个基本类型变量赋值给…

k8s部署Kubeflow v1.7.0

文章目录 环境介绍部署访问kubeflow ui问题记录 环境介绍 K8S版本&#xff1a;v1.23.17&#xff0c;需要配置默认的sc 参考&#xff1a;https://github.com/kubeflow/manifests/tree/v1.7.0 部署 #获取安装包 wget https://github.com/kubeflow/manifests/archive/refs/tag…

faiss 原理和使用总结

FAISS&#xff08;Facebook AI Similarity Search&#xff09;是由 Facebook AI Research 开发的一个高效的相似性搜索和密集向量索引库。它主要用于大规模向量搜索和高维数据的聚类。下面&#xff0c;我将为你概述 FAISS 的工作原理和使用方法。 ### 原理 1. **向量量化&…

致远M3 Session 敏感信息泄露漏洞复现

0x01 产品简介 M3移动办公是致远互联打造的一站式智能工作平台,提供全方位的企业移动业务管理,致力于构建以人为中心的智能化移动应用场景,促进人员工作积极性和创造力,提升企业效率和效能,是为企业量身定制的移动智慧协同平台。 0x02 漏洞概述 致远M3 server多个日志文…

函数练习.

1.打印乘法口诀表 口诀表的行数和列数自己指定如&#xff1a;输入9&#xff0c;输出99口诀表&#xff0c;输出12&#xff0c;输出1212的乘法口诀表。 multiplication(int index) { ​if (index 9) { ​int i 0; ​for (i 1; i < 10; i) { ​int j 0; ​for (j 1; j &…

《系统架构设计师教程(第2版)》第10章-软件架构的演化和维护-04-软件架构演化原则

文章目录 1. 演化成本控制原则2. 进度可控原则3. 风险可控原则4. 主体维持原则5. 系统总体结构优化原则6. 平滑演化原则7. 目标一致原则8. 模块独立演化原则9. 影响可控原则10. 复杂性可控原则11. 有利于重构原则12. 有利于重用原则13. 设计原则遵从性原则14. 适应新技术原则15…

Django 4.x 智能分页get_elided_page_range

Django智能分页 分页效果 第1页的效果 第10页的效果 带输入框的效果 主要函数 # 参数解释 # number: 当前页码&#xff0c;默认&#xff1a;1 # on_each_side&#xff1a;当前页码前后显示几页&#xff0c;默认&#xff1a;3 # on_ends&#xff1a;首尾固定显示几页&#…

html5基础知识——表单

表单由三个部分组成&#xff0c;分别是表单域、表单控件、提示信息&#xff08;也就是默认显示的内容&#xff09; 表单域 使用form标签定义 将所有的元素信息定义在一块区域中 用于将表单中的所有元素信息提交给服务器 其中&#xff1a;action表示该表单将要提交到哪个地址&am…

5. DNS 记录和报文

DNS 服务器中以资源记录的形式存储信息&#xff0c;每一个 DNS 响应报文一般包含多条资源记录。一条资源记录的具体的格式为 &#xff08;Name&#xff0c;Value&#xff0c;Type&#xff0c;TTL&#xff09; 其中 TTL 是资源记录的生存时间&#xff0c;它定义了资源记录能够…

LWIP+TCP客户端

一、TCP API函数 其中tcp_poll()函数的第三个参数表示隔几秒调用一次这个周期性函数 二、修改服务器的IP 三、TCP客户端编程思路 申请套接字绑定服务器IP和端口号等待客户端连接 进入连接回调函数在连接回调函数中 配置一些回调函数&#xff0c;如接收回调函数&#xff0c;周期…

ADC STM32

/// STM32ADC模拟/数字转换详解 FOC控制库MCSDK5.4.4梳理(2)——电流采样 ///