Spring Finance > Part 2: Spring @MVC & Spring 3.0 REST integration

After a brief introduction of the Spring Finance Manager application in part 1 of this series, I am now discussing the technical aspects of the sample application. The main focus of this part is on the new REST features introduced since the first milestone release of Spring 3.0.

To keep things clear I am not providing code for the complete application (as laid out in the initial class diagram) in this article but rather just a cut-down version of the application. I decided to create a Spring MVC application with only one controller, one service, and two domain objects, Person and Address.

Project Code Repository & Build Instructions

I have created a project over at Google code to host my SVN repository. The project can be found here and the SVN repository is available via:

svn checkout http://spring-finance-manager.googlecode.com/svn/tags/FinanceManager-0.1/

Detailed build instructions are available on this Wiki page.

Spring @MVC

As mentioned before, the application uses Spring @MVC with annotations. Taking a look at PersonController.java we can see that a controller in Spring MVC is actually nothing more than a POJO with a few annotations which register this controller in the Spring application context as a controller:

@Controller
@RequestMapping("/person/**")
public class PersonController {

   @Autowired
   private PersonService personService;

   @RequestMapping(value = "person/{id}", method = RequestMethod.GET)
   public String show(@PathVariable("id") Long id, ModelMap modelMap) {
      Assert.notNull(id, "Identifier must be provided.");
      modelMap.addAttribute("person", personService.find(id));
      return "person/show";
   }
   //further methods omitted
}

Most likely, you will be familiar with the @Controller annotation. This annotation registers the controller class in the Spring application context as an MVC controller. The only configuration required to make Spring aware of Pojo’s annotated with @Controller is captured in the FinanceManager-servlet.xml configuration:

<context:component-scan base-package="net.stsmedia.financemanager"
      use-default-filters="false">
   <context:include-filter expression="org.springframework.stereotype.Controller"
         type="annotation"/>
</context:component-scan>

Apart from the @Controller annotation, I have used the @RequestMapping annotation to define a URI-to-class mapping. This maps this controller to the /FinanceManager/person/ path and all URIs under it. If you are unfamiliar with Spring’s @MVC model you can take a look at Juergen Hoellers blog post entitled ‘Annotated Web MVC Controllers in Spring 2.5′.

After injecting the PersonService using the @Autowired annotation, we are ready to take a look at the show() method shown above. This method is used to retrieve details of a specific person in REST style.

Spring 3.0 REST

Again, we use the @RequestMapping annotation to define a URI-to-method mapping. Further, a RequestMethod is defined as part of the @RequestMapping annotation to specify the HTTP request method the show method should apply to. So in this case a HTTP GET request to /FinanceManager/person/1 would return the desired data provided a person with id=1 exists. The Spring Dispatcher servlet supports the following HTTP request methods: GET, HEAD, POST, PUT and DELETE.

Spring 3.0 introduces the @PathVariable annotation allows convenient binding of a variable supplied in the request URI. The @PathVariable is the heart of the new Spring 3.0 REST features. In the code shown above the path variable designated as {id} is automatically mapped to a Long object (@PathVariable(“id”) Long id) thanks to the default Spring property editor support.

The only thing left is to query the personService.find(id) and to insert the result into a ModelMap object. As you have noticed, the show() method returns only a String which indicates the location of the view to which the results are to be rendered. An InternalResourceViewResolver is used to complete the mapping from “person/show” to “/WEB-INF/jsp/person/show.jsp”:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
   p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>

Let’s take a look at the update.jsp page:

<form:form action="/FinanceManager/person/${person.id}"
   method="PUT" modelAttribute="person">
[...]
</form:form>

You notice that the HTTP method is defined as method=”PUT”. Since this is not directly supported by the Web browser (most Web browsers only support GET and POST), we need to register an additional listener in web.xml:

<filter>
   <filter-name>httpMethodFilter</filter-name>
   <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter
      </filter-class>
</filter>

<filter-mapping>
   <filter-name>httpMethodFilter</filter-name>
   <servlet-name>FinanceManager</servlet-name>
</filter-mapping>

REST Mappings

In this section I wanted to elaborate a little bit on the REST mappings I am following for my PersonController. In a typical Web application such as the Spring Finance Manager, four types of functionalities are exposed to the user. These are: create a new person (resource), read (or show) details of an existing person (resource), update a person (resource), and delete (remove) a person (resource). This is what we call CRUD functions for reading and manipulating the Person entity. When creating REST applications it is recommended to adhere to the following pattern which maps the CRUD functions for an entity to HTTP methods.

HTTP CRUD
POST CREATE
GET READ
PUT UPDATE
DELETE DELETE

Apart from the standard CRUD functions an MVC controller also needs to supply form backing objects for the create.jsp and update.jsp forms for our Person entity. So for our PersonController the following REST mappings apply:

Resource GET PUT POST DELETE
Collection URI such as http://domain.com/financemanager/person/ List the members of the collection. For example list all the persons available in the system. Not used. Create a new person in the collection where the ID is assigned automatically by the collection. Not used.
Member URI such as http://domain.com/financemanager/person/5 Retrieve the addressed person with id=5 Update the addressed person with id=5. Not used. Delete the addressed person with id=5.
Member URI such as http://domain.com/financemanager/person/form Create Form – returns an initialized, but empty person for form binding. Not used. Not used. Not used.
Member URI such as http://domain.com/financemanager/person/5/form Update Form returns the person resource which is pre-populated for form binding Not used. Not used. Not used.

This table provides an overview of the REST mappings used in the Spring Finance Manager sample application. As you can see, the first two rows deal solely with the manipulation of resources while the last two rows of this table add some form mapping required when using Spring MVC. It would be possible to combine the forms for the create.jsp and update.jsp as they differ only in minor aspects. However, the REST mappings for the create form submits a HTTP POST message and the update form submits a HTTP PUT message. Hence, merging both forms require some more hacking in the JSPs and the controller.

Conclusion & Further Pointers

This article has demonstrated the general use of the Spring MVC framework with the (relatively) new Spring @MVC annotation style as well as the (brand new) REST capabilities of Spring @MVC. I have not shown how content negotiation works, such as delivering a XML, ATOM, RSS, or even a JSON document, however if someone presents a good use case how this fits into the Spring Finance Manager application I am happy to include a brief article as part of this series.

In the meantime, I would like to refer you to the excellent posts by my colleagues Arjen Poutsma and Alef Arendsen:

Also, along with the upcoming release of Spring 3.0 M3 documentation for these features should be available.

In the next part of this series I am planning to explain the backend implementation of the Spring Finance Manager application. In particular, I am planning to express some brief thoughts on the current domain model and it’s relationship to DDD. Further, I would like to discuss the integration of the sample application with the JPA API, Hibernate and the HSQL database.

  • Share/Bookmark

17 Responses Subscribe to comments


  1. Spring Finance > Part 3: DDD, JPA & Transaction Support | StSMedia

    [...] article is the exception to the rule :-) . The code for this article was already realeased with the previous article on the Google code project website. This was needed to get get the sample application running to [...]

    Mar 29, 2009 @ 12:17


  2. cease

    Hi I downloaded your example app. When I try to serve static files it goes to continuous redirect loop. I’m deploying on google app engine. any Ideas ?

    Apr 21, 2009 @ 20:16


  3. sschmidt

    Well, I guess I would need to see some logs :-) .

    I was planning to try it out myself one of these days but I am currently quite busy with work. So I won’t get to it very soon.

    Obviously you changed the persistence to use GAEs JPA or JDO support. Can you possibly share the changed sources and configurations for the complete application so I can deploy it and take a look myself? You could attach them to a bug ticket here: http://code.google.com/p/spring-finance-manager/issues/list ?

    Thanks.

    Stefan

    Apr 22, 2009 @ 20:37


  4. Mahesh Yamsani

    Hi,

    This was very helpful, at the same time it will be better for us, if you could provide some info about how to integrate rest in Spring dm Server(OSGi bundle development) module with a small example.

    May 22, 2009 @ 00:29


  5. sschmidt

    Hi Mahesh,

    This is on my TODO list, but the next part of this series will be looking at Spring Security.

    The REST features depend on Spring 3 which is not supported by the current dmServer release 1.0.

    However, there are milestone releases for it available so I would encourage you to try out the Spring Finance application there and gradually convert it to a bundle based solution. Alternatively, you can wait until the smServer sample applications have been updated for release 2.0 or wait for my blog post :) .

    Best,
    Stefan

    May 22, 2009 @ 11:04


  6. Mahesh Yamsani

    Hi Stefan,

    I just written a sample program for HelloWorld Rest API Using Spring 3.0 as a Web Module(OSGi). Please find it at
    http://maheshyamsani.blogspot.com/2009/05/rest-in-spring-30-sample-application-in.html

    May 27, 2009 @ 16:50


  7. Prashant

    This is a very good initiave.
    1. First it helps understand how to put spring framework technologies together
    2. Since you are releasing the source code, it actually reduces the ramp up time.
    I appreciate your effort and thank you. Soon your blog will be on top of every chart of enterprise application development :-)

    Jun 04, 2009 @ 00:50


  8. Jettro

    Very nice post. I am using your sample application to create something as well. Is helping me a lot to understand things better.

    thanks

    Jul 09, 2009 @ 23:47


  9. Arokia Raj

    hi mate,

    Its great article to kick start the application..

    Thanks for your service…

    Hope to see more contribution from you…

    Thanks,
    Arokia

    Aug 07, 2009 @ 15:54


  10. Peepod

    Hi Mate,

    Very nice tutorial series. I am working my way through from the beginning.

    I have a question for you. Building and deploying version 0.1, I am seeing strange x and y values appearing in the links for show and update.

    When I click on the show person link, the RESTful url appears as http://localhost:8080/FinanceManager/person/4?x=8&y=7.

    When I click on the update person link, the RESTful url appears as http://localhost:8080/FinanceManager/person/4/form?x=12&y=6.

    The actual values of x and y appear to be random, and moreover, they don’t appear as input form parameters.

    Therefore, my question for you is, where do these parameters come from? Some sort of debug/test code in spring M2?

    Aug 27, 2009 @ 19:04


  11. Stefan Schmidt

    @Peepod,

    Yes, these params appear to be added by dojo. I am not 100% sure but I think it has to do with back button support. I’ll take a look if this can be disabled by any means.

    -Stefan

    Aug 30, 2009 @ 10:31


  12. dddavid

    HI Stefan,

    I’ve imported your sample (Part 2) into SprinSource Tool Suite. It runs fine.

    However, I didn’t figure out how the hsqldb in-memory DB is started and how can I load some test data into the tables.

    Thanks,
    Dave

    Oct 02, 2009 @ 07:06


  13. Stefan Schmidt

    @ddavid,

    The in-memory DB is started with your application (when you deploy your war file in tomcat). Since it is in memory all data you entered will be lost as soon as you undeploy your application or shut down the container.

    As an alternative you can use a DB which saves your data persistently (HSQLDB persistent, MySQL, …). The connector setups for these are documented in the Spring framework documentation and fairly easy to setup since all the bits and pieces are already configured in this sample application.

    Hope this helps..

    -Stefan

    Oct 17, 2009 @ 12:25


  14. Dennis

    Hello Stefan,

    First of all, happy new year!

    After installing the application via maven, the created FinanceManager-0.5.war file worked fine after deploying it in Tomcat. However, when I imported the project into eclipse (I used STS), I keep on getting this error after building and deploying the project to STS tc server…

    org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named ‘conversionService’ must be of type [org.springframework.core.convert.ConversionService], but was actually of type [net.stsmedia.financemanager.web.flow.ApplicationConversionService]

    I haven’t even modifed the codes yet.

    Thanks,
    Dennis

    Dec 31, 2009 @ 22:21


  15. dragos

    hi Stefan,

    in the controller you used a some requestmappings path I’m not used to.
    First, the class annontation is @RequestMapping(“/person/**”) and then the methods @RequestMapping(value = “person”, method = ….). Can you give me some details about this kind of mappings?
    I’m using “/person” for class and “/create” or “/list” for methods.

    Thanks

    Jan 04, 2010 @ 10:54


  16. Mayur

    You rock. I used your application to get started 3.0 very easily. Your site is on top of my list. Thank you and appriciated

    Nov 20, 2010 @ 09:11


  17. yewint

    great sample app. I created my project based on this sample one.
    thank u vry much . And can u please provide another sample app that include session management?

    Jan 08, 2011 @ 05:52

Reply