无法绑定 Thymeleaf 中的复选框列表以获取回发的修改数据

Unable to bind list of checkboxes in Thymeleaf to get modified data POSTed back

我正在尝试为用户管理编写 UI,其中重要的事情之一是能够更改用户角色。

模型简单,用户属于多个角色,角色有多个用户。

下面的代码展示了用于编辑现有用户的独立@Controller:

@Controller
public class NewController {

    final Role r1 = new Role("admin");
    final Role r2 = new Role("user");
    final Role r3 = new Role("editor");

    final List<Role> allRoles = Arrays.asList(r1, r2, r3);

    final List<Role> userRoles = Arrays.asList(r3);

    @RequestMapping(value = "/edit", method = RequestMethod.GET)
    public ModelAndView editUser() {

        final User user = new User();
        user.setEmail("asdasdsa@email.com");
        user.setUsername("username");

        user.setAuthorities(userRoles);

        final ModelAndView mav = new ModelAndView("edit");

        allRoles.stream()
                .filter(r-> user.getAuthorities().contains(r))
                .forEach(r -> r.setChecked(true));

        mav.addObject("roles", allRoles);
        mav.addObject("user", user);
        return mav;
    }

    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    public ModelAndView updateUser(
            @ModelAttribute("user") User user,
            @ModelAttribute("roles") ArrayList<Role> roles,
            ModelMap model) {

        final List<Role> newRoles = roles.stream()
                .filter(r -> r.isChecked() != null)
                .filter(r -> r.isChecked() == true)
                .collect(Collectors.toList());

        user.setAuthorities(newRoles);

        return new ModelAndView("redirect:/edit");
    }
}

那是我的 Spring-Thymeleaf 页面,我可以在其中编辑用户:

<form th:action="'/edit'" method="POST" enctype="utf8">

    <div class="form-group row">
        <label class="col-sm-3" th:text="#{label.user.id}">Id</label>
        <span class="col-sm-5" th:text="${user.id}">id</span>
    </div>

    <div class="form-group row">
        <label class="col-sm-3" th:text="#{label.user.username}">Username</label>
        <input class="form-control" name="username" th:value="${user.username}" required="required"/></span>
    </div>

    <div class="form-group row">
        <label class="col-sm-3" th:text="#{label.user.email}">email</label>
        <input type="email" class="form-control" name="email" th:value="${user.email}"
               required="required"/></span>
    </div>

    <div class="form-group row">
        <label class="col-sm-3" th:text="#{label.user.password}">password</label>
        <input id="password" class="form-control" name="password" value=""
               type="password"/></span>
    </div>

    <div class="form-group row">
        <label class="col-sm-3" th:text="#{label.user.confirmPass}">confirm</label>
        <input id="matchPassword" class="form-control" name="matchingPassword" value=""
               type="password"/></span>
    </div>

    <div th:each="item, index : ${roles}">
        <input type="checkbox"
               th:text="${item.authority}"
               name="${item.authority}"
               th:checked="${item.checked}" />
    </div>

    <button type="submit" class="btn btn-primary" th:text="#{label.edit.save}">save</button>
</form>

当我点击 'Save' 按钮时,updateUser 方法被触发,但是 ArrayList roles 是空的。用户模型的其他值已正确传递,我可以毫无问题地更改 username/email/password,用户 bean 已正确填充。

好的,以不同的方式解决:

带有复选框处理的 HTML 页面片段应为:

<th:block th:each="role : ${roles}">
    <input type="checkbox"
           name="newRoles"
           th:checked="${role.checked}"
           th:value="${role.id}"/>
    <label th:text="${role.authority}"></label>
</th:block>

因此,当您提交表单时,您会在 newRoles RequestParam 中获得角色 ID 列表,这是我的 POST 控制器:

@RequestMapping(value = "/users/{id}/edit", method = RequestMethod.POST)
public ModelAndView updateUser(
        @ModelAttribute("user") User user,
        @RequestParam(value = "newRoles") ArrayList<Long> roles,
        BindingResult bindingResult , Model model) {

    final List<Role> newRoles =
            roles.stream()
                 .map(id -> roleService.findOne(id))
                 .collect(Collectors.toList());
    user.setAuthorities(newRoles);

    userService.update(user);

    return new ModelAndView("redirect:/users");
}