In this quick article, we’ll discuss the difference between @Controller
and
@RestController
annotations in Spring MVC.
The first annotation is used for traditional Spring controllers and has been part of the framework for a very
long time. The @RestController
annotation was introduced in Spring 4.0 to
simplify the creation of RESTful
web services. It’s a convenience annotation that combines @Controller
and
@ResponseBody
– which eliminates
the need to annotate every request handling method of the controller class with the @ResponseBody
annotation.
The key difference between a traditional Spring MVC controller and the RESTful web service controller 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.
Classic controllers can be annotated with the @Controller
annotation. This
is simply a specialization of the
@Component
class and allows implementation classes to be autodetected
through classpath scanning.
In order to develop REST web services using Spring MVC @Controller, we need to add a @ResponseBody annotation to each of the @RequestMapping methods in the return value as shown in the below diagram.
@Controller
is typically used in combination with a @RequestMapping
annotation used on request handling methods.
Notice that in the below example, we added @ResponseBody
annotation to each
of the @RequestMapping
methods in the return value.
@Controller
@RequestMapping("/api/v1")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@GetMapping("/employees")
public @ResponseBody List getAllEmployees() {
return employeeRepository.findAll();
}
@GetMapping("/employees/{id}")
public @ResponseBody ResponseEntity getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
return ResponseEntity.ok().body(employee);
}
@PostMapping("/employees")
public @ResponseBody Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@PutMapping("/employees/{id}")
public @ResponseBody ResponseEntity updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employee.setEmailId(employeeDetails.getEmailId());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
final Employee updatedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(updatedEmployee);
}
@DeleteMapping("/employees/{id}")
public @ResponseBody Map deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employeeRepository.delete(employee);
Map response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
Spring 4.0 introduced @RestController, a specialized version of the controller which is a convenience
annotation that does nothing more than add the @Controller
and @ResponseBody
annotations.
@Controller
@RequestMapping("/api/v1")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@GetMapping("/employees")
public @ResponseBody List getAllEmployees() {
return employeeRepository.findAll();
}
@GetMapping("/employees/{id}")
public @ResponseBody ResponseEntity getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
return ResponseEntity.ok().body(employee);
}
@PostMapping("/employees")
public @ResponseBody Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@PutMapping("/employees/{id}")
public @ResponseBody ResponseEntity updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employee.setEmailId(employeeDetails.getEmailId());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
final Employee updatedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(updatedEmployee);
}
@DeleteMapping("/employees/{id}")
public @ResponseBody Map deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employeeRepository.delete(employee);
Map response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
Spring 4.0 introduced @RestController, a specialized version of the controller which is a convenience
annotation that does nothing more than add the @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.
To use @RestController in our example, all we need to do is modify the @Controller to
@RestController and
remove the @ResponseBody from each method. The resultant class should look like the following:
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@GetMapping("/employees")
public List getAllEmployees() {
return employeeRepository.findAll();
}
@GetMapping("/employees/{id}")
public ResponseEntity getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
return ResponseEntity.ok().body(employee);
}
@PostMapping("/employees")
public Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeRepository.save(employee);
}
@PutMapping("/employees/{id}")
public ResponseEntity updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employee.setEmailId(employeeDetails.getEmailId());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
final Employee updatedEmployee = employeeRepository.save(employee);
return ResponseEntity.ok(updatedEmployee);
}
@DeleteMapping("/employees/{id}")
public Map deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employeeRepository.delete(employee);
Map response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
You can find a complete example using Spring MVC @RestController annotation at Spring Boot 2 JPA MySQL CRUD Example
The controller is annotated with the @RestController annotation, therefore the @ResponseBody isn’t required.
Every request handling method of the controller class automatically serializes return objects into HttpResponse.