Как связать список объектов с тимелистом?
У меня много трудностей с отправкой формы обратно в контроллер, который должен содержать просто массив объектов, которые пользователь может редактировать.
Форма загружается правильно, но когда она публикуется, кажется, что она ничего не публикует.
Вот моя форма:
<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:Тобиас предположил, что мне нужно завернуть свой список в обертку. Вот что я сделал:
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"
в заголовке формы.
Я добился определенного прогресса! Наконец, отправленная форма выбирается методом 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>
Я также добавил конструктор по умолчанию без параметров в мой класс-обертку и добавилbindingResult
Параметр для метода POST (не уверен, если это необходимо).
public String processQuery(@ModelAttribute ClientWithSelectionListWrapper wrapper, BindingResult bindingResult, Model model)
Поэтому, когда объект публикуется, он выглядит так:
Конечно, systemInfo должен быть нулевым (на данном этапе), но clientID всегда равен 0, а ipAddress / Description всегда равен нулю. Выбранное логическое значение верно для всех свойств. Я уверен, что я сделал ошибку в одном из свойств где-то. Вернуться к расследованию.
ОБНОВЛЕНИЕ 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>
Теперь мне нужно выяснить, как отобразить его в виде простых данных, в идеале без какого-либо присутствия поля ввода ...