Home > Articles > Programming > Java

Java Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

RESTful Web Services in Spring 3

Last updated Mar 14, 2003.

If youโ€™re looking for more up-to-date information on this topic, please visit our Java article, podcast, and store pages.

In the previous section I reviewed what RESTful web services are and how they can be used to simplify web service development and consumption. In this section I provide an example of building a RESTful web service using Spring 3.

If you're new to Spring then you're in for a double treat: not only will you see how easy it is to build a RESTful web service, but you'll also see how elegant it can be developing enterprise applications using Spring. If you're a Spring veteran, but have not developed a RESTful web service in Spring 3, I think you'll still be pleasantly surprised at how elegant the solution is.

The sample project is an “article service” that serves the following content:

  • A list of article categories
  • A specific article, requested by id, with the ability to request just the article summary or the entire article

The project is built using Maven and the new Spring 3 MVC annotations. Listing 1 shows the Maven POM file, which defines the dependencies needed to build the service.

Listing 1. pom.xml

<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.informit</groupId>
  	<artifactId>articleservice</artifactId>
  	<packaging>war</packaging>
  	<version>1.0-SNAPSHOT</version>
  	<name>articleservice Maven Webapp</name>
  	<url>http://maven.apache.org</url>
  	<properties>
    		<spring.version>3.0.0.RELEASE</spring.version>
    		<java.version>1.6</java.version>
    		<servlet-api.version>2.5.0</servlet-api.version>
  	</properties>
  	<build>
  		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
    		<finalName>articleservice</finalName>
  	</build>
  	<dependencies>
		<!-- Spring Dependencies -->
    		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.web.servlet</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.oxm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>com.springsource.javax.servlet</artifactId>
			<version>${servlet-api.version}</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
  			<groupId>com.thoughtworks.xstream</groupId>
  			<artifactId>xstream</artifactId>
  			<version>1.3.1</version>
  		</dependency>
  		<dependency>
    		<groupId>commons-logging</groupId>
    		<artifactId>commons-logging</artifactId>
    		<version>1.1.1</version>
		</dependency>
		<dependency>
      		<groupId>junit</groupId>
      		<artifactId>junit</artifactId>
      		<version>4.6</version>
      		<scope>test</scope>
    	</dependency>
  	</dependencies>

  	<!-- Add the Spring Maven Repositories to this project -->
	<repositories>
		<repository>
		  <id>com.springsource.repository.bundles.release</id>
		  <name>SpringSource Enterprise Bundle Repository - Release</name>
		  <url>http://repository.springsource.com/maven/bundles/release</url>
		</repository>
	</repositories>
</project>

The POM file defines the following main sections:

  • Build: the build section includes the maven-compiler-plugin that tells Maven to build against Java 1.6 and has a <finalName> node that tells Maven to name the final web application articleservice.war.
  • Dependencies: Spring 3 differs from Spring 2.5.x in that there is no longer on large Spring JAR file, but rather several small JAR files. Therefore you need to include the sections that you want. In this example I included Spring's core files, web file, and ORM files (although the ORM files are not needed for this example, if you later integrate Hibernate with the application then you'll need that dependency.) Finally, it includes the Thoughtworks XStream library, which we'll use via annotations to convert our model objects into XML documents.
  • Repositories: In order to use the new Spring 3.0.0 RELEASE classes, you'll need to add the Spring release repository to your POM file (or to your settings.xml file).

Listing 2 shows the web.xml file, which configures how requests are delivered to the Spring DispatcherServlet.

Listing 2. web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

  	<display-name>Article Web Service</display-name>
  	
  	<servlet>
		<servlet-name>article</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

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

There are not any real surprises in the web.xml file. It defines the standard Spring DispatcherServlet with the name “article” and then matches all requests “/*” to that article servlet. In Spring 2.5.x you needed to define a context listener and tell it where your application context configuration files were, but in Spring 3, when it sees that you have an “article” servlet, it automatically looks for a file named article-servlet.xml in the WEB-INF directory (you must include it, it is not optional.) Listing 3 shows the contents of the article-servlet.xml file.

Listing 3. article-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/
   schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/
               schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/oxm http://www.springframework.org/
               schema/oxm/spring-oxm-3.0.xsd">

    <context:component-scan base-package="com.informit.articleservice" />

	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />

	<bean id="articleXmlView" 
		  class="org.springframework.web.servlet.view.xml.MarshallingView">
		<constructor-arg>
			<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
				<property name="autodetectAnnotations" value="true"/>
			</bean>
		</constructor-arg>
	</bean>
</beans>

The article-servlet.xml file does a couple important things:

  1. It tells Spring to scan the com.informit.articleservice package, and its sub packages, for Spring components
  2. It defines an articleXmlView bean that it initializes with a ThoughtWorks XStreamMarshaller instance. The XStreamMarshaller class will convert any class annotated with an XStreamAlias annotation to an XML document, as we'll see shortly.

With that configuration behind us, the rest is downhill: we define our classes and annotate them and then Spring takes care of the rest. The most important class in our project is the Spring MVC ArticleController class, shown in listing 4.

Listing 4. ArticleController.java

package com.informit.articleservice;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.informit.articleservice.model.Article;
import com.informit.articleservice.model.Category;
import com.informit.articleservice.service.ArticleService;

/**
 * Spring MVC controller for processing RESTful web service requests for the article service
 * 
 * @author shaines
 */
@Controller
public class ArticleController
{
	/**
	 * Provides access to article business methods
	 */
	@Autowired
	private ArticleService articleService;
	
	@RequestMapping( value="/article/{category}/{id}", method=RequestMethod.GET )
	public ModelAndView loadArticle( @PathVariable String category,
									 @PathVariable int id,
									 @RequestParam( value="mode", required=false ) String mode ) 
	{
		// Load the article based on the mode
		Article article = null;
		if( mode != null && mode.equalsIgnoreCase( "summary" ) )
		{
			article = articleService.getArticleSummary( category, id );
		}
		else
		{
			article = articleService.getArticle( category, id );
		}
		
		// Create and return a ModelAndView that presents the article to the caller
		ModelAndView mav = new ModelAndView( "articleXmlView", BindingResult.MODEL_KEY_PREFIX +
       "article", article );
		return mav;
	}
	
	@RequestMapping( value="/article", method=RequestMethod.GET )
	public ModelAndView loadArticleCategories() 
	{
		List<Category> categories = articleService.loadCategories();
		
		// Create and return a ModelAndView that presents the article to the caller
		ModelAndView mav = new ModelAndView( "articleXmlView", BindingResult.MODEL_KEY_PREFIX +
       "article", categories );
		return mav;
	}

}

The ArticleController class is annotated with the @Controller annotation, which identifies it as a Spring MVC controller class. It then marks up specific methods with the @RequestMapping annotation, which tells Spring the exact URI, in the case of “/article”, or the URI template, in the case of “/article/{category}/{id}”, that handles the request. URI templates are interesting because you can see that in the case of “/article/{category}/{id}”, Spring automatically identifies the pattern in the URI and then makes the actual values passed into the handler method available by using the @PathVariable annotation. So when is sees a URI like the following:

/article/games/1

It will automatically set the category variable to “games” and the id to 1 in the loadArticle() method invocation. And just to make things a little interesting, I added an additional optional (required=false) request parameter named “mode” that will be set in the loadArticle() method if the URI is of the form:

/article/games/1?mode=summary

The ArticleController class has injected into it an ArticleService (via the @Autowired annotation, which wires resources based on variable type.) It uses the ArticleService in both methods to load the appropriate business objects. With those business objects in place, each method returns a ModelAndView object that explicitly references the XStreamMarshaller as the “marshalling view” to present the result to the user, which was defined in the article-servlet.xml file. In the case of loadArticle() it converts a single Article object to XML and in the case of loadArticleCategories() it converts a list of Category objects to XML.

The rest of the application just fills in the blanks: the ArticleService interface and ArticleServiceImpl class define and implement, respectively, the business methods for interacting with articles, and are shown in listings 5 and 6.

Listing 5. ArticleService.java

package com.informit.articleservice.service;

import java.util.List;

import com.informit.articleservice.model.Article;
import com.informit.articleservice.model.Category;

/**
 * Defines the business methods for interacting with articles
 * 
 * @author shaines
 */
public interface ArticleService
{
	/**
	 * Returns a fully populated article
	 * 
	 * @param category		The article category
	 * @param id			The article id
	 * 
	 * @return				A fully populated article
	 */
	public Article getArticle( String category, int id );
	
	/**
	 * Returns an article that contains only the summary, no body.
	 * 
	 * @param category		The article category
	 * @param id			The article id
	 * 
	 * @return				An article that contains only a summary and no body
	 */
	public Article getArticleSummary( String category, int id );
	
	/**
	 * Returns a list of article categories
	 * 
	 * @return				A List of article categories
	 */
	public List<Category> loadCategories();
}

Listing 6. ArticleServiceImpl.java

package com.informit.articleservice.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Service;

import com.informit.articleservice.model.Article;
import com.informit.articleservice.model.Category;

/**
 * Implements the business methods for interacting with articles
 * 
 * @author shaines
 */
@Service( "articleService" )
public class ArticleServiceImpl implements ArticleService
{
	/**
	 * Returns a fully populated article
	 * 
	 * @param category		The article category
	 * @param id			The article id
	 * 
	 * @return				A fully populated article
	 */
	@Override
	public Article getArticle( String category, int id )
	{
		return new Article( 1,
							"My Article",
							"Steven Haines",
							new Date(),
							"A facinating article",
							"Wow, aren't you enjoying this article?" );
		
	}
	
	/**
	 * Returns an article that contains only the summary, no body.
	 * 
	 * @param category		The article category
	 * @param id			The article id
	 * 
	 * @return				An article that contains only a summary and no body
	 */
	@Override
	public Article getArticleSummary( String category, int id )
	{
		return new Article( 1,
				           "My Article",
				           "Steven Haines",
				           new Date(),
						   "A facinating article" );
	}
	
	/**
	 * Returns a list of article categories
	 * 
	 * @return				A List of article categories
	 */
	public List<Category> loadCategories()
	{
		List<Category> categories = new ArrayList<Category>();
		categories.add( new Category( "fun" ) );
		categories.add( new Category( "work" ) );
		return categories;
	}
}

In a practical application, the ArticleService would probably delegate article and category searches to an ORM tool like Hibernate, but for this example I hard coded the result for clarity. Feel free to implement such a solution by defining an ArticleDao interface and an ArticleDaoImpl class, annotated by Spring's @Repository annotation and then wire it into the ArticleServiceImpl class using a declaration like the following:

@Autowired
private ArticleDao articleDao;

The two model objects, Article and Category, are shown in listings 7 and 8, respectively.

Listing 7 Article.java

package com.informit.articleservice.model;

import java.io.Serializable;
import java.util.Date;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias( "article" )
public class Article implements Serializable
{
	private static final long serialVersionUID = 1L;
	
	private int id;
	private String title;
	private String author;
	private Date publishDate;
	private String summary;
	private String body;
	
	public Article()
	{
	}
	
	public Article( int id, String title, String author, Date publishDate, String summary, String body )
	{
		this.id = id;
		this.title = title;
		this.author = author;
		this.publishDate = publishDate;
		this.summary = summary;
		this.body = body;
	}
	
	public Article( int id, String title, String author, Date publishDate, String summary )
	{
		this.id = id;
		this.title = title;
		this.author = author;
		this.publishDate = publishDate;
		this.summary = summary;
	}

	public int getId()
	{
		return id;
	}

	public void setId( int id )
	{
		this.id = id;
	}

	public String getTitle()
	{
		return title;
	}
	public void setTitle( String title )
	{
		this.title = title;
	}
	public String getAuthor()
	{
		return author;
	}
	public void setAuthor( String author )
	{
		this.author = author;
	}
	public Date getPublishDate()
	{
		return publishDate;
	}
	public void setPublishDate( Date publishDate )
	{
		this.publishDate = publishDate;
	}
	public String getSummary()
	{
		return summary;
	}
	public void setSummary( String summary )
	{
		this.summary = summary;
	}
	public String getBody()
	{
		return body;
	}
	public void setBody( String body )
	{
		this.body = body;
	}
	
	
}

Listing 8. Category.java

package com.informit.articleservice.model;

import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
 * Defines a a category of articles
 * 
 * @author shaines
 */
@XStreamAlias( "category" )
public class Category
{
	private String name;

	public Category()
	{
	}
	
	public Category( String name )
	{
		this.name = name;
	}

	public String getName()
	{
		return name;
	}

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

The Article and Category classes are straightforward JavaBeans with one exception: they are annotated with the @XStreamAlias annotation. The alias defines the name of the bean, “article” and “cateogory” in this example, as it should appear in the XML document. Then the bean property names will be inferred from the method names, e.g. getTitle() will resolve to “title”.

With all of these pieces in place, you can build the application by executing mvn clean install and deploy it to your web container, e.g. if you are using Tomcat then copy it to Tomcat's webapps directory.

You can retrieve the article categories through the following URL:

http://localhost:8080/articleservice/article

Which returns the following document:

<list>
  <category>
    <name>fun</name>
  </category>
  <category>
    <name>work</name>
  </category>
</list>

Then you can retrieve an article with a category and id with the following URL:

http://localhost:8080/articleservice/article/fun/1

This returns the following document:

<article>
  <id>1</id>
  <title>My Article</title>
  <author>Steven Haines</author>
  <publishDate>2010-01-25 23:39:09.323 EST</publishDate>
  <summary>A facinating article</summary>
  <body>Wow, aren't you enjoying this article?</body>
</article>

Or if you just want to see the summary of the article you can load it as follows:

http://localhost:8080/articleservice/article/fun/1?mode=summary

And it returns the following document:

<article>
  <id>1</id>
  <title>My Article</title>
  <author>Steven Haines</author>
  <publishDate>2010-01-25 23:39:09.323 EST</publishDate>
  <summary>A facinating article</summary>
</article>

Spring provides a very elegant approach to help you rapidly build RESTful web services that uses a small amount of configuration and then a set of annotations. In the next section I demonstrate how easy it is to consume RESTful web services using Spring's RestTemplate class.