Monday, December 27, 2010

Spring 3 MVC: Using @ModelAttribute in Your JSPs

In this tutorial we will create a simple Spring 3 MVC application that uses JSPs for the presentation layer. We will create a simnple CRUD system using the @ModelAttribute

What is @ModelAttribute
@ModelAttribute has two usage scenarios in controllers. When you place it on a method parameter, @ModelAttribute maps a model attribute to the specific, annotated method parameter (see the processSubmit() method below). This is how the controller gets a reference to the object holding the data entered in the form.

You can also use @ModelAttribute at the method level to provide reference data for the model (see the populatePetTypes() method in the following example). For this usage the method signature can contain the same types as documented previously for the @RequestMapping annotation.

Note
@ModelAttribute annotated methods are executed before the chosen @RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through @ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.

Source: Spring 3 Reference Documentation
The @ModelAttribute is a convenient annotation for exposing your objects to your JSP pages, and returning the object back to your Controllers.

If you're familiar with the classin Spring of doing things, this annotation combines functionalities of a formBackingObject (or commandObject) and SimpleFormController's referenceData. However, as of Spring 3.0, these have been deprecated in favor of annotated controllers (Source: Spring 3 API SimpleFormController)

Let's start by declaring the required Spring configurations.

To enable Spring MVC we need to add it in the web.xml

web.xml

Take note of the URL pattern. When accessing any pages in our MVC application, the host name must be appended with
/krams
In the web.xml we declared a servlet-name spring. By convention, we must declare a spring-servlet.xml as well.

spring-servlet.xml


This XML config declares a view resolver. All references to a JSP name in the controllers will map to a corresponding JSP in the /WEB-INF/jsp location.

By convention, we must declare an applicationContext.xml

applicationContext.xml

This XML config declares three beans to activate the Spring 3 MVC programming model.

We're done with the required Spring XML configurations. We now focus on the two usage patterns of the @ModelAttribute annotation.

Pattern 1: Method Level
You can also use @ModelAttribute at the method level to provide reference data for the model (see the populatePetTypes() method in the following example). For this usage the method signature can contain the same types as documented previously for the @RequestMapping annotation.
Source: Spring 3 Reference Documentation
This means we declare a method in our controller and annotate the method with @ModelAttribute.

We will examine this pattern by displaying a list of addresses. First let's declare our controller.

AddressController

The controller has a method named getAllAddresses() that's been annotated with @ModelAttribute. We also provide a model name addresses

The model attribute addresses is referenced in the JSP page.

addressespage.jsp

In this controller we have to mappings:
/address/list1
/address/list2
Both mappings will yield the same result. However the models are retrieved in different ways.

The getAllUsingModelAttribute() method doesn't pass any model but instead relies on the @ModelAttribute for its data

Here's the actual screenshot of the JSP page from /address/list1

The getAllUsingModel() method retrieves the model by manually adding it on the Model. It also adds an extra model data named greetings

Here's the actual screenshot of the JSP page from /address/list2

They both produce the same list of addresses. So what's the difference? I don't see any except for one major difference:
@ModelAttribute annotated methods are executed before the chosen @RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database.

Source: Spring 3 Reference Documentation
Using the @ModelAttribute automatically prepopulates your list. If you're doing some updates in your controller, you might still get the old list unless you specifically override the list from the @ModelAttribute.

This is better explained when we move to the next usage pattern.

Pattern 2: Method Parameter Level
When you place it on a method parameter, @ModelAttribute maps a model attribute to the specific, annotated method parameter (see the processSubmit() method below). This is how the controller gets a reference to the object holding the data entered in the form.rameters in the chosen handler method, potentially with binding and validation applied to it.

Source: Spring 3 Reference Documentation
This means we have a method with a parameter and we annotate that parameter with a @ModelAttribute. The purpose of this pattern is to pass the data from the JSP page back to your controller. The data is automatically converted to a Java object.

We will examine this pattern by displaying a list of persons that we can edit and update. This example will also showcase some of Spring 3's RESTful annotations.

We begin by defining our main controller.

MainController.

This controller declares two @ModelAttribute at the method level. We already know what that does. Then there's a @ModelAttribute at the method parameter level:

This basically means your JSP page is sending a model attribute named personAttribute. Your controller picks this model attribute and assign it to a Java object Person. In this way you're manipulating an object instead of HTTP request parameters.

