Course topics

By WebNest Studio Engineering Team

Spring Framework Tutorial

Spring MVC Fundamentals

Spring MVC is Spring's web framework for building request-driven web applications and REST APIs, built around the classic Model-View-Controller pattern. A central component called the DispatcherServlet receives every incoming HTTP request and delegates it to the appropriate handler method, based on URL mappings you declare with annotations.

Rather than writing raw servlets, you write plain Java classes annotated with @Controller (or @RestController for APIs that return data directly rather than rendering a view), and annotate individual methods with request-mapping annotations that describe which HTTP method and URL pattern they handle. Spring MVC then takes care of binding request parameters, invoking the method, and converting the return value into an HTTP response.

The Request Flow Through DispatcherServlet

Every request first hits the DispatcherServlet, which acts as the "front controller." It consults a HandlerMapping to find which controller method matches the request's URL and HTTP method, invokes that method (resolving its arguments — path variables, request parameters, request bodies — along the way), and then hands the return value to a HandlerAdapter and, for @Controller classes returning view names, a ViewResolver to render the final response. For @RestController classes, the return value is instead serialized directly (typically to JSON) via an HttpMessageConverter.

@Controller vs @RestController

@Controller marks a class as a traditional MVC controller whose methods typically return a view name (a template to render, such as a Thymeleaf page) unless a method is separately annotated with @ResponseBody. @RestController is a convenience annotation equal to @Controller + @ResponseBody applied to every method — its methods return data (objects, strings) that Spring serializes directly into the HTTP response body, making it the standard choice for REST APIs.

Mapping Requests

@RequestMapping is the general-purpose annotation for mapping a URL (and optionally an HTTP method) to a handler method or class. Shortcut annotations built on top of it are preferred for readability in modern code.

  • @GetMapping("/orders/{id}") — handles HTTP GET requests, commonly paired with @PathVariable to extract "{id}" from the URL.
  • @PostMapping("/orders") — handles HTTP POST requests, typically paired with @RequestBody to deserialize the JSON request body into a Java object.
  • @PutMapping / @DeleteMapping / @PatchMapping — handle the corresponding HTTP verbs with the same pattern.
  • @RequestParam — binds an individual query string parameter to a method argument.

Example

A REST controller handling GET and POST requests for orders

Java
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping("/api/orders")
class OrderController {

    private final Map<String, String> orders = new ConcurrentHashMap<>();

    @GetMapping("/{id}")
    public String getOrder(@PathVariable String id) {
        return orders.getOrDefault(id, "Order not found: " + id);
    }

    @PostMapping
    public String createOrder(@RequestBody Map<String, String> payload) {
        String id = payload.get("id");
        orders.put(id, "Order " + id + " created for " + payload.get("customer"));
        return "Created order " + id;
    }
}
// A GET to /api/orders/ORD-5 before creation returns: "Order not found: ORD-5"
// A POST to /api/orders with body {"id":"ORD-5","customer":"Asha"} returns: "Created order ORD-5"
Output
GET /api/orders/ORD-5  -> "Order not found: ORD-5"
POST /api/orders {"id":"ORD-5","customer":"Asha"} -> "Created order ORD-5"
GET /api/orders/ORD-5 (after POST) -> "Order ORD-5 created for Asha"

Common Mistakes

  • Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body).
  • Forgetting @RequestBody on a method parameter that should be deserialized from the JSON request body, causing Spring to instead look for it as a request parameter.
  • Mismatching the HTTP method annotation (e.g. using @GetMapping for an operation that mutates state), which also has semantic and caching implications beyond just Spring wiring.
  • Not scoping @RequestMapping's base path on the class, leading to inconsistent or duplicated path prefixes across handler methods.

Exercise

A teammate is about to make this mistake: Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body). Use The Request Flow Through DispatcherServlet to review the decision. Write a corrected implementation or design sketch that follows DispatcherServlet is the front controller that routes every incoming request to the matching handler method., then name one edge case you would check.

Show hints
  • Start with The Request Flow Through DispatcherServlet and compare your approach with A REST controller handling GET and POST requests for orders. Identify the decision or behavior the lesson recommends.
  • Walk through your scenario step by step. Confirm that it follows DispatcherServlet is the front controller that routes every incoming request to the matching handler method. and that it would catch the failure described by Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body)..

Quick quiz

1. Which choice best describes the recommended approach in Spring MVC Fundamentals?

  • A. Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body).
  • B. Forgetting @RequestBody on a method parameter that should be deserialized from the JSON request body, causing Spring to instead look for it as a request parameter.
  • C. DispatcherServlet is the front controller that routes every incoming request to the matching handler method.
Show answer

C. This is the recommended approach: DispatcherServlet is the front controller that routes every incoming request to the matching handler method. Avoid: Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body).

Interview questions

Why does this principle matter in Spring MVC Fundamentals: DispatcherServlet is the front controller that routes every incoming request to the matching handler method.

Show answer

DispatcherServlet is the front controller that routes every incoming request to the matching handler method. Apply this in The Request Flow Through DispatcherServlet; the example A REST controller handling GET and POST requests for orders shows one way to do it. Avoid Using @Controller when @RestController was intended, then being confused why the returned String is treated as a view name to resolve instead of raw response text (a "view not found" error appears instead of the expected JSON/text body). and explain how your implementation or design prevents that failure.

Key Points to Remember

  • DispatcherServlet is the front controller that routes every incoming request to the matching handler method.
  • @RestController = @Controller + @ResponseBody, returning data directly instead of a view name.
  • @GetMapping, @PostMapping, @PutMapping, and @DeleteMapping are HTTP-verb-specific shortcuts for @RequestMapping.
  • @PathVariable extracts values from the URL path; @RequestBody deserializes the request body; @RequestParam reads query parameters.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

These examples need a JDK project with their libraries on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering