如下將介紹application/json
,multipart/form-data
,application/x-www-form-urlencoded
三種 Content-Type 傳參狀況下,Spring MVC 控制器中參數綁定的方式。
這裏主要介紹三種 Content-Type:前端
multipart/form-data
請求中既能夠攜帶文件,又能夠攜帶參數。其中參數以鍵值對的方式傳遞,參數之間、參數與文件之間以 content-disposition
分隔;application/x-www-form-urlencoded
只能上傳參數,不能攜帶文件,參數經過 ?xxx=xxx&xxx=xxx
的方式被組織在一塊兒;application/json
只能上傳參數,不能攜帶文件,參數不被特殊組織,保持原 JSON 字符串的形式。在前端發送請求時,咱們能夠經過瀏覽器看到請求的參數。在瀏覽器調試工具中,參數欄會有多種標題:jquery
當使用 GET 方式提交請求時,採用這一標題spring
當使用 application/json 方式提交時,採用這一標題chrome
當使用 multipart/form-data
或 application/x-www-form-urlencoded
方式提交時,採用這一標題,注意這兩種 form-data 的區別。json
這裏採用嵌套數據以下:數組
{ "username": "dailybird", "password": "dailybirdo", "ids": [1,2,3], "detail": { "gender": "male", "location": "Beijing", "ids": [4,5,6] } }
注:與文件上傳相關的參數後面會單獨提到,這裏先進行非文件參數提交的實驗。瀏覽器
這裏,仿照請求參數的格式建立 User
對象,咱們試圖將請求參數綁定到該對象上。這裏使用 Lombok
來減小 setter
的建立:app
@ToString @Data public class User { private String username; private String password; private List<Integer> ids; private Detail detail; @Data public static class Detail { private String gender; private String location; private List<Integer> ids; } }
控制器代碼以下:框架
@RequestMapping(value = "/application/json") public String applicationJson(@RequestBody User user) { log.info("{}", user.toString()); return user.toString(); }
當使用 POST,並攜帶 Content-Type: application/json
頭髮送請求時,控制器可以徹底解析嵌套的參數。函數
注:因爲 @RequestBody 自己是調用 HttpMessageConverter
解析請求體中的數據,而 GET 方式的參數不會存在於請求體中,因此 @RequestBody 不能處理 GET 方式的請求。
控制器代碼以下:
public String xWwwFormUrlencoded(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("ids")List<Integer> ids, @RequestParam("detail") Detail detail) { log.info("{}, {}, {}, {}", username, password, ids, detail); return ""; }
其中 Detail 類爲與以前 User 內部類等同的類。
這裏咱們藉助 jquery 的相關函數進行測試:
$.post("http://localhost:8083/application/x-www-form-urlencoded", { "username": "aaa", "password": "bbb", "ids": [1,2,3], "detail": { "gender": "ccc", "location": "ddd", "ids": [4,5,6] } })
而後咱們收到了以下提示:
Required List parameter 'ids' is not present
但咱們確實已經發送了 ids
參數,爲何沒有獲取到呢?這一點咱們放到以後再談,先試一下 multipart/form-data 的方式。
固然,採用這一方式,咱們會收到一樣的提示:
Required List parameter 'ids' is not present
讓咱們在瀏覽器的開發者工具中看一看請求參數實際的樣子:
不一樣於 PHP 框架 Laravel,@RequestParam 並不會將 ids[]
之類的數組類參數和 detail[xxx]
之類的嵌套參數進行重組。於是,控制器會認爲收到了 ids[]
參數,而不是 ids
參數,同理也適用於嵌套參數。
那咱們該怎麼作的?我在 Stack Overflow 上獲得瞭解答,咱們能夠採用如下方法之一:
ids[]
改成 ids
傳參,即 ids=1&ids=2&...
的方式( 注意對比上圖 ),將嵌套類參數 detail[gender]
等改成 detail.gender
;注:在 Spring MVC 中,咱們能夠不書寫 @RequestParam,直接使用相與請求參數同名的變量進行接收( 或直接使用一個 POJO 對象 ),但該方式也存在着與以上相同的問題。
最開始已經說過,若要上傳文件,在上述三種 Content-Type 中,只能使用 multipart/form-data,在注意到 2.2 中所提到的問題後,咱們即可以經過 MultipartFile
類型的屬性來獲取到文件參數了。
從 Laravel 過渡到 Spring Boot,確實感到了在控制器層面兩者的差別( 固然在 DAO 層更是如此 ),如下給出一個列表,用以記念本身踩的坑: