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
- spring-core-4.0.0-RELEASE
- spring-context-4.0.0-RELEASE
- spring-beans-4.0.0-RELEASE
- spring-aop-4.0.0-RELEASE
- spring-expression-4.0.0-RELEASE
- spring-webmvc-4.0.0-RELEASE
- spring-web-4.0.0-RELEASE
- commons-logging-1.1.1
- aopalliance-1.0
- servlet-api-2.5
- jstl-1.2
- jackson-core-asl-1.9.13.jar
- jackson-mapper-asl-1.9.13.jar
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
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
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>
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
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:
- Spring MVC Framework
- Creating Maven-based project for Spring MVC web application in Eclipse Kepler IDE
- Spring MVC: Creating “Hello World” web application based on XML configuration
- Spring MVC: Annotation based “Hello World” web application
- Spring MVC: Multi-Controller actions using @Controller
- Spring MVC: Creating RESTful web service using annotation
- Spring MVC: Change default Spring-Dispatcher-Servlet.xml to user-defined context filename in web.xml
Happy Coding !!
Happy Learning !!