Home > Software Development > Practical Spring MVC Part 4: Web Services

Practical Spring MVC Part 4: Web Services

In this fast-paced, demo-driven series, I will take you on an exciting tour of Spring MVC. Unlike “pet clinic” style demonstrations, I will make use of practical solutions to real-world problems in order to demonstrate the breadth of functionality offered by Spring MVC. This article is a perfect fit for anyone looking for a quick overview of Spring MVC and its capabilities. Furthermore, complete code is included for those who wish to a follow along closely and explore the concepts presented.

Introduction

In the previous part we created a REST-full web application that exposed its results in JSON.  However, I strongly recommended building a separate controller for your application if you wish to offer a true web service interface to your application.  Fortunately, Spring MVC makes writing Web services as easy as writing controllers.

Reusable Controllers

Let us start by taking a look at the complete source code for the RestArticleController:

@Controller
@RequestMapping("/rest/articles")
public class RestArticleController extends AbstractRestController<Article> {
	@Autowired
	private ArticleService service;

	@Override
	public ArticleService getService() {
		return service;
	}
}

That is it!  So where is all of the functionality?  I wanted to take this as an opportunity to demonstrate how straightforward it is to create extensible/reusable controllers in Spring MVC.  Notice that the controller extends AbstractRestController.  The write-up controller will merely inherit all of the methods and request mappings from the abstract controller.  And, of course, the write-up controller can pick to override techniques when necessary.

@RequestMapping(value="{id}", method=RequestMethod.PUT)
@Transactional
public void update(@PathVariable long id, @RequestBody T object) {
	getService().save(object);
}

First, notice that this method is mapped to “{id}”.  Since RestArticleController is annotated with @RequestMapping (“/rest/articles”), this URL will be prepended to every request mapping defined within the controller and its superclasses.  As such, the update method is actually bound to “/rest/articles/{id}”.  This approach allows each controller that subclasses AbstractRestController to have unique URLs.

Next, notice that the second parameter is defined as T.  This is a class parameter, which, for RestArticleController, is bound to the class Article.  Despite the use of generics, Spring is able to determine that you are expecting an Article and “do the right thing”.  As such, for RestArticleController, the object will always be an instance of Article.

Finally, the implementation of the update method is based off of an abstract method called getService.  This method is implemented by RestArticleController, which returns an instance of ArticleService.

Armed with these three techniques one can easily create comprehensive controller hierarchies that consolidate functionality and eliminate “copy and paste” coding.  In fact, one can take this a step further and create mixable controller traits using AspectJ.  Unfortunately, I will have to reserve that for another article.

ResponseBody

Consider the view method:

@ResponseBody
@RequestMapping(value="{id}", method=RequestMethod.GET)
@Transactional
public T view(@PathVariable long id) {
	return getService().load(id);
}

The method is annotated with @ResponseBody and simply returns the instance of the article for the given ID.  Spring will analyze the request headers (specifically the Accepts header) to determine what type of content the client desires (e.g. XML, JSON) and use the appropriate converter to convert the entity object.  The approach is nearly identical with that of the ContentNegotiatingViewResolver discussed in the previous article.

RequestBody

While @ResponseBody converts an entity object to a transport format, @RequestBody goes the other direction and converts a transport format into an entity object.  Consider the insert method:

@RequestMapping(value="", method=RequestMethod.POST)
@Transactional
public void insert(@RequestBody T object) {
	getService().save(object);
}

The object parameter is annotated with @RequestBody, which tells Spring to convert the entire request body into an instance of this object (i.e. Article).  Spring does this by inspecting the request headers (specifically the Content Type) and uses the appropriate converter. The method does not need to return anything. In the absence of an exception, Spring will return a 200 response. In the event of exception, Spring will return an appropriate error response.

Other than the use of @RequestBody and @ResponseBody, building a REST web service controller is identical to that of building a standard controller.

@ResponseBody
@RequestMapping(value="", method=RequestMethod.GET)
@Transactional
public Collection<T> list() {
	return getService().find();
}

@RequestMapping(value="", method=RequestMethod.POST)
@Transactional
public void insert(@RequestBody T object) {
	getService().save(object);
}

@ResponseBody
@RequestMapping(value="{id}", method=RequestMethod.GET)
@Transactional
public T view(@PathVariable long id) {
	return getService().load(id);
}

@RequestMapping(value="{id}", method=RequestMethod.PUT)
@Transactional
public void update(@PathVariable long id, @RequestBody T object) {
	getService().save(object);
}

@RequestMapping(value="{id}", method=RequestMethod.DELETE)
@Transactional
public void delete(@PathVariable long id) {
	getService().remove(getService().load(id));
}

RestTemplate

To demonstrate the web service in action, I created a JUnit test that uses Spring’s RestTemplate to communicate with our web service.

RestTemplate rest = new RestTemplate();
Article article = rest.getForObject(ARTICLE_URL, Article.class, 1);

article.setTitle("UPDATED");
rest.put(ARTICLE_URL, article, 1);

article = rest.getForObject(ARTICLE_URL, Article.class, 1);
logger.log(Level.SEVERE, article.getTitle());

rest.delete(ARTICLE_URL, 1);

logger.log(Level.SEVERE, rest.getForObject(ARTICLES_URL, LinkedList.class).toString());

We start by creating the RestTemplate.  We use the getForObject method to issue a GET request to the ARTICLE_URL.  The third parameter, 1, is a URL parameter that expanded into the URL (replacing {id}).  Effectively, this is analogous to pointing a web browser to the corresponding URL, taking the resultant JSON, and converting it into an Article.

Next, we modify the article’s title and use the put method to post the article back to the server.  This is done by performing a PUT request to the same URL and including the article in the request body.  On the server, this content is converted back into an article instance and merged back to the database.

We can see the results of the update by retrieving the article a second time.  The result of the logging statement is the new title: “UPDATED”.

Similarly we can use the delete method to execute a DELETE request to remove an article from the database.  The results can be seen in the last statement which retrieves the list of articles in the database.

Summary

Writing web service controllers in Spring MVC is just as easy and nearly identical to writing controllers for web browsers.  In this example we used JSON; but, we could have used XML or even SOAP.

In the final part, I will discuss how to handle multi-request conversations and session data in Spring MVC.

  1. No comments yet.