Introduction

This page describes how to create quick and easy "Hello World" web-application using the Spring-MVC-REST framework.

Prerequisites

The reader is expected to have the following items installed, configured, and working:

  • Java 1.5+
  • A Java Servlet 2.4+ container (e.g. Tomcat 6)
  • Maven2

The reader is also expected to have a working knowledge of:

  • The Spring Framework
  • Spring-MVC
  • Java EE web technologies
    • JSP
    • JSTL
    • Servlets
  • Maven2

Overview

In this example we will create a simple web application that:

  • Accepts requests on the URI pattern: /user/{name}
  • Responds with a HTML page "Hello {name}!"
  • Responds with an XML page "<hello>{name}</hello>"

By following this example you will learn:

  • How to map URI patterns to controllers
  • How to bind URI parameters to commands
  • How to configure views selection

Part 1: Setup

The first thing to do is setup a simple Maven2 project. Create the following directory/file structure:

restexample/
  src/
    main/
      java/
        webapp/
          WEB-INF/
            web.xml
            dispatcher-servlet.xml
  pom.xml

At this point your pom.xml , web.xml , and dispatcher-servlet.xml files should be empty. Let's fix that.

This is a simple pom.xml . It declares that the project builds a war and uses the spring-webmvc-rest library. The rest of the Spring Framework libraries are brought in as transitive dependencies.

<?xml version="1.0" encoding="ISO-8859-1"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany</groupId>
  <artifactId>restexample</artifactId>
  <name>REST Example</name>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
  <dependencies>
    <dependency>
      <groupId>org.springframework.contrib</groupId>
      <artifactId>spring-webmvc-rest</artifactId>
      <version>0.9.1</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.14</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>restexample</finalName>
  </build>
</project>

Here's a simple web.xml file. It configures the Spring-MVC DispatcherServlet.

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

  <display-name>Example</display-name>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

Here's an empty dispatcher-servlet.xml file. This file configures the main Spring application context for this tutorial. The remainder of this tutorial will walk through the steps to fill in its contents.

<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <!-- TODO: follow the steps below to fill in this file -->
</beans>

At this point it might not be a bad idea to build your new project and make sure it deploys correctly on your application server. If it does not, you may need to tweak your dependencies.

Part 2: Define your URL mappings

Now that we have a basic Spring-MVC web-application set up, lets start to configure the actual application behavior. As we discussed in the Overview, the goal is to respond to URLs in the form: /user/{name} .

In traditional Spring-MVC we would use a SimpleUrlHandlerMapping. The Spring-MVC-REST framework extends SimpleUrlHandlerMapping with the MethodUrlHandlerMapping class. Add the following snippet to your dispatcher-servlet.xml file.

  <bean class="org.springframework.web.servlet.handler.MethodUrlHandlerMapping">
    <property name="mappings">
      <props>
        <prop key="GET /user/*">getUserController</prop>
        
        <!-- Some other example mappings
          <prop key="PUT /user/*">updateUserController</prop>
          <prop key="DELETE /user/*">removeUserController</prop>
          <prop key="POST /user">createUserController</prop>
        -->
      </props>
    </property>
  </bean>

The syntax is nearly identical to the SimpleUrlHandlerMapping . The one exception is the presence of the HTTP method at the beginning of the property key; hence the name, MethodUrlHandlerMapping .

This example also illustrates the relationship between HTTP methods, URLs, and controllers. Notice that several of the controllers share the same URL but have a different HTTP method.

Part 3: Create a Command and Controller

Next, lets define the controller configuration in dispatcher-servlet.xml . As you will see below, the controller class extends from AbstractRestController which is a type of Spring-MVC command controller. If you are unfamiliar with command controllers, see the Spring-MVC documentation.

  <bean name="getUserController" class="com.mycompany.web.controller.GetUserController">
    <property name="commandClass" value="com.mycompany.command.GetUserCommand" />
    <property name="uriPattern" value="/user/{name}" />
    <!-- TODO: ViewNameSelector -->
  </bean>

The uriPattern is used during data binding. Behind the scenes, Spring-MVC-REST uses a special data binder (UriPatternRequestDataBinder ) which reads the pattern syntax and parses out the parameters. This allows all the normal command data binding and validation to occur using this extra information.

Ignore the ViewNameSelector TODO for now. We will fill it in later.

Next, lets create a simple command class to capture the URI parameters. Save it as src/main/java/com/mycompany/command/GetUserCommand.java .

package com.mycompany.command;

public class GetUserCommand {
    private String name;

    public GetUserCommand() {
        this.name = null;
    }
    
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Spring-MVC data binding will ensure that setName() gets called with the value of {name} . The Spring-MVC documentation explains how this works.

The next step is to create the actual controller class. Save the example below as src/main/java/com/mycompany/web/controller/GetUserController.java .

package com.mycompany.web.controller;

import org.springframework.web.servlet.mvc.AbstractRestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;

import com.mycompany.command.GetUserCommand;

public class GetUserController extends AbstractRestController {

    public GetUserController() {
        super();
        
        // Make sure to set which method this controller will support.
        this.setSupportedMethods(new String[] { METHOD_GET });
    }

    protected ModelAndView handle(HttpServletRequest request,
            HttpServletResponse response, Object commandObj, BindException errors)
            throws Exception {

        GetUserCommand command = (GetUserCommand) commandObj;

        ModelAndView mav = new ModelAndView();
        mav.addObject("name", command.getName());
        return mav;
    }

}

Since this is just an example, we have omitted all error checking, etc. Notice that the command class is used to put the name of the user into the ModelAndView.

Part 4: Create Views

Here are two simple JSPs which will render our HTML and XML views:

HTML: Save as src/main/webapp/WEB-INF/jsp/user.html.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ page contentType="text/html; charset=ISO-8859-1"%>

<html>
  <head>
    <title>Hello <c:out value="${name}" />!</title>
  </head>
  <body>
    Hello <c:out value="${name}" />!
  </body>
</html>

XML: Save as src/main/webapp/WEB-INF/jsp/user.xml.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<%@ page contentType="text/xml; charset=ISO-8859-1"%>

<hello><c:out value="${name}" /></hello>

Next, lets configure the JSP view resolver. Add this bean to your dispatcher-servlet.xml file:

  <bean id="jspViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
      value="org.springframework.web.servlet.view.JstlView" />
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
  </bean>

Now we need to configure the controller to use these two views. The way we do that is by defining a ViewNameSelector . Add the following properties to your controller bean configuration in dispatcher-servlet.xml :

    <property name="viewNameSelector">
      <bean class="org.springframework.web.servlet.RestViewNameSelector">
        <property name="defaultViewName" value="user.html" />
        <property name="views">
          <map>
            <entry key="text/html" value="user.html" />
            <entry key="text/xml" value="user.xml" />
          </map>
        </property>
      </bean>
    </property>

The ViewNameSelector will look at the user request and determine which view name to use. At the moment, it looks primarily at the URI to see if there is a file-name-style suffix (.xml, .html, etc). If none exists, it will select the default view name. In the future, the ViewNameSelector will take the HTTP 'Accept' header into account.

Part 5: Test

Build:

  mvn clean package

Deploy to your servlet container.

Open your web browser to:

  • http://myserver/restexample/rest/user/World
  • http://myserver/restexample/rest/user/World.xml
  • http://myserver/restexample/rest/user/World.html

Completed Example

restexample.tar.gz