Spring MVC 4.0 Restful web service using @RestController annotation

In the previous article, we have seen how to extend the Spring MVC web application to convert it into REST web service using annotations. With Spring 4.0 introduction, same application can be achieved with even lesser annotations.

@Controller & @ResponseBody are clubbed inside the single annotation called @RestController. Definition for @RestController from spring doc

@Target (value =TYPE )
 @Retention (value =RUNTIME )
 @Documented
 @Controller
 @ResponseBody
public @interface RestController

Note: you don’t need to write/use @ResponseBody on top of each and every method

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 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

Technology Used

  • Java 1.7
  • Eclipse Luna IDE
  • Spring-4.0.0-RELEASE
  • Apache-Maven-3.2.1
  • Apache-Tomcat-7.0.54

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-4_package_structure

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
<?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 spring container
  • Basically these classes are annotated with @RestController on top of the class with value attribute for URL path
  • <mvc:annotation-driven /> declares explicit support for annotation-driven MVC controllers

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>

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 with JDK 1.5. These JAXB annotations are basically to do serialization/De- serialization process automatically.

Note: for our application, using JDK 1.7

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;
	}
}

My Controller

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.

Class is annotated with @RestController and there is @ResponseBody in any of the three public methods.

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.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

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

	// http://localhost:8080/SpringMVC-REST-4/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)
	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:8080/SpringMVC-REST-4/cricket/getplayer/1

	/**
	 * Returns Player OBJECT, based on the player id
	 *
	 * @param id
	 * @return
	 */
	@RequestMapping(value="/getplayer/{id}", method=RequestMethod.GET)
	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("International Player");
			player.setMatches("000");
		}
		return player;
	}

	// http://localhost:8080/SpringMVC-REST-4/cricket/createplayer

	@RequestMapping(value="/createplayer", method=RequestMethod.POST)
	public String createOrSavePlayer(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 @RestController & @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-4/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-4/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-4/cricket/createplayer
Description: c 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-4/cricket/getiplteam/MI
Output: Mumbai Indians
2_SpringMVC-REST-4_testing_method_1

 

Enter the URL for the second method in the REST client and the see output
URL: http://localhost:8080/SpringMVC-REST-4/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-4_testing_method_2

 

Enter the URL for the third method in the REST client and the see output
URL: http://localhost:8080/SpringMVC-REST-4/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-4_testing_method_3_1
5_SpringMVC-REST-4_testing_method_3_2

 

Using RestTemplate from spring (org.springframework.web.client.RestTemplate)

Test class for the three methods

TestSpringMVCRest.java

package test.spring.series.mvc.rest;

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

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-4/cricket/getiplteam/MI", String.class);
		System.out.println(strIplTeamName);

		HttpHeaders headers1 = new HttpHeaders();
		List<MediaType> ls = new ArrayList<MediaType>();
		ls.add(MediaType.APPLICATION_JSON);
		headers1.setAccept(ls);
		HttpEntity<String> request1= new HttpEntity<String>(headers1);

		System.out.println("\n\nExecuting and Testing method two using RestTemplate");
		Player player = restTemplate.getForObject("http://localhost:8080/SpringMVC-REST-4/cricket/getplayer/1", Player.class, request1);
		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-4/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: Spring 4.0 annotation @RestController really helpful to write REST-based web services

Download project

Spring-MVC-4.0-Restful-Web-Service-using-@RestController-Annotation (5kB)

 

Read Also:

 

Happy Coding !!
Happy Learning !!

Spring MVC - Change default Spring-Dispatcher-Servlet.xml to user-defined context filename in web.xml
Spring MVC: Creating RESTful web service using annotation