[Java Backend Zero to Hello] BÀI 5.5: SPRING WEB MVC
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 5: Spring Framework & Spring Boot | Bài 51/86
BÀI 5.5: SPRING WEB MVC
Mục tiêu
- Hiểu kiến trúc Spring MVC
- Tạo Controller
- Xử lý Request, Response
- Sử dụng Thymeleaf template
1. KIẾN TRÚC SPRING MVC
HTTP Request
↓
DispatcherServlet (Front Controller)
↓
HandlerMapping
↓
Controller
↓
Service / Repository
↓
ViewResolver (cho MVC) hoặc trả JSON (cho REST)
↓
HTTP Response
2. @CONTROLLER
@Controller
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String listUsers(Model model) {
model.addAttribute("users", userService.findAll());
return "users/list"; // Tên view (Thymeleaf template)
}
@GetMapping("/{id}")
public String userDetail(@PathVariable Long id, Model model) {
model.addAttribute("user", userService.findById(id));
return "users/detail";
}
}
3. @REQUESTMAPPING
@Controller
@RequestMapping("/api/users") // Base path
public class UserController {
@RequestMapping(method = RequestMethod.GET) // Tương đương @GetMapping
public String list() { ... }
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String detail(@PathVariable Long id) { ... }
}
Shortcut annotations
| Annotation | HTTP Method |
|---|---|
@GetMapping |
GET |
@PostMapping |
POST |
@PutMapping |
PUT |
@DeleteMapping |
DELETE |
@PatchMapping |
PATCH |
4. NHẬN DỮ LIỆU TỪ REQUEST
4.1 @PathVariable
@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) { ... }
@GetMapping("/users/{id}/orders/{orderId}")
public String getOrder(@PathVariable Long id, @PathVariable Long orderId) { ... }
4.2 @RequestParam
@GetMapping("/search")
public String search(@RequestParam String keyword,
@RequestParam(defaultValue = "0") int page,
@RequestParam(required = false) String sort) { ... }
// URL: /search?keyword=java&page=1&sort=name
4.3 @RequestBody
@PostMapping("/users")
public String create(@RequestBody UserDTO user) { ... }
4.4 @RequestHeader
@GetMapping("/users")
public String list(@RequestHeader("Authorization") String token) { ... }
4.5 @CookieValue
@GetMapping("/profile")
public String profile(@CookieValue("sessionId") String sessionId) { ... }
4.6 @ModelAttribute
@PostMapping("/users")
public String create(@ModelAttribute UserForm form) { ... }
5. TRẢ VỀ DỮ LIỆU
5.1 String (View name)
@GetMapping("/users")
public String list(Model model) {
model.addAttribute("users", userService.findAll());
return "users/list"; // users/list.html
}
5.2 ModelAndView
@GetMapping("/users")
public ModelAndView list() {
ModelAndView mav = new ModelAndView("users/list");
mav.addObject("users", userService.findAll());
return mav;
}
5.3 ResponseEntity (REST)
@GetMapping("/api/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
6. MODEL
@GetMapping("/users")
public String list(Model model) {
model.addAttribute("users", userService.findAll());
model.addAttribute("title", "Danh sách user");
return "users/list";
}
Thymeleaf template
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">Title</title>
</head>
<body>
<h1 th:text="${title}">Title</h1>
<table>
<tr th:each="user : ${users}">
<td th:text="${user.id}">1</td>
<td th:text="${user.name}">Name</td>
<td th:text="${user.email}">Email</td>
</tr>
</table>
</body>
</html>
7. FORM HANDLING
7.1 Controller
@GetMapping("/users/new")
public String showForm(Model model) {
model.addAttribute("user", new UserForm());
return "users/form";
}
@PostMapping("/users")
public String create(@ModelAttribute("user") @Valid UserForm form,
BindingResult result) {
if (result.hasErrors()) {
return "users/form";
}
userService.save(form);
return "redirect:/users";
}
7.2 Form template
<form th:action="@{/users}" th:object="${user}" method="post">
<div>
<label>Name:</label>
<input type="text" th:field="*{name}" />
<span th:errors="*{name}"></span>
</div>
<div>
<label>Email:</label>
<input type="email" th:field="*{email}" />
<span th:errors="*{email}"></span>
</div>
<button type="submit">Save</button>
</form>
8. REDIRECT VÀ FORWARD
@PostMapping("/users")
public String create(@ModelAttribute UserForm form) {
userService.save(form);
return "redirect:/users"; // Redirect (PRG pattern)
}
@GetMapping("/old-path")
public String oldPath() {
return "forward:/new-path"; // Forward
}
9. SESSION VÀ FLASH ATTRIBUTES
9.1 @SessionAttributes
@Controller
@SessionAttributes("user")
public class UserController {
@ModelAttribute("user")
public UserForm getUser() {
return new UserForm();
}
}
9.2 RedirectAttributes (Flash)
@PostMapping("/users")
public String create(@ModelAttribute UserForm form, RedirectAttributes ra) {
userService.save(form);
ra.addFlashAttribute("message", "Tạo user thành công!");
return "redirect:/users";
}
10. EXCEPTION HANDLING
10.1 @ExceptionHandler
@ExceptionHandler(UserNotFoundException.class)
public String handleNotFound(UserNotFoundException ex, Model model) {
model.addAttribute("error", ex.getMessage());
return "error/404";
}
10.2 @ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public String handleNotFound(UserNotFoundException ex, Model model) {
model.addAttribute("error", ex.getMessage());
return "error/404";
}
@ExceptionHandler(Exception.class)
public String handleGeneric(Exception ex, Model model) {
model.addAttribute("error", "Đã xảy ra lỗi");
return "error/500";
}
}
11. INTERCEPTOR
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// Kiểm tra trước khi vào controller
if (!isAuthenticated(request)) {
response.sendRedirect("/login");
return false;
}
return true;
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/admin/**");
}
}
12. STATIC RESOURCES
spring:
web:
resources:
static-locations: classpath:/static/, classpath:/public/
Mặc định: /static/, /public/, /resources/, /META-INF/resources/
13. BÀI TẬP THỰC HÀNH
Bài 1: CRUD với Thymeleaf
Tạo ứng dụng quản lý user với:
- Danh sách user
- Form thêm/sửa
- Xóa user
Bài 2: Validation
Thêm validation cho form (name không rỗng, email hợp lệ).
Bài 3: Exception Handling
Xử lý UserNotFoundException với trang 404 đẹp.
14. TÓM TẮT
| Khái niệm | Mô tả |
|---|---|
| @Controller | MVC Controller |
| @RequestMapping | Map URL |
| @PathVariable | Biến trong URL |
| @RequestParam | Query parameter |
| @RequestBody | JSON body |
| @ModelAttribute | Form binding |
| Model | Truyền data sang view |
| Thymeleaf | Template engine |
| @ControllerAdvice | Global exception handler |
| Interceptor | Xử lý trước/sau request |
Bài tiếp theo: 5.6 Spring Boot REST
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 5.4: SPRING DATA JPA
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 5.6: SPRING BOOT REST API
All rights reserved