dineshonjava

Difference between @Controller vs @RestController in Spring MVC

The key difference between a traditional Spring MVC @Controller and the RESTful web service @RestController is the way the HTTP response body is created. While the traditional MVC controller relies on the View technology, the RESTful web service controller simply returns the object and the object data is written directly to the HTTP response as JSON/XML by registered HttpMessageConverters.

Traditional Spring MVC Workflow
The following image describe a traditional Spring MVC Request workflow:
Spring MVC traditional workflow
@ImageSource-https://www.genuitec.com

  • Step 1: The browser or client sends a request to the web application.
  • Step 2: The request lands to the dispachter servlet and consult with handler mapping.
  • Step 3: The Handler mappings defined in the application context file, this has information about which is controller need to be invoked.
  • Step 4: The controller will be invoked and it can request the model for some information using DAOs and Services.
  • Step 5: After Requests are processed by the Controller and the response is returned to the DispatcherServlet with logical view name
  • Step 6: Then return to the view resolver prepared the view based on your configuration decide the which configuration (JSP, Velocity, PDF etc.) to be invoked.

For Example:
@Controller
public class AccountController {
  @RequestMapping(value="/account", method=RequestMethod.GET)
  public ModelAndView get(Long accountId) {
    //Process model object
    return new ModelAndView("account-detail", model) ;
  }
}

Spring MVC REST Workflow
The following image describe a Spring MVC REST workflow:

Spring REST workflow
@ImageSource-https://www.genuitec.com

  • Step 1: The client sends a request to a web service in URI form.
  • Step 2: The request lands to the dispachter servlet and consult with handler mapping.
  • Step 3: The Handler mappings defined in the application context file, this has information about which is controller need to be invoked.
  • Step 4: The controller will be invoked and process model.
  • Step 5: Requests are processed by the Controller and the response is returned to the DispatcherServlet which then dispatches to the view.

In Traditional Spring MVC Workflow, notice that controller return the ModelAndView object with logical view name to dispactcher servlet, it is forwarded to the ViewResolver in step 6. But in the Spring MVC REST Workflow, Spring lets you return data directly from the controller, without looking for a view, using the @ResponseBody annotation on a method. As of Spring Version 4.0, this process has been more simplified by the @RestController annotation.

For Example:

Using the @ResponseBody Annotation
If any handler method of controller class is annotated with @ResponseBody, Spring converts the return value of this method and writes it to the http response automatically.

What is Behind the @ResponseBody
There is a list of HttpMessageConverters registered in the background when we enable Spring web mvc feature to the web application by using @EnableWebMvc or <mvc:annotation-driven> namespace. HTTPMessageConverter is responsible to convert the request body to a specific class and back to the response body again, depending on a predefined mime type.

Create the following @Controller class:
/**
 * 
 */
package com.doj.restapi.web.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
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.doj.restapi.bean.Account;
import com.doj.restapi.service.IAccountService;

/**
 * @author Dinesh.Rajput
 *
 */
@Controller
public class AccountController {
 
 @Autowired
 IAccountService accountService;
 
 @RequestMapping(value = "/", method = RequestMethod.GET)
 public @ResponseBody String home (){
  return "Spring REST Dinesh on Java!!!";
 }
 
 @RequestMapping(value = "/accounts", method = RequestMethod.GET)
 public @ResponseBody List<Account> all (){
  return accountService.list();
 }
 
 @RequestMapping(value = "/account", method = RequestMethod.POST)
 public @ResponseBody Account create (@RequestBody Account account){
  return accountService.create(account);
 }
 
 @RequestMapping(value = "/account/{accountId}", method = RequestMethod.GET)
 public @ResponseBody Account get (@PathVariable Long accountId){
  return accountService.get(accountId);
 }
 
 @RequestMapping(value = "/account", method = RequestMethod.PUT)
 public @ResponseBody Account update (@RequestBody Account account){
  return accountService.update(account);
 }
 
 @RequestMapping(value = "/account/{accountId}", method = RequestMethod.DELETE)
 public @ResponseBody void delete (@PathVariable Long accountId){
  accountService.delete(accountId);
 }
}

Notice the @ResponseBody added to each of the @RequestMapping methods in the return value.

Using the @RestController Annotation
@RestController annotation is introduced as of Spring 4.0, it is actually combination of @Controller and @ResponseBody. It is a convenience way to use this annotation instead of using @Controller and @ResponseBody annotations. By annotating the controller class with @RestController annotation, you no longer need to add @ResponseBody to all the request mapping methods. The @ResponseBody annotation is active by default.

Spring REST workflow using RestController
@ImageSource-https://www.genuitec.com

Let's use @RestController in our example, all we need to do is modify the @Controller to @RestController and remove the @ResponseBody from each method. As following:

/**
 * 
 */
package com.doj.restapi.web.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.doj.restapi.bean.Account;
import com.doj.restapi.service.IAccountService;

/**
 * @author Dinesh.Rajput
 *
 */
@RestController
public class AccountController {
 
 @Autowired
 IAccountService accountService;
 
 @GetMapping("/")
 public String home (){
  return "Spring REST Dinesh on Java!!!";
 }
 
 @GetMapping("/accounts")
 public List<Account> all (){
  return accountService.list();
 }
 
 @PostMapping("/account")
 public Account create (@RequestBody Account account){
  return accountService.create(account);
 }
 
 @GetMapping("/account/{accountId}")
 public Account get (@PathVariable Long accountId){
  return accountService.get(accountId);
 }
 
 @PutMapping("/account")
 public Account update (@RequestBody Account account){
  return accountService.update(account);
 }
 
 @DeleteMapping("/account/{accountId}")
 public void delete (@PathVariable Long accountId){
  accountService.delete(accountId);
 }
}


As per as above controller file with @RestController annotation, we can see, using this annotation is quite simple and is the preferred method for creating MVC RESTful web services if we are using Spring v4.0 and above.