Spring MVC - Выпадающий объект - Нет первичного идентификатора
Существует довольно распространенный случай использования, когда есть список объектов Java, из которых можно сделать выбор в веб-форме - обычно вы должны использовать первичный ключ объекта в качестве значения, чтобы контроллер мог либо делать поиск или просто привязать ключ к тому, какой объект создан/обновлен.
Моя проблема заключается в том, что список на выбор не является постоянным, ключевым объектам, они являются бизнес-моделями из службы, которые не имеют разумного способа получить их на основе содержащихся данных. Ниже приведен какой-то код psuedo, где список Foo указан на странице, и мы можем легко связаться с контроллером onSubmit имя Foo, но что, если есть другие поля Foo, которые необходимо отправить?
контроллер:
referenceData() {
...
List foos = fooService.getFoosForBar( bar )
return { 'foos', foos }
}
JSP:
<form>
...
<spring:bind path="formData.foo">
<select name="<c:out value="${status.expression}" />">
<c:forEach items="${foos}" var="foo">
<option value="<c:out value="${foo.name}"/>">
<c:out value="${foo.name}"/>
</option>
</c:forEach>
</select>
</spring:bind>
...
</form>
Некоторые примеры решений заключались бы в использовании скрытых полей для отправки других свойств Foo и синхронизации их с изменением выбора, но я предпочитаю не использовать JavaScript в такой ситуации, где он, вероятно, добавит путаницу. Конечно, есть и другие способы сделать это.
Мой вопрос: существует ли какая-либо стандартная практика для этого? Или я должен просто придумать свой собственный способ сделать это? Я бы предпочел не изобретать колеса, если это возможно, и это настолько очевидно, что просто крыло может быть не лучшим.
Ответы
Ответ 1
Исходя из ваших ограничений, вы должны закодировать другие данные memobers foos как значение параметра.
<option label="${foo.name}" value="${foo.encodedValues}"/>
Метод encodedValues
может выглядеть примерно так:
private String SEPARATOR = ",";
public String getEncodedValues()
{
final StringBuffer returnValue = new StringBuffer();
returnValue.append(field1);
returnValue.append(SEPARATOR);
returnValue.append(field2);
returnValue.append(SEPARATOR);
returnValue.append(field3);
return returnValue.toString();
}
Если у вас есть выбор, который должен иметь закодированные значения, вы можете создать класс, который кодирует и декодирует эти значения, чтобы централизовать код.
Ответ 2
Вы можете использовать индекс элемента в списке, чтобы вернуть его в запрос POST.
<spring:bind path="formData.fooIndex">
<select name="<c:out value="${status.expression}" />">
<c:forEach items="${foos}" var="foo" varStatus="i">
<option value="<c:out value="${i.index}"/>">
<c:out value="${foo.name}"/>
</option>
</c:forEach>
</select>
</spring:bind>
В вашем обработчике POST используйте foos.get(formData.getFooIndex())
Если foos может измениться между запросами GET и POST, вам нужно поместить foos
в сеанс, чтобы вы определенно ссылались на один и тот же объект в обработчике POST, как и в обработчике GET.