首页 > 其他分享 >Spring RestTemplate为何必须搭配MultiValueMap?

Spring RestTemplate为何必须搭配MultiValueMap?

时间:2023-04-27 10:24:50浏览次数:53  
标签:Body Spring 编解码器 RestTemplate 表单 MultiValueMap 提交

微服务之间的大多都是使用 HTTP 通信,这自然少不了使用 HttpClient。 在不适用 Spring 前,一般使用 Apache HttpClient 和 Ok HttpClient 等,而一旦引入 Spring,就有了更好选择 - RestTemplate。

 

想接受一个 Form 表单请求,读取表单定义的两个参数 para1 和 para2,然后作为响应返回给客户端。

定义完接口后,使用 RestTemplate 来发送一个这样的表单请求,代码示例如下:

 上述代码定义了一个 Map,包含了 2 个表单参数,然后使用 RestTemplate 的 postForObject 提交这个表单。 执行代码提示 400 错误,即请求出错:

 

就是缺少 para1 表单参数,why?

解析

RestTemplate 提交的表单,最后提交请求啥样? Wireshark 抓包:

 实际上是将定义的表单数据以 JSON 提交过去了,所以我们的接口处理自然取不到任何表单参数。 why?怎么变成 JSON 请求体提交数据呢?注意 RestTemplate 执行调用栈:

 最终使用的 Jackson 工具序列化了表单

 

用到 JSON 的关键原因在

RestTemplate.HttpEntityRequestCallback#doWithRequest

 

根据当前要提交的 Body 内容,遍历当前支持的所有编解码器:

  • 若找到合适编解码器,用之完成 Body 转化

看下 JSON 的编解码器对是否合适的判断

AbstractJackson2HttpMessageConverter#canWrite

 

可见,当使用的 Body 为 HashMap,是可完成 JSON 序列化的。 所以后续将这个表单序列化为请求 Body了。

但我还是疑问,为何适应表单处理的编解码器不行? 那就该看编解码器判断是否支持的实现:

FormHttpMessageConverter#canWrite

 

可见只有当我们发送的 Body 是 MultiValueMap 才能使用表单来提交。 原来使用 RestTemplate 提交表单必须是 MultiValueMap! 而我们案例定义的就是普通的 HashMap,最终是按请求 Body 的方式发送出去的。

修正

换成 MultiValueMap 类型存储表单数据即可:

 

修正后,表单数据最终使用下面的代码进行了编码:

FormHttpMessageConverter#write

 

 发送出的数据截图如下:

 这就对了!其实官方文档也说明了:

 

参考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html


================================================================================================
作者:JavaEdge在掘金
链接:https://juejin.cn/post/7035246763069947918
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:Body,Spring,编解码器,RestTemplate,表单,MultiValueMap,提交
From: https://www.cnblogs.com/Im-Victor/p/17358179.html

相关文章

  • Spring AOP 支持两种模式的动态代理
    SpringAOP支持两种模式的动态代理,JDKProxy或者cglib,jdkproxy:publicclassMyDynamicProxy{publicstaticvoidmain(String[]args){HelloImplhello=newHelloImpl();MyInvocationHandlerhandler=newMyInvocationHandler(hello);......
  • springboot入门时,发现Java版本与Spring boot版本无法对应导致错误的问题解决
    <?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/......
  • 小团队真的适合引入SpringCloud微服务吗?
    单体应用时代接口定义持续集成(CI)微服务时代服务拆分原则框架选择架构改造自动化部署链路跟踪运维监控容器化时代架构改造SpringCloud与k8s的融合CI的改造小结微服务是否适合小团队是个见仁见智的问题。回归现象看本质,随着业务......
  • SpringBoot SpringSecurity 介绍(基于内存的验证)
    SpringBoot集成SpringSecurity+MySQL+JWT附源码,废话不多直接盘SpringBoot已经为用户采用默认配置,只需要引入pom依赖就能快速启动SpringSecurity。目的:验证请求用户的身份,提供安全访问优势:基于Spring,配置方便,减少大量代码内置访问控制方法permitAll()表示所匹配的......
  • Spring Security 报:Encoded password does not look like BCrypt
    SpringBoot集成Security时,报EncodedpassworddoesnotlooklikeBCrypt原因:SecurityConfig必须Bean的形式实例化/***配置用户身份的configure()方法**@paramauth*@throwsException*/@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder......
  • SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
    SpringBoot集成SpringSecurity+MySQL+JWT无太多理论,直接盘一般用于Web管理系统可以先看SpringBootSpringSecurity基于内存的使用介绍本文介绍如何整合SpringSecurity+MySQL+JWT数据结构数据库脚本:https://gitee.com/VipSoft/VipBoot/blob/develop/vipsoft-sec......
  • SpringBoot配置MongoDb
    MongoDb建表:MongoDB不需要建表,直接插入数据就会建表。日期用ISODate()转换。db.getCollection("mongoDbTest").insert({userId:"dxcefg",status:1,price:1.23,updateTime:ISODate("2022-02-13T07:06:25.371Z")})添加maven依赖:<dependency>......
  • SpringMcv 文件上传下载
    文件上传SpringMVC为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的。Spring用JakartaCommonsFileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResovlerSpringMVC上下文中默认没有装配MultipartResovler,因此默认情况......
  • springboot自定义拦截器
    springboot自定义拦截器操作说明1、编写一个拦截器实现HandlerInterceptor接口2、拦截器注册到容器中(实现WebMvcConfigures的addInterceptors)3、指定拦截规则(如果是拦截所有,静态资源也会被拦截)LoginInterceptor.javapackagecom.example.springtxiangmu.interceptor;im......
  • spring jdbc 编程式事务
    所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。新建maven工程,pom文件如下:<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http:/......