序言
我有一个带有User
实体和一组Role
的spring boot应用程序。
在编辑用户模板上,我以<select>
的倍数显示用户的角色。当使用一组User
来渲染现有Role
的视图时,我试图仅将集合中的角色标记为选中。
Thymeleaf为此提供了两个工具:
th:selected
:期望为布尔值(选择了true)
#sets
:它提供了一些类似于java.util.Set
的有用方法,在这种情况下使用的是contains()
。
问题
将找到的User
和所有可能的Role
以HashSet的形式添加到模型时,使用#sets.contains()
时,在使用找到的用户的角色和所有角色时始终返回false作为参数,因此在加载表单时不会选择用户的角色。
如果我使用th:selected="${{user.roles}}"
表示法,则所有选项都被选中(甚至那些用户没有的选项)。
代码
用户
public class User
{
private Long id;
private String username;
private String password;
private String passwordConfirm;
private Set<Role> roles;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
@Transient
public String getPasswordConfirm()
{
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm)
{
this.passwordConfirm = passwordConfirm;
}
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "users_role", joinColumns = @JoinColumn(name = "users_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
public Set<Role> getRoles()
{
return roles;
}
public void setRoles(Set<Role> roles)
{
this.roles = roles;
}
}
角色
public class Role
{
private Long id;
private String name;
private Set<User> users;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
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;
}
@ManyToMany(mappedBy = "roles")
public Set<User> getUsers()
{
return users;
}
public void setUsers(Set<User> users)
{
this.users = users;
}
}
控制器
@Controller
@RequestMapping("/admin")
public class AdminController
{
@Autowired
UserService userService;
@Autowired
RoleService roleService;
@RequestMapping("/user/edit/{id}")
public String editUser(Model model, @PathVariable("id") long id)
{
User user = userService.findByUserId(id);
HashSet<Role> foundRoles = roleService.getAllRoles();
model.addAttribute("user", user);
model.addAttribute("userRoles", foundRoles);
return "admin/adminUserDetail";
}
}
表格
<form role="form" th:action="@{/registration}" method="POST"
th:object="${user}">
<div th:if="${#fields.hasErrors('*')}">
<div class="alert alert-danger" role="alert">
<h3 class="alert-heading">It seems we have a couple problems with your input</h3>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
</div>
</div>
<div class="form-group">
<label>Username: </label> <input class="form-control" type="text" th:field="${user.username}"
placeholder="Username" name="username"/>
<label>Password: </label> <input class="form-control" type="password" th:field="${user.password}"
placeholder="Password" name="password"/>
<label>Password Confirm: </label> <input type="password"
th:field="${user.passwordConfirm}" class="form-control"
placeholder="Password Confirm"/>
<select class="form-control" multiple="multiple">
<option th:each="role : ${userRoles}"
th:value="${role.id}"
th:selected="${#sets.contains(user.roles, role)}"
th:text="${role.name}">Role name
</option>
</select>
<button type="submit" class="btn btn-success">Update</button>
</div>
</form>
答案 0 :(得分:1)
使用Set
时,其中的对象必须同时实现hashCode
和equals
,因为它们用于确定对象是否已在Set
中。除非是SortedSet
使用Comparator
或通过实现Comparable
的对象表示的自然顺序。
由于您不执行任何一项操作,因此即使对于看似相同的contains
实例,使用false
的人也只会返回Role
。因为根据合同,他们不是。
要修复在equals
和hashCode
对象中实现User
和Role
方法的问题。
public class Role {
public int hashCode() {
return Objects.hash(this.name);
}
public boolean equals(Object o) {
if (o == this) { return true; }
if (o == null || !(o instanceof Role) ) { return false; }
return Objects.equals(this.name, ((Role) o).name);
}
}
遵循这些原则可以解决问题。