springMVC对简单对象、Set、List、Map的数据绑定和常见问题

来源:互联网 发布:《java大学基础教程》 编辑:程序博客网 时间:2024/05/06 05:51
1、相关的类:

查看spring源码可以看出spring支持转换的数据类型:
org.springframework.beans.PropertyEditorRegistrySupport:

  1.   
  2. private void createDefaultEditors()  
  3.     this.defaultEditors new HashMap(64);  
  4.     // Simple editors, without parameterization capabilities.  
  5.     // The JDK does not contain default editor for any of these target types.  
  6.     this.defaultEditors.put(Charset.classnew CharsetEditor());  
  7.     this.defaultEditors.put(Class.classnew ClassEditor());  
  8.     this.defaultEditors.put(Class[].classnew ClassArrayEditor());  
  9.     this.defaultEditors.put(Currency.classnew CurrencyEditor());  
  10.     this.defaultEditors.put(File.classnew FileEditor());  
  11.     this.defaultEditors.put(InputStream.classnew InputStreamEditor());  
  12.     this.defaultEditors.put(InputSource.classnew InputSourceEditor());  
  13.     this.defaultEditors.put(Locale.classnew LocaleEditor());  
  14.     this.defaultEditors.put(Pattern.classnew PatternEditor());  
  15.     this.defaultEditors.put(Properties.classnew PropertiesEditor());  
  16.     this.defaultEditors.put(Resource[].classnew ResourceArrayPropertyEditor());  
  17.     this.defaultEditors.put(TimeZone.classnew TimeZoneEditor());  
  18.     this.defaultEditors.put(URI.classnew URIEditor());  
  19.     this.defaultEditors.put(URL.classnew URLEditor());  
  20.     this.defaultEditors.put(UUID.classnew UUIDEditor());  
  21.   
  22.     // Default instances of collection editors.  
  23.     // Can be overridden by registering custom instances of those as custom editors.  
  24.     this.defaultEditors.put(Collection.classnew CustomCollectionEditor(Collection.class));  
  25.     this.defaultEditors.put(Set.classnew CustomCollectionEditor(Set.class));  
  26.     this.defaultEditors.put(SortedSet.classnew CustomCollectionEditor(SortedSet.class));  
  27.     this.defaultEditors.put(List.classnew CustomCollectionEditor(List.class));  
  28.     this.defaultEditors.put(SortedMap.classnew CustomMapEditor(SortedMap.class));  
  29.   
  30.     // Default editors for primitive arrays.  
  31.     this.defaultEditors.put(byte[].classnew ByteArrayPropertyEditor());  
  32.     this.defaultEditors.put(char[].classnew CharArrayPropertyEditor());  
  33.   
  34.     // The JDK does not contain default editor for char!  
  35.     this.defaultEditors.put(char.classnew CharacterEditor(false));  
  36.     this.defaultEditors.put(Character.classnew CharacterEditor(true));  
  37.   
  38.     // Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.  
  39.     this.defaultEditors.put(boolean.classnew CustomBooleanEditor(false));  
  40.     this.defaultEditors.put(Boolean.classnew CustomBooleanEditor(true));  
  41.   
  42.     // The JDK does not contain default editors for number wrapper types!  
  43.     // Override JDK primitive number editors with our own CustomNumberEditor.  
  44.     this.defaultEditors.put(byte.classnew CustomNumberEditor(Byte.classfalse));  
  45.     this.defaultEditors.put(Byte.classnew CustomNumberEditor(Byte.classtrue));  
  46.     this.defaultEditors.put(short.classnew CustomNumberEditor(Short.classfalse));  
  47.     this.defaultEditors.put(Short.classnew CustomNumberEditor(Short.classtrue));  
  48.     this.defaultEditors.put(int.classnew CustomNumberEditor(Integer.classfalse));  
  49.     this.defaultEditors.put(Integer.classnew CustomNumberEditor(Integer.classtrue));  
  50.     this.defaultEditors.put(long.classnew CustomNumberEditor(Long.classfalse));  
  51.     this.defaultEditors.put(Long.classnew CustomNumberEditor(Long.classtrue));  
  52.     this.defaultEditors.put(float.classnew CustomNumberEditor(Float.classfalse));  
  53.     this.defaultEditors.put(Float.classnew CustomNumberEditor(Float.classtrue));  
  54.     this.defaultEditors.put(double.classnew CustomNumberEditor(Double.classfalse));  
  55.     this.defaultEditors.put(Double.classnew CustomNumberEditor(Double.classtrue));  
  56.     this.defaultEditors.put(BigDecimal.classnew CustomNumberEditor(BigDecimal.classtrue));  
  57.     this.defaultEditors.put(BigInteger.classnew CustomNumberEditor(BigInteger.classtrue));  
  58.   
  59.     // Only register config value editors if explicitly requested.  
  60.     if (this.configValueEditorsActive 
  61.         StringArrayPropertyEditosae new StringArrayPropertyEditor();  
  62.         this.defaultEditors.put(String[].classsae);  
  63.         this.defaultEditors.put(short[].classsae);  
  64.         this.defaultEditors.put(int[].classsae);  
  65.         this.defaultEditors.put(long[].classsae);  
  66.      
  67.  

 2、基本数据类型绑定:

  1. @RequestMapping("test.do"   
  2. public void test(int num)    
  3.         
  4.   
  1. "test.do" method="post" 
  2.    "num" value="10" type="text"/>  
  3.    ......  
  4.   

注意:表单中input的name值和Controller的参数变量名保持一致,就能完成基本数据类型的数据绑定,如果不一致可以使用@RequestParam标注实现。值得一提的是,如果Controller方法参数中定义的是基本数据类型,但是从jsp提交过来的数据为null或者""的话,会出现数据转换的异常。也就是说,必须保证表单传递过来的数据不能为null或"",所以,在开发过程中,对可能为空的数据,最好将参数数据类型定义成包装类型。

3、包装类型

  1. @RequestMapping("test.do" 
  2. public void test(Integer num)  
  3.       
  4.  

 

  1. "test.do" method="post" 
  2.    "num" value="10" type="text"/>  
  3.    ......  
  4.   

和基本数据类型基本一样,不同之处在于,JSP表单传递过来的数据可以为null或"",以上面代码为例,如果jsp中num为""或者表单中无num这个input,那么,Controller方法参数中的num值则为null。

4、自定义对象类型

  1. public class User  
  2.   
  3.     private String firstName;  
  4.   
  5.     private String lastName;  
  6.   
  7.     ...  
  8.   
  9.  
  1. @RequestMapping("test.do" 
  2. public void test(User user)  
  3.       
  4.  

  1. "test.do" method="post" 
  2.    "firstName" value="张" type="text"/>  
  3.    "lastName" value="三" type="text"/>  
  4.    ......  
  5.   
只需将对象的属性名和input的name值一一对应即可。

 5、自定义复合对象类型

  1. public class ContactInfo  
  2.   
  3.     private String tel;  
  4.   
  5.     private String address;  
  6.   
  7.     。。。  
  8.   
  9.  
  10.   
  11. public class User  
  12.   
  13.     private String firstName;  
  14.   
  15.     private String lastName;  
  16.   
  17.     private ContactInfo contactInfo;  
  18.   
  19.     。。。  
  20.   
  21.  

  1. @RequestMapping("test.do" 
  2. public void test(User user)  
  3.     System.out.println(user.getFirstName());  
  4.     System.out.println(user.getLastName());  
  5.     System.out.println(user.getContactInfo().getTel());  
  6.     System.out.println(user.getContactInfo().getAddress());  
  7.  

  1. <</span>form action="test.do" method="post">  
  2.    <</span>input name="firstName" value="张" /><</span>br>  
  3.    <</span>input name="lastName" value="三" /><</span>br>  
  4.    <</span>input name="contactInfo.tel" value="13809908909" /><</span>br>  
  5.    <</span>input name="contactInfo.address" value="北京海淀" /><</span>br>  
  6.    <</span>input type="submit" value="Save" />  
  7. </</span>form>  

User对象中有ContactInfo属性,Controller中的代码和第3点说的一致,但是,在jsp代码中,需要使用“属性名(对象类型的属性).属性名”来命名input的name。

6、List绑定

List需要绑定在对象上,而不能直接写在Controller方法的参数中。

  1. public class User  
  2.   
  3.     private String firstName;  
  4.   
  5.     private String lastName;  
  6.   
  7.     。。。  
  8.   
  9.  
  10.   
  11.        public class UserListForm  
  12.   
  13.     private List users;  
  14.   
  15.     。。。  
  16.   
  17. }  

 

  1. @RequestMapping("test.do" 
  2. public void test(UserListForm userForm)  
  3.     for (User user userForm.getUsers())  
  4.         System.out.println(user.getFirstName() " user.getLastName());  
  5.      
  6. }  

 

  1. <</span>form action="test.do" method="post">  
  2.    <</span>table>  
  3.       <</span>thead>  
  4.          <</span>tr>  
  5.             <</span>th>First Name</</span>th>  
  6.             <</span>th>Last Name</</span>th>  
  7.          </</span>tr>  
  8.       </</span>thead>  
  9.       <</span>tfoot>  
  10.          <</span>tr>  
  11.             <</span>td colspan="2"><</span>input type="submit" value="Save" /></</span>td>  
  12.          </</span>tr>  
  13.       </</span>tfoot>  
  14.       <</span>tbody>  
  15.          <</span>tr>  
  16.             <</span>td><</span>input name="users[0].firstName" value="aaa" /></</span>td>  
  17.             <</span>td><</span>input name="users[0].lastName" value="bbb" /></</span>td>  
  18.          </</span>tr>  
  19.          <</span>tr>  
  20.             <</span>td><</span>input name="users[1].firstName" value="ccc" /></</span>td>  
  21.             <</span>td><</span>input name="users[1].lastName" value="ddd" /></</span>td>  
  22.          </</span>tr>  
  23.          <</span>tr>  
  24.             <</span>td><</span>input name="users[2].firstName" value="eee" /></</span>td>  
  25.             <</span>td><</span>input name="users[2].lastName" value="fff" /></</span>td>  
  26.          </</span>tr>  
  27.       </</span>tbody>  
  28.    </</span>table>  
  29. </</span>form>  

      其实,这和第4点User对象中的contantInfo数据的绑定有点类似,但是这里的UserListForm对象里面的属性被定义成List,而不是普通自定义对象。所以,在JSP中需要指定List的下标。值得一提的是,Spring会创建一个以最大下标值为size的List对象,所以,如果JSP表单中有动态添加行、删除行的情况,就需要特别注意,譬如一个表格,用户在使用过程中经过多次删除行、增加行的操作之后,下标值就会与实际大小不一致,这时候,List中的对象,只有在jsp表单中对应有下标的那些才会有值,否则会为null,看个例子:

  1. <</span>form action="test.do" method="post">  
  2.    <</span>table>  
  3.       <</span>thead>  
  4.          <</span>tr>  
  5.             <</span>th>First Name</</span>th>  
  6.             <</span>th>Last Name</</span>th>  
  7.          </</span>tr>  
  8.       </</span>thead>  
  9.       <</span>tfoot>  
  10.          <</span>tr>  
  11.             <</span>td colspan="2"><</span>input type="submit" value="Save" /></</span>td>  
  12.          </</span>tr>  
  13.       </</span>tfoot>  
  14.       <</span>tbody>  
  15.          <</span>tr>  
  16.             <</span>td><</span>input name="users[0].firstName" value="aaa" /></</span>td>  
  17.             <</span>td><</span>input name="users[0].lastName" value="bbb" /></</span>td>  
  18.          </</span>tr>  
  19.          <</span>tr>  
  20.             <</span>td><</span>input name="users[1].firstName" value="ccc" /></</span>td>  
  21.             <</span>td><</span>input name="users[1].lastName" value="ddd" /></</span>td>  
  22.          </</span>tr>  
  23.          <</span>tr>  
  24.             <</span>td><</span>input name="users[20].firstName" value="eee" /></</span>td>  
  25.             <</span>td><</span>input name="users[20].lastName" value="fff" /></</span>td>  
  26.          </</span>tr>  
  27.       </</span>tbody>  
  28.    </</span>table>  
  29. </</span>form>  

      这个时候,Controller中的userForm.getUsers()获取到List的size为21,而且这21个User对象都不会为null,但是,第2到第19的User对象中的firstName和lastName都为null。打印结果:

  1. aaa bbb  
  2. ccc ddd  
  3. null null  
  4. null null  
  5. null null  
  6. null null  
  7. null null  
  8. null null  
  9. null null  
  10. null null  
  11. null null  
  12. null null  
  13. null null  
  14. null null  
  15. null null  
  16. null null  
  17. null null  
  18. null null  
  19. null null  
  20. null null  
  21. eee fff  

7、Set绑定:

Set和List类似,也需要绑定在对象上,而不能直接写在Controller方法的参数中。但是,绑定Set数据时,必须先在Set对象中add相应的数量的模型对象。

  1. public class User  
  2.   
  3.     private String firstName;  
  4.   
  5.     private String lastName;  
  6.   
  7.     。。。  
  8.   
  9.  
  10.   
  11. public class UserSetForm  
  12.   
  13.     private Set users new HashSet();  
  14.       
  15.     public UserSetForm(){  
  16.         users.add(new User());  
  17.         users.add(new User());  
  18.         users.add(new User());  
  19.      
  20.   
  21.     。。。  
  22.   
  23. }  

 

  1. @RequestMapping("test.do" 
  2. public void test(UserSetForm userForm)  
  3.     for (User user userForm.getUsers())  
  4.         System.out.println(user.getFirstName() " user.getLastName());  
  5.      
  6. }  

 

  1. <</span>form action="test.do" method="post">  
  2.    <</span>table>  
  3.       <</span>thead>  
  4.          <</span>tr>  
  5.             <</span>th>First Name</</span>th>  
  6.             <</span>th>Last Name</</span>th>  
  7.          </</span>tr>  
  8.       </</span>thead>  
  9.       <</span>tfoot>  
  10.          <</span>tr>  
  11.             <</span>td colspan="2"><</span>input type="submit" value="Save" /></</span>td>  
  12.          </</span>tr>  
  13.       </</span>tfoot>  
  14.       <</span>tbody>  
  15.          <</span>tr>  
  16.             <</span>td><</span>input name="users[0].firstName" value="aaa" /></</span>td>  
  17.             <</span>td><</span>input name="users[0].lastName" value="bbb" /></</span>td>  
  18.          </</span>tr>  
  19.          <</span>tr>  
  20.             <</span>td><</span>input name="users[1].firstName" value="ccc" /></</span>td>  
  21.             <</span>td><</span>input name="users[1].lastName" value="ddd" /></</span>td>  
  22.          </</span>tr>  
  23.          <</span>tr>  
  24.             <</span>td><</span>input name="users[2].firstName" value="eee" /></</span>td>  
  25.             <</span>td><</span>input name="users[2].lastName" value="fff" /></</span>td>  
  26.          </</span>tr>  
  27.       </</span>tbody>  
  28.    </</span>table>  
  29. </</span>form>  

     基本和List绑定类似。需要特别提醒的是,如果最大下标值大于Set的size,则会抛出org.springframework.beans.InvalidPropertyException异常

 

8、Map绑定:

  1. public class User  
  2.   
  3.     private String firstName;  
  4.   
  5.     private String lastName;  
  6.   
  7.     。。。  
  8.   
  9.  
  10.   
  11. public class UserMapForm  
  12.   
  13.     private Map users;  
  14.   
  15.     。。。  
  16.   
  17.  

 

 

  1. @RequestMapping("test.do" 
  2. public void test(UserMapForm userForm)  
  3.     for (Map.Entry entry userForm.getUsers().entrySet())  
  4.         System.out.println(entry.getKey() ": " entry.getValue().getFirstName() "  
  5.                                  entry.getValue().getLastName());  
  6.      
  7. }  

 

  1. <</span>form action="test.do" method="post">  
  2.    <</span>table>  
  3.       <</span>thead>  
  4.          <</span>tr>  
  5.             <</span>th>First Name</</span>th>  
  6.             <</span>th>Last Name</</span>th>  
  7.          </</span>tr>  
  8.       </</span>thead>  
  9.       <</span>tfoot>  
  10.          <</span>tr>  
  11.             <</span>td colspan="2"><</span>input type="submit" value="Save" /></</span>td>  
  12.          </</span>tr>  
  13.       </</span>tfoot>  
  14.       <</span>tbody>  
  15.          <</span>tr>  
  16.             <</span>td><</span>input name="users['x'].firstName" value="aaa" /></</span>td>  
  17.             <</span>td><</span>input name="users['x'].lastName" value="bbb" /></</span>td>  
  18.          </</span>tr>  
  19.          <</span>tr>  
  20.             <</span>td><</span>input name="users['y'].firstName" value="ccc" /></</span>td>  
  21.             <</span>td><</span>input name="users['y'].lastName" value="ddd" /></</span>td>  
  22.          </</span>tr>  
  23.          <</span>tr>  
  24.             <</span>td><</span>input name="users['z'].firstName" value="eee" /></</span>td>  
  25.             <</span>td><</span>input name="users['z'].lastName" value="fff" /></</span>td>  
  26.          </</span>tr>  
  27.       </</span>tbody>  
  28.    </</span>table>  
  29. </</span>form>  

最后:

       像test(int num)这种把表单字段直接映射到方法参数名的方式是不太靠谱的,这是Spring MVC最大的问题,并且是无法解决的问题,因为它是基于字节码来取方法参数名的,如果在编译源码时不生成debug信息,比如javac -g:none 或者 在eclipse中在Preference那个窗口中选"Java->Compiler"把"Add varible..."那个复选框取消,这样生成的字节码中是不会保存方法参数名的。最靠谱的办法就是基于java源代码来做,或者Spring MVC目前已提供的比较啰嗦的注解方式:  在参数名前加@RequestParam把test(int num)改成下面这样才是万无一失的:

 

  1. test(@RequestParam("num"int num)  

所以最后在控制器方法上带上这个注解。

0 0
原创粉丝点击