【问题标题】:Binding a map of lists in Spring MVC在 Spring MVC 中绑定列表映射
【发布时间】:2012-09-09 12:21:37
【问题描述】:

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

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 表达式不正确

【问题讨论】:

  • 在这种情况下要注意的另一件事是嵌套类。将PrsCDData 设为顶级类可以避免这个问题。

标签: java jsp spring-mvc jstl


【解决方案1】:

解释:如果您的控制器中有@ModelAttribute("user") User user,并且您加载了包含&lt;form:form commandName="user"&gt; 的相应页面,则会实例化一个空用户。

它的所有属性都为空,或者在 List 或 Map 的情况下为空。此外,它的空列表/地图已通过自动增长实现进行实例化。这是什么意思 ?假设我们有一个空的自动增长List&lt;Coconut&gt; coconuts。如果我执行coconuts.get(someIndex).setDiameter(50),它将起作用而不是抛出异常,因为列表会自动增长并为给定索引实例化一个椰子。
由于这种自动增长,提交具有以下输入的表单将像魅力一样工作:

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

现在回到您的问题: Spring MVC 自动增长非常适用于一系列对象,每个对象都包含一个映射/列表 (see this post)。但是考虑到您的例外情况,Spring 似乎不会自动增长自动增长的列表/地图所包含的可能对象。在Map&lt;String, List&lt;PrsCDData&gt;&gt; prsCDData 中,List&lt;PrsCDData&gt; 只是一个没有自动增长的空列表,因此会导致您的异常。

所以解决方案必须使用某种 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));
          }

      });
  }

}

【讨论】:

  • 很好的解释!将根据您的建议尝试并更新
  • 尝试第一种方法给出以下异常org.springframework.beans.NullValueInNestedPathException: Invalid property 'prsBTOData' of bean class [com.data.PrsData]: Could not instantiate property type [org.springframework.util.AutoPopulatingList] to auto-grow nested property path: java.lang.IllegalArgumentException: Could not instantiate Collection type: org.springframework.util.AutoPopulatingList
  • 你能解释一下第二种方法吗,因为它对我来说不是很清楚。
  • 我不确定您最新更新的答案,因为我将实现更改为 AutoPopulatingList 并且我得到了告诉我的异常。
  • @UmeshAwasthi 查看我编辑的答案。这看起来比我想象的要复杂......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-14
  • 2017-03-22
  • 2012-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多