精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-11-10
最后修改:2012-11-12
SpringMVC 3.1 提供了HandlerMethodArgumentResolver以支持更灵活的自定义的数据绑定方式。
扩展SpringMVC以支持更精准的数据绑定
问题描述: springMVC 数据绑定 多个对象 如何准确绑定?
<form> <input name="student.name" value="Kate" /> <input name="student.type" value="自费" /> <input name="teacher.name" value="Gavin" /> <input name="teacher.level" value="2" /> </form> @RequestMapping("/school.do") public String school(Student student, Teacher teacher) { return "school"; } 如果还是想刚才的jsp那些写表单,是不能封装参数的,必须把“student.”和“teacher.”去掉,但是这样封装就不能准确封装了。
这个问题最近老是有人问,所以写一个扩展很容易解决这个问题,springmvc和spring一样,预留的扩展点足够多。
我们都知道struts2默认就是这种方案,这是因为struts2采用了OGNL,并通过栈(根对象)进行操作的,而且栈中默认有action实例,所以很自然的没有这种问题。 springmvc不同,没有根对象的概念,而且本身很难来解决这个问题,因此大家在使用时最好避免这种方式或者使用类似于struts1的FormBean组合对象来解决。
解决方案: 扩展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用于注入自定义的参数解析器,此处我们注了FormModelMethodArgumentResolver;FormModelMethodArgumentResolver我直接修改的org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;
3、使用方式 public String user(@FormModel("student") Student student, @FormModel("teacher") Teacher teacher)
4、测试控制器 package cn.javass.chapter6.web.controller.formmodel; import java.util.Arrays; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import cn.javass.chapter6.model.UserModel; import cn.javass.spring.mvc.bind.annotation.FormModel; import cn.javass.spring.mvc.util.MapWapper; @Controller @RequestMapping("/formmodel") public class FormModelController { //ok http://localhost:9080/springmvc-chapter6/formmodel/user?user.username=zhang&user.password=123 @RequestMapping("/user/{user.realname}") public String user(@FormModel("user") UserModel user) { System.out.println(user); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/array1?array[0]=zhang&array[1]=li @RequestMapping("/array1") public String array1(@FormModel("array") String[] array) { System.out.println(Arrays.toString(array)); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/array2?array[0].username=zhang&array[0].password=123&array[1].username=li @RequestMapping("/array2") public String array2(@FormModel("array") UserModel[] array) { System.out.println(Arrays.toString(array)); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/list1?list[0]=123&list[1]=234 @RequestMapping("/list1") public String list1(@FormModel("list") List<Integer> list) { System.out.println(list); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/list2?list[0].username=zhang&list[1].username=li @RequestMapping("/list2") public String list2(@FormModel("list") List<UserModel> list) { System.out.println(list); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/map1?map['0']=123&map["1"]=234 @RequestMapping("/map1") public String map1(@FormModel("map") MapWapper<String, Integer> map) { System.out.println(map); return "redirect:/success"; } //ok http://localhost:9080/springmvc-chapter6/formmodel/map2?map['0'].password=123&map['0'].username=123&map["1"].username=234 @RequestMapping("/map2") public String map2(@FormModel("map") MapWapper<Integer, UserModel> map) { System.out.println(map); return "redirect:/success"; } }
具体使用可以下载之前springmvc第六章源代码http://jinnianshilongnian.iteye.com/blog/1683388 将附件中的FormModel.rar解压放到src下进行测试。
支持的spring版本: springmvc 3.1.x,暂不支持3.0。为什么不支持呢?springmvc 3.1 和 3.0 从架构上发生了变化,而且springmvc3.1更容易扩展。
支持绑定的数据: 模型、集合、数组、MapWapper(Map的一个包装器,通过getInnerMap获取真实Map)
缺点: spring自定义的参数解析器会放在默认解析器之后,不能指定order,因此如果我们@FormModel("map") Map map,此map会变成Model(请参考http://jinnianshilongnian.iteye.com/blog/1698916 第六部分、Model Map ModelMap),希望未来的版本支持自定义顺序来解决这个问题;此处我们使用MapWapper解决,可以通过MapWapper.getInnerMap()拿到我们需要的Map
其他方案: [SpringMVC]修改源码使之能够更加智能的自动装配request请求参数.(不建议修改源代码解决) @rainsoft 也给出了类似的方案, http://www.iteye.com/topic/1124433#2357830
欢迎大家反馈问题,我会及时修正。
下一个扩展: 绑定请求参数(JSON字符串,如 deptIds=[{"deptId":4,"isPrimary":true}] ) 到 模型对象。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-11-10
最后修改:2012-11-12
扩展SpringMVC以支持绑定JSON格式的请求参数
此方案是把请求参数(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数据校验。
欢迎大家反馈问题,我会及时修正。
|
|
返回顶楼 | |
浏览 13641 次