当表单中仅使用少量属性时,将完整的模型对象发布到控制器
问题内容:
我在某处已经读到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方法。那可能吗?
我知道有人可能已经问过这个问题,但是我找不到答案。
谢谢!
问题答案:
您可能不希望将实体用作可能存在安全隐患的表单后备对象。例如,可以伪造一个恶意请求来设置一些不需要的属性。
因此,通常最好为每个要处理的表单创建一个显式的表单支持对象。这将需要您编写更多的代码,但同时也消除了一些常见的问题(例如您遇到的问题)。
使用表单支持对象时,处理程序看起来像:
请注意,我将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:/";
}
PS使用bPostService.getPosts()
添加帖子到模型,并立即返回重定向似乎很没有意义;)
[编辑]验证
您可以使用Hibernate批注通过声明性验证或在中设置自定义验证器来验证表单支持对象WebdataBinder
。
hibernate注释
使用Hibernate批注时,可以将任何批注放在字段或getter上。为了使这些验证生效,您需要做两件事。
- 注册一个验证器bean
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
。 - 使用注释处理程序中表单支持对象的参数
@valid
。
例: 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());
}