Introduction
In Spring Boot, the controller class is responsible for processing incoming REST API requests, preparing a model, and returning the view to be rendered as a response.
The controller classes in Spring are annotated either by the @Controller
or the @RestController
annotation. These mark controller classes as a request handler to allow Spring to recognize it as a RESTful service during runtime.
In this tutorial, we'll cover the definition of the @Controller
and the @RestController
annotations, their use-cases, and the difference between the two annotations.
If you are new to Spring Boot, you might also want to check out our full guide on How to Build a Spring Boot REST API.
Spring Boot REST API Workflow
Before defining the two annotations, we'll quickly go through the workflow of how Spring Boot handles REST API requests and processes and returns a response:
First, the request is received by the DispatcherServlet
, which is responsible for processing any incoming URI requests and mapping them to their corresponding handlers in the form of controller methods. After the controller method has been executed, the resource is then processed as a response which can either be JSON or XML.
In the diagram above, the two processes encapsulated in the rectangle are the processes actually implemented by a developer. The rest are executed by Spring services that are running in the background, including the DispatcherServlet
.
The @Controller Annotation
The @Controller
annotation is a specialization of the generic stereotype @Component
annotation, which allows a class to be recognized as a Spring-managed component.
The @Controller
annotation extends the use-case of @Component
and marks the annotated class as a business or presentation layer. When a request is made, this will inform the DispatcherServlet
to include the controller class in scanning for methods mapped by the @RequestMapping
annotation.
Now, we'll declare the actual controller to define the business logic and handle all the requests related to the model Tree
.
First, mark the class with the @Controller
annotation together with @RequestMapping
and specify the path to /api/tree
:
@Controller
@ResponseBody
@RequestMapping("/api/tree")
public class TreeController {
@Autowired
private TreeRepository repository;
@GetMapping("/{id}")
public Tree getTreeById(@PathVariable int id) {
return repository.findById(id);
}
@GetMapping
public Tree getTreeById(@RequestParam String name,
@RequestParam int age) {
return repository.findFirstByCommonNameIgnoreCaseAndAge(name, age);
}
}
The @Autowired
annotation is used to automatically inject dependencies of the specified type into the current bean. In this case, the TreeRepository
bean is injected as a dependency of TreeController
.
@GetMapping
is a shortcut for @RequestMapping(method = RequestMethod.GET)
, and is used to map HTTP GET
requests to the mapped controller methods.
We've applied a @ResponseBody
annotation to the class-level of this controller. When the request handlers return data back, such as return repository.findById()
, the response will be serialized to JSON before being returned to the client.
Alternatively, you could've annotated each response type with the @ResponseBody
annotation instead:
@GetMapping("/{id}")
public @ResponseBody Tree getTreeById(@PathVariable int id) {
return repository.findById(id);
}
If we run this application, assuming we've already got a Tree
instance saved to the database, with the ID of 1, and hit the localhost:8080/1
endpoint, we'd be greeted with:
{"species":"Salix babylonica","commonName":"Weeping willow", "age":"150"}
Because of the @ResponseBody
annotation, the fields from the fetched object are serialized into JSON and returned to the client that requested it.
The @RestController Annotation
The @RestController
annotation in Spring is essentially just a combination of @Controller
and @ResponseBody
. This annotation was added during Spring 4.0 to remove the redundancy of declaring the @ResponseBody
annotation in your controller.
That's one less annotation declaration! If you also look at the interface definition of the two annotations to see the difference between the two:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
//..
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
//..
}
The RestController
interface is annotated by @Controller
and @ResponseBody
instead of directly annotating it with @Component
.
If we replace the annotation of our controller with @RestController
, we won't need to change the domain and persistence layer as they still will be compatible with this annotation.
Using the example controller TreeController
above, let's compare the changes when we use this annotation:
@RestController
@RequestMapping("/api/tree")
public class TreeController {
@Autowired
private TreeRepository repository;
@GetMapping("/{id}")
public Tree getTreeById(@PathVariable int id) {
return repository.findById(id);
}
@GetMapping
public Tree getTreeById(@RequestParam String name,
@RequestParam int age) {
return repository.findFirstByCommonNameIgnoreCaseAndAge(name, age);
}
}
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Now, all methods have the @ResponseBody
annotation applied to them, as @RestController
applies it at class-level.
If we run this application, assuming we've already got a Tree
instance saved to the database, with the ID of 1, and hit the localhost:8080/1
endpoint, we'd be greeted with:
{"species":"Salix babylonica","commonName":"Weeping willow", "age":"150"}
Conclusion
Essentially, @RestController
extends the capabilities of both the @Controller
and @ResponseBody
annotations.
Other than the fact that @RestController
exists to allow Spring controllers to be one line shorter, there aren't any major differences between the two annotations.
The primary function of both annotations is to allow a class to be recognized as a Spring-managed component and to allow handling of HTTP requests using REST API.