Spring Boot bài 05: Spring MVC: request, Controller, Model và View
- 18-10-2026
- Toanngo92
- 0 Comments
Giáo trình Spring Boot MVC và REST API · Chương 3/12: Spring MVC và dữ liệu hiển thị · Bài 05/28 · Biên soạn tháng 10/2026.
Mục lục
Mục tiêu bài học
Theo dõi một request GET từ tham số URL đến template Thymeleaf và hiểu ý nghĩa của tên view.
Request được ánh xạ vào phương thức nào?
Trình duyệt gửi GET /courses?q=Spring&page=0. Hạ tầng Spring MVC tìm phương thức có mapping phù hợp, chuyển kiểu tham số rồi gọi Controller. @GetMapping chỉ định đường dẫn và HTTP method; không nên dùng cùng một endpoint GET để thay đổi dữ liệu vì trình duyệt, cache hoặc công cụ tìm kiếm có thể gọi lại nó.
Trong ví dụ, q là từ khóa, page là chỉ số trang bắt đầu từ 0, size là số dòng và sort là trường sắp xếp. @RequestParam lấy tham số query string; defaultValue giúp URL ngắn vẫn có giá trị hợp lệ. Service tiếp tục kiểm tra giới hạn thay vì tin mọi số do client gửi lên.
Tệp trong mã nguồn mẫu: src/main/java/com/hocvietcode/academy/CourseWebController.java. Đoạn dưới được trích từ tệp này; xem bản tải về để có đủ import và phần còn lại.
@GetMapping({"/","/courses"})
String list(@RequestParam(defaultValue="") String q,@RequestParam(defaultValue="0") int page,@RequestParam(defaultValue="10") int size,@RequestParam(defaultValue="id") String sort,Model model){
model.addAttribute("result",service.search(q,page,size,sort));model.addAttribute("q",q);model.addAttribute("sort",sort);return "courses/list";
}
Model là dữ liệu của lần render này
Model chứa các tên mà template sẽ đọc: result, q và sort. Tên chuỗi courses/list được view resolver hiểu là template courses/list.html trong resources/templates. Nó không phải URL để trình duyệt truy cập trực tiếp và cũng không phải nội dung trả ra màn hình.
Controller chỉ cần chuẩn bị dữ liệu đã sẵn sàng hiển thị. Không để template tự gọi Repository hoặc mở transaction. Trong mẫu, Service trả Page<CourseDto>; mỗi DTO có tên khóa học, giá và tên danh mục. Việc chuyển đổi hoàn thành trước khi render nên không phụ thuộc lazy loading trong template.
Phân biệt đường dẫn, query string và request body
/courses/12 chỉ một tài nguyên; @PathVariable nhận 12. /courses?q=Java là thao tác tìm kiếm và @RequestParam đọc q. Khi gửi biểu mẫu hoặc JSON, dữ liệu thường nằm trong body. Chọn annotation theo dạng request, không theo cảm giác tên tham số giống nhau.
Nếu URL chứa /courses/abc trong khi phương thức cần Long, lỗi chuyển kiểu xảy ra trước khi nghiệp vụ chạy. Nếu id có kiểu đúng nhưng không tồn tại, Service ném CourseNotFound và ứng dụng trả 404. Hai tình huống này khác nhau và nên có cách phản hồi tương ứng.
Dùng DevTools của trình duyệt để quan sát
Mở tab Network, tải /courses rồi chọn request dạng document. Bạn sẽ thấy URL, method GET, mã 200 và response HTML. Trang CSS có request riêng. Việc có HTML trong response cho thấy server đã render; không cần viết JavaScript để tạo bảng cho cách làm này.
Thử đổi q trong URL và quan sát ô tìm kiếm giữ lại giá trị. Nếu Controller trả được 200 nhưng bảng trống, hãy kiểm tra model và dữ liệu. Nếu nhận 404, kiểm tra mapping; nếu lỗi template, đọc tên template và biểu thức được nêu trong log. Đừng xóa Security hay đổi toàn bộ cấu hình chỉ vì một đường dẫn bị gõ sai.
Lỗi thường gặp và lưu ý
- Trong @Controller, return "courses/list" là tên view; trong @RestController, cùng chuỗi có thể trở thành nội dung response.
- @PathVariable và @RequestParam không thay thế tùy tiện cho nhau.
Ghi nhớ
Luồng MVC là request → Controller → Service → Model → template HTML. Biết luồng này giúp khoanh vùng lỗi nhanh hơn.

