Categories: springmvc

Spring 4 MVC REST Service Example using @RestController

Spring provides first class support for developing REST services. In this article, we will be developing a Spring 4 MVC based RESTful JSON service & RESTful XML service using Spring 4 @RestController annotation. Spring, behind the scenes, uses HttpMessageConverters to convert the response into desired format [ JSON/XML/etc..] based on certain libraries available on the classpath and optionally, Accept Headers in request.

In order to serve JSON, we will be using Jackson library [jackson-databind.jar]. For XML, we will use Jackson XML extension [jackson-dataformat-xml.jar]. Mere presence of these libraries in classpath will trigger Spring to convert the output in required format. Additionally, We will go a step further by annotating the domain class with JAXB annotations to support XML in case Jackson’s XML extension library is not available for some reason.

Note: If you are sending the request by just typing the URL in browser, you may add the suffix [.xml/.json] which help spring to determine the type of content to be served.

In case you want to dive bit deeper in details, have a look at Spring MVC 4 RESTFul Web Services CRUD Example+RestTemplate post. Let’s get going.


Following technologies being used:

  • Spring 4.3.0.RELEASE
  • jackson-databind 2.7.5
  • jackson-dataformat-xml 2.7.5
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse MARS.1

Let’s begin.

Step 1: Create the directory structure

Post Creating a maven web project with eclipse contains step-by-step instruction to create a maven project with eclipse.

Following will be the final project structure:

We will be using Spring Java configuration with no xml. Now let’s add/update the content mentioned in above project structure.

Step 2: Update pom.xml with required dependencies

<?xml version="1.0"?>
<project
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
 xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 <modelVersion>4.0.0</modelVersion>
 <groupId>com.websystique.springmvc</groupId>
 <artifactId>Spring4MVCHelloWorldRestServiceDemo</artifactId>
 <packaging>war</packaging>
 <version>1.0.0</version>
 <name>Spring4MVCHelloWorldRestServiceDemo Maven Webapp</name>

 <properties>
  <springframework.version>4.3.0.RELEASE</springframework.version>
  <jackson.library>2.7.5</jackson.library>
 </properties>

 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${springframework.version}</version>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.1.0</version>
  </dependency>
  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.library}</version>
  </dependency>
  <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-xml</artifactId>
      <version>${jackson.library}</version>
  </dependency>
 </dependencies>


 <build>
  <pluginManagement>
   <plugins>
    <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-war-plugin</artifactId>
     <version>2.4</version>
     <configuration>
      <warSourceDirectory>src/main/webapp</warSourceDirectory>
      <warName>Spring4MVCHelloWorldRestServiceDemo</warName>
      <failOnMissingWebXml>false</failOnMissingWebXml>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>

  <finalName>Spring4MVCHelloWorldRestServiceDemo</finalName>
 </build>
</project>

Main dependencies to be noticed here are Jackson library (jackson-databind) which will be used to convert the response data into JSON string, and Jackson XML Extension library (jackson-dataformat-xml) which will help to provide XML converted response. Again, if the jackson-dataformat-xml is not included, only JSON response will be served, unless the domain object is annotated explicitly with JAXB annotations.

Step 3: Add a Pojo/domain object

package com.websystique.springmvc.domain;

public class Message {

 String name;
 String text;

 public Message(String name, String text) {
  this.name = name;
  this.text = text;
 }

 public String getName() {
  return name;
 }

 public String getText() {
  return text;
 }

}

Above object will be returned from controllers and converted by Jackson into JSON format. If the jackson-dataformat-xml is present, then it can also be converted into XML.

Step 4: Add a Controller

Add a controller class under src/main/java with mentioned package as shown below.

package com.websystique.springmvc.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.websystique.springmvc.domain.Message;

@RestController
public class HelloWorldRestController {

 @RequestMapping("/")
 public String welcome() {//Welcome page, non-rest
  return "Welcome to RestTemplate Example.";
 }

 @RequestMapping("/hello/{player}")
 public Message message(@PathVariable String player) {//REST Endpoint.

  Message msg = new Message(player, "Hello " + player);
  return msg;
 }
}

@PathVariable indicates that this parameter will be bound to variable in URI template. More interesting thing to note here is that here we are using @RestController annotation, which marks this class as a controller where every method returns a domain object/pojo instead of a view. It means that we are no more using view-resolvers, we are no more directly sending the html in response but we are sending domain object converted into format understood by the consumers. In our case, due to jackson library included in class path, the Message object will be converted into JSON format[ or in XML if either the jackson-dataformat-xml.jar is present in classpath or Model class i annotated with JAXB annotations].

Step 5: Add Configuration Class

package com.websystique.springmvc.configuration;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.springmvc")
public class HelloWorldConfiguration {
 

}

Here this class is mainly providing the component-scanning and annotation support.Note that we don’t have any view-resolvers configured as we don’t need one in Rest case.

Step 6: Add Initialization class

Add an initializer class as shown below(which in this case acts as replacement of any spring configuration defined in web.xml). During Servlet 3.0 Container startup, this class will be loaded and instantiated.

package com.websystique.springmvc.configuration;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class HelloWorldInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

 @Override
 protected Class<?>[] getRootConfigClasses() {
  return new Class[] { HelloWorldConfiguration.class };
 }
 
 @Override
 protected Class<?>[] getServletConfigClasses() {
  return null;
 }
 
 @Override
 protected String[] getServletMappings() {
  return new String[] { "/" };
 }

}

Step 7: Build and Deploy the application

Now build the war (either by eclipse using m2e plugin) or via maven command line( mvn clean install). Deploy the war to a Servlet 3.x container . Since here i am using Tomcat, i will simply put this war file into tomcat webapps folder and click on startup.bat inside tomcat bin directory.

In order to test it, you can use either the browser or a true-client.POSTMAN is a nice tool to test your REST Endpoints as in a real scenario. Advantage of Postman is that you can send the “Accept” header along with request which will then be used by Spring while sending the response in required format. With browsers it is not so straight-forward to send the “Accept” Header but you can suffix the URL with format[.json/.xml] to get similar results.

Let’s start with the browser.

Now let’s access the REST Endpoint. Please note that since we have included the jackson-dataformat-xml.jar in classpath, the response you will get will be XML.

If you want Spring to serve JSON response instead, you can either
– remove the jackson-dataformat-xml.jar [comment it in pom.xml, build and deploy it again].
– Or Suffix the URL with .json

Had you redeployed the app with removing the dataformat dependency, you would have seen the following:

Without redeployment, you can get the same result by suffixing url with format.


Using Postman:
Set the ‘Accept’ request header [to appliction/json or application/xml ] and send the request. Check the response body:


With JAXB
In case jackson-dataformat-xml.jar is not available, and you still want to get the XML response, just by adding JAXB annotations on model class (Message), we can enable XML output support. Below is the demonstration of same :

package com.websystique.springmvc.domain;

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

@XmlRootElement(name = "player")
public class Message {

 String name;
 String text;

 public Message(){
  
 }
 
 public Message(String name, String text) {
  this.name = name;
  this.text = text;
 }

 @XmlElement
 public String getName() {
  return name;
 }
 
 @XmlElement
 public String getText() {
  return text;
 }

}

Remove dataformat dependency[jackson-dataformat-xml.jar], Compile, deploy and run it again, Send the request, you should see following response:

That’s it. Check out Spring MVC 4 RESTFul Web Services CRUD Example+RestTemplate post for more advanced example.

Download Source Code


References

View Comments

  • Hello,

    I have downloaded and running Spring4MVCHelloWorldRestServiceDemo example as it is on weblogic sever.
    But I am getting below error on chrome.

    Error 403--Forbidden

    From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:

    10.4.4 403 Forbidden

    Can you please help fixing this.

    Thanks,

    • Hi Vaibhav, Sorry i don't have weblogic setup with me at the moment. Are you able to deploy a simple hello world to see if you are missing some basic weblogic configuration?

  • Using this code , Jboss EAP will throw 404 . It is a simple fix , in the HelloWorldInitializer class , getServletMappings() method , return "/*" instead of "/"

  • Example works fine .But i have a question from where json/xml object is being produced ? simply i want to ask who is taking care of creating json object.

    • Hi Vinay, First of all. this application doesn't involve any tradition view resolver. Before delivering the response [can be anything] , spring will try to convert the response into appropriate format the client is interested in. To convert, it relies on presence of certain libraries in classpath + any other input from client[Accept header/url suffix extension].If nothing is specified from client,Spring will generate the JSON response by default. If client asked for XML, spring will try to convert the response into XML. You can help spring by annotating the file with appropriate JAXB annotations.
      Hope this helps.

  • Thank you a lot for this great series.

    Can you please explain why welcome()-method of the controller returns here what is considered to be http response body, and not the name of the jsp-resource as was the case in 'Hello World' example ?

    Thank you in advance

    • Hi Andrey, goal of welcome method was not to return the REST response but just to act as a 'welcome page' handler.Even this method is not required at all. You as a developer decide which part of your app will be available as a REST service.

  • The problem is giving for ResponseEntity return type.If I return "string" by converting JSON object, then its working

  • Hi, Whenever I am running this application on Tomcat, its working fine. but on Jboss EAP 6.4.0, its not working. please help

  • Hi I meant to ask if it may be ok for me to use this project as base ground for the project at my company.

    Seeking your consent please.

    • H Raaj, Yes you can use this project for your company's internal projects. Glad you liked it.

      • Thanks so very sincerely. Though ever part is done so well, I think the AbstractDao allows so easy to transition to JPA based entity manager factory.

Share
Published by

Recent Posts

Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…

7 years ago

Spring Boot Rest API Example

Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…

7 years ago

Spring Boot WAR deployment example

Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…

7 years ago

Spring Boot Introduction + hello world example

Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…

7 years ago

Secure Spring REST API using OAuth2

Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…

8 years ago

AngularJS+Spring Security using Basic Authentication

This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…

8 years ago