当前位置: 代码迷 >> JavaScript >> 扩张SpringMVC以支持绑定JSON格式的请求参数
  详细解决方案

扩张SpringMVC以支持绑定JSON格式的请求参数

热度:388   发布时间:2012-11-23 22:54:33.0
扩展SpringMVC以支持绑定JSON格式的请求参数

?

上一篇:《扩展SpringMVC以支持更精准的数据绑定》

?

此方案是把请求参数(JSON字符串)绑定到java对象,,@RequestBody是绑定内容体到java对象的。


问题描述:

你好,对于如下的json数据,springmvc的数据绑定该如何做? 
accessionDate	2012-11-21 
deptIds	[{"deptId":4,"isPrimary":true}] 
email	ewer@dsfd.com 
fax	3423432 
gender	true 
其实就是我前台一表单提交的数据,extjs form提交的,关键在于deptIds的映射,数组不知怎么解决,还有就是springmvc的数据绑定好像要求javabean与json中的数据一一对应,否则也会出错


?如请求参数是deptIds={"deptId":4,"isPrimary":true}] ?是一个json数组,此时需要绑定为一个对象,该如何实现呢?


解决方案:

类似于之前写的《扩展SpringMVC以支持更精准的数据绑定》,扩展spring的HandlerMethodArgumentResolver以支持自定义的数据绑定方式。


1、请下载附件的代码,放到工程中;

2、在RequestMappingHandlerAdapter添加自定义HandlerMethodArgumentResolver Bean;

     <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> 
        <!--线程安全的访问session-->
         <property name="synchronizeOnSession" value="true"/> 
         <property name="customArgumentResolvers">
            <list>
               <bean class="cn.javass.spring.mvc.method.annotation.RequestJsonParamMethodArgumentResolver"/>
               <bean class="cn.javass.spring.mvc.method.annotation.FormModelMethodArgumentResolver"/>
            </list>
         </property>
     </bean>  

??//customArgumentResolvers用于注入自定义的参数解析器,此处我们注入了RequestJsonParamMethodArgumentResolver

3、使用方式

@RequestMapping("/list")  
public String list(@RequestJsonParam("list") List<Integer> list) 

?

4、测试控制器

package cn.javass.chapter6.web.controller.jsonparam;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import cn.javass.chapter6.model.DataBinderTestModel;
import cn.javass.chapter6.model.UserModel;
import cn.javass.spring.mvc.bind.annotation.RequestJsonParam;
import cn.javass.spring.mvc.util.MapWapper;


@Controller
@RequestMapping("/jsonparam")  
public class JsonParamController {

    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/list?list=[1,2,34]
    //fail http://localhost:9080/springmvc-chapter6/jsonparam/list?list=[1,2,a]
    @RequestMapping("/list")  
    public String list(@RequestJsonParam("list") List<Integer> list) {
        System.out.println(list);
        return "redirect:/success";        
    }
    
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/set?set=[1,2,34]
    //fail http://localhost:9080/springmvc-chapter6/jsonparam/set?set=[1,2,a]
    @RequestMapping("/set")  
    public String set(@RequestJsonParam("set") Set<Integer> set) {
        System.out.println(set);
        return "redirect:/success";        
    }
    
    
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/array?array=[1,2,3]
    //fail http://localhost:9080/springmvc-chapter6/jsonparam/array?array=[1,2,a]
    @RequestMapping("/array")  
    public String list(@RequestJsonParam("array") int[] array) {
        System.out.println(Arrays.toString(array));
        return "redirect:/success";        
    }
    
    
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/map?map={"a":1, "b":2}
    //fail http://localhost:9080/springmvc-chapter6/jsonparam/map?map={"a":1, "b":a}
    @RequestMapping("/map")  
    public String map(@RequestJsonParam(value = "map", required=false) MapWapper<String, Integer> map) {
        System.out.println(map);
        return "redirect:/success";        
    }
    
    
    //UserModel[]
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/array2?array=[{"username":"123"},{"username":"234"}]
    @RequestMapping("/array2")  
    public String array2(@RequestJsonParam(value = "array") UserModel[] array) {
        System.out.println(Arrays.toString(array));
        return "redirect:/success";        
    }

    //List<UserModel>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/list2?list=[{"username":"123"},{"username":"234"}]
    @RequestMapping("/list2")  
    public String list2(@RequestJsonParam(value = "list") List<UserModel> list) {
        System.out.println(list);
        return "redirect:/success";        
    }

    //Set<UserModel>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/set2?set=[{"username":"123"},{"username":"234"}]
    @RequestMapping("/set2")  
    public String set2(@RequestJsonParam(value = "set") Set<UserModel> set) {
        System.out.println(set);
        return "redirect:/success";        
    }
    
    //Map<String, UserModel>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/map2?map={"a":{"username":"123"},"b":{"username":"234"}}
    //暂不支持 Map<UserModel, UserModel>
    @RequestMapping("/map2")  
    public String map2(@RequestJsonParam(value = "map") MapWapper<String, UserModel> map) {
        System.out.println(map);
        return "redirect:/success";        
    }
    
    
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model1?model={"username":123,"password":234,"realname":"zhang","workInfo":{"city":"abc","job":"abc","year":"abc"}, "schoolInfo":{"schoolType":"1","schoolName":"1","specialty":"1"}}
    //没有realname1
    //fail http://localhost:9080/springmvc-chapter6/jsonparam/model1?model={"username":123,"password":234,"realname1":123}
    @RequestMapping("/model1")  
    public String model1(@RequestJsonParam(value = "model", required=true) UserModel user) {
        System.out.println(user);
        return "redirect:/success";        
    }
    
    //ENUM
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model2?model={"state":"normal"}
    //List<基本类型>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model2?model={"hobbyList":["film", "music"]}
    //Map<基本类型,基本类型>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model2?model={"map":{"key":"value", "a":"b"}}    
    @RequestMapping("/model2")  
    public String model2(@RequestJsonParam(value = "model", required=true) DataBinderTestModel model) {
        System.out.println(model);
        return "redirect:/success";        
    }
    
    //List<UserModel>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model3?model={"userList":[{"username":"1"},{"username":"2"}]}
    //Map<String,UserModel>
    //ok   http://localhost:9080/springmvc-chapter6/jsonparam/model3?model={"userMap":{"1":{"username":"1"},"2":{"username":"2"}}}

    //暂不支持 类似于 Map<UserModel, UserModel> 形式
    @RequestMapping("/model3")  
    public String model3(@RequestJsonParam(value = "model") DataBinderTestModel model) {
        System.out.println(model);
        return "redirect:/success";        
    }
    
}

?

支持的spring版本:

springmvc 3.0 和 3.1.x。

?

支持绑定的数据:

模型、集合、数组、MapWapper(Map的一个包装器,通过getInnerMap获取真实Map)


暂时不支持JSR-303数据校验.

?

缺点:

1、和《扩展SpringMVC以支持更精准的数据绑定》一样的缺点。

