有不清楚的问题的几件事情,但是基于代码中,我假设myMap
属性是Map
,因为你将提供多对对使用这些选择字段来选择一些值密钥数量。
如果上面的假设是错误的,那么为什么有myMap
作为Map
而不是MyDTO
的两个不同属性/属性?
与我的假设去,你需要选择对被转换成一个List
或阵列MyDTO
,并有一个创建基于列表的Map
的吸气剂(getMyMap()
)。上面列表中的条目将是一个简单的值对象,其中Long key
和List<String>
作为其属性。这是这个用例的一个工作示例。看看Thymeleaf如何改变这种状况,你可能会发现一个适合你的解决方案的调整版本。
此外,次要的事情:恕我直言,我不认为keys
和values
属性在MyDTO
之内是合适的,但它可能只是简化了这个问题。它们应该是模型属性,因为它们不是表单的用户输入。它在技术上有效,但并不严格遵守关注点分离。
参考/学分:动态表单域 - http://www.thymeleaf.org/doc/thymeleafspring.html#dynamic-fields
春控制器:
package net.martian111.examples.spring.web;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/public/stackoverflow/q26181188")
public class StackoverflowQ26181188Controller {
public static class Entry {
private Long id;
private List<String> values;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<String> getValues() {
return values;
}
public void setValues(List<String> values) {
this.values = values;
}
}
public static class FormBackingBean {
List<Entry> entries;
public List<Entry> getEntries() {
return entries;
}
public void setEntries(List<Entry> entries) {
this.entries = entries;
}
public Map<Long, List<String>> getMyMap() {
Map<Long, List<String>> map = new HashMap<>();
for (Entry entry : entries) {
// StringListWrapper constructed from entry.getValues() here...
map.put(entry.getId(), entry.getValues());
}
return map;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
int i = 1;
for (Entry entry : entries) {
sb.append("Pair #" + i + ": ID=" + entry.getId() + ", Values="
+ entry.getValues() + "\n");
++i;
}
return sb.toString();
}
}
// Can be set within the @RequestMapping methods too (mv.addObject())
@ModelAttribute("keys")
public List<Long> getKeys() {
return Arrays.asList(null, 1L, 2L, 3L);
}
@ModelAttribute("values")
public List<String> getValues() {
return Arrays.asList(null, "abc", "def", "ghi");
}
@RequestMapping(method = RequestMethod.GET)
public ModelAndView get() {
ModelAndView mv = new ModelAndView("stackoverflow/q26181188");
// Blank Form Backing Bean
FormBackingBean fbb = new FormBackingBean();
fbb.setEntries(Arrays.asList(new Entry(), new Entry(), new Entry(),
new Entry(), new Entry()));
mv.addObject("fbb", fbb);
return mv;
}
@RequestMapping(method = RequestMethod.POST)
public ModelAndView post(FormBackingBean fbb) {
ModelAndView mv = new ModelAndView("stackoverflow/q26181188");
mv.addObject("fbb", fbb);
// Print Form Backing Bean
System.out.println("FBB: \n" + fbb);
// Redisplay submitted from
return mv;
}
}
Thymeleaf模板:
<div th:each="entry,entryStat : *{entries}">
Pair #<span th:text="${entryStat.count}">1</span>
<select th:field="*{entries[__${entryStat.index}__].id}">
<option th:each="key : ${keys}" th:value="${key}" th:text="${key}"></option>
</select>
<select multiple="multiple" th:field="*{entries[__${entryStat.index}__].values}">
<option th:each="value : ${values}" th:value="${value}" th:text="${value}"></option>
</select>
</div>
<button type="submit" name="submit" class="btn btn-primary">Submit</button>
</form>
</body>
</html>
编辑:响应的其他细节第一公司mment Map
和List
属性都可以映射到HTML表单字段的集合。每个Map.Entry
或列表元素都映射到单个HTML表单字段,其名称格式为propertyName[index]
,其中index是List
的情况下元素的整数索引,或者是条件的键值一个Map
。上面的解决方案说明了List
的情况。
为了说明Map
情况下,说你要导致myMap
具有以下内容的HTML表单:
123L : ["abc", "def"]
234L : ["abc", "ghi"]
工作倒退,对Spring MVC所需要的查询字符串(URL编码之前)创建上面的Map
将需要如下所示:myMap[123]=abc&myMap[123]=def&myMap[234]=abc&myMap[234]=ghi
。要让浏览器提交该查询字符串,HTML表单将必须具有两个多<select>
表单元素,其中一个使用name="myMap[123]"
,另一个使用name="myMap[234]"
。但是,表单元素的名称不能由标准HTML中的其他表单字段设置。换句话说,没有th:field
值的关键<select>
元素来做到这一点(回答这个Stackoverflow的问题)。
即便如此,一个开箱即用的解决方案将是客户端JavaScript脚本,它从表单字段收集必要的数据并创建提交表单所需的查询字符串。对于不同的观众来说,这将是一个不同的问题,但我认为这将是一个不必要的复杂和专业化的问题。此外,尽管上述解决方案既可以使用相同的 HTML表单生成来自MyDTO
的HTML视图,也可以通过表单提交生成MyDTO
,但JavaScript解决方案需要针对每个方向使用不同的专用代码。
谢谢。在这里,通过创建一个名为'Entity'的新类来提供另一种使用地图的方法,该类包含'id'(类似于'myMap'的键,而'List'是值。 。但是,如果不修改架构,没有办法解决吗? –
user12458
2014-10-06 11:04:33
我在原始问题的末尾添加了更多细节,简短答案是“否”,原因是StackOverflow问题的参数。可能包含诸如客户端JavaScript之类的东西,但我不明白为什么这是必要的。如果'MyDTO'是整个应用程序用于其他目的的模型对象,那么'MyDTO'可能不应该用作表单-backing bean for this form。视图和控制器之间的表单支持bean存在用于特定目的,并且不应该影响应用程序其余部分的体系结构。 – 2014-10-06 23:42:45