springmvc绑定Set的解决方案

来源:互联网 发布:淘宝手机端图片不清楚 编辑:程序博客网 时间:2024/05/17 08:07

1、模型

Java代码  收藏代码
  1. public class Vote {  
  2.     private Integer id;  
  3.     private String title;  
  4.     private Set<VoteItem> voteItems;  
  5.     private VoteSubject voteSubject;  
  6. }  
  7.   
  8. public class VoteItem {  
  9.     private Integer id;  
  10.     private String content;  
  11.     private Vote vote;  
  12. }  

 

2、控制器

 

Java代码  收藏代码
  1. @RequestMapping  
  2. public String vote(@FormModel("votes") Set<Vote> votes) {  
  3.     System.out.println(votes);  
  4.     return "";  
  5. }  

 

@FormModel注解请参考《扩展SpringMVC以支持更精准的数据绑定1》。

 

当我们在地址栏输入如:http://localhost:9080/es-web/vote?votes[0].voteItems[0].content=123时,会报:

org.springframework.beans.InvalidPropertyException: Invalid property 'voteItems[0]' of bean class [com.sishuok.es.test.Vote]: Cannot get element with index 0 from Set of size 0, accessed using property path 'voteItems[0]'

 

3、原因:

原因很明显,Set是无序列表,所以我们使用有顺序注入是不太合适的,BeanWrapperImpl实现:

 

Java代码  收藏代码
  1. else if (value instanceof Set) {  
  2.     // Apply index to Iterator in case of a Set.  
  3.     Set set = (Set) value;  
  4.     int index = Integer.parseInt(key);  
  5.     if (index < 0 || index >= set.size()) {  
  6.         throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,  
  7.                 "Cannot get element with index " + index + " from Set of size " +  
  8.                 set.size() + ", accessed using property path '" + propertyName + "'");  
  9.     }  
  10.     Iterator it = set.iterator();  
  11.     for (int j = 0; it.hasNext(); j++) {  
  12.         Object elem = it.next();  
  13.         if (j == index) {  
  14.             value = elem;  
  15.             break;  
  16.         }  
  17.     }  
  18. }  

从实现上可以看出,如果set里边有值,那么就能实现绑定。

 

 

4、解决方案:

只要保证在springmvc绑定数据之前,给Set里边加上数据即可:

 

Java代码  收藏代码
  1. @ModelAttribute("votes")  
  2. public Set<Vote> initVotes() {  
  3.     Set<Vote> votes = new HashSet<Vote>();  
  4.     Vote vote = new Vote();  
  5.     votes.add(vote);  
  6.   
  7.     vote.setVoteItems(new HashSet<VoteItem>());  
  8.     vote.getVoteItems().add(new VoteItem());  
  9.   
  10.     return votes;  
  11. }  

这样我们就可以把votes暴露给之前的@FormModel("votes") ,它会使用这个来绑定,所以就有数据了。@ModelAttribute方法请参考《暴露表单引用对象为模型数据》。

 

但是缺点也很明显,前台必须告诉后台,Set里有几个数据,好让@ModelAttribute方法准备好那么多数据用于数据绑定,比较麻烦。

 

更简单的解决方案就是使用有序集合,如List,这样最简单

 

如上方案通用适用于@ModelAttribute的绑定。

 

最新的@FormModel的实现请到FormModelMethodArgumentResolver.java下载。

0 0