@RequestBody解密,說點你不知道的
大家好,我是路人,這是 SpringMVC 系列第 24 篇。
本文將介紹@RequestBody 注解常見的一些用法和原理,這個注解日常用到的特別多。
1、預備知識
2、@RequestBody 介紹
標注在接口的參數上,用來獲取 HTTP 請求 body 中的值,下面通過案例列出常見的用法。
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public?@interface?RequestBody?{
?/**
??* body是不是必須的,默認為true,若不傳body,會有異常;若為false,這body可不傳
??*/
?boolean?required()?default?true;
}
推薦閱讀:尚硅谷 Java 學科全套教程(總 207.77GB)
3、案例 1:使用字符串接收 body 中的數據
3.1、接口代碼
注意方法的參數,使用@RequestBody 標注,參數類型是 String,表示以字符串的方式接收 body 的數據。
@RequestMapping("/requestbody/test1")
public?String?test1(@RequestBody?String?body)?{
????System.out.println("body:"?+?body);
????return?"ok";
}
下面來模擬發(fā)送 5 種格式的數據,然后看控制臺的輸出。
3.2、用例 1:發(fā)送純文本數據
Content-Type 用來指定客戶端發(fā)送的數據的類型。
###?發(fā)送純文本
POST?http://localhost:8080/chat18/requestbody/test1
Content-Type:?text/plain
這里是body部分,歡迎訪問我的博客:itsoku.com,上面有更多系列文章
運行,接口內部控制臺輸出
body:這里是body部分,歡迎訪問我的博客:itsoku.com,上面有更多系列文章
3.3、用例 2:發(fā)送表單數據,相當于提交表單
Content-Type: application/x-www-form-urlencoded 相當于頁面中提交表單,表單中的所有元素會以 name=value&name=value 的方式拼接起來,然后在進行 urlencoded,之后丟在 body 中發(fā)送。
###?發(fā)送表單數據,相當于提交表單
POST?http://localhost:8080/chat18/requestbody/test1
Content-Type:?application/x-www-form-urlencoded
name=路人&blogs=itsoku.com
運行輸出如下,可以看出來是亂碼的格式,是由于被中文被 urlencoded 編碼了。
body:name=%E8%B7%AF%E4%BA%BA&blogs=itsoku.com
3.4、用例 3:發(fā)送 xml 數據
###?發(fā)送xml數據
POST?http://localhost:8080/chat18/requestbody/test1
Content-Type:?text/xml
????Java高并發(fā)系列
????MyBatis系列
????MySQL系列
????Spring高手系列
????分布式事務高手系列
運行,控制臺輸出
body:
????Java高并發(fā)系列
????MyBatis系列
????MySQL系列
????Spring高手系列
????分布式事務高手系列
3.5、用例 4:發(fā)送 json 數據
###?發(fā)送json數據
POST?http://localhost:8080/chat18/requestbody/test1
Content-Type:?application/json;charset=UTF-8
{
??"blog":?"itsoku.com",
??"course":?[
????"Spring高手系列",
????"MySQL系列",
????"高并發(fā)系列"
??]
}
運行,控制臺輸出
body:{
??"blog":?"itsoku.com",
??"course":?[
????"Spring高手系列",
????"MySQL系列",
????"高并發(fā)系列"
??]
}
從上面可以看出,接口參數 body 的值為 http 請求 body 中的原始數據。
推薦閱讀:2021 最新版 Java 微服務學習線路圖 + 視頻
4、案例 2:使用對象接收 json 格式的數據
4.1、用法
發(fā)送 json 格式的數據,這種用到的比較多,http 請求發(fā)送這種數據,有 3 點要求:
Content-Type 的值需要為:application/json;charset=UTF-8,告訴服務器端客戶端 body 中的數據是 json 格式 & UTF-8 編碼 body 中數據為 json 格式 接口端用對象接收,參數使用@RequestBody 標注
4.2、接口代碼
@RequestMapping("/requestbody/test2")
public?String?test2(@RequestBody?User?user)?{
????System.out.println("user:"?+?user);
????return?"ok";
}
User 類
public?class?User?{
????private?String?name;
????private?Integer?age;
????private?List?skills;
????//省略get、set
????@Override
????public?String?toString()?{
????????return?"User{"?+
????????????"name='"?+?name?+?'\''?+
????????????",?age="?+?age?+
????????????",?skills="?+?skills?+
????????????'}';
????}
}
4.3、調用接口
重點注意了,頭中需要加上Content-Type: application/json
###?發(fā)送json數據,后端用對象接收
POST?http://localhost:8080/chat18/requestbody/test2
Content-Type:?application/json;charset=UTF-8
{
??"name":?"路人",
??"age":?35,
??"skills":?[
????"高并發(fā)",
????"Spring",
????"分布式事務",
????"MQ",
????"MySQL"
??]
}
4.4、控制臺輸出
user:User{name='路人',?age=35,?skills=[高并發(fā),?Spring,?分布式事務,?MQ,?MySQL]}
推薦閱讀:阿里技術大佬整理的《Spring 學習筆記.pdf》
5、案例 3:使用 Resource 資源對象接收
5.1、用法
有時候,我們想以流的方式接收 body 中的數據,那么可以參考下面的寫法,參數類型為[ByteArrayResource,InputStreamResource]這2種類型即可,第一種類型獲取的是一個字節(jié)數組,第二個是一個 InputStream 輸入流。
比如我們需要快速上傳文件到阿里云,那么接口接收到客戶端的流之后,直接將流轉發(fā)到 oss,效率更高。
/**
?*?參數為如果為?org.springframework.core.io.Resource?類型,
?*?則只能為Resource的[ByteArrayResource,InputStreamResource]這2種子類型:
?*
?*?@param?body
?*?@return
?*?@throws?IOException
?*/
@RequestMapping("/requestbody/test3")
public?String?test3(@RequestBody?InputStreamResource?body)?throws?IOException?{
????String?content?=?IOUtils.toString(body.getInputStream(),?"UTF-8");
????System.out.println("content:"?+?content);
????return?"ok";
}
5.2、調用接口
###?后端使用Resource接收數據
POST?http://localhost:8080/chat18/requestbody/test3
Content-Type:?text/plain;charset=UTF-8
后端使用Resource接收數據
5.3、控制臺輸出
content:后端使用Resource接收數據
6、案例 4:以字節(jié)數組接受數據
6.1、代碼
/**
?*?使用字節(jié)數組接收
?*
?*?@param?bodyBytes
?*?@return
?*/
@RequestMapping("/requestbody/test4")
public?String?test4(@RequestBody?byte[]?bodyBytes)?{
????System.out.println("body長度(bytes):"?+?bodyBytes.length);
????System.out.println("body內容:"?+?new?String(bodyBytes));
????return?"ok";
}
6.2、調用接口
###?后端使用字節(jié)數組接收數據
POST?http://localhost:8080/chat18/requestbody/test4
Content-Type:?text/plain;charset=UTF-8
itsoku.com
6.3、控制臺輸出
body長度(bytes):10
body內容:itsoku.com
推薦閱讀:2021 版 java 高并發(fā)常見面試題匯總.pdf
7、案例 5:使用 HttpEntity 接收數據
7.1、HttpEntity:含有頭和 body 信息
如果想同時拿到頭和 body 的數據,可以使用,org.springframework.http.HttpEntity來接收數據,這個類中包含了頭和 body 的信息,body 是一個泛型,http 請求的數據會被轉換為 body 對應的 T 類型。

