Spring MVC
Spring MVC Architecture
Spring MVC is a web framework built on the Servlet API. It follows the Model-View-Controller pattern. The central component is the DispatcherServlet, which acts as a front controller — it receives all requests and delegates them to the appropriate handler (controller).
Request flow: Browser → DispatcherServlet → HandlerMapping → Controller → Service → Model → ViewResolver → View (JSP/Thymeleaf) → Response
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import javax.validation.Valid;
@Controller
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
// GET /products - List all products
@GetMapping
public String listProducts(Model model) {
model.addAttribute("products", productService.findAll());
model.addAttribute("title", "Product List");
return "products/list"; // View name: templates/products/list.html
}
// GET /products/{id} - Show product detail
@GetMapping("/{id}")
public String showProduct(@PathVariable Long id, Model model) {
Product product = productService.findById(id);
model.addAttribute("product", product);
return "products/detail";
}
// GET /products/new - Show create form
@GetMapping("/new")
public String showCreateForm(Model model) {
model.addAttribute("product", new Product());
return "products/form";
}
// POST /products - Create product
@PostMapping
public String createProduct(@Valid @ModelAttribute Product product,
BindingResult result) {
if (result.hasErrors()) {
return "products/form"; // Return to form with errors
}
productService.save(product);
return "redirect:/products"; // Post-Redirect-Get pattern
}
// GET /products/{id}/edit - Show edit form
@GetMapping("/{id}/edit")
public String showEditForm(@PathVariable Long id, Model model) {
model.addAttribute("product", productService.findById(id));
return "products/form";
}
// POST /products/{id} - Update product
@PostMapping("/{id}")
public String updateProduct(@PathVariable Long id,
@Valid @ModelAttribute Product product,
BindingResult result) {
if (result.hasErrors()) return "products/form";
product.setId(id);
productService.save(product);
return "redirect:/products/" + id;
}
// POST /products/{id}/delete - Delete product
@PostMapping("/{id}/delete")
public String deleteProduct(@PathVariable Long id) {
productService.deleteById(id);
return "redirect:/products";
}
}
Request Mapping Annotations
| Annotation | HTTP Method | Equivalent |
|---|---|---|
@RequestMapping | Any | Base mapping |
@GetMapping | GET | @RequestMapping(method=GET) |
@PostMapping | POST | @RequestMapping(method=POST) |
@PutMapping | PUT | @RequestMapping(method=PUT) |
@DeleteMapping | DELETE | @RequestMapping(method=DELETE) |
@PatchMapping | PATCH | @RequestMapping(method=PATCH) |
<!-- templates/products/list.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">Products</title>
</head>
<body>
<h1 th:text="${title}">Product List</h1>
<a th:href="@{/products/new}">Add New Product</a>
<table>
<thead>
<tr><th>ID</th><th>Name</th><th>Price</th><th>Actions</th></tr>
</thead>
<tbody>
<tr th:each="product : ${products}">
<td th:text="${product.id}"></td>
<td th:text="${product.name}"></td>
<td th:text="${#numbers.formatCurrency(product.price)}"></td>
<td>
<a th:href="@{/products/{id}(id=${product.id})}">View</a>
<a th:href="@{/products/{id}/edit(id=${product.id})}">Edit</a>
<form th:action="@{/products/{id}/delete(id=${product.id})}" method="post">
<button type="submit">Delete</button>
</form>
</td>
</tr>
</tbody>
</table>
</body>
</html>
@Controller
public class BindingExamples {
// @PathVariable: /users/42
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id, Model model) {
model.addAttribute("user", userService.findById(id));
return "user/detail";
}
// Multiple path variables: /orders/5/items/3
@GetMapping("/orders/{orderId}/items/{itemId}")
public String getOrderItem(@PathVariable Long orderId,
@PathVariable Long itemId, Model model) {
model.addAttribute("item", orderService.getItem(orderId, itemId));
return "order/item";
}
// @RequestParam: /search?q=java&page=1&size=10
@GetMapping("/search")
public String search(@RequestParam String q,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String category,
Model model) {
model.addAttribute("results", searchService.search(q, page, size, category));
return "search/results";
}
// @ModelAttribute: binds form fields to object
@PostMapping("/register")
public String register(@ModelAttribute @Valid UserForm form,
BindingResult errors, Model model) {
if (errors.hasErrors()) {
return "auth/register";
}
userService.register(form);
return "redirect:/login?registered=true";
}
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.