我已经读过某个地方,对于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方法。这可能吗?
我知道有人可能已经问过这个问题,但我找不到答案。
感谢!
答案 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注释时,您可以在字段或getter上放置任何注释。要进行这些验证,您需要做两件事。
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());
}
答案 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的现有用户合并。