Detailed explanation
In Spring MVC, @Controller and @RestController both identify classes that handle web requests, but they establish different defaults for processing handler return values. @Controller is commonly used for server-rendered applications, where a handler supplies model data and returns a logical view name. @RestController is intended for endpoints that return data directly in the HTTP response body, such as REST APIs. The distinction is about response handling, not URL mapping: both support @RequestMapping, @GetMapping, and related annotations.
With @Controller, a method returning a String such as "users" normally identifies a view rather than response content. Spring uses configured ViewResolver implementations to locate the corresponding view, such as a Thymeleaf template. The view renders HTML using attributes supplied through Model or ModelAndView. However, saying that @Controller always returns view names is inaccurate. A handler can use @ResponseBody to write its return value directly to the response, or return ResponseEntity to control the body, status, and headers without view resolution.
@RestController is a composed annotation that includes @Controller and @ResponseBody. Its response-body behaviour therefore applies across the controller's handler methods, avoiding repeated method-level @ResponseBody annotations. For example, a /users handler returning List<User> typically produces a JSON array. Under the hood, DispatcherServlet dispatches the request through a handler adapter, and Spring's return-value handling infrastructure delegates body conversion to an appropriate HttpMessageConverter. Jackson commonly handles JSON when available and configured. Converter selection considers the return type, supported media types, the client's Accept header, and any produces constraint; JSON is not guaranteed merely by choosing @RestController.
A useful interview example is a String return value: "users" from a typical @Controller handler selects a view, while the same return value from a @RestController handler is normally written as text in the response body. Interviewers look for this practical distinction, awareness of message conversion, and recognition that either annotation can support data responses. Choose @Controller for view-oriented handlers and @RestController for body-oriented endpoints to make intent clear.
Key points to remember
- @RestController combines @Controller and @ResponseBody.
- A String returned by a typical @Controller handler is a logical view name.
- @ResponseBody enables direct response-body handling on individual @Controller methods.
- HttpMessageConverter implementations serialize response bodies; JSON depends on configuration and content negotiation.
- ResponseEntity works with either annotation to specify the response body, HTTP status, and headers.
Common mistakes candidates make
- Claiming that @Controller can only return HTML or view names.
- Assuming that @RestController always produces JSON, including for String return values.
- Confusing @ResponseBody, which affects outgoing responses, with @RequestBody, which binds incoming request content.
Likely follow-up questions
Can one @Controller serve both HTML pages and JSON responses?
Yes. Keep view-returning methods without @ResponseBody and annotate data-returning methods with @ResponseBody, or return ResponseEntity from those methods. Separate controllers often make the responsibilities clearer.
How does Spring decide whether to return JSON or XML?
Spring negotiates a response media type using factors such as the Accept header, the mapping's produces constraint, and available message converters. XML requires suitable converter support; if no acceptable representation can be produced, Spring can respond with HTTP 406.
Why use ResponseEntity inside a @RestController?
Returning a DTO directly is sufficient when the default status and headers are appropriate. ResponseEntity lets you explicitly set details such as HTTP 201 Created, a Location header, and the response body.
Interview tip: Explain the combined annotations first, then contrast returning "users" as a view name versus returning it as response text.
