java 在 Spring MVC 中绑定列表映射

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12339013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 08:28:53  来源:igfitidea点击:

Binding a map of lists in Spring MVC

javajspspring-mvcjstl

提问by Umesh Awasthi

I am not sure if this is a complex problem but as a starting person this seems a bit complex to me. I have an object based on which i need to show some values on the UI and let user select some of them, i need to send data back to another controller when user click on the submit button.Here is the structure of my data object

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

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

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

public ConfiguredDesignData{
  // simple fields
}

I have set the object in model before showing the view like

在显示视图之前,我已经在模型中设置了对象

model.addAttribute("prsData", productData.getPrData());

In the form i have following settings

在表格中,我有以下设置

<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>

This is what i have at AddProductToCartController

这就是我所拥有的 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)

On submitting the form i am getting following exception

在提交表单时,我收到以下异常

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

It seems like its trying to access the values on this controller while i am trying to send value to that controller and trying to create same object with selected values

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

Can any one tell me where i am doing wrong and what i need to take care of

谁能告诉我我哪里做错了以及我需要注意什么

Edit

编辑

I did some more research and came to know that Spring do not support auto-populating list/map for custom objects and based on the answer i tried to change implementation like

我做了一些更多的研究,并开始知道 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));

    }
    }

but i am getting following exception

但我收到以下异常

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]

i am not sure which thing i am doing wrong, it seems that either my JSTL expression is not right

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

回答by Jerome Dalbert

Explanation :if in you controller you have @ModelAttribute("user") User user, and you load a corresponding page that contains <form:form commandName="user">, an empty User is instantiated.

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

All its attributes are null, or empty in case of a List or a Map. Moreover, its empty lists/maps have been instantiated with an autogrowing implementation. What does it mean ? Let's say we have an empty autogrowing List<Coconut> coconuts. If I do coconuts.get(someIndex).setDiameter(50), it will work instead of throwing an Exception, because the list auto grows and instantiate a coconut for the given index.
Thanks to this autogrowing, submitting a form with the below input will work like a charm :

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

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


Now back to your problem :Spring MVC autogrowing works quite well with a chain of objects, each containing a map/list (see this post). But given your exception, it looks like Spring doesn't autogrow the possible objects contained by the autogrowed list/map. In Map<String, List<PrsCDData>> prsCDData, the List<PrsCDData>is a mere empty list with no autogrowing, thus leading to your Exception.

现在回到你的问题:Spring MVC 自动增长与一系列对象一起工作得很好,每个对象都包含一个地图/列表(参见这篇文章)。但是考虑到您的例外情况,Spring 似乎不会自动增长自动增长的列表/映射所包含的可能对象。在 中Map<String, List<PrsCDData>> prsCDData, theList<PrsCDData>只是一个没有自动增长的空列表,从而导致您的异常。

So the solution must use some kind of Apache Common's LazyListor Spring's AutoPopulatingList.
You must implement your own autogrowing map that instantiates a LazyList/AutoPopulatingList for a given index. Do it from scratch or using some kind of Apache Common's LazyMap/ MapUtils.lazyMapimplementation (so far I have not found a Spring equivalent for LazyMap).

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

Example of solution, using Apache Commons Collections :

使用 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));
          }

      });
  }

}