Spring MVC использование формы: флажок для привязки данных
Я знаю, что уже были вопросы по этой теме, но я не понял, как решить следующую проблему:
У меня есть отношение пользователь / роли, и я хочу перечислить все доступные роли в JSP в качестве элементов флажков, где выбраны назначенные пользователям флажки. Тем не менее, соответствующие элементы не проверяются (здесь я использую Spring 3.1).
Извлечение из объекта User:
private Set<RoleEntity> roles = new HashSet<RoleEntity>();
Извлечение из Spring Controller (добавление объекта пользователя и списка ролей в модель):
UserEntity userEntity = userEntityService.findById(UserEntity.class, new Long(id));
model.addAttribute("userAttribute", userEntity);
List<RoleEntity> roleList = roleEntityService.findAll();
model.addAttribute("roleList", roleList);
Выписка из JSP:
<form:form modelAttribute="userAttribute" method="POST" action="${saveUrl}">
...
<table align="center">
<tr>
<td>ID</td>
<td>Role Name</td>
</tr>
<c:forEach items="${roleList}" var="role" varStatus="status">
<tr>
<td><form:checkbox path="roles" value="${role}" label="${role.id}" /></td>
<td><c:out value="${role.name}" /></td>
</tr>
</c:forEach>
</table>
...
</form:form>
Документация Spring MVC гласит следующее: Когда связанное значение имеет тип array или java.util.Collection, вход (флажок) помечается как "флажок", если сконфигурированное значение setValue(Object) присутствует в связанной коллекции.
Разве это не тот случай здесь? Что мне здесь не хватает?
Большое спасибо.
Павел
1 ответ
Я предполагаю, что вам не хватает реализации для equals
а также hashcode
методы класса RoleEntity.
Когда связанное значение имеет тип array или java.util.Collection, вход (флажок) помечается как "флажок", если сконфигурированное значение setValue(Object) присутствует в связанной коллекции.
Это правильно, но для проверки наличия в HashSet
тебе нужно equals
а также hashcode
реализовано правильно.
В качестве быстрого теста, чтобы увидеть, если это проблема, замените эту строку:
model.addAttribute("roleList", roleList);
с этой строкой:
model.addAttribute("roleList", userEntity.getRoles());
Вы отметили все свои флажки? Если да, то вы не предоставили свой equals
а также hashcode
и используются по умолчанию (наследуются от Object
).
По умолчанию equals
сравнивает идентичность, что означает, что переменная содержит тот же экземпляр, что и другая переменная. Равенство означает, что два разных объекта содержат одно и то же состояние или имеют, так сказать, одинаковое значение.
С помощью model.addAttribute("roleList", userEntity.getRoles())
запускает значение по умолчанию equals
метод для возврата true, потому что список и значения, которые вы проверяете на наличие в списке, идентичны (два одинаковых объекта всегда равны).
Но в вашем случае вы используете userEntityService.findById
для одного и roleEntityService.findAll
для другого, что означает разные объекты. На этом этапе вы должны использовать правильный тест на равенство, а не идентичность.
У тебя есть equals
/ hashcode
реализованы?
Основываясь на вашем коде, вот пример, который работает:
контроллер:
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class SomeController {
@RequestMapping(value = "/something", method = { RequestMethod.GET, RequestMethod.POST })
public String handle(Model model) {
UserEntity userEntity = new UserEntity();
userEntity.setRoles(new HashSet<RoleEntity>());
Collections.addAll(userEntity.getRoles(),
new RoleEntity(1, "one"),
new RoleEntity(3, "three"));
model.addAttribute("userAttribute", userEntity);
List<RoleEntity> roleList = Arrays.asList(
new RoleEntity(1, "one"),
new RoleEntity(2, "two"),
new RoleEntity(3, "three")
);
model.addAttribute("roleList", roleList);
return "view";
}
}
Класс пользователя:
import java.util.HashSet;
import java.util.Set;
public class UserEntity {
private Set<RoleEntity> roles = new HashSet<RoleEntity>();
public Set<RoleEntity> getRoles() {
return roles;
}
public void setRoles(Set<RoleEntity> roles) {
this.roles = roles;
}
}
Роли класс (обратите внимание на equals
а также hashcode
методы; если вы удалите их, пример больше не работает):
public class RoleEntity {
private long id;
private String name;
@Override
public int hashCode() {
return new Long(id).hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (! (obj instanceof RoleEntity)) {
return false;
}
return this.id == ((RoleEntity)obj).getId();
}
public RoleEntity(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Посмотреть:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<form:form modelAttribute="userAttribute" method="POST" action="/something">
<table align="center">
<tr>
<td>ID</td>
<td>Role Name</td>
</tr>
<c:forEach items="${roleList}" var="role">
<tr>
<td><form:checkbox path="roles" value="${role}" label="${role.id}" /></td>
<td><c:out value="${role.name}" /></td>
</tr>
</c:forEach>
</table>
</form:form>
PS Только одно замечание о вашей JSP. Если вы делаете value="${role}"
для вашей формы: флажок вы получите атрибуты флажок HTML, как value="your.pack.age.declaration.RoleEntity@1"
что может привести к другим неприятностям позже.