7.2、案例代碼
注意:HttpEntity 類型的參數不要用@RequestBody 標注。
@RequestMapping("/requestbody/test5")
public?String?test5(HttpEntity?httpEntity) ?{
????//header信息
????HttpHeaders?headers?=?httpEntity.getHeaders();
????System.out.println("headers:"?+?headers);
????//body中的內容會自動轉換為HttpEntity中泛型指定的類型
????User?user?=?httpEntity.getBody();
????System.out.println("body:"?+?user);
????return?"ok";
}
7.3、調用案例接口
###?發(fā)送json數據,后端用HttpEntity接收
POST?http://localhost:8080/chat18/requestbody/test5
Content-Type:?application/json;charset=UTF-8
{
??"name":?"路人",
??"age":?35,
??"skills":?[
????"高并發(fā)",
????"Spring",
????"分布式事務",
????"MQ",
????"MySQL"
??]
}
7.4、控制臺輸出
headers:[content-type:"application/json;charset=UTF-8", content-length:"130", host:"localhost:8080", connection:"Keep-Alive", user-agent:"Apache-HttpClient/4.5.12 (Java/11.0.10)", accept-encoding:"gzip,deflate"]
body:User{name='路人', age=35, skills=[高并發(fā), Spring, 分布式事務, MQ, MySQL]}
推薦閱讀:Idea 快捷鍵大全.pdf
8、案例 6:使用 RequestEntity 接受數據
8.1、RequestEntity:包含更多請求信息(頭、method、url,body)
RequestEntity 的用法和案例 5 中的 HttpEntity 用法類似,RequestEntity 繼承了 HttpEntity,包含了更多的信息,比RequestEntity多了 2 個 http 請求信息(method 和 url)

8.2、案例代碼
@RequestMapping("/requestbody/test6")
public?String?test6(RequestEntity?requestEntity) ?{
????//請求方式
????HttpMethod?method?=?requestEntity.getMethod();
????System.out.println("method:"?+?method);
????//請求地址
????URI?url?=?requestEntity.getUrl();
????System.out.println("url:"?+?url);
????//body的類型,即RequestEntity后面尖括號中的類型
????Type?type?=?requestEntity.getType();
????System.out.println("body的類型,即RequestEntity后面尖括號中的類型:"?+?type);
????//header信息
????HttpHeaders?headers?=?requestEntity.getHeaders();
????System.out.println("headers:"?+?headers);
????//body中的內容會自動轉換為HttpEntity中泛型指定的類型
????User?user?=?requestEntity.getBody();
????System.out.println("body:"?+?user);
????return?"ok";
}
8.3、調用案例接口
###?發(fā)送json數據,后端用對象接收
POST?http://localhost:8080/chat18/requestbody/test6
Content-Type:?application/json;charset=UTF-8
{
??"name":?"路人",
??"age":?35,
??"skills":?[
????"高并發(fā)",
????"Spring",
????"分布式事務",
????"MQ",
????"MySQL"
??]
}
8.4、控制臺輸出
method:POST
url:http://localhost:8080/chat18/requestbody/test6
body的類型,即RequestEntity后面尖括號中的類型:class com.javacode2018.springmvc.chat18.controller.RequestBodyController$User
headers:[content-type:"application/json;charset=UTF-8", content-length:"130", host:"localhost:8080", connection:"Keep-Alive", user-agent:"Apache-HttpClient/4.5.12 (Java/11.0.10)", accept-encoding:"gzip,deflate"]
body:User{name='路人', age=35, skills=[高并發(fā), Spring, 分布式事務, MQ, MySQL]}
9、@RequestBody 還可以如何使用呢?
這里留給大家去研究,大家在運行一下案例 1 中的用例 1
###?發(fā)送純文本
POST?http://localhost:8080/chat18/requestbody/test1
Content-Type:?text/plain
這里是body部分,歡迎訪問我的博客:itsoku.com,上面有更多系列文章
控制臺有更詳細的輸出如下,注意里面的RequestResponseBodyMethodProcessor,這個就是@ReqeustBody類型的參數處理器,@ReqeustBody標注的參數的值都是有這個類來解析請求得到的,大家可以去看看這個類的代碼,debug 一番,就知道@ReqeustBody還有那些更炫的用法了。
23:17:05.595?[http-nio-8080-exec-9]?DEBUG?org.springframework.web.servlet.DispatcherServlet?-?POST?"/chat18/requestbody/test1",?parameters={}
23:17:05.595?[http-nio-8080-exec-9]?DEBUG?org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping?-?Mapped?to?com.javacode2018.springmvc.chat18.controller.RequestBodyController#test1(String)
23:17:05.596 [http-nio-8080-exec-9] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Read "text/plain;charset=UTF-8" to ["這里是body部分,歡迎訪問我的博客:itsoku.com,上面有更多系列文章"]
body:這里是body部分,歡迎訪問我的博客:itsoku.com,上面有更多系列文章
23:17:05.597?[http-nio-8080-exec-9]?DEBUG?org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor?-?Using?'text/plain',?given?[*/*]?and?supported?[text/plain,?*/*,?application/json,?application/*+json]
23:17:05.597?[http-nio-8080-exec-9]?DEBUG?org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor?-?Writing?["ok"]
23:17:05.598?[http-nio-8080-exec-9]?DEBUG?org.springframework.web.servlet.DispatcherServlet?-?Completed?200?OK
主要有 5 行日志,每行日志這里做一下解釋
第 1 行:接收到了請求,請求的信息(url,參數)
第 2 行:找到了能夠處理請求的方法,即 RequestBodyController#test1(String)方法可以處理當前請求
第 3 行:參數解析器,@RequestBody 對應的是 RequestResponseBodyMethodProcessor
第 4 行:接口中 System.out.println 輸出的內容
第 5 行:返回值處理器,這個以后會有專題講解
10、@RequestBody 原理
@RequestBody 標注的參數取值是由RequestResponseBodyMethodProcessor#resolveArgument方法處理的,可以去看源碼。
11、代碼位置及說明
11.1、git 地址
https://gitee.com/javacode2018/springmvc-series
11.2、本文案例代碼結構說明

12、SpringMVC 系列目錄
SpringMVC 系列第 1 篇:helloword SpringMVC 系列第 2 篇:@Controller、@RequestMapping SpringMVC 系列第 3 篇:異常高效的一款接口測試利器 SpringMVC 系列第 4 篇:controller 常見的接收參數的方式 SpringMVC 系列第 5 篇:@RequestBody 大解密,說點你不知道的 SpringMVC 系列第 6 篇:上傳文件的 4 種方式,你都會么? SpringMVC 系列第 7 篇:SpringMVC 返回視圖常見的 5 種方式,你會幾種? SpringMVC 系列第 8 篇:返回 json & 通用返回值設計 SpringMVC 系列第 9 篇:SpringMVC 返回 null 是什么意思? SpringMVC 系列第 10 篇:異步處理 SpringMVC 系列第 11 篇:集成靜態(tài)資源 SpringMVC 系列第 12 篇:攔截器 SpringMVC 系列第 13 篇:統(tǒng)一異常處理 SpringMVC 系列第 14 篇:實戰(zhàn)篇:通用返回值 & 異常處理設計 SpringMVC 系列第 15 篇:全注解的方式 ?&? 原理解析 SpringMVC 系列第 16 篇:通過源碼解析 SpringMVC 處理請求的流程 SpringMVC 系列第 17 篇:源碼解析 SpringMVC 容器的啟動過程 SpringMVC 系列第 18 篇:強大的 RequestBodyAdvice 解密 SpringMVC 系列第 19 篇:強大的 ResponseBodyAdvice 解密 SpringMVC 系列第 20 篇:RestFull 詳解 SpringMVC 系列第 21 篇:接口調用過利器 RestTemplate SpringMVC 系列第 22 篇:參數解析器 HandlerMethodArgumentResolver 解密 SpringMVC 系列第 23 篇:@RequestParam 用法及原理詳解
13、更多系列文章
Spring 高手系列(共 56 篇) Java 高并發(fā)系列(共 34 篇) MySql 高手系列(共 27 篇) Maven 高手系列(共 10 篇) Mybatis 系列(共 12 篇) 聊聊 db 和緩存一致性常見的實現(xiàn)方式 接口冪等性這么重要,它是什么?怎么實現(xiàn)? 泛型,有點難度,會讓很多人懵逼,那是因為你沒有看這篇文章!
14、最新資料
尚硅谷 Java 學科全套教程(總 207.77GB) 2021 最新版 Java 微服務學習線路圖 + 視頻 阿里技術大佬整理的《Spring 學習筆記.pdf》 阿里大佬的《MySQL 學習筆記高清.pdf》 2021 版 java 高并發(fā)常見面試題匯總.pdf Idea 快捷鍵大全.pdf
