
Introduction
Anyone who has worked on Spring would have definitely used Spring Web MVC. That is how I also started with Spring. Spring Web MVC is a core part of the Spring Framework and its main purpose is to simplify the development of web applications. It provides a lot of features to build robust and flexible web applications. In this blog, we will cover the basics of Spring Web MVC and some of the most commonly used annotations and features. Knowing these features will help you build web applications and APIs more efficiently.
Spring Web MVC Architecture
Spring Web uses the Model-View-Controller (MVC) design pattern to separate the concerns of an application.
- Model: Represents the data of the application. Handles the business logic and interacts with the databases, APIs, files, or other data sources.
- View: Represents the UI of the application (technologies like JSP, Thymeleaf, or HTML templates). When you build REST APIs, the view is the JSON data itself.
- Controller: Handles the user requests, processes the data, and returns the response.
Spring MVC uses Servlets under the hood to handle HTTP requests and responses. The DispatcherServlet
is the front controller that receives all incoming requests and dispatches them to the appropriate controllers based on the request mappings.
Spring Web uses Tomcat as the default embedded server, but you can use other servers like Jetty or Undertow as well.
Spring Web Cheat Sheet
1. Spring MVC Controllers
@Controller
- Marks a class as a Spring MVC controller to handle HTTP requests.
@Controller public class HomeController { @GetMapping("/") public String home() { return "home"; // Returns the view name "home" } }
@RestController
- Combines
@Controller
and@ResponseBody
. Suitable for RESTful APIs which typically returns JSON data. Returned objects are automatically serialized to JSON.
record Customer(Long id, String name) {} @RestController public class CustomerController { @GetMapping("/customers") public List<Customer> getCustomer() { return List.of(new Customer(1L, "Alice"), new Customer(2L, "Bob")); } }
2. Request Mappings
@RequestMapping
- Maps HTTP requests to specific handler methods or classes.
@RequestMapping("/users") @RestController public class UserController { @GetMapping public List<String> getUsers() { return List.of("User1", "User2"); } }
@GetMapping, @PostMapping, @PutMapping, @DeleteMapping
- Specific mappings for HTTP methods.
@GetMapping("/users/{id}") public String getUser(@PathVariable String id) { return "User ID: " + id; } @PostMapping("/users") public String createUser(@RequestBody User user) { return "Created user: " + user.getName(); }
3. Request Parameters and Path Variables
@RequestParam
- Extracts query parameters from the request.
@GetMapping("/search") public String search(@RequestParam String query) { return "Searching for: " + query; }
@PathVariable
- Extracts values from the URL path.
@GetMapping("/users/{id}") public String getUserById(@PathVariable("id") String userId) { return "User ID: " + userId; }
4. Request and Session Attributes
@RequestAttribute
- Accesses attributes stored in the request. Normally used for attributes set by filters or interceptors.
@GetMapping("/request-attribute") public String getRequestAttribute(@RequestAttribute("attribute1") String attribute1) { return "Attribute1: " + attribute1; }
@SessionAttributes
- Used to store model attributes in the HTTP Servlet session between requests. Used only when stateful controllers are needed which is quite rare nowadays.
@Controller @SessionAttributes("user") public class UserController { @ModelAttribute("user") public User getUser() { return new User("Default Name"); } }
4. Request and Response Bodies
@RequestBody
- Binds the body of the HTTP request to a Java object.
@PostMapping("/users") public String createUser(@RequestBody User user) { return "User created: " + user.getName(); }
@ResponseBody
- Indicates the return value is serialized directly to the HTTP response body. You don't need this while using
@RestController
.
@ResponseBody @GetMapping("/message") public String getMessage() { return "Hello, World!"; }
5. HTTP Headers and Cookies
@RequestHeader
- Accesses HTTP headers.
@GetMapping("/header") public String getHeader(@RequestHeader("User-Agent") String userAgent) { return "User-Agent: " + userAgent; }
@CookieValue
- Accesses cookie values.
@GetMapping("/cookie") public String getCookie(@CookieValue("sessionId") String sessionId) { return "Session ID: " + sessionId; }
6. Exception Handling
@ExceptionHandler
- Handles exceptions thrown from controllers.
@ControllerAdvice public class GlobalExceptionHandler { // Handles UserNotFoundException @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<String> handleUserNotFoundException(UserNotFoundException ex) { return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND); } // Handles all other exceptions @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex) { return new ResponseEntity<>("Error: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } }
7. Model and View
@ModelAttribute
- Binds a method parameter or return value to the model.
@ModelAttribute("user") public User getUser() { return new User("Default Name"); } @GetMapping("/form") public String showForm() { return "formView"; }
Model
- Passes data to the view.
@GetMapping("/greeting") public String greeting(Model model) { model.addAttribute("message", "Hello, World!"); return "greetingView"; }
8. ResponseEntity
- Provides full control over the HTTP response.
@GetMapping("/response") public ResponseEntity<String> getResponse() { return ResponseEntity.ok("Success response"); }
ResponseEntity
allows you to set the status code, headers, and body of the response. In the example above, we are returning a 200 OK response with the body "Success response".
Say if you want to return a 404 Not Found response, you can do it like this:
@GetMapping("/not-found") public ResponseEntity<String> notFound() { return ResponseEntity.notFound().build(); }
9. File Uploads
Upload Files
- Handles multipart file uploads.
@PostMapping("/upload") public String uploadFile(@RequestParam("file") MultipartFile file) { // Save the file return "Uploaded file: " + file.getOriginalFilename(); }
Download Files
- Sends files as a response. Streams the file content to the client.
@GetMapping("/download/{fileName}") public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) { Path file = Paths.get("uploads/" + fileName); Resource resource = new UrlResource(file.toUri()); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); }
10. Cross-Origin Resource Sharing (CORS)
@CrossOrigin
- Allows cross-origin requests.
@CrossOrigin(origins = "http://example.com") @GetMapping("/cors") public String corsEnabledEndpoint() { return "CORS enabled"; }
11. Validation
@Valid
- Validates the request body using Bean Validation.
record User(@NotBlank(message = "Name is required") String name) {} @PostMapping("/users") public String createUser(@Valid @RequestBody User user) { return "User created: " + user.getName(); }
If name is not provided in the request body, a MethodArgumentNotValidException
will be thrown with the message "Name is required". This can be handled using @ExceptionHandler
.
This cheat sheet provides an overview of key annotations and concepts in Spring Web. Did I miss something? Let me know in the comments in Medium or LinkedIn. Happy coding!
follow us on YouTube, LinkedIn, and Medium.
Video Version
Check out this where I am applying most of these concepts in a real-world project:
Related Posts
Mastering New RestClient API in Spring
This guide explores the features and usage of the RestClient introduced in Spring 6, providing a modern and fluent API for making HTTP requests. It demonstrates how to create and customize RestClient instances, make API calls, and handle responses effectively.
Master Integration Testing Spring Boot API using Testcontainers
Learn how to create efficient integration tests for your Spring Boot APIs using Testcontainers and the Rest Assured library. This blog will guide you through building fluent integration tests for an API that interacts with MongoDB and AWS S3.