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
- 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
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
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>
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
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:
- 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 4.0 Restful web service using @RestController annotation
- Spring MVC: Change default Spring-Dispatcher-Servlet.xml to user-defined context filename in web.xml
Happy Coding !!
Happy Learning !!