spring自定义的参数解析器会放在默认解析器之后,不能指定order,因此如果我们@FormModel("map") Map map,此map会变成Model(请参考http://jinnianshilongnian.iteye.com/blog/1698916?第六部分、Model Map ModelMap),希望未来的版本支持自定义顺序来解决这个问题;此处我们使用MapWapper解决,可以通过MapWapper.getInnerMap()拿到我们需要的Map。

2、支持的jackson版本是1.4.2,版本比较老,spring3.2里程碑版已升级到2.x。

3、暂时没有提供JSR303数据校验。

?

欢迎大家反馈问题,我会及时修正。

?

?

?

支持一下博主:------------------------------------------

http://blog.51cto.com/contest2012/2058573

--------------------------


1 楼 char1st 2012-11-08  
博主 ,早上好。 这个和springmvc自带的@responseBody  和@requestBody 比起来,处理简单的json的请求和响应那个好点?
2 楼 jinnianshilongnian 2012-11-08  
char1st 写道
博主 ,早上好。 这个和springmvc自带的@responseBody  和@requestBody 比起来,处理简单的json的请求和响应那个好点?

@requestBody  绑定请求的内容体部分 不是参数部分 不要混淆
3 楼 7454103 2012-11-08  
同样给出另外一种方案:
使用@RequestBody绑定请求对象,Spring会帮你进行协议转换,将Json、Xml协议转换成你需要的对象。

4 楼 jinnianshilongnian 2012-11-08  
7454103 写道
同样给出另外一种方案:
使用@RequestBody绑定请求对象,Spring会帮你进行协议转换,将Json、Xml协议转换成你需要的对象。


这个是绑定请求内容体的,不是请求参数, 我这个是把请求参数绑定到json对象
5 楼 thc1987 2012-11-08  
支持一个,如果我用ajax post方式也是可以的吧?
6 楼 jinnianshilongnian 2012-11-08  
thc1987 写道
支持一个,如果我用ajax post方式也是可以的吧?

当然支持, 只要是请求参数即可
7 楼 vvvpig 2012-11-08  
jinnianshilongnian 写道
7454103 写道
同样给出另外一种方案:
使用@RequestBody绑定请求对象,Spring会帮你进行协议转换,将Json、Xml协议转换成你需要的对象。


这个是绑定请求内容体的,不是请求参数, 我这个是把请求参数绑定到json对象

就是只支持Post操作不支持get操作
8 楼 jinnianshilongnian 2012-11-08  
vvvpig 写道
jinnianshilongnian 写道
7454103 写道
同样给出另外一种方案:
使用@RequestBody绑定请求对象,Spring会帮你进行协议转换,将Json、Xml协议转换成你需要的对象。


这个是绑定请求内容体的,不是请求参数, 我这个是把请求参数绑定到json对象

就是只支持Post操作不支持get操作

我说的不明白,都支持。
9 楼 char1st 2012-11-08  
jinnianshilongnian 写道
char1st 写道
博主 ,早上好。 这个和springmvc自带的@responseBody  和@requestBody 比起来,处理简单的json的请求和响应那个好点?

@requestBody  绑定请求的内容体部分 不是参数部分 不要混淆

哦 了解了  说句题外话吧 。我总觉得把json字符串作为请求的参数值这种方式很蛋疼。
10 楼 jinnianshilongnian 2012-11-08  
char1st 写道
jinnianshilongnian 写道
char1st 写道
博主 ,早上好。 这个和springmvc自带的@responseBody  和@requestBody 比起来,处理简单的json的请求和响应那个好点?

@requestBody  绑定请求的内容体部分 不是参数部分 不要混淆

哦 了解了  说句题外话吧 。我总觉得把json字符串作为请求的参数值这种方式很蛋疼。

是,哈哈,有时候确实有人需要,我就写了一个
11 楼 key232323 2012-11-08  
我个人觉得request form式的key-value方式不如这种json传递――js端组装复杂对象已经很成熟了,服务端只要关注绑定和一般校验就可以了

但spring的这种做法麻烦而且只是简单的数据类型支持,还不如用字符串,通过一个json库解析下,然后再转换成java集合对象或自定义对象

BS:动态语言更简练些,LZ为何不去了解下groovy之类?
12 楼 jinnianshilongnian 2012-11-08  
key232323 写道
我个人觉得request form式的key-value方式不如这种json传递――js端组装复杂对象已经很成熟了,服务端只要关注绑定和一般校验就可以了

但spring的这种做法麻烦而且只是简单的数据类型支持,还不如用字符串,通过一个json库解析下,然后再转换成java集合对象或自定义对象

BS:动态语言更简练些,LZ为何不去了解下groovy之类?

嗯,此处只是springmvc个别案例(之前有朋友非要绑定json请求参数到对象,所以写了一个扩展),从实用性角度看:此场景应用极少,一般都可以通过改造。

但spring的这种做法麻烦而且只是简单的数据类型支持,还不如用字符串,通过一个json库解析下,然后再转换成java集合对象或自定义对象:现在我加的这个扩展,支持复杂类型(缺点是不支持Map[因为无法指定解析器order造成的])
13 楼 jayuton 2012-11-08  
spring本身就支持JSON,多此一举
14 楼 jinnianshilongnian 2012-11-08  
jayuton 写道
spring本身就支持JSON,多此一举

支持的是内容体绑定  不支持参数是json字符串的绑定
  相关解决方案