为什么使用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的区别的表格:

特性 MultiValueMap HashMap
数据结构 键对应值的列表 哈希表
是否支持多值
用途 表单数据、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则需要手动处理更多的细节。

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

相关推荐
七星静香10 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员11 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU11 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie615 分钟前
在IDEA中使用Git
java·git
Elaine20239130 分钟前
06 网络编程基础
java·网络
G丶AEOM31 分钟前
分布式——BASE理论
java·分布式·八股
落落鱼201332 分钟前
tp接口 入口文件 500 错误原因
java·开发语言
想要打 Acm 的小周同学呀33 分钟前
LRU缓存算法
java·算法·缓存
镰刀出海36 分钟前
Recyclerview缓存原理
java·开发语言·缓存·recyclerview·android面试
阿伟*rui3 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel