我正在尝试在列表框中显示我的命令对象集合字段。里面的集合是一个字段,id和名称。我想使用id作为html选项值,使用名称作为选项文本。请参阅以下代码;
<form:select id="customCollection" path="customCollection" size="10">
<form:options items="${command.customCollection}" itemValue="id" itemLabel="name"/>
</form:select>
名称打印正常,但值保留为空白。这是输出HTML;
<option selected="selected" value="">name-value</option>
我最初的假设是我的数据不正确,但在我的页面中放入以下代码之后;
<c:forEach items="${command.customCollection}" var="c">
${c.id} : ${c.name} <br>
</c:forEach>
正确打印出id和名称。所以我的数据正确地传递给我的观点。这让我觉得我要么使用表单:选项不正确,要么在表单中遇到一些错误:选项。
有人可以帮助我吗?
修改
感谢BacMan和delfuego的帮助,我已经能够将这个问题缩小到我的活页夹。
以前我将元素中的值分配给行的名称,这是我的初始绑定器;
binder.registerCustomEditor(Collection.class, "customCollection",
new CustomCollectionEditor(Collection.class) {
@Override
protected Object convertElement(Object element) {
String name = null;
if (element instanceof String) {
name = (String) element;
}
return name != null ? dao.findCustomByName(name) : null;
}
});
当我从initBinder方法中删除此代码时,行值正确地插入到表单中,但我需要一个customEditor来将所述值转换为数据库对象。
所以这是我对活页夹的新尝试;
binder.registerCustomEditor(Collection.class, "customCollection",
new CustomCollectionEditor(Collection.class) {
@Override
protected Object convertElement(Object element) {
Integer id = null;
if (element instanceof Integer) {
id = (Integer) element;
}
return id != null ? dao.find(Custom.class, id) : null;
}
});
但是,这会导致与上一个活页夹相同的行为并使值不显示。关于我在这里做错了什么的想法?
编辑2:
正如我上面提到的,如果我注释掉我的自定义绑定器,那么Custom对象会为表单的视图部分正确加载其id和名称,但是当我尝试保存它时,它永远不会绑定回父对象。所以我真的认为问题出在我的活页夹上。
我在我的convertElement方法中放置了调试语句。一切看起来都应该工作,dao正确地从数据库中提取对象。 唯一令我怀疑的行为是每个自定义项目都会调用convertElement方法两次。
答案 0 :(得分:4)
这是其中一个问题,一旦我明白出了什么问题,我就不明白它是如何起作用的。
我完全以错误的方式使用CustomCollectionEditor。根据Marten Deinum在this thread,
中的帖子正如我在另一个帖子中所说,CustomCollectionEditor是创建集合(List,Set,?)。因此,它将使用所需类型的元素填充所需的集合。
但是,它并不打算将单个元素转换为值。它旨在处理集合,而不是单个Role实例。您希望1个PropertyEditor为您完成2个任务。
所以它为每个元素创建了一个唯一的集合,当它试图生成HTML时,最终在Spring代码中被忽略了。
这就是我最终要做的事情,
binder.registerCustomEditor(Custom.class,
new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
Custom custom = dao.find(Custom.class,
Integer.parseInt(text));
setValue(Custom);
}
});
我不知道为什么我以前的CustomCollectionEditor使用名称作为值。
答案 1 :(得分:2)
我将尝试提供一个工作示例,这可能有助于调试您遇到的问题:
<form:form commandName="client" method="post" action="${edit_client}">
<form:select path="country">
<form:options items="${requestScope.countries}" itemValue="id" itemLabel="name"/>
</form:select>
</form:form>
这是我的Country类,它是我的命令对象中的成员变量。
public class Country {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(final Object anObject) {
if (anObject == null) {
return false;
} else if (this == anObject) {
return true;
} else if (anObject instanceof Country) {
final Country aCountry = (Country) anObject;
Integer aCountryId = aCountry.getId();
if (aCountryId != null) {
return aCountry.getId().equals(id);
}
}
return false;
}
@Override
public int hashCode() {
return id;
}
}
我在Controller的initBinder方法中使用自定义属性编辑器。我将省略实现,因为它使用了通用实现。
binder.registerCustomEditor(Country.class, "country", editorServiceFactory.getPropertyEditor(Country.class, CustomPropertyEditor.class));
这是参考数据(此方法是从Controller的referenceData方法调用的):
public Map<String, List<?>> getDemographicReferenceData() {
Map<String, List<?>> referenceData = new HashMap<String, List<?>>();
referenceData.put("countries", countryDAO.findAll());
return referenceData;
}
我正在使用Spring 2.5
答案 2 :(得分:1)
对我来说似乎不对的一件事是command.customCollection
用于填充表单选择输入的可能值并绑定到用户选择的最终值。选择输入。这没有任何意义,至少对我而言......例如,如果我有一个表单选择选择美国地址状态,我会用一组有效状态填充该选择,但我会绑定select到 one 状态的值,最终由用户选择。
尝试此操作:在customCollection
对象的上下文之外创建command
对象。换句话说,现在您的customCollection
是command
对象的属性;而不是这个,将该对象从command
对象中拉出并使其成为自己的页面属性。在Spring MVC模型中,类似于将用作下拉数据源的东西通常被称为参考数据;在SimpleFormController
中,此数据将以适当命名的SipleFormController#referenceData
方法填充。这将两个不同的概念分开 - 参考数据中的select live的可能值,以及用户在绑定到表单和/或选择输入的命令对象中选择的最终值。
假设这是SimpleFormController
,请尝试添加(或适当修改)referenceData
:
@Override
protected Map<?, ?> referenceData(HttpServletRequest request, Object command, Errors errors) throws Exception {
CustomCollection customCollection = new CustomCollection();
// ...populate your custom collection
request.setAttribute("customCollection", customCollection);
return super.referenceData(request, command, errors);
}
然后将您更改为:
<form:select id="customCollection" path="command" size="10">
<form:options items="${customCollection}" itemValue="id" itemLabel="name"/>
</form:select>
这有意义吗?