0

[Java Backend Zero to Hello] [Phase 5] BÀI 5.5: SPRING WEB MVC

📚 Series: Java Backend Zero to Hello 📂 Phân đoạn: Phase 5: Spring Framework & Spring Boot 📖 Nội dung: BÀI 5.5: SPRING WEB MVC 💡 Khóa học lập trình Backend Java & Spring Boot chuẩn doanh nghiệp từ con số 0.


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 bài học

⭐ Hãy bookmark (clip) lại series để tiện theo dõi các bài học tiếp theo nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí