I've read somewhere that for spring mvc, it is a expected behavior to get back NULL in case a form does not contain all the attributes of the model object set by the @ModelAttribute annotiation. S how can I use forms that don't have all the fields of the model object and still recieve the whole but updated object back to the post method of the controller.
A short example code of my intention:
Part of the controller:
....
@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:/";
}
....
The entity mapped by 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
}
Part of the JSP view:
<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>
As you can see the "anothertext" attribute is not used on the JSP, but I wan't it unchanged returned to the POST method of the controller. Is that possible?
I know some one probably already asked this question, but I cant find the answer to that.
Thank!
As suggested by @Bart if possible replace the usage of entity pojo to form pojo directly in the jsp. If you want to continue with the existing approach you can use those fields as hidden parameters.
So when the form is getting submitted this value will be set automatically.
Here you may have another 2 issues.
Hidden Field with another value
Suppose you want to keep it as hidden value, but value should be different, then you can use like below.
where object is any object available in the view scope.
Hidden Field As Object What if you have have anothertext as object instead of plain text. For example if it is a User object with id and name as value and you have used like below under your entity
In that case you have to use two values as hidden parameters. The id field of the object and the linking field (here it is name)
So it will go like below.
While persisting this back, hibernate will automatically merge with existing user from db with same id.
You might not want to use the entity as a form backing object which could have security implications. For example an malicious request could be forged to set some unwanted properties.
Therefor it's better in general to create a explicit form backing object for each form to process. It will require you to write more code but it also negates some common problems (like the one you're having).
When using a form backing object your handler looks more like:
Note that I altered the
BPost
argument toBPostForm
.P.s. Using
bPostService.getPosts()
to add posts to the model and immediately return a redirect seems rather pointless ;)[EDIT] Validation
Your form backing object can be validated using declarative validation using the Hibernate annotations or settings a custom validator in the
WebdataBinder
.Hibernate annotations
When using the Hibernate annotations you can place any annotation on a field or getter. For these validations to kick in you'll need to do two things.
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
.@valid
.Example:
public String editProcessPost(Model model, @PathVariable Integer id, @ModelAttribute @Valid BPostForm editPost, BindingResult result)
Note that using validation needs a
BindingResult
to be present in the argument list and it needs to be directly after the backing object. ThisBindingResult
will be a container for all validation errors.Custom validator
A custom validator is a bit more work. You will need to write your own first.
MyPostValidator extends org.springframework.validation.Validator
After writing the validator you can add it to the
WebDataBinder
.It's much easier than this actually....I've been using this method for years
In your Controller class do the following: