Spring MVC Introduction

The DispatcherServlet front controller pattern, the request lifecycle, and @Controller vs @RestController.

The front controller pattern

Spring MVC is Spring's web framework, built around a single, central entry point for every incoming HTTP request: the DispatcherServlet. Rather than each URL mapping to its own separate servlet (the old pre-framework Java web model), one servlet receives everything and delegates to the right application code — this is the front controller pattern.

Plaintext
                 ┌─────────────────────┐
 HTTP request -->│   DispatcherServlet   │
                 └──────────┬───────────┘
                            │  "who handles /api/books/3 ?"
                            v
                 ┌─────────────────────┐
                 │    HandlerMapping     │
                 └──────────┬───────────┘
                            │  "BookController.getBook(), method getBook"
                            v
                 ┌─────────────────────┐
                 │      Controller        │  <- your @Controller/@RestController code runs here
                 └──────────┬───────────┘
                            │  returns data or a view name
                            v
                 ┌─────────────────────┐
                 │   View Resolution      │  (skipped entirely for @RestController)
                 └──────────┬───────────┘
                            v
                     HTTP response

Spring Boot auto-configures the DispatcherServlet and registers it to handle all incoming requests the moment spring-boot-starter-web is on the classpath — you never construct or register it yourself.

The request lifecycle, step by step

  1. DispatcherServlet receives the raw HTTP request. It's the single front door for the whole application.
  2. HandlerMapping works out which controller method should handle this specific URL and HTTP method, based on @RequestMapping/@GetMapping/etc. annotations across all registered controllers.
  3. The matched controller method runs — your business logic reads path variables, query parameters, and the request body, and produces a result.
  4. For a traditional @Controller, that result is a logical view name, which a ViewResolver maps to an actual template (e.g. a Thymeleaf .html file) to render. For a @RestController, this step is skipped entirely — the return value is serialized straight to the response body.
  5. The final HTTP response — a rendered HTML page, or a JSON/XML payload — goes back to the client.

Along the way, request/response filters and interceptors (logging, authentication, CORS) can run before the controller and after the response is produced, without either the controller or the client knowing they exist.

@Controller vs @RestController

Java
@Controller
public class BookPageController {

    @GetMapping("/books/{id}")
    public String bookDetails(@PathVariable Long id, Model model) {
        model.addAttribute("book", bookService.findById(id));
        return "book-details"; // a VIEW NAME — resolved to templates/book-details.html
    }
}
Java
@RestController
public class BookApiController {

    @GetMapping("/api/books/{id}")
    public Book bookDetails(@PathVariable Long id) {
        return bookService.findById(id); // serialized straight to the response body as JSON
    }
}
@Controller @RestController
Composition Plain Spring stereotype @Controller + @ResponseBody
Return value means A logical view name to resolve and render The actual response body
Typical use Server-rendered HTML pages (Thymeleaf, JSP) JSON/XML APIs
Needs @ResponseBody per-method for JSON? Yes, if you want to return raw data from an otherwise view-returning controller No — implied on every method

Both annotations are picked up by the same DispatcherServlet/HandlerMapping machinery described above — the difference is entirely in what happens to the return value.

Common mistakes

  • Forgetting @ResponseBody on an individual method inside a plain @Controller when that one method should return JSON instead of a view name — without it, Spring tries (and fails) to resolve the returned string as a view name.
  • Assuming the DispatcherServlet needs manual setup in a Spring Boot app — it's auto-configured the moment spring-boot-starter-web is present.
  • Mixing view-returning and data-returning methods in the same @Controller without being deliberate about which annotation each needs — it's usually clearer to keep API controllers and page controllers as separate classes.