In this controller we have three mappings:
/main - retrieve all persons
/main/edit/{id} - (GET) retrieve and edit a person by his id 
/main/edit/{id} - (POST) save a person based on his id
Notice we have two /main/edit/{id}. How does our controller know which one to call? The controller's @RequestMapping doesn't just rely on the mapping value but it also uses the method type. In our case, it's either POST or GET. The GET method is used when we retrieve a page; whereas, the POST method is used when we're submitting a form. For more info, please check the following blog from SpringSource Annotated Web MVC Controllers in Spring 2.5

Also, we're using a special identifier in the mappings. We have declared a {id} in the path, and referenced that as @PathVariable in the method parameter. This is a URI template, one of the RESTful features of Spring 3 MVC.

What is a URI template?
A URI template is a URI-like string, containing one or more variable names. When these variables are substituted for values, the template becomes a URI. For more information, see the proposed RFC.

Source: REST in Spring 3: @MVC
For a thorough description of this subject, please visit the blog from SpringSourceREST in Spring 3: @MVC

Let's examine the associate JSP view for each mappings.

personspage.jsp

This is referenced by the mapping /main. There's nothing special here. This is exactly similar with our Address example earlier.

editpage.jsp

This JSP page is returned by the following controller method:

This method searches a person based on his id. If found, a model attribute is added in the Model. The name of the attribute is personAttribute. This can be any name.

To access the edit page, we need to manually type the following URL in the browser:
http://localhost:8080/spring-jsp-model-attribute/krams/main/edit/2
Just make sure to change the number to match the id that you want to edit.

Here's the Edit page:

When we're done editing the person, we submit the form.

Notice we use POST to submit the data. We also use the same model attribute name. We also pass the id in the action URL.

Once the data is sent, it is picked by the controller and assigned to the saveEdit method.

I advise my readers to read the important comments within this method. To display again the list of persons we can either pass the model manually or rely on the @ModelAttribute on the Method Level. However, there's a problem if you follow the Method Level. It doesn't show the updated list. You have to refresh the browser again to see it. Why?
Note
@ModelAttribute annotated methods are executed before the chosen @RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database.

Source: Spring 3 Reference Documentation
Because the list is populated even before it's processed by the method! As a workaround, you must pass the model manually so that you don't need to refresh the browser.

Here's the final JSP page.

Our application is now finished. We've managed to build a simple Spring 3 MVC application that uses JSPs for the presentation layer. We've also discussed the usage patterns of the @ModelAttribute.

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-jsp-model-attribute/

You can download the project as a Maven build. Look for the spring-jsp-model-attribute.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and Jasper, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3 MVC: Using @ModelAttribute in Your JSPs ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

42 comments:

  1. Thanks for the nice explanation!

    ReplyDelete
  2. Thank you so much for your examples! I'll download the code and see how it works....

    ReplyDelete
  3. Thanks for sharing, just one correction needed should remove these lines from pom.xml


    commons-logging
    commons-logging

    ReplyDelete
  4. @ronald132, thanks for pointing that out. I'm gonna check it later when I get home. Probably it's an old entry from an old pom.xml

    ReplyDelete
  5. Very helpful - thanks a lot.

    ReplyDelete
  6. Thanks for clear explanation!

    ReplyDelete
  7. thank you very much

    ReplyDelete
  8. great explanation,

    thanks

    ReplyDelete
  9. Replies
    1. http://localhost:8080/spring-jsp-classic-crud/krams/address/list1

      good luck!

      Delete
  10. I am sorry that this is a stupid question, but I am stuck. Can you tell me what is the starting URL for your sample?

    http://localhost:8080/spring-jsp-model-attribute/krams/addresspage.html?

    Thanks! Great tutorial, but I am stuck with this trivial roadblock.

    ReplyDelete
  11. great explanation
    thanks

    ReplyDelete
  12. Awesome ! I was struggling with @ModelAtrribute usage . Now I got the hold of it.But what I am still confused about is how JSP page where is form tag is used knows it has to bind form data onto Person object. Would be great if you could explain that.

    ReplyDelete
  13. Hi!
    Thanks for the explabation. I am currently faced with a similar modelattribute problem. Days of googling couldn't find me a solution... Maybe you could help me out?

    I have a similar setup as you use in your example. Except that the curency is not a string but a currency class. I could not find a way of creating a new object via spring mvc in a form thatwould reference an existing currency. I allways end up with a new currency object embedded in the newly created object.

    Could you post an exanple of such a spring mvc project.

    Thanks
    Dominik

    ReplyDelete
  14. @Anonymous, make sure the Currency objects that you pass are initialized and populated with values already. Then to access them on your JSP, you use dot notation, ie. currencies.currency.value or currencies.currency.name

    ReplyDelete
  15. Hi krams!
    Thanks for your reply. My problem is that i create a new object in a form and the object references a currency. But i end up with a new currency not with a reference to an existing currency in the newly created object.

    Access to the currencies works fine. They get displayed in the form as items if a select list. Do I need a form backing object and then a controller that generates my new object with the reference after the form is submitted?

    Thanks again!
    Dominik

    ReplyDelete
  16. @Dominik, I see the problem now. You're trying to create a new record that references an existing currency, but on your form, after submission, always creates a new currency. Usually what I do in such case is, I prepopulate the form with the currency's id. So when I submit the record, the currency's id is transmitted back to the controller. You will need to write a custom object to capture this information, meaning your domain object is now different from your data transfer object which sits on your controller. So all data you transmit will be mapped to the data transfer object. Then you map the dto to your domain object. The reason you must create a dto is because you're only passing the currency's ID not the whole object. So the property will be of type Long or Integer instead of a Currency.

    ReplyDelete
  17. @Dominik, instead of using Spring's form support, I suggest you use jQuery or similar and work on JSON objects instead. Another advantage in this approach is you don't need to use the @ModelAttribute anymore. You use standard HTML form tags as well.

    ReplyDelete
  18. Hi Krams, Could you explain how to pass the entire object from jsp to spring controller? Example:

    var="deleteUrl" value="/main/persons/delete.htm?id=person.id"


    href="${deleteUrl}">Delete

    And the controller is:


    @RequestMapping(value = "/persons/delete", method = RequestMethod.GET)
    public String delete(@ModelAttribute("id") PersonsID id, Model model) {

    id.getId();
    id.getInf();


    return "deleted_";
    }

    Thanks in advance, have a nice day!!.
    Vulcano

    ReplyDelete
  19. Great article !

    Thank you for your work

    ReplyDelete
  20. I am really new to Spring3.Amazing source code. really very helpful for me. Appreciate your help in uploading and explaining.

    ReplyDelete
  21. Amazing stuff and explanation.

    ReplyDelete
  22. How do you get errors back to the page if your not using a BindingResult?

    ReplyDelete
  23. Nice explanation! Very well done.

    ReplyDelete
  24. I have one doubt..What are the cases in which model attribute values are automatically pushed into the handler methods.??and when we need to manually add into our model.??Pls help..Am in bit confusion..

    ReplyDelete
  25. Can someone explain me how to setup project in eclipse propply

    ReplyDelete
  26. Thanks for the great tutorial, I'm trying to use it on a Weblogic 10.3.5 instance but I got a java exception about ELResolver unable to handle null base object. Can somebody help me?

    ReplyDelete
  27. Still fairly new to Spring, but to solve the updated modelattribute after POST issue, couldn't/shouldn't you use a redirect to the same page if the addition of the object was successful? In doing so wouldn't the modelattribute update and also the add form would be cleared to add another person?

    ReplyDelete
  28. Thanks for the explanation

    ReplyDelete
  29. After update, method saveEdit should redirect to show person list instead of forwarding. This will avoid duplicate submit (Edit multiple times)

    ReplyDelete
  30. Great!!

    Thanks Krams :)

    ReplyDelete
  31. Thanks.

    Although, I had to add an exclude of commons-logging for spring-web (in pom.xml) in order to make it work. Commons-logging is only excluded for spring-core for some reason.

    ReplyDelete
  32. Hi Krams,

    Thanks for your post. I have a quick question about css file. I have a project, which is using css file for styles and background images, after providing static content path in my spring servlet like:

    I am able to access all images and static files in jsp using like <img src="”, but there is some background images path defined in my css. Can you please advise how to give a path in css about images since css file doesn’t understand spring tags.

    Thank you very much your help.

    Thanks,
    Srini

    ReplyDelete
    Replies
    1. I suggest you looked at some of my latest tutorials on how I've exposed resources.

      Delete
  33. Hi Krams,
    thank you for you tutorial. I downloaded the zip file, xtracted it and imported it into STS. It is compiling, but a load of http://localhost:8080/spring-jsp-classic-crud/krams/address/list1 gives me a white page.
    Any hint?
    Thank you

    ReplyDelete
  34. Great tutorial!
    THANKS!

    ReplyDelete
  35. free work at home job work at home
    completing simple surveys from home. no registration fees. join today (http://tinyurl.com/6j53ne6) ids (11672)

    ReplyDelete
  36. Thank you for this nice and well explained Tutorial.

    ReplyDelete
  37. One of the simple and easy example to understand the concept quickly and clearly

    ReplyDelete