Spring MVC: Creating RESTful web service using annotation

In the previous articles, we have discussed about Spring MVC web application using both XML-based & @Controller annotation-based approach in detail. Now let’s explore by extending Spring MVC web application to develop RESTful web service using more annotations

REST Web Service (Learn REST)

REST stands for Representational State Transfer which is a simple stateless architecture communicated over the HTTP protocol for inter-platform interaction. It got verbs such as GET, POST, PUT, and DELETE to identify the difference amongst different operations exposed to external world

REST is much simpler to develop/implement than advanced SOAP based web services. Normally REST is used in Mobile application development as it’s faster. And in various social networking sites, REST is preferred over the matured SOAP services

With this introduction, we will see how we can implement REST web services in Spring MVC based web application for inter-platform communications

Spring MVC RESTful service

We have covered most of the annotations in Spring MVC web application; in additions to this we will add few more like @PathVariable, @RequestBody & @ResponseBody annotations to develop a working REST based application

Annotation used:

  • @Controller
  • @ResponseBody
  • @RequestBody
  • @RequestMapping
  • @PathVariable

Note: Folks who are all familiar with REST implementations and & got basic idea about Spring MVC will find easier to grasp it

Technology Used

  • Java 1.7
  • Eclipse Kepler IDE
  • Spring-4.0.0-RELEASE
  • Apache-Maven-3.0.4
  • Apache-Tomcat-7.0.41

Mavenize or download required jars

Add Spring-4.0.0 dependencies to the pom.xml

	<dependencies>
		<!-- for compile only -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<!-- JSTL tag library -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- Spring Core and Context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Jackson JSON mapper -->
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>jackson-mapper-asl</artifactId>
			<version>1.9.13</version>
		</dependency>
	</dependencies>

Folks who aren’t familiar with Maven concepts or don’t require maven for their project, can download the below jars individually from the spring site and include them in the classpath

Directory Structure

Before moving on, let us understand the directory/package structure once you create project in Eclipse IDE
Maven has to follow certain directory structure

  • src/test/java –> test related files, mostly JUnit test cases
  • src/main/java –> create source java files under this source folder
  • src/main/resources –> all configuration files placed here
  • Maven Dependencies or Referenced Libraries –> includes jars in the classpath
  • WEB-INF under webapp –> stores web.xml & other configuration files related to web application

1_SpringMVC-REST-3

Web application:

For any web application, entry point is web.xml which describes how the incoming http requests are served / processed. Further, it describes about the global-context and local-context param (i.e.; <context-param> & <init-param>) for loading the files particular to project requirements & contains respective listener.

With this introduction, we will understand how we configured web.xml for our REST application in Spring MVC

web.xml (the entry point –> under WEB-INF)

This web.xml file describes,

  • all http requests with wild card pattern “/” will be intercepted by the configured servlet called “DispatcherServlet” (org.springframework.web.servlet.DispatcherServlet)
  • </servlet-name> name mentioned in the web.xml is mvc-rest-dispatcher, which on loading/exploding the war into the application server(Tomcat application server for our example) looks for the servlet filename called “mvc-rest-dispatcher-servlet.xml”
  • <context-param> with its attributes describes the location of the file from where it has to be loaded
  • “mvc-rest-dispatcher-servlet.xml” is the file which describes how exactly specific http requests are handled or which controllers gets invoked for certain http requests. We will see “mvc-rest-dispatcher-servlet.xml” file for our Spring MVC REST application
  • <welcome-file-list> files under this tag is the start-up page

web.xml

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

	<!-- project display for web application -->
	<display-name>SpringMVC-REST</display-name>

	<!-- welcome file list -->
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<!-- Spring MVC DispatcherServlet: dispatches HTTP requests to registered controllers -->
	<servlet>
		<servlet-name>mvc-rest-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-rest-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- location of the root application context xml file -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/mvc-rest-dispatcher-servlet.xml</param-value>
	</context-param>

	<!-- context loader listener -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

Dispatcher Servlet

Below mvc-rest-dispatcher-servlet.xml file defines,

  • <context:component-scan base-package=”” /> this tag scans all classes & sub-classes under the value of base-package attribute and register them with the container
  • Basically these classes are annotated with @Controller on top of the class with value attribute for URL path
  • <mvc:annotation-driven /> declares explicit support for annotation-driven MVC controllers (i.e. @RequestMapping, @Controller and message body marshalling/unmarshalling with @RequestBody/ResponseBody)
  • We will understand @ResponseBody & @RequestBody in detail before coding implementation

mvc-rest-dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

	<!-- scans packages to register controllers using annotations -->
	<context:component-scan base-package="com.spring.series.mvc.rest.controller" />

	<!-- support for mvc-annotation -->
	<mvc:annotation-driven />

	<!-- view resolver for rendering the final output -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/jsp/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
</beans>

@ResponseBody & @RequestBody

They are Spring MVC annotations used to serialize/de-serialize the incoming request message & out-going response body from java object to XML/JSON and vicey-versay

@ResponseBody – converts return value from our object to http response (i.e.; XML/JSON)
@RequestBody – converts incoming http request to our object on the fly

Really helpful …..rite? huh cumbersome boilerplate code is avoided to do marshalling/un-marshalling steps.

Let’s see coding in action

 

Model Class (my POJO’s)

Simple Java POJO with three member variables and its getter/setter with few JAXB annotations which comes shipped in JDK from 1.5. These JAXB annotations are basically to do serialization/De- serialization process automatically.

Note: for our application we have used JDK 1.7 0r JDK 7.0

Player.java

package com.spring.series.mvc.rest.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="player")
@XmlAccessorType(XmlAccessType.NONE)
public class Player {

	@XmlElement(name = "id")
	private int id;
	@XmlElement(name = "name")
	private String name;
	@XmlElement(name = "matches")
	private String matches;

	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getMatches() {
		return matches;
	}
	public void setMatches(String matches) {
		this.matches = matches;
	}
}

Controller class

Component class called “MyRestController” with three public methods with various combinations of incoming http request message & return value from simple java primitive to complex types

Go-through the java class first & after that read it description scripted in detail.

MyRestController.java

package com.spring.series.mvc.rest.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.spring.series.mvc.rest.model.Player;

@Controller
@RequestMapping("/cricket")
public class MyRestController {

	// http://localhost:8081/SpringMVC-REST/cricket/getiplteam/MI

	/**
	 * Returns full-form of the IPL team in STRING format, based on the input arguments(iplcode)
	 *
	 * @param iplcode
	 * @return
	 */
	@RequestMapping(value="/getiplteam/{iplcode}", method=RequestMethod.GET)
	@ResponseBody
	public String getIPLTeam(@PathVariable String iplcode) {

		if(null != iplcode && !"".equalsIgnoreCase(iplcode)){

			if("MI".equalsIgnoreCase(iplcode)){
				return "Mumbai Indians";
			}
			else if("DD".equalsIgnoreCase(iplcode)){
				return "Delhi Daredevils";
			}
			else{
				return "Chennai Super Kings";
			}
		}
		else{
			return "Enter correct IPL team code";
		}
	}

	// http://localhost:8081/SpringMVC-REST/cricket/getplayer/1

	/**
	 * Returns Player OBJECT, based on the player id
	 *
	 * @param id
	 * @return
	 */
	@RequestMapping(value="/getplayer/{id}", method=RequestMethod.GET)
	@ResponseBody
	public Player getPlayer(@PathVariable String id) {

		// create an object of type Player
		Player player = new Player();

		if(null != id && id.equalsIgnoreCase("1")){
			player.setId(1);
			player.setName("Sachin Tendulkar");
			player.setMatches("200");
		}
		else{
			player.setId(000);
			player.setName("Unknown Player");
			player.setMatches("000");
		}
		return player;
	}

	// http://localhost:8081/SpringMVC-REST/cricket/createplayer

	@RequestMapping(value="/createplayer", method=RequestMethod.POST)
	@ResponseBody
	public String createOrSavePlayer(@RequestBody Player player) {
		// insert new record into database and return primary id ~ playerId
		int playerId = 0;
		String playerInfo = "New Player created/inserted with player id " + ++playerId;
		return playerInfo;
	}
}

The Component class

The Component class is annotated with @Controller & @RequestMapping with value “/cricket” which is root-path for this particular class. So to access any of the public methods of this class one has to follow below URL pattern

http://://cricket

Above URL path forms the root-path for this particular component class. Now append @RequestMapping value attribute of the method further to this path to access any specific method of this component class

Drill-down to understand each method in detail.

Method Signature:
@RequestMapping(value=”/getiplteam/{iplcode}”, method=RequestMethod.GET)
@ResponseBodypublic String getIPLTeam(@PathVariable String iplcode)
HTTP Method: GET
URL: http://localhost:8081/SpringMVC-REST/cricket/getiplteam/MI
Description: Value at the end of the URL will be extracted and it is mapped to the formal argument ‘iplcode’ with datatype ‘String’. This is due to the @PathVariable annotation present before the input arguments to the method

Returns: a String value based on the input
Method Signature:
@RequestMapping(value=”/getplayer/{id}”, method=RequestMethod.GET)
@ResponseBodypublic Player getPlayer(@PathVariable String id)
HTTP Method: GET
URL: http://localhost:8081/SpringMVC-REST/cricket/getplayer/1
Description: similar to the above method but return the Player object
Returns: a Player object based on the input argument id

Method Signature:
@RequestMapping(value=”/createplayer”, method=RequestMethod.POST)
@ResponseBodypublic String createOrSavePlayer(@RequestBody Player player)
HTTP Method: POST
URL: http://localhost:8081/SpringMVC-REST/cricket/createplayer
Description: this is same above method that inputs the Player object
Returns: a String value with playerId after creating a player

Testing: Using “Advanced REST Client” from Google chrome

 

Enter the URL for the first method in the REST client and the see output
URL: http://localhost:8080/SpringMVC-REST/cricket/getiplteam/MI
Output: Mumbai Indians
2_SpringMVC-REST-3_Rest_client_1

Enter the URL for the second method in the REST client and the see output
URL: http://localhost:8080/SpringMVC-REST/cricket/getplayer/1
Output: <?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><player><id>1</id><name>Sachin Tendulkar</name><matches>200</matches></player>
3_SpringMVC-REST-3_Rest_client_2

Enter the URL for the third method in the REST client and the see output
URL: http://localhost:8080/SpringMVC-REST/cricket/createplayer
Input: <?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><player><id>1</id><name>Sachin Tendulkar</name><matches>200</matches></player>
Output: New Player created/inserted with player id 1
4_SpringMVC-REST-3_Rest_client_3_first
5_SpringMVC-REST-3_Rest_client_3_second

Using RestTemplate from spring (org.springframework.web.client.RestTemplate)
Test class for the three methods
TestSpringMVCRest.java

package test.spring.series.mvc.rest;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import com.spring.series.mvc.rest.model.Player;

public class TestSpringMVCRest {

	public static void main(String args[]) {
		RestTemplate restTemplate = new RestTemplate();

		System.out.println("Executing and Testing method one using RestTemplate");
		String strIplTeamName = restTemplate.getForObject("http://localhost:8080/SpringMVC-REST/cricket/getiplteam/MI", String.class);
		System.out.println(strIplTeamName);

		System.out.println("\n\nExecuting and Testing method two using RestTemplate");
		Player player = restTemplate.getForObject("http://localhost:8080/SpringMVC-REST/cricket/getplayer/1", Player.class);
		System.out.println(player.getId() + "\t" + player.getName() + "\t" + player.getMatches());

		System.out.println("\n\nExecuting and Testing method third using RestTemplate");
		String requestType = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><player><id>1</id><name>Sachin Tendulkar</name><matches>200</matches></player>";

		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_XML);
		HttpEntity<String> request= new HttpEntity<String>(requestType, headers);
		String strPlayerId = restTemplate.postForObject("http://localhost:8080/SpringMVC-REST/cricket/createplayer", request, String.class);
		System.out.println(strPlayerId);
	}
}

Output in Console

Executing and Testing method one using RestTemplate
Mumbai Indians

Executing and Testing method two using RestTemplate
1	Sachin Tendulkar	200

Executing and Testing method third using RestTemplate
New Player created/inserted with player id 1

Conclusion: It is easy to convert the Spring MVC based web project into Rest service using few Spring-3 annotations

In the next article, we will extend the same application to develop Rest services using Spring-4 with even lesser annotations i.e. with the introduction of @RestController annotation

Download project

Spring-MVC-RESTful-Web-Service-using-Spring-3.0-Annotation (5kB)

 

Read Also:

 

Happy Coding !!
Happy Learning !!

Spring MVC 4.0 Restful web service using @RestController annotation
Spring MVC: Multi-Controller actions using @Controller
  • ujwwala

    Hi.

    I have execute the above code but for creaton of player ,I am getting http status 415 ,GET not supported,

    I requesting from chrome,

    Thanks,
    Uj

  • sss

    Very good explanation !