绑定Spring MVC中的列表映射

时间:2012-09-09 12:21:38

标签: java jsp spring-mvc jstl

我不确定这是否是一个复杂的问题,但作为一个初学者,这对我来说似乎有点复杂。 我有一个对象,我需要在UI上显示一些值,让用户选择其中的一些,我需要在用户点击提交按钮时将数据发送回另一个控制器。这是我的数据对象的结构< / p>

public class PrsData{
private Map<String, List<PrsCDData>> prsCDData;
}

public class PrsCDData{
  private Map<String, Collection<ConfiguredDesignData>> configuredDesignData;
}

public ConfiguredDesignData{
  // simple fields
}

我在显示像

这样的视图之前已经在模型中设置了对象
model.addAttribute("prsData", productData.getPrData());

在表格中我有以下设置

<form:form method="post" commandName="prsData" action="${addProductToCartAction}" >
<form:hidden path="prsCDData['${prsCDDataMap.key}']
  [${status.index}].configuredDesignData['${configuredDesignDataMap.key}']
  [${configuredDesignDataStatus.index}].code"/>

<form:hidden path="prsCDData['${prsCDDataMap.key}']
  [${status.index}].configuredDesignData['${configuredDesignDataMap.key}']
  [${configuredDesignDataStatus.index}].description"/>

</form:form>

这就是我在AddProductToCartController

所拥有的
public String addToCart(@RequestParam("productCodePost") final String code,
@ModelAttribute("prsData") final PrsData prsData, final Model model,
@RequestParam(value = "qty", required = false, defaultValue = "1") final long qty)

在提交表单时,我遇到异常

org.springframework.beans.NullValueInNestedPathException: Invalid property 'prsCDData[Forced][0]' 
of bean class [com.product.data.PrsData]: 
Cannot access indexed value of property referenced in indexed property path 'prsCDData[Forced][0]': returned null

当我尝试向该控制器发送值并尝试使用所选值创建相同的对象时,它似乎试图访问此控制器上的值

任何人都可以告诉我我做错了什么以及我需要照顾什么

修改

我做了一些更多的研究,并且发现Spring不支持自动填充自定义对象的列表/地图,并根据我试图改变实现的答案,如

public class PrsData{
    private Map<String, List<PrsCDData>> prsCDData;
    // lazy init
    public PrsData()
    {
           this.prsCDData = MapUtils.lazyMap(new HashMap<String, List<PrsCDData>>(),
                FactoryUtils.instantiateFactory(PrsCDData.class));
        }
    }

    public class PrsCDData{
      private Map<String, Collection<ConfiguredDesignData>> configuredDesignData;
      public PrsCDData()
    {

       this.configuredDesignData = MapUtils.lazyMap(new HashMap<String,  
                                      List<ConfiguredDesignData>>(),
            FactoryUtils.instantiateFactory(ConfiguredDesignData.class));

    }
    }

但我得到了以下异常

org.springframework.beans.InvalidPropertyException: 
Invalid property 'prsCDData[Forced][0]' of bean class [com.data.PrsData]:
Property referenced in indexed property path 'prsCDData[Forced][0]' 
is neither an array nor a List nor a Set nor a Map; 
returned value was [com.data.PrsCDData@6043a24d]

我不确定我做错了什么,似乎我的JSTL表达不正确

1 个答案:

答案 0 :(得分:7)

说明:如果您在控制器中有@ModelAttribute("user") User user,并且加载了包含<form:form commandName="user">的相应页面,则会实例化一个空用户。

它的所有属性都为null,如果是List或Map,则为空。此外,它的空列表/映射已经使用自动增长实现进行了实例化。这是什么意思 ?假设我们有一个空的自动增长List<Coconut> coconuts。如果我执行coconuts.get(someIndex).setDiameter(50),它将起作用而不是抛出异常,因为列表自动增长并实例化给定索引的椰子。
由于这种自动增长功能,提交带有以下输入的表单将像魅力一样:

<form:input path="coconuts[${someIndex}].diameter" />

现在回到你的问题: Spring MVC自动增长对一组对象很有效,每个对象都包含一个map / list(see this post)。但是,鉴于您的异常,看起来Spring不会自动增长自动增长列表/映射包含的可能对象。在Map<String, List<PrsCDData>> prsCDData中,List<PrsCDData>只是一个空列表,没有自动增长,从而导致您的例外。

因此解决方案必须使用某种Apache Common LazyList或Spring AutoPopulatingList
您必须实现自己的自动增长映射,该映射为给定索引实例化LazyList / AutoPopulatingList。从头开始或使用某种Apache Common的LazyMap / MapUtils.lazyMap实现(到目前为止,我还没有找到LazyMap的Spring等价物)。

解决方案示例,使用Apache Commons Collections:

public class PrsData {

  private Map<String, List<PrsCDData>> prsCDData;

  public PrsData() {
      this.prsCDData = MapUtils.lazyMap(new HashMap<String,List<Object>>(), new Factory() {

          public Object create() {
              return LazyList.decorate(new ArrayList<PrsCDData>(), 
                             FactoryUtils.instantiateFactory(PrsCDData.class));
          }

      });
  }

}