问题
最近遇到个需求,需要将一个对象数组从前端用ajax传递给后端的Spring MVC Controller,例如传递如下数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
其中locale是一个字符串,products是一个对象数组。该对象的attributes属性名是不固定的,例如有的产品的attributes是volume+color,而有的则是size+color;所以这个attributes属性我们用Map来表示。
传递基本数组
首先看看如何传递基本类型数组,例如Long[]。
在后端接收该参数时很简单,只需要使用Long[]类型的@RequestParam即可,例如:
1 2 3 4 5 6 7 |
|
前端代码如下:
1 2 3 4 5 6 7 8 9 10 11 |
|
关于traditional: true
注意ajax中有个参数traditional: true
,网上很多文章说只有这样才能让Java后台识别数组参数,但貌似并非如此。
traditional默认值为false,jquery会深度序列化参数对象,以适应如PHP和Ruby on Rails框架。序列化后的格式为:
1 2 3 |
|
但servelt api无法处理,我们可以通过设置traditional: true阻止深度序列化,这样序列化结果如下:
1 2 3 |
|
区别仅仅是参数名不一样,那么是否将后台的@RequestParam(value="objectValues")
改成@RequestParam(value="objectValues[]")
,就能接收traditional:false的参数了呢?测试下来貌似确实是可以的!
传递Map
前文说到要传递的对象中有个Map属性,那么如果只仅仅传递Map参数应该怎么做呢?如果直接使用Map类型的RequestParam,例如@RequestParam(required = false) Map<String, String> params
,那么这个params参数实际是所有传入参数的集合。如果我们发送的参数是:
1 2 3 4 5 6 7 |
|
那么接收到的params为:
可见这个params里不仅有attributes这个Map,还有其他参数。
如果要让params仅仅包含我们关心的attributes map改怎么处理呢?我们需要自己新建一个Wrapper类:
1 2 3 4 |
|
然后在Controller方法参数里这样写:
1
|
|
传递对象数组
前面讲了如何传递基本数组和Map,那么现在问题来了,如何才能传递对象数组呢?
网络上能找到一些方法,例如下面这两个:
- http://stackoverflow.com/questions/14459171/spring-mvc-and-jquery-post-request-with-array-of-pojo
- http://stackoverflow.com/questions/17987234/passing-json-array-from-javascript-to-spring-mvc-controller
基本思路是通过@RequestBody
来获取Map,但是我在本地没有测试成功,可能原因是这里输入的并不是单一的数组,还有一个和数组并列的locale变量。
HttpServletRequest + GSon
可以利用HttpServletRequest获取传回的string,然后利用Gson转换为对象。
1 2 3 4 5 6 7 |
|
这里为参数对象写了一个Wrapper类:
1 2 3 4 5 6 7 8 9 10 |
|
这样就能成功接收本文开头那种对象数组参数了。
@RequestBody
HttpServletRequest方法显得太过于底层,过于面向细节。上文说到因为和数组并列有个locale变量,导致无法使用@RequestBody,那是否可以通过修改API输入参数的设计来解决呢,把locale变量放到ParameterWrapper
中是否就可以使用@RequestBody了呢?
当然可以,代码如下:
1 2 3 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
如果不能移动locale的位置该怎么办呢?可以再建一个类,其中包含两个变量:
- ParameterWrapper[]
- String locale
总结
本文讨论了如何往Spring MVC Controller中传入基本数组、传入Map、传入对象数组。当遇到技术瓶颈时,不妨换个思路,有时修改一下设计就能豁然开朗。