Java Spring MVC 形式:选项标记未连接到我的对象 ID 中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1928929/
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
Spring MVC form:options tag not wiring into my objects Id?
提问by James McMahon
I am trying to display my command objects collection field inside a list box. Inside said collection is a field, id and name. I want use the id as the html option value and the name as the option text. See the code below;
我正在尝试在列表框中显示我的命令对象集合字段。在所述集合中是一个字段、ID 和名称。我想使用 id 作为 html 选项值,使用名称作为选项文本。看下面的代码;
<form:select id="customCollection" path="customCollection" size="10">
<form:options items="${command.customCollection}" itemValue="id" itemLabel="name"/>
</form:select>
Name prints out fine, but value is left blank. Here is the output HTML;
名称打印正常,但值留空。这是输出 HTML;
<option selected="selected" value="">name-value</option>
My initial assumption was that my data was incorrect, but after putting the following code in my page;
我最初的假设是我的数据不正确,但在我的页面中放入以下代码后;
<c:forEach items="${command.customCollection}" var="c">
${c.id} : ${c.name} <br>
</c:forEach>
both the id and the name are correctly printed out. So my data is correctly being delivering to my view. Which makes me assume I am either using form:options incorrectly or hitting some bug in form:options.
id 和 name 都正确打印出来。所以我的数据正确地传递给我的观点。这让我假设我要么错误地使用了 form:options,要么在 form:options 中遇到了一些错误。
Can anyone help me out here?
有人可以帮我从这里出去吗?
EDIT:
Thanks to the help of BacMan and delfuego, I've been able to narrow down this issue to my binder.
编辑:
感谢 BacMan 和 delfuego 的帮助,我已经能够将这个问题缩小到我的活页夹。
Previously I was assigning the value in my element to the name of the row, here is my initial binder;
以前我将元素中的值分配给行的名称,这是我的初始活页夹;
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;
}
});
When I remove this code from my initBinder method the row value is correctly inserted into the form, but I need a customEditor to convert said value into a database object.
当我从 initBinder 方法中删除此代码时,行值正确插入到表单中,但我需要一个 customEditor 将所述值转换为数据库对象。
So this is my new attempt at a binder;
所以这是我对活页夹的新尝试;
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;
}
});
However this is causing the same behavior as the previous binder and making the value not show up. Any ideas about what I am doing wrong here?
然而,这会导致与之前的活页夹相同的行为,并使值不显示。关于我在这里做错了什么的任何想法?
EDIT 2:
As I mentioned above, if I comment out my custom binder then the Custom object does load its id and name correctly for the view portion of the form, but then never binds back into the parent object when I attempt to save it. So I really think the issue is with my binder.
编辑 2:
正如我上面提到的,如果我注释掉我的自定义绑定器,那么自定义对象确实会为表单的视图部分正确加载它的 id 和名称,但是当我尝试保存它时永远不会绑定回父对象。所以我真的认为问题出在我的活页夹上。
I've placed debugging statements inside my convertElement method. Everything looks like it should be worked, the dao is correctly pulling objects from the database. The only behavior that strikes me as suspect is that the convertElement method is called twice for each Custom item.
我已经在我的 convertElement 方法中放置了调试语句。一切看起来都应该正常工作,dao 正确地从数据库中提取对象。唯一让我怀疑的行为是每个自定义项目都调用了 convertElement 方法两次。
采纳答案by James McMahon
This is one of those issues that once I understood what was going wrong I don't understand how it ever worked in the first place.
这是其中一个问题,一旦我明白出了什么问题,我就无法理解它最初是如何工作的。
I was using CustomCollectionEditor in completely the wrong way. According to Marten Deinum's post in this thread,
我以完全错误的方式使用 CustomCollectionEditor。根据 Marten Deinum 在此线程中的帖子,
As I stated in the other thread already the CustomCollectionEditor is to create Collections (List, Set, ?). So it will populate the desired collection with elements of the desired type.
However it is not intended to convert single elements into a value. It is designed to work on Collections, not on a single Role instance. You want 1 PropertyEditor to do 2 tasks for you.
正如我在另一个线程中所述,CustomCollectionEditor 将创建集合(列表、设置、?)。因此,它将使用所需类型的元素填充所需的集合。
但是,它并不打算将单个元素转换为值。它旨在处理集合,而不是单个 Role 实例。您希望 1 个 PropertyEditor 为您完成 2 个任务。
So it was creating a unique collection for each element that eventually got nulled out in the Spring code when it attempted to generate the HTML.
因此,它为每个元素创建了一个唯一的集合,当它尝试生成 HTML 时,这些元素最终在 Spring 代码中被清除了。
This is what I ended up doing,
这就是我最终做的,
binder.registerCustomEditor(Custom.class,
new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
Custom custom = dao.find(Custom.class,
Integer.parseInt(text));
setValue(Custom);
}
});
I have no idea why my previous CustomCollectionEditor ever worked with the names as values.
我不知道为什么我以前的 CustomCollectionEditor 曾经使用名称作为值。
回答by delfuego
One thing that doesn't seem right to me is that command.customCollection
is being used both to populate the possible values for your form's select input AND to bind to the ultimate value(s) selected by the user with that select input. This doesn't make sense, at least to me... for example, if I had a form select for choosing the U.S. state of an address, I'd populate that select with a collection of valid states, but I'd bind the value of the select to the onestate which was ultimately chosen by the user.
对我来说似乎不正确的一件事是,command.customCollection
它既用于填充表单选择输入的可能值,又用于绑定到用户使用该选择输入选择的最终值。这没有意义,至少对我来说......例如,如果我有一个用于选择美国地址状态的表单选择,我会用一组有效状态填充该选择,但我会绑定select 的值到用户最终选择的一种状态。
Try this: create your customCollection
object outside of the context of your command
object. In other words, right now your customCollection
is a property of your command
object; instead of this, pull that object out of the command
object and make it its own page attribute. In the Spring MVC model, things like that that'll be used as the data sources for pulldowns and whatnot are typically known as reference data; in a SimpleFormController
, this data gets populated in the appropriately-named SipleFormController#referenceData
method. This separates the two different concepts -- the possible values for the select live in the reference data, and the ultimate value(s) chosen by the user live in the command object bound to the form and/or the select input.
试试这个:在你的customCollection
对象的上下文之外创建你的command
对象。换句话说,现在你customCollection
是你的command
对象的一个属性;取而代之的是,将该对象从对象中拉出command
并使其成为自己的页面属性。在 Spring MVC 模型中,像这样的东西将被用作下拉菜单的数据源等等,通常被称为参考数据;在 a 中SimpleFormController
,此数据以适当命名的SipleFormController#referenceData
方法填充。这将两个不同的概念分开——选择存在于参考数据中的可能值,以及用户选择的最终值存在于绑定到表单和/或选择输入的命令对象中。
So assuming this is in a SimpleFormController
, try to add (or appropriately modify) referenceData
as such:
因此,假设这是在 a 中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);
}
And then change your to:
然后将您的更改为:
<form:select id="customCollection" path="command" size="10">
<form:options items="${customCollection}" itemValue="id" itemLabel="name"/>
</form:select>
Does this make sense?
这有意义吗?
回答by BacMan
I'll attempt to provide a working sample, which may help to debug the issue you are having:
我将尝试提供一个工作示例,这可能有助于调试您遇到的问题:
<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>
Here is my Country class, which is member variable in my command object.
这是我的 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;
}
}
I use a custom property editor in the initBinder method of my Controller. I'll leave out the implementation because it uses a generic implementation.
我在控制器的 initBinder 方法中使用了自定义属性编辑器。我将省略实现,因为它使用通用实现。
binder.registerCustomEditor(Country.class, "country", editorServiceFactory.getPropertyEditor(Country.class, CustomPropertyEditor.class));
Here is the reference data (this method is called from the referenceData method of the Controller):
下面是参考数据(这个方法是从Controller的referenceData方法调用的):
public Map<String, List<?>> getDemographicReferenceData() {
Map<String, List<?>> referenceData = new HashMap<String, List<?>>();
referenceData.put("countries", countryDAO.findAll());
return referenceData;
}
I'm using Spring 2.5
我正在使用 Spring 2.5