如下将介绍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 层更是如此 ),如下给出一个列表,用以记念本身踩的坑: