模型属性被Thymeleaf设置为null。

4

我一直在处理以下问题:

我有一个简单的模型类叫做User。

public class User{

  private Long id;
  private String name;
  ...}

这是我的控制器代码:

@RequestMapping ( value = "/users", params = { "id" } )
public String showEditForm( final Model model, final HttpServletRequest req )
{
    User edit = this.userRepository.findOne( Long.valueOf( req.getParameter( "id" ) ) );
    model.addAttribute( "user", edit );
    return "edit-user";
}


@RequestMapping ( value = "/users", method = RequestMethod.POST, params = {"edit"     
}) 
public String editUser( @Valid @ModelAttribute ( "user" ) final User user,
final BindingResult bindingResult, final Model model )
{
   if ( bindingResult.hasErrors() )
    {
        return "edit-user";
    }

    return "redirect:/users";
}

以下是显示所有用户的代码片段:
<div class="userlist" th:unless="${#lists.isEmpty(users)}">
    <h2 th:text="#{list.user.title}"></h2>
    <table>
        <thead>
            <tr>
                <th th:text="#{name}" />
                <th th:text="#{details}" />                 
            </tr>
        </thead>
        <tbody>
            <tr th:each="u : ${users}">
                <td th:text="${u.name}" />                  
                <td><a th:href="@{/users(id=${tc.id})}" th:text="#{edit}"></a></td>
            </tr>
        </tbody>
    </table>
</div>

最终提交表单:
<form action="#" th:action="@{/users}" th:object="${user}"
        method="post">
        <fieldset>
            <ul th:if="${#fields.hasErrors('*')}" class="errorlist">
                <li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
            </ul>
            <div>
                <input type="text" th:field="*{id}"/>
            </div>
            <div>
                <label for="name"> <span th:text="#{name}"></span>
                </label> <input type="text" th:field="*{name}"
                    th:class=" ${#fields.hasErrors('name')}? 'fieldError'" />
            </div>          
            <div class="submit">
                <button type="submit" th:text="#{update}" name="edit"></button>                 
            </div>
        </fieldset>
    </form>

现在是问题描述: 只要提交表单中存在“id”字段,一切都正常。但是,如果我从提交表单中删除“id”字段,因为id属性不应该被修改,工作流程就不再起作用了。实际上,在editUser()方法中,id为null。我认为Thymeleaf会将id属性的值设置为null,如果它不在提交表单中。但我不确定这一点。我认为必须有一些解决这个问题的方法,而不是让id属性驻留在提交表单中。
我希望有人能在这里提供帮助。
谢谢。
Edmond

2018年: 请查看手册,第6章 http://www.baeldung.com/thymeleaf-in-spring-mvc 或教程7.2 https://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#creating-a-form 只需在表单中使用th:object,并在input / textarea / ...中使用th:field =“* {xxx}” codes - Yuanbing Chen
2个回答

11

这与Thymeleaf无关,而是与绑定工作方式有关。Spring仅将在请求参数中存在的属性绑定到模型对象上。如果您删除不存在的id,它就无法被绑定(那么它应该绑定到哪里呢?)。

解决此问题的方法是要么将id指定为隐藏表单以确保其存在。或者在请求之间使用@SessionAttributes 将对象存储在会话中(在控制器上使用),这样先前检索的对象将用于绑定。

@Controller
@SessionAttributes("user")
public class UserController {

    @ModelAttribute("user")
    public User initUser(@RequestParam("id") Long id) {
        return this.userRepository.findOne(id);
    }

    RequestMapping ( value = "/users", params = { "id" } )
    public String showEditForm() {
        return "edit-user";
    }

    @RequestMapping ( value = "/users", method = RequestMethod.POST, params = {"edit"}) 
    public String editUser( @Valid @ModelAttribute ( "user" ) final User user, final BindingResult bindingResult, SessionStatus status;) {
       if ( bindingResult.hasErrors() ) {
            return "edit-user";
        }
        status.setComplete(); // Indicate we are done,so @SessionAttributes can be cleaned up
        return "redirect:/users";
    }

类似于这样的东西应该在会话之间保留用户,然后可以使用SessionStatus来触发对会话属性进行清理。


谢谢,添加@SessionAttributes()帮助我将对象的隐藏属性(如ID等)存储在会话中,这样我就不必在表单中公开它了。我很关心安全问题。 - Cristian

0

表单中应该包含ID字段,否则控制器将不知道应该更新哪个用户。

如果此字段对客户端没有意义(即它是一些生成的唯一ID),则应该将其隐藏。如果此字段可能对客户端有所兴趣,则可以将其设置为只读。


2
尽可能避免在屏幕上公开技术密钥/ID。如果我是一个恶意用户,我可以更改ID并修改完全不同的用户。因此,从安全角度来看,这不是明智之举。 - M. Deinum
1
M.Deinum - 是的,但这就是为什么表单应该在服务器端进行验证(例如使用BindingResult)的原因。 - Iwo Kucharski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接