0

我在某处读到过,对于 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 方法。那可能吗?

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

感谢!

4

3 回答 3

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:/";
}

PsbPostService.getPosts()用于向模型添加帖子并立即返回重定向似乎毫无意义;)

[编辑] 验证

可以使用 Hibernate 注释或在WebdataBinder.

休眠注解

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

  1. 注册一个验证器 bean org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
  2. 在处理程序中用 . 注释表单支持对象的参数@valid

例子:public String editProcessPost(Model model, @PathVariable Integer id, @ModelAttribute @Valid BPostForm editPost, BindingResult result)

请注意,使用验证需要 aBindingResult出现在参数列表中,并且它需要直接位于支持对象之后。这BindingResult将是所有验证错误的容器。

自定义验证器

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

MyPostValidator extends org.springframework.validation.Validator

编写验证器后,您可以将其添加到WebDataBinder.

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setValidator(new MyPostValidator());
}
于 2014-03-09T11:37:24.880 回答
0

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

在您的 Controller 类中执行以下操作:

// this method gets called by Spring after the GET/POST request but before the // binding of request parameters...
// for POST requests, we want the enity
@ModelAttribute("formName") // <---- Note the attribute name...this is    important
public Object getFormBackingObject(HttpServletRequest request) {
   if(!request.getMethod().equals("POST")) {
        return null;
   }

   // find primary key
   String id = request.getParameter("id");

   return serviceObject.getMyEntity(id);
}

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

   // editPost is the fully populated entity from the DB after request params
   // have been bound to it.

   myService.save(editPost);

   return "whatever....";
}
于 2016-12-25T01:41:28.813 回答
0

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

<form:hidden path="anothertext"/>

所以当表单被提交时,这个值将被自动设置。

在这里,您可能还有另外 2 个问题。

具有另一个值的隐藏字段

假设您想将其保留为隐藏值,但值应该不同,那么您可以像下面这样使用。

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

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

隐藏字段作为对象 如果您有另一个文本作为对象而不是纯文本怎么办。例如,如果它是一个用户对象,其 id 和 name 作为值,并且您在您的实体下使用如下

    @OneToOne
    @JoinColumn(name = "ownerName", referencedColumnName = "name")
    private User owner;

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

所以它会像下面这样。

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

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

于 2018-05-24T09:35:09.127 回答