- Overview
-
Table of Contents
- J2SE: Standard Java
- Java Windows NT Services
- Apache Velocity
- Advanced J2SE
- Bytecode Instrumentation
- Dynamic Languages and the JVM
- J2SE 1.5.0: "Tiger"
- Java SE 6
- Java 7
- Core Computer Science Principles in Java (Data Structures)
- Annotations
- Java Generics
- Java New I/O
- Java Sound
- Java Applets
- JavaFX
- Java SE Threading
- Resource Management Using Semaphores
- Java Atomic Operations
- JavaTemplate Pages
- Executing Templates with the JtpExecutor
- Java Cryptography Extensions (JCE)
- Java Database Connectivity (JDBC) API
- Jakarta Commons - Net Class Library
- Jakarta Commons HttpClient
- Apache POI
- Regular Expressions
- JavaMail
- Cool Tools
- Building an Really Simple Syndication (RSS) Java App
- Embedding JavaScript in Java with Rhino
- Logging with Log4J
- Inside Swing
- Swing Components
- SwingX
- Swing Styled Documents
- Web Rendering in Java Swing Applications
- Java Look-and-Feel Graphics Repository
- Java Media Framework
- Quicktime for Java
- Media in Java Review 2008
- External Multimedia in Java
- Graphs and Charts
- Holiday Special: Electronic Greeting Card
- Media Framework: Presenter Application
- Standard Widget Toolkit
- JFace
- Java Performance Tuning
- J2EE Performance Tuning
- Caches and Pools
- Java Caching System
- EHCache
- Java Compression and Decompression
- Obfuscating Java Applications
- Continuous Integration
- Load Testing
- Tomcat Clustering
- High Scalability with Terracotta
- Troubleshooting Production Performance Issues
- Enterprise Java Testing
- Automated Unit Testing with JUnit and Ant
- Unit Testing: Tips From The Trenches
- Custom Ant Tasks
- Extensible Markup Language (XML)
- Java Web Technologies
- Web Frameworks
- Struts 2
- Wicket
- JavaServer Faces
- Distributed Programming / RMI
- Behavior Tracking Servlet Filter
- Servlet Filters
- Building a Robust Java Server
- J2EE: Enterprise Java
- Spring
- Spring 3
- Java Design Patterns
- Model-Driven Architecture
- Enterprise Messaging with ActiveMQ
- Event-Driven Architecture
- XDoclet
- Hibernate
- Developing Standalone Database Applications with Hypersonic DB
- Project Backup
- J2EE Project: Hands-On
- Enterprise Java Beans (EJB) 3.0
- Disaster Recovery
- Java Management Extensions (JMX)
- Service-Oriented Architecture
- Web Services
- RESTful Web Services
- Web Services with Apache CXF
- Atom Syndication
- Project: Building a Web Photo Gallery
- J2ME: Micro Java
- Specialized J2ME
- Optional Packages
- Other Java Technologies
- Derivatives and Competitors
- Java, Engineered for Integration
-
Additional Resources
- The World of Java Tools
- Building Java Applications with Ant
- Managing Java Build Lifecycles with Maven
- Acceptance Testing with FitNesse
- Source Control with Subversion
- Inversion of Control and Dependency Injection
- Certification
- Roadmap: Becoming an Enterprise Java Developer
- Roadmap: Becoming an Enterprise Java Developer in 2007
- The Business of Enterprise Software
- JavaOne 2006
- JavaOne 2007
- JavaOne 2008 Wrap-Up
- JavaOne 2009 Wrap-Up
- JavaOne 2010
- JavaOne 2011
- How to Survive in a Turbulent Job Market
- How to Hire the Best Talent
- Unified Modeling Language (UML)
- Cloud Computing
- Amazon EC2 and Java
- MongoDB
- Enterprise Java in 2008 and Beyond
- Predictions for 2018
RESTful Web Services in Spring 3
Last updated Mar 14, 2003.
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:
- It tells Spring to scan the com.informit.articleservice package, and its sub packages, for Spring components
- 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.
