在表单中仅使用少数属性时,将完整的模型对象发布到控制器

时间:2014-03-09 11:22:07

标签: spring hibernate spring-mvc hibernate-mapping spring-form

我已经读过某个地方,对于spring mvc,如果表单不包含@ModelAttribute注释设置的模型对象的所有属性,则返回NULL是一种预期的行为。我如何使用没有模型对象的所有字段的表单,仍然将整个但更新的对象接收回控制器的post方法。

我的意图的简短示例代码:

控制器的一部分:

....

    @RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
    public String editPost(Model model, @PathVariable Integer id) {
        model.addAttribute("editPost", bPostService.getPost(id));
        return "editPost";
    }

    @RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
    public String editProcessPost(Model model, @PathVariable Integer id, @ModelAttribute BPost editPost) {
        bPostService.updatePost(editPost);
        model.addAttribute("posts", bPostService.getPosts());
        return "redirect:/";
    }

....

由hibernate映射的实体:

@Entity
@Table(name = "sometable")
public class BPost {

    @Id
    @GeneratedValue
        @Column(name = "id")
    private int id;

    @Column(name = "title")
    private String title;

    @Column(name = "description")
    private String description;

    @Column(name = "text")
    private String text;

    @Column(name = "anothertext")
    private String anothertext;

    // getters and setters
}

JSP视图的一部分:

<form:form method="POST" modelAttribute="editPost" action="${pageContext.request.contextPath}/secure/post/edit/${editPost.id}">
<table>
<tbody>
    <tr>
        <td>title:</td>
        <td><form:input path="title"></form:input></td>
    </tr>
    <tr>
        <td>description:</td>
        <td><form:input path="description"></form:input></td>
    </tr>
    <tr>
        <td>text:</td>
        <td><form:input path="text"></form:input></td>
    </tr>
    <tr>
        <td><input value="Edit" type="submit"></td>
        <td></td>
    </tr>
</tbody>
</table>
</form:form>

正如您所看到的,JSP上没有使用“anothertext”属性,但我没有将它保持不变,返回到控制器的POST方法。这可能吗?

我知道有人可能已经问过这个问题,但我找不到答案。

感谢!

3 个答案:

答案 0 :(得分:2)

您可能不希望将该实体用作可能具有安全隐患的表单支持对象。例如,可以伪造恶意请求来设置一些不需要的属性。

因此,为每个要处理的表单创建一个显式的表单支持对象通常会更好。它需要你编写更多代码,但它也会消除一些常见问题(比如你所拥有的那些)。

使用表单支持对象时,处理程序看起来更像:

请注意,我将BPost参数更改为BPostForm

@RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
public String editProcessPost(Model model, @PathVariable Integer id, @ModelAttribute BPostForm editPost) {

    // fetch the original post
    BPost post = bPostService.findById(editPost.getId());

    // set the properties
    post.setTitle(editPost.getTitle());
    post.setDescription(editPost.getDescription());
    post.setText(editPost.getText());

    // update
    bPostService.updatePost(post);

    model.addAttribute("posts", bPostService.getPosts());
    return "redirect:/";
}

P.S。使用bPostService.getPosts()向模型添加帖子并立即返回重定向似乎毫无意义;)

[编辑]验证

您的表单支持对象可以使用Hibernate注释使用声明性验证进行验证,也可以在WebdataBinder中设置自定义验证器。

Hibernate注释

使用Hibernate注释时,您可以在字段或getter上放置任何注释。要进行这些验证,您需要做两件事。

  1. 注册验证器bean org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
  2. 使用@valid在处理程序中注释表单支持对象的参数。
  3. 示例:public String editProcessPost(Model model, @PathVariable Integer id, @ModelAttribute @Valid BPostForm editPost, BindingResult result)

    请注意,使用验证需要BindingResult存在于参数列表中,并且需要直接在后备对象之后。此BindingResult将是所有验证错误的容器。

    自定义验证器

    自定义验证器需要更多工作。你需要先写自己的。

    MyPostValidator extends org.springframework.validation.Validator

    编写验证程序后,您可以将其添加到WebDataBinder

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.setValidator(new MyPostValidator());
    }
    

答案 1 :(得分:0)

实际上比这更容易....我多年来一直在使用这种方法

在Controller类中,执行以下操作:

Rectangle

答案 2 :(得分:0)

正如@Bart所建议的那样,如果可能的话,将实体pojo的用法替换为直接在jsp中形成pojo。如果要继续使用现有方法,可以将这些字段用作隐藏参数。

<form:hidden path="anothertext"/>

因此,当表单提交时,将自动设置此值。

您可能还有另外两个问题。

具有其他值的隐藏字段

假设您想将其保留为隐藏值,但值应该不同,那么您可以使用如下所示。

<input type="hidden" name="anothertext" value ="{object.value}">

其中object是视图范围中可用的任何对象。

隐藏字段为对象 如果您将其他文本作为对象而不是纯文本,该怎么办?例如,如果它是一个具有id和name作为值的User对象,并且您在实体

下使用了类似的内容
    @OneToOne
    @JoinColumn(name = "ownerName", referencedColumnName = "name")
    private User owner;

在这种情况下,您必须使用两个值作为隐藏参数。对象的id字段和链接字段(这里是名称)

所以它将如下所示。

<form:hidden path="owner.id"/>
<form:hidden path="owner.name"/>

在坚持这一点的同时,hibernate将自动与具有相同id的db的现有用户合并。