diff --git a/spring-framework-reference/src/mvc.xml b/spring-framework-reference/src/mvc.xml
index 4a60c74079d..001ff47a3dd 100644
--- a/spring-framework-reference/src/mvc.xml
+++ b/spring-framework-reference/src/mvc.xml
@@ -1468,94 +1468,224 @@ public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntit
linkend="rest-message-conversion">Message Converters.
-
- Command and Form Objects
+
+ Using @ModelAttribute on a controller method
+
+ The @ModelAttribute annotation can be used on a
+ method or on a method argument. This section explains its usage on a method while the
+ next section explains its usage on a method argument.
+
+ An @ModelAttribute on a method indicates a method
+ for adding model attributes. A few examples:
+
+ @ModelAttribute
+public void populateModel(Model model) {
+ model.addAttribute("types", this.clinic.getPetTypes();
+ // add more attributes ...
+}
- The @ModelAttribute annotation is central to
- working with command and form objects. It has a couple of usage scenarios
- described in this section.
-
+@ModelAttribute
+public void addAccount(@RequestParam String number, Model model) {
+ Account account = accountManager.findAccount(number);
+ model.addAttribute(account);
+}
+
+@ModelAttribute
+public Account addAccount(@RequestParam String number) {
+ return accountManager.findAccount(number);
+}
+
+
+ @ModelAttribute methods are not associated
+ with any request mappings. Simply they are invoked prior
+ to the invocation of every
+ @RequestMapping method in the same controller.
+ In terms of method arguments they support the same argument types as
+ @RequestMapping methods, hence allowing access to request
+ parameters, path variables, and so on -- see
+ for a complete listing.
+
+ There are two common use cases for @ModelAttribute
+ methods. One, is to add commonly needed model attributes - see the first example
+ above where the model is populated with pet types to be shown in a drop-down.
+ The second use case is to pre-load a command object - see the second and third
+ examples above with the Account object (more on command objects in the next section).
+
+ Note the two styles of @ModelAttribute methods.
+ In one style, the method accepts a Model and adds any number
+ of model attributes to it. In the second style, the method adds an attribute implicitly
+ by having it as its return value. That results in the object being added as an
+ attribute to the model. You can choose between the two styles depending on
+ whether you need to add one model attribute or multiple.
+
+ A controller can have any number of @ModelAttribute
+ methods. All such methods are invoked before @RequestMapping
+ methods within the same controller each contributing model attributes.
+
+ What happens when a model attribute name is not explicitly provided? In such cases
+ a default name is assigned to the model attribute.
+ For example if the method returns an object of type Account,
+ the default name used is "account". However, you can also change it to something else
+ through the value of the @ModelAttribute annotation.
+ Or if adding attributes directly to the Model, use the
+ appropriate overloaded addAttribute(..) method providing
+ both the attribute name and the attribute value.
+
+ Lastly the @ModelAttribute annotation can also
+ be used directly on an @RequestMapping method. In this
+ cause, the return value of the @RequestMapping method
+ will be added as a model attribute and the view name will be derived using
+ a convention -- see .
+
+
+
+
+ Using @ModelAttribute on a controller method argument
- The main scenario is using @ModelAttribute on
- a method parameter in order to get access to data received from a form submission
- or from request parameters. For example an object of type
- Person with fields firstName
- and lastName will be populated accordingly assuming
- the presence of either form or query string parameters with matching names:
- e.g. firstName=Rod and lastName=Johnson.
- Below is an example of a @ModelAttribute-annotated
- method parameter.
+ As explained in the previous section an @ModelAttribute
+ annotation can be used on a method or on a method argument. When used on a method argument,
+ the @ModelAttribute annotation indicates a command object. A command
+ object is an object with properties (e.g. Account rather than
+ a simple type like int or String) that is used to
+ populate a form or reversely to be populated with the data from an HTML form.
+ As you will see command objects can significantly automate the process of
+ working with forms -- rather than dealing with individual form
+ parameters one at a time you'll be have them in a one command object.
- @Controller
-@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
-@SessionAttributes("pet")
-public class EditPetForm {
+ To be more precise annotating a method argument with
+ @ModelAttribute means 3 things:
+
+ The command object should be located and/or instantiated.
+ It should be populated with request parameters from the current request.
+ The object should be added to the model.
+
+ See the following example:
+
- @RequestMapping(method = RequestMethod.POST)
- public String processSubmit(
- @ModelAttribute("pet") Pet pet,
- BindingResult result, SessionStatus status) {
+
+@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
+public String processSubmit(@ModelAttribute("pet") Pet pet) {
+
+}
+
+ The @ModelAttribute annotation
+ designates "pet" as a command object. But where does the object come from? There are two options.
+ It may have been added to the model by an @ModelAttribute
+ method as explained in the previous section. Or otherwise if it's not already in the model, it
+ is instantiated through the default constructor. Typically if the object needs to be retrieved
+ from a database first, you can create an @ModelAttribute
+ method to do that. Or otherwise rely on the default constructor. If multiple methods in the
+ controller work on the same object, you can have it stored in the HTTP session between requests.
+ That is explained in .
+
+
+ Using a URI template variable to retrieve a command object
+
+ There is one other more advanced way of instantiating a command object.
+ It is useful when the command object can be retrieved based on a URI template
+ variable. Here is an example:
- }
+
+@RequestMapping(value="/accounts/{account}", method = RequestMethod.PUT)
+public String save(@ModelAttribute("account") Account account) {
}
+ The name of the model attribute "account" matches to the name of a URI
+ template variable. Assuming there is a registered
+ Converter<String, Account>
+ or PropertyEditor that can turn a String
+ account number into an Account instance, those will be used
+ to provision the command object and have it added to the model.
+ If such a Converter or PropertyEditor does not exist, however the default
+ constructor will still be used.
+
+
+
- Before invoking the method, Spring MVC will create a Pet
- instance, populate it using request parameters, and also add it to the model
- under the name pet.
- The Pet instance may have been created using the
- default constructor (if available), it may have been obtained from the HTTP session in
- conjunction with use of @SessionAttributes (see the next section), or
- it may have been created by another @ModelAttribute-annotated method
- in the same class. A @ModelAttribute-annotated method
- is the second scenario for using the annotation.
+
+ Data binding and validation with @ModelAttribute
+
+ As mentioned in the previous section an @ModelAttribute
+ annotation means 3 things:
+
+ The command object should be located and/or instantiated.
+ It should be populated with request parameters from the current request.
+ The object should be added to the model.
+
+ In this section we'll focus on the second: data binding and validation.
+
+ After the command object has been provisioned using one of the methods described in the
+ previous section, the next step is to apply data binding and validation.
+ Spring's WebDataBinder does that by matching request parameters --
+ usually form data fields but can also be query string parameters -- to command object
+ properties, including properties of nested objects, and populates those properties
+ accordingly also applying type conversion as necessary.
+ For example an object of type Person with
+ properties firstName and age
+ will be populated assuming the presence of such named form fields.
+ As a result of data binding the command object is populated with the form data.
+
+ There are various ways to customize the data binding process.
+ For example you may wish to specify required fields, allowed and disallowed
+ fields, or extend type conversion.
+ See and also .
+
+ As a result of data binding there may be errors such as missing required
+ fields or type conversion errors. To check for such errors
+ add a BindingResult argument immediately following
+ the @ModelAttribute argment:
+
+
+@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
+public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
- When used at the method level a @ModelAttribute
- contributes one or more objects to the model. See the populatePetTypes()
- method in the following example:
+ if (result.hasErrors()) {
+ return "petForm";
+ }
+
+ // ...
- @Controller
-@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
-@SessionAttributes("pet")
-public class EditPetForm {
+}
+
+ BindingResult allows you to check if errors were found in
+ which case it's common to return to the same form where the errors
+ can be rendered with the help of Spring's <errors> form tag.
+
+ In addition to data binding you can apply validation using your own custom
+ validator passing the same BindingResult that was used to record
+ data binding errors. That allows for data binding and validation errors to be accumulated
+ in one place and subsequently reported back to the user:
- // ...
+
+@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
+public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
- @ModelAttribute("types")
- public Collection<PetType> populatePetTypes() {
- return this.clinic.getPetTypes();
+ new PetValidator().validate(pet, result);
+ if (result.hasErrors()) {
+ return "petForm";
}
+
+ // ...
+}
- @RequestMapping(method = RequestMethod.POST)
- public String processSubmit(
- @ModelAttribute("pet") Pet pet,
- BindingResult result, SessionStatus status) {
+ Or you can have validation invoked automatically by adding the
+ JSR-303 @Valid annotation:
+
+
+@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
+public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
- new PetValidator().validate(pet, result);
- if (result.hasErrors()) {
- return "petForm";
- }
- else {
- this.clinic.storePet(pet);
- status.setComplete();
- return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
- }
+ if (result.hasErrors()) {
+ return "petForm";
}
-
+
+ // ...
}
+
+ See and
+ for details on how to configure and use Spring's Validation support.
- @ModelAttribute methods are
- executed before the chosen
- @RequestMapping annotated handler method.
- They effectively pre-populate the model with specific
- attributes, often loaded from a database. Such an attribute can then
- be accessed through a @ModelAttribute-annotated
- @RequestMapping parameter.
- An @ModelAttribute method can contain the same
- method arguments as documented previously for
- @RequestMapping methods.
-
-
+
Specifying attributes to store in a session with