分享

扩展SpringMVC以支持更精准的数据绑定1

 贾朋亮博客 2015-03-19

最新版请点击查看FormModelMethodArgumentResolver.java 

 

问题描述:

springMVC 数据绑定 多个对象 如何准确绑定?

Java代码  收藏代码
  1. <form>  
  2.   
  3.     <input name="student.name" value="Kate" />  
  4.   
  5.     <input name="student.type" value="自费" />  
  6.   
  7.     <input name="teacher.name" value="Gavin" />  
  8.   
  9.     <input name="teacher.level" value="2" />  
  10.   
  11. </form>  
Java代码  收藏代码
  1. @RequestMapping("/school.do")  
  2.   
  3. public String school(Student student, Teacher teacher) {  
  4.   
  5.      return "school";  
  6.   
  7. }  

如果还是想刚才的jsp那些写表单,是不能封装参数的,必须把“student.”和“teacher.”去掉,但是这样封装就不能准确封装了。

 

这个问题最近老是有人问,所以写一个扩展很容易解决这个问题,springmvc和spring一样,预留的扩展点足够多。

 

我们都知道struts2默认就是这种方案,这是因为struts2采用了OGNL,并通过栈(根对象)进行操作的,而且栈中默认有action实例,所以很自然的没有这种问题。

springmvc不同,没有根对象的概念,而且本身很难来解决这个问题,因此大家在使用时最好避免这种方式或者使用类似于struts1的FormBean组合对象来解决。

 

解决方案:

扩展spring的HandlerMethodArgumentResolver以支持自定义的数据绑定方式。

 

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

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

Java代码  收藏代码
  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">   
  2.    <!--线程安全的访问session-->  
  3.     <property name="synchronizeOnSession" value="true"/>   
  4.     <property name="customArgumentResolvers">  
  5.        <list>  
  6.           <bean class="cn.javass.spring.mvc.method.annotation.RequestJsonParamMethodArgumentResolver"/>  
  7.           <bean class="cn.javass.spring.mvc.method.annotation.FormModelMethodArgumentResolver"/>  
  8.        </list>  
  9.     </property>  
  10. </bean>    

 //customArgumentResolvers用于注入自定义的参数解析器,此处我们注了FormModelMethodArgumentResolver;FormModelMethodArgumentResolver我直接修改的org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

 

3、使用方式

Java代码  收藏代码
  1. public String user(@FormModel("student") Student student, @FormModel("teacher") Teacher teacher)   

 

4、测试控制器

Java代码  收藏代码
  1. package cn.javass.chapter6.web.controller.formmodel;  
  2.   
  3. import java.util.Arrays;  
  4. import java.util.List;  
  5.   
  6. import org.springframework.stereotype.Controller;  
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8.   
  9. import cn.javass.chapter6.model.UserModel;  
  10. import cn.javass.spring.mvc.bind.annotation.FormModel;  
  11. import cn.javass.spring.mvc.util.MapWapper;  
  12.   
  13.   
  14. @Controller  
  15. @RequestMapping("/formmodel")    
  16. public class FormModelController {  
  17.   
  18.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/user?user.username=zhang&user.password=123  
  19.     @RequestMapping("/user/{user.realname}")    
  20.     public String user(@FormModel("user") UserModel user) {  
  21.         System.out.println(user);  
  22.         return "redirect:/success";          
  23.     }  
  24.       
  25.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/array1?array[0]=zhang&array[1]=li  
  26.     @RequestMapping("/array1")    
  27.     public String array1(@FormModel("array") String[] array) {  
  28.         System.out.println(Arrays.toString(array));  
  29.         return "redirect:/success";          
  30.     }  
  31.       
  32.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/array2?array[0].username=zhang&array[0].password=123&array[1].username=li  
  33.     @RequestMapping("/array2")    
  34.     public String array2(@FormModel("array") UserModel[] array) {  
  35.         System.out.println(Arrays.toString(array));  
  36.         return "redirect:/success";          
  37.     }  
  38.       
  39.       
  40.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/list1?list[0]=123&list[1]=234  
  41.     @RequestMapping("/list1")    
  42.     public String list1(@FormModel("list") List<Integer> list) {  
  43.         System.out.println(list);  
  44.         return "redirect:/success";          
  45.     }  
  46.       
  47.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/list2?list[0].username=zhang&list[1].username=li  
  48.     @RequestMapping("/list2")    
  49.     public String list2(@FormModel("list") List<UserModel> list) {  
  50.         System.out.println(list);  
  51.         return "redirect:/success";          
  52.     }  
  53.       
  54.     //ok   http://localhost:9080/springmvc-chapter6/formmodel/map1?map['0']=123&map["1"]=234  
  55.     @RequestMapping("/map1")    
  56.     public String map1(@FormModel("map") MapWapper<String, Integer> map) {  
  57.         System.out.println(map);  
  58.         return "redirect:/success";          
  59.     }  
  60.   //ok   http://localhost:9080/springmvc-chapter6/formmodel/map2?map['0'].password=123&map['0'].username=123&map["1"].username=234  
  61.     @RequestMapping("/map2")    
  62.     public String map2(@FormModel("map") MapWapper<Integer, UserModel> map) {  
  63.         System.out.println(map);  
  64.         return "redirect:/success";          
  65.     }  
  66. }  

 

具体使用可以下载之前springmvc第六章源代码http://jinnianshilongnian./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./blog/1698916 第六部分、Model Map ModelMap),希望未来的版本支持自定义顺序来解决这个问题;此处我们使用MapWapper解决,可以通过MapWapper.getInnerMap()拿到我们需要的Map

 

其他方案:

[SpringMVC]修改源码使之能够更加智能的自动装配request请求参数.(不建议修改源代码解决)

@rainsoft 也给出了类似的方案, http://www./topic/1124433#2357830

 

如果你使用的是mvc:annotation-driven,请这样配置

Java代码  收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:argument-resolvers>  
  3.            <bean class="com.sishuok.es.common.web.bind.method.annotation.FormModelMethodArgumentResolver"/>  
  4.        </mvc:argument-resolvers>  
  5. </mvc:annotation-driven>  

  

 

 

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

 

 

下一个扩展: 绑定请求参数(JSON字符串,如 deptIds=[{"deptId":4,"isPrimary":true}] ) 到 模型对象。

 

 

15 
2 
分享到:  
评论
45 楼 blademainer 2014-11-14  
你好,请问一下BindingResult支持吗?如果我按照平时用的话会报错:
@RequestMapping(value = "/test")
    public void binderTest(@Valid @FormModel("user")User user, BindingResult bindingResult)
错误:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public void com.kingray.web.UserController.binderTest(com.xiongyingqi.hibernate.domain.User,org.springframework.validation.BindingResult)
44 楼 edison87915 2014-09-23  
请问,对于包含复杂类型对象的对象, spring 不能用"."来表示层级关系进行值的自动绑定吗?
我觉得 spring 应该可以吧
看这篇:http://www./topic/973918

这样的话,如果要在提交一个表单的过程中,给两个平级(不是父子关系)的对象分别绑定自己的表单数据,可以把这两个对象封装到一个对象中,这样就可以使用 "." 来分层级绑定、或精准绑定了?
43 楼 lping2 2014-07-15  
有个问题:
tmainVo[0].prePolicy=1&tmainVo[1].prePolicy=2 可以装载到  @FormModel("tmainVo") List<PrpTmainVo> tmainVoList;
但是一般多行编辑的时候,序号0,1,不会赋值上去,能不能将tmainVo.prePolicy=1&tmainVo.prePolicy=2 也能自动装载为List
42 楼 LinApex 2014-06-26  
为什么不使用拦截器解决问题.
41 楼 DS_Mars 2014-04-30  
DS_Mars 写道
此问题还可以如此解决 侵入性更小
首先 自定义注解ExtModelAttribute 
Java代码  收藏代码
  1. import java.lang.annotation.Documented;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. /** 
  8.  */  
  9. @Target({ElementType.PARAMETER, ElementType.METHOD})  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Documented  
  12. public @interface ExtModelAttribute {  
  13.   
  14.     String value() default "";  
  15.   
  16. }  


然后利用方法
Java代码  收藏代码
  1. void org.springframework.web.bind.WebDataBinder.setFieldDefaultPrefix(String fieldDefaultPrefix)  
在对应自定义注解ExtModelAttribute的处理器ExtServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder binder, NativeWebRequest request)
改变默认前缀
不过到3.2.8 还是有点小问题 前缀后面要加一个字符 比如“.”
以下是自定义注解对应处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. import javax.servlet.ServletRequest;  
  2.   
  3. import org.springframework.core.MethodParameter;  
  4. import org.springframework.web.bind.ServletRequestDataBinder;  
  5. import org.springframework.web.bind.WebDataBinder;  
  6. import org.springframework.web.bind.annotation.ModelAttribute;  
  7. import org.springframework.web.context.request.NativeWebRequest;  
  8. import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;  
  9. import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;  
  10.   
  11. public class ExtServletModelAttributeMethodProcessor extends ServletModelAttributeMethodProcessor  
  12.  {  
  13.     public ExtServletModelAttributeMethodProcessor(){  
  14.         super(false);   
  15.     }  
  16.   
  17.     public ExtServletModelAttributeMethodProcessor(boolean annotationNotRequired) {  
  18.         super(annotationNotRequired);  
  19.     }  
  20.   
  21.         @Override  
  22.     public boolean supportsParameter(MethodParameter parameter) {  
  23.         if (parameter.hasParameterAnnotation(ExtModelAttribute.class)) {  
  24.             return true;  
  25.         }  
  26.         else{  
  27.             return false;  
  28.         }  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {  
  33.         ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);  
  34.         ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;  
  35. servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+".");  
  36.         servletBinder.bind(servletRequest);;  
  37.     }  


加入自定义注解ExtModelAttribute 的处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:argument-resolvers>  
  3.         <bean class="ExtServletModelAttributeMethodProcessor"/>  
  4.     </mvc:argument-resolvers>  
  5. </mvc:annotation-driven>  


控制器中使用
Java代码  收藏代码
  1.        @RequestMapping(value="/test")  
  2. public String ftl(@ExtModelAttribute("testVo")TestVo testVo){  
  3.     System.out.println(testVo.getValue());  
  4.     return "test";  
  5. }  


页面使用
Java代码  收藏代码
  1. <form action="" method="post">  
  2. Date Inpout<Input id="value" name="testVo.value" value="${testVo.value}" />  
  3.     <input type="submit" value="submit">  
  4. </form>  





DS_Mars 写道
此问题还可以如此解决 侵入性更小
首先 自定义注解ExtModelAttribute 
Java代码  收藏代码
  1. import java.lang.annotation.Documented;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. /** 
  8.  */  
  9. @Target({ElementType.PARAMETER, ElementType.METHOD})  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Documented  
  12. public @interface ExtModelAttribute {  
  13.   
  14.     String value() default "";  
  15.   
  16. }  


然后利用方法
Java代码  收藏代码
  1. void org.springframework.web.bind.WebDataBinder.setFieldDefaultPrefix(String fieldDefaultPrefix)  
在对应自定义注解ExtModelAttribute的处理器ExtServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder binder, NativeWebRequest request)
改变默认前缀
不过到3.2.8 还是有点小问题 前缀后面要加一个字符 比如“.”
以下是自定义注解对应处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. import javax.servlet.ServletRequest;  
  2.   
  3. import org.springframework.core.MethodParameter;  
  4. import org.springframework.web.bind.ServletRequestDataBinder;  
  5. import org.springframework.web.bind.WebDataBinder;  
  6. import org.springframework.web.bind.annotation.ModelAttribute;  
  7. import org.springframework.web.context.request.NativeWebRequest;  
  8. import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;  
  9. import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;  
  10.   
  11. public class ExtServletModelAttributeMethodProcessor extends ServletModelAttributeMethodProcessor  
  12.  {  
  13.     public ExtServletModelAttributeMethodProcessor(){  
  14.         super(false);   
  15.     }  
  16.   
  17.     public ExtServletModelAttributeMethodProcessor(boolean annotationNotRequired) {  
  18.         super(annotationNotRequired);  
  19.     }  
  20.   
  21.         @Override  
  22.     public boolean supportsParameter(MethodParameter parameter) {  
  23.         if (parameter.hasParameterAnnotation(ExtModelAttribute.class)) {  
  24.             return true;  
  25.         }  
  26.         else{  
  27.             return false;  
  28.         }  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {  
  33.         ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);  
  34.         ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;  
  35. servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+".");  
  36.         servletBinder.bind(servletRequest);;  
  37.     }  


加入自定义注解ExtModelAttribute 的处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:argument-resolvers>  
  3.         <bean class="ExtServletModelAttributeMethodProcessor"/>  
  4.     </mvc:argument-resolvers>  
  5. </mvc:annotation-driven>  


控制器中使用
Java代码  收藏代码
  1.        @RequestMapping(value="/test")  
  2. public String ftl(@ExtModelAttribute("testVo")TestVo testVo){  
  3.     System.out.println(testVo.getValue());  
  4.     return "test";  
  5. }  


页面使用
Java代码  收藏代码
  1. <form action="" method="post">  
  2. Date Inpout<Input id="value" name="testVo.value" value="${testVo.value}" />  
  3.     <input type="submit" value="submit">  
  4. </form>  





代码还是有问题 这里获取servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+".");是默认的没加注解的name 靠!ModelFacory 搞死了 只支持 ModelAttribute
ServletModelAttributeMethodProcessor 
ModelAttributeMethodProcessor 里的 final 方法限制了扩展,只能复制到新类里面了

40 楼 DS_Mars 2014-04-30  
此问题还可以如此解决 侵入性更小
首先 自定义注解ExtModelAttribute 
Java代码  收藏代码
  1. import java.lang.annotation.Documented;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6.   
  7. /** 
  8.  */  
  9. @Target({ElementType.PARAMETER, ElementType.METHOD})  
  10. @Retention(RetentionPolicy.RUNTIME)  
  11. @Documented  
  12. public @interface ExtModelAttribute {  
  13.   
  14.     String value() default "";  
  15.   
  16. }  


然后利用方法
Java代码  收藏代码
  1. void org.springframework.web.bind.WebDataBinder.setFieldDefaultPrefix(String fieldDefaultPrefix)  
在对应自定义注解ExtModelAttribute的处理器ExtServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder binder, NativeWebRequest request)
改变默认前缀
不过到3.2.8 还是有点小问题 前缀后面要加一个字符 比如“.”
以下是自定义注解对应处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. import javax.servlet.ServletRequest;  
  2.   
  3. import org.springframework.core.MethodParameter;  
  4. import org.springframework.web.bind.ServletRequestDataBinder;  
  5. import org.springframework.web.bind.WebDataBinder;  
  6. import org.springframework.web.bind.annotation.ModelAttribute;  
  7. import org.springframework.web.context.request.NativeWebRequest;  
  8. import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;  
  9. import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;  
  10.   
  11. public class ExtServletModelAttributeMethodProcessor extends ServletModelAttributeMethodProcessor  
  12.  {  
  13.     public ExtServletModelAttributeMethodProcessor(){  
  14.         super(false);   
  15.     }  
  16.   
  17.     public ExtServletModelAttributeMethodProcessor(boolean annotationNotRequired) {  
  18.         super(annotationNotRequired);  
  19.     }  
  20.   
  21.         @Override  
  22.     public boolean supportsParameter(MethodParameter parameter) {  
  23.         if (parameter.hasParameterAnnotation(ExtModelAttribute.class)) {  
  24.             return true;  
  25.         }  
  26.         else{  
  27.             return false;  
  28.         }  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {  
  33.         ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);  
  34.         ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;  
  35. servletBinder.setFieldDefaultPrefix(servletBinder.getObjectName()+".");  
  36.         servletBinder.bind(servletRequest);;  
  37.     }  


加入自定义注解ExtModelAttribute 的处理器ExtServletModelAttributeMethodProcessor
Java代码  收藏代码
  1. <mvc:annotation-driven>  
  2.     <mvc:argument-resolvers>  
  3.         <bean class="ExtServletModelAttributeMethodProcessor"/>  
  4.     </mvc:argument-resolvers>  
  5. </mvc:annotation-driven>  


控制器中使用
Java代码  收藏代码
  1.        @RequestMapping(value="/test")  
  2. public String ftl(@ExtModelAttribute("testVo")TestVo testVo){  
  3.     System.out.println(testVo.getValue());  
  4.     return "test";  
  5. }  


页面使用
Java代码  收藏代码
  1. <form action="" method="post">  
  2. Date Inpout<Input id="value" name="testVo.value" value="${testVo.value}" />  
  3.     <input type="submit" value="submit">  
  4. </form>  




39 楼 jinnianshilongnian 2014-03-12  
lanxia39 写道
看了你写的,但是你引用的是spring test包,就不想用了

1、你可以把它抽出来;2、你可以自己实现
38 楼 lanxia39 2014-03-12  
看了你写的,但是你引用的是spring test包,就不想用了
37 楼 yuezixin 2014-01-15  
LZ,你这么牛B,你家里人知道吗
36 楼 jinnianshilongnian 2013-11-21  
俗人 写道
这个也不支持spring3.2啊

支持的  你可以到github下载最新版本
35 楼 俗人 2013-11-21  
这个也不支持spring3.2啊
34 楼 fncj 2013-09-04  
好东西   
33 楼 jinnianshilongnian 2013-08-03  
landy8530 写道
你好,发现一个小小的bug哦。(不知道有没有错)在代码
Java代码  收藏代码
  1. //ok   http://localhost:9080/springmvc-chapter6/formmodel/user?user.username=zhang&user.password=123    
  2.     @RequestMapping("/user/{user.realname}")      
  3.     public String user(@FormModel("user") UserModel user) {    
  4.         System.out.println(user);    
  5.         return "redirect:/success";            
  6.     }    
  7.         

中,{user.realname}部分应该去掉吧。不然会报404错误哦!

嗯,得去掉
32 楼 jinnianshilongnian 2013-08-03  
landy8530 写道
你好,你在formModel中定义的FormModelMethodArgumentResolver这个类中的MockHttpServletRequest是spring-test包中的呢。如果我maven坐标写成
Java代码  收藏代码
  1. <dependency>    
  2.     <groupId>org.springframework</groupId>    
  3.     <artifactId>spring-test</artifactId>    
  4.     <version>3.1.0.RELEASE</version>    
  5.     <scope>test</scope>    
  6. </dependency>   

真正运行时就报错了呢。说找不到这个类了。

因为使用了这里边的MockRequest 所以需要加上
31 楼 landy8530 2013-08-02  
你好,发现一个小小的bug哦。(不知道有没有错)在代码
Java代码  收藏代码
  1. //ok   http://localhost:9080/springmvc-chapter6/formmodel/user?user.username=zhang&user.password=123    
  2.     @RequestMapping("/user/{user.realname}")      
  3.     public String user(@FormModel("user") UserModel user) {    
  4.         System.out.println(user);    
  5.         return "redirect:/success";            
  6.     }    
  7.         

中,{user.realname}部分应该去掉吧。不然会报404错误哦!
30 楼 landy8530 2013-08-02  
你好,你在formModel中定义的FormModelMethodArgumentResolver这个类中的MockHttpServletRequest是spring-test包中的呢。如果我maven坐标写成
Java代码  收藏代码
  1. <dependency>    
  2.     <groupId>org.springframework</groupId>    
  3.     <artifactId>spring-test</artifactId>    
  4.     <version>3.1.0.RELEASE</version>    
  5.     <scope>test</scope>    
  6. </dependency>   

真正运行时就报错了呢。说找不到这个类了。
29 楼 jinnianshilongnian 2013-08-02  
mrvoce 写道
Java代码  收藏代码
  1. //ok   http://localhost:9080/springmvc-chapter6/formmodel/list2?list[0].username=zhang&list[1].username=li    
  2.    @RequestMapping("/list2")     

作者您好,看到您的文章后觉得这里是否有问题,我测试了下您的FormModelMethodArgumentResolver类,觉得
Java代码  收藏代码
  1.  for(Object key : servletRequest.getParameterMap().keySet()) {  
  2. }  
  3. //。。。。。  
  4. target.add(component);  

这里是否有问题呢,例如您上面的url测试时正确的,那么list[0].username=abc&list[0].其他字段=111&list[1].username=bcd&list[1].其他字段=222
下标为0的list,如果我写N个参数那么您的扩展类将会add N个对应的model实例,所以这里是否有一点点bug。

会的,如果用户恶意添加很多个,很可能造成内存溢出(此处没考虑限定集合增加的量 后期加上)
28 楼 mrvoce 2013-08-02  
Java代码  收藏代码
  1. //ok   http://localhost:9080/springmvc-chapter6/formmodel/list2?list[0].username=zhang&list[1].username=li    
  2.    @RequestMapping("/list2")     

作者您好,看到您的文章后觉得这里是否有问题,我测试了下您的FormModelMethodArgumentResolver类,觉得
Java代码  收藏代码
  1.  for(Object key : servletRequest.getParameterMap().keySet()) {  
  2. }  
  3. //。。。。。  
  4. target.add(component);  

这里是否有问题呢,例如您上面的url测试时正确的,那么list[0].username=abc&list[0].其他字段=111&list[1].username=bcd&list[1].其他字段=222
下标为0的list,如果我写N个参数那么您的扩展类将会add N个对应的model实例,所以这里是否有一点点bug。
27 楼 jinnianshilongnian 2013-06-26  
huangyunbin 写道
jinnianshilongnian 写道

估计你是用了mvc:annotation-driven,这样的话需要这样配:

<mvc:annotation-driven>
     <mvc:argument-resolvers>
            <bean class="com.sishuok.es.common.web.bind.method.annotation.FormModelMethodArgumentResolver"/>
        </mvc:argument-resolvers>
</mvc:annotation-driven>


谢谢,我这样修改后ok了。
不过为什么 <mvc:annotation-driven>情况下要这么做呢。我网上看到说<mvc:annotation-driven>和RequestMappingHandlerAdapter其实是一样的,所以只会读取<mvc:annotation-driven>,忽略掉了RequestMappingHandlerAdapter。但是我试验的结果是:只要RequestMappingHandlerAdapter写在<mvc:annotation-driven>的前面就可以了。
我的这个配置是ok的:

Java代码  收藏代码
  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">   
  2.       <!--线程安全的访问session-->  
  3.        <property name="synchronizeOnSession" value="true"/>   
  4.        <property name="customArgumentResolvers">  
  5.           <list>  
  6.              <bean class="com.dianxin.secure.controller.annotation.FormModelMethodArgumentResolver"/>  
  7.           </list>  
  8.        </property>  
  9.    </bean>    
  10. lt;mvc:annotation-driven/>   


求解释,为什么这样也可以,具体的原理是什么?<mvc:annotation-driven>和RequestMappingHandlerAdapter的关系是什么?

注册顺序的问题(如果注册了就不会再注册),实现问题  一般情况就是二者选一 没必要纠结
26 楼 huangyunbin 2013-06-26  
jinnianshilongnian 写道

估计你是用了mvc:annotation-driven,这样的话需要这样配:

<mvc:annotation-driven>
     <mvc:argument-resolvers>
            <bean class="com.sishuok.es.common.web.bind.method.annotation.FormModelMethodArgumentResolver"/>
        </mvc:argument-resolvers>
</mvc:annotation-driven>


谢谢,我这样修改后ok了。
不过为什么 <mvc:annotation-driven>情况下要这么做呢。我网上看到说<mvc:annotation-driven>和RequestMappingHandlerAdapter其实是一样的,所以只会读取<mvc:annotation-driven>,忽略掉了RequestMappingHandlerAdapter。但是我试验的结果是:只要RequestMappingHandlerAdapter写在<mvc:annotation-driven>的前面就可以了。
我的这个配置是ok的:

Java代码  收藏代码
  1. <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">   
  2.       <!--线程安全的访问session-->  
  3.        <property name="synchronizeOnSession" value="true"/>   
  4.        <property name="customArgumentResolvers">  
  5.           <list>  
  6.              <bean class="com.dianxin.secure.controller.annotation.FormModelMethodArgumentResolver"/>  
  7.           </list>  
  8.        </property>  
  9.    </bean>    
  10. lt;mvc:annotation-driven/>   


求解释,为什么这样也可以,具体的原理是什么?<mvc:annotation-driven>和RequestMappingHandlerAdapter的关系是什么?
jinnianshilongnian
  • 浏览: 3771402 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:773958
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:693183
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:1212182
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:94078
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:269526
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:96046
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:421580
Group-logo
跟我学Nginx+Lua开...
浏览量:12752
社区版块
存档分类
最新评论

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多