Lets say we have an entity Person, a controller PersonController and an edit.jsp page (creating a new or editing an existing person)
Controller
@RequestMapping(value = "/edit", method = RequestMethod.POST) public String editPerson(@RequestParam("fname") String fname, Model model) { if(fname == null || fname.length() == 0){ model.addAttribute("personToEditOrCreate", new Person()); } else{ Person p = personService.getPersonByFirstName(fname); model.addAttribute("personToEditOrCreate", p); } return "persons/edit"; } @RequestMapping(value = "/save", method = RequestMethod.POST) public String savePerson(Person person, BindingResult result) { personService.savePerson(person); return "redirect:/home"; }
edit.jsp
<form:form method="post" modelAttribute="personToEditOrCreate" action="save"> <form:hidden path="id"/> <table> <tr> <td><form:label path="firstName">First Name</form:label></td> <td><form:input path="firstName" /></td> </tr> <tr> <td><form:label path="lastName">Last Name</form:label></td> <td><form:input path="lastName" /></td> </tr> <tr> <td><form:label path="money">Money</form:label></td> <td><form:input path="money" /></td> </tr> <tr> <td colspan="2"> <input type="submit" value="Add/Edit Person"/> </td> </tr> </table> </form:form>
Im trying the code above (without using the @ModelAttribute annotation in the savePerson method, and it works correct. Why and when do i need to add the annotation to the person object:
@RequestMapping(value = "/save", method = RequestMethod.POST) public String savePerson(@ModelAttribute("personToEditOrCreate") Person person, BindingResult result) { personService.savePerson(person); return "redirect:/home"; }
As described in the Spring MVC documentation - the @ModelAttribute annotation can be used on methods or on method arguments.
@ModelAttribute is used for binding data from request param (in key value pairs), but @RequestBody is used for binding data from whole body of the request like POST,PUT.. request types which contains other format like json, xml.
The @ModelAttribute annotation can be used at the parameter level or the method level. The use of this annotation at the parameter level is to accept the request form values while at the method level is to assign the default values to a model.
The @ModelAttribute annotation is used as part of a Spring MVC web app and can be used in two scenarios. Firstly, it can be used to inject data objects in the model before a JSP loads. This makes it particularly useful by ensuring that a JSP has all the data it needs to display itself.
You don't need @ModelAttribute
(parameter) just to use a Bean as a parameter
For example, these handler methods work fine with these requests:
@RequestMapping("/a") void pathA(SomeBean someBean) { assertEquals("neil", someBean.getName()); } GET /a?name=neil @RequestMapping(value="/a", method=RequestMethod.POST) void pathAPost(SomeBean someBean) { assertEquals("neil", someBean.getName()); } POST /a name=neil
Use @ModelAttribute
(method) to load default data into your model on every request - for example from a database, especially when using @SessionAttributes
. This can be done in a Controller
or in a ControllerAdvice
:
@Controller @RequestMapping("/foos") public class FooController { @ModelAttribute("foo") String getFoo() { return "bar"; // set modelMap["foo"] = "bar" on every request } }
Any JSP forwarded to by FooController
:
${foo} //=bar
or
@ControllerAdvice public class MyGlobalData { @ModelAttribute("foo") String getFoo() { return "bar"; // set modelMap["foo"] = "bar" on every request } }
Any JSP:
${foo} //=bar
Use @ModelAttribute
(parameter) if you want to use the result of @ModelAttribute
(method) as a default:
@ModelAttribute("attrib1") SomeBean getSomeBean() { return new SomeBean("neil"); // set modelMap["attrib1"] = SomeBean("neil") on every request } @RequestMapping("/a") void pathA(@ModelAttribute("attrib1") SomeBean someBean) { assertEquals("neil", someBean.getName()); } GET /a
Use @ModelAttribute
(parameter) to get an object stored in a flash attribute:
@RequestMapping("/a") String pathA(RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("attrib1", new SomeBean("from flash")); return "redirect:/b"; } @RequestMapping("/b") void pathB(@ModelAttribute("attrib1") SomeBean someBean) { assertEquals("from flash", someBean.getName()); } GET /a
Use @ModelAttribute
(parameter) to get an object stored by @SessionAttributes
@Controller @SessionAttributes("attrib1") public class Controller1 { @RequestMapping("/a") void pathA(Model model) { model.addAttribute("attrib1", new SomeBean("neil")); //this ends up in session due to @SessionAttributes on controller } @RequestMapping("/b") void pathB(@ModelAttribute("attrib1") SomeBean someBean) { assertEquals("neil", someBean.getName()); } } GET /a GET /b
Your question appears to be answered already:
What is @ModelAttribute in Spring MVC?
To summarize the answer and blog post: when you want your form backing object (instance of Person) to be persisted across requests.
Otherwise, without the annotation, the request mapped method will assume Person is a new object and in no way linked to your form backing object. The blog post that poster references is really awesome by the way, definitely a must-read.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With