У меня много трудностей с отправкой назад формы на контроллер, который должен содержать просто аррайалист объектов, которые пользователь может редактировать.
Форма загружается правильно, но когда она отправляется, она никогда ничего не публикует.
Вот моя форма:
<form action="#" th:action="@{/query/submitQuery}" th:object="${clientList}" method="post">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Select</th>
<th>Client ID</th>
<th>IP Addresss</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr th:each="currentClient, stat : ${clientList}">
<td><input type="checkbox" th:checked="${currentClient.selected}" /></td>
<td th:text="${currentClient.getClientID()}" ></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}" ></td>
</tr>
</tbody>
</table>
<button type="submit" value="submit" class="btn btn-success">Submit</button>
</form>
Выше работает отлично, он правильно загружает список. Однако, когда я POST, он возвращает пустой объект (размером 0). Я считаю, что это связано с отсутствием th:field
, но в любом случае это метод POST контроллера:
...
private List<ClientWithSelection> allClientsWithSelection = new ArrayList<ClientWithSelection>();
//GET method
...
model.addAttribute("clientList", allClientsWithSelection)
....
//POST method
@RequestMapping(value="/submitQuery", method = RequestMethod.POST)
public String processQuery(@ModelAttribute(value="clientList") ArrayList clientList, Model model){
//clientList== 0 in size
...
}
Я попытался добавить th:field
, но независимо от того, что я делаю, это вызывает исключение.
Я пробовал:
...
<tr th:each="currentClient, stat : ${clientList}">
<td><input type="checkbox" th:checked="${currentClient.selected}" th:field="*{}" /></td>
<td th th:field="*{currentClient.selected}" ></td>
...
Я не могу получить доступ к currentClient (ошибка компиляции), я даже не могу выбрать clientList, он дает мне такие параметры, как get()
, add()
, clearAll()
и т.д., поэтому он должен иметь массив, однако я не может пройти в массив.
Я также пытался использовать что-то вроде th:field=${}
, это вызывает исключение времени выполнения
Я пробовал
th:field = "*{clientList[__currentClient.clientID__]}"
но также и ошибку компиляции.
Любые идеи?
ОБНОВЛЕНИЕ 1:
Тобиас предположил, что мне нужно обернуть свой список в wapapper. Итак, что я сделал:
ClientWithSelectionWrapper:
public class ClientWithSelectionListWrapper {
private ArrayList<ClientWithSelection> clientList;
public List<ClientWithSelection> getClientList(){
return clientList;
}
public void setClientList(ArrayList<ClientWithSelection> clients){
this.clientList = clients;
}
}
Моя страница:
<form action="#" th:action="@{/query/submitQuery}" th:object="${wrapper}" method="post">
....
<tr th:each="currentClient, stat : ${wrapper.clientList}">
<td th:text="${stat}"></td>
<td>
<input type="checkbox"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:checked="${currentClient.selected}" />
</td>
<td th:text="${currentClient.getClientID()}" ></td>
<td th:text="${currentClient.getIpAddress()}"></td>
<td th:text="${currentClient.getDescription()}" ></td>
</tr>
Затем мой контроллер:
@RequestMapping(value="/submitQuery", method = RequestMethod.POST)
public String processQuery(@ModelAttribute ClientWithSelectionListWrapper wrapper, Model model){
...
}
Страница загружается правильно, данные отображаются как ожидалось. Если я отправлю форму без какого-либо выбора, я получаю следующее:
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'clientList' cannot be found on null
Не уверен, почему он жалуется
(В методе GET он имеет: model.addAttribute("wrapper", wrapper);
)
Если я затем сделаю выбор, т.е. отметьте первую запись:
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='clientWithSelectionListWrapper'. Error count: 1
Я предполагаю, что мой контроллер POST не получает clientWithSelectionListWrapper. Не знаю, почему, поскольку я установил, чтобы оберточный объект был отправлен обратно через th:object="wrapper"
в заголовке FORM.
ОБНОВЛЕНИЕ 2:
Я добился определенного прогресса! Наконец, представленная форма подбирается методом POST в контроллере. Однако все свойства кажутся нулевыми, за исключением того, был ли элемент отмечен или нет. Я внес различные изменений, вот как он выглядит:
<form action="#" th:action="@{/query/submitQuery}" th:object="${wrapper}" method="post">
....
<tr th:each="currentClient, stat : ${clientList}">
<td th:text="${stat}"></td>
<td>
<input type="checkbox"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:checked="${currentClient.selected}"
th:field="*{clientList[__${stat.index}__].selected}">
</td>
<td th:text="${currentClient.getClientID()}"
th:field="*{clientList[__${stat.index}__].clientID}"
th:value="${currentClient.getClientID()}"
></td>
<td th:text="${currentClient.getIpAddress()}"
th:field="*{clientList[__${stat.index}__].ipAddress}"
th:value="${currentClient.getIpAddress()}"
></td>
<td th:text="${currentClient.getDescription()}"
th:field="*{clientList[__${stat.index}__].description}"
th:value="${currentClient.getDescription()}"
></td>
</tr>
Я также добавил конструктор param-less по умолчанию в мой класс оболочки и добавил параметр bindingResult
в метод POST (не уверен, если это необходимо).
public String processQuery(@ModelAttribute ClientWithSelectionListWrapper wrapper, BindingResult bindingResult, Model model)
Итак, когда объект отправляется, вот как он выглядит:
Конечно, системная информация должна быть нулевой (на данном этапе), но clientID всегда 0, а ipAddress/Description всегда null. Выбранное логическое значение корректно, хотя для всех свойств. Я уверен, что я допустил ошибку в одном из свойств где-то. Вернемся к расследованию.
ОБНОВЛЕНИЕ 3:
Хорошо, мне удалось правильно заполнить все значения! Но мне пришлось изменить td
, чтобы включить <input />
, который не то, что я хотел... Тем не менее, значения заполняются правильно, предполагая, что spring ищет входной тег, возможно, для сопоставления данных?
Вот пример того, как я изменил данные таблицы clientID:
<td>
<input type="text" readonly="readonly"
th:name="|clientList[${stat.index}]|"
th:value="${currentClient.getClientID()}"
th:field="*{clientList[__${stat.index}__].clientID}"
/>
</td>
Теперь мне нужно выяснить, как отображать его как простые данные, в идеале без присутствия окна ввода...