@RestController & Request Mapping: Xây Dựng REST API
Tìm hiểu meta-annotation @RestController, cú pháp @RequestMapping và các shortcut annotation định tuyến HTTP request trong Spring Boot.
TL;DR: @RestController là meta-annotation kết hợp giữa @Controller và @ResponseBody, tự động áp dụng cơ chế tuần tự hóa dữ liệu cho toàn bộ các phương thức bên trong class. Thay vì trả về tên view HTML, các phương thức sẽ chuyển đổi trực tiếp đối tượng Java thành định dạng JSON/XML thông qua HttpMessageConverter. Các shortcut annotation như @GetMapping hay @PostMapping giúp gắn chặt phương thức HTTP ngay tại thời điểm biên dịch, ngăn ngừa lỗi cấu hình sai sót lúc runtime.
Quá trình tiến hóa của Controller trong Spring qua 3 thế hệ?
Cách thức định nghĩa controller trong Spring Framework đã trải qua ba giai đoạn cải tiến lớn:
Thế hệ 1 (Spring 1.x - 2.x): Mỗi controller bắt buộc phải cài đặt giao diện Controller và cấu hình đường dẫn ánh xạ thủ công trong file web.xml hoặc XML bean. Cách làm này rất cồng kềnh và khó bảo trì.
Thế hệ 2 (Spring 2.5+): Giới thiệu mô hình hướng annotation với @Controller và @RequestMapping:
@Controller
@RequestMapping("/api/orders")
public class LegacyOrderController {
@RequestMapping(method = RequestMethod.GET, value = "/{id}")
@ResponseBody
public OrderDto getOrder(@PathVariable Long id) {
return orderService.findById(id);
}
}
Dù đã loại bỏ được file XML, lập trình viên vẫn phải lặp lại annotation @ResponseBody trên từng phương thức nếu muốn trả về JSON.
Thế hệ 3 (Spring 4+ đến nay): Chuẩn hóa với @RestController kết hợp các shortcut annotation chuyên biệt:
@RestController
@RequestMapping("/api/orders")
public class ModernOrderController {
@GetMapping("/{id}")
public OrderDto getOrder(@PathVariable Long id) {
return orderService.findById(id);
}
@PostMapping
public OrderDto createOrder(@RequestBody OrderRequest req) {
return orderService.create(req);
}
}
Bản chất @RestController là gì và vì sao cần @ResponseBody?
Khi một phương thức trong controller trả về một đối tượng Java, Spring MVC đứng trước hai lựa chọn xử lý:

- Nếu không có
@ResponseBody: Spring xem đối tượng trả về là tên của một giao diện HTML (view name) và chuyển giao choViewResolvertìm kiếm file template tương ứng. Nếu không tìm thấy, hệ thống sẽ báo lỗi 500. - Nếu có
@ResponseBody: Spring bỏ qua hoàn toànViewResolver, trực tiếp gọiHttpMessageConverter(mặc định là Jackson) để tuần tự hóa đối tượng thành chuỗi JSON và ghi vào thân HTTP response.
Mã nguồn định nghĩa của @RestController trong Spring:
// Spring Framework source code snippet
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
Bản chất của @RestController là gắn sẵn @ResponseBody ở cấp độ lớp. Toàn bộ các phương thức bên trong tự động kế thừa hành vi này mà không cần khai báo lặp lại.
Cấu trúc và 7 thuộc tính then chốt của @RequestMapping là gì?
@RequestMapping là annotation nền tảng hỗ trợ cấu hình chi tiết luồng định tuyến:
@RequestMapping(
value = "/orders",
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE,
headers = "X-API-Version=2",
params = "status=active"
)
public List<OrderDto> listOrders() {
return orderService.findActive();
}
7 thuộc tính cấu hình bao gồm:
value(hoặcpath): Mẫu đường dẫn URL cần so khớp.method: Mảng các phương thức HTTP được chấp nhận (nếu không khớp trả về 405 Method Not Allowed).consumes: Lọc theo headerContent-Typecủa request gửi lên (không khớp trả về 415 Unsupported Media Type).produces: Lọc theo headerAcceptmà client mong muốn nhận về (không khớp trả về 406 Not Acceptable).headers: Ràng buộc sự tồn tại hoặc giá trị của một request header cụ thể.params: Ràng buộc sự xuất hiện của query parameter.name: Tên gán định danh để phục vụ việc tạo URL tự động.
Khi đặt @RequestMapping ở cấp độ lớp, chuỗi URL sẽ đóng vai trò tiền tố chung cho tất cả các phương thức con bên trong.
Vì sao nên ưu tiên các shortcut annotation thay cho @RequestMapping?
Từ Spring 4.3, 5 shortcut annotation được giới thiệu nhằm thay thế @RequestMapping(method = ...):
@GetMapping: Tương đương HTTP GET (an toàn và idempotent).@PostMapping: Tương đương HTTP POST (tạo mới tài nguyên).@PutMapping: Tương đương HTTP PUT (cập nhật toàn phần, idempotent).@DeleteMapping: Tương đương HTTP DELETE (xóa tài nguyên, idempotent).@PatchMapping: Tương đương HTTP PATCH (cập nhật một phần).
Lợi ích cốt lõi của shortcut annotation không chỉ dừng lại ở việc làm ngắn gọn mã nguồn, mà còn giúp bảo vệ tính đúng đắn ngay tại thời điểm biên dịch. Bạn không thể vô tình truyền tham số method vào @GetMapping vì trình biên dịch Java sẽ phát hiện lỗi ngay lập tức.
Quy tắc so khớp đường dẫn của PathPatternParser diễn ra ra sao?
Spring Boot 3 sử dụng PathPatternParser với các biểu thức đường dẫn đa dạng:
@GetMapping("/orders") // Exact match
@GetMapping("/orders/{id}") // Single path variable
@GetMapping("/orders/{id:\\d+}") // Regex constraint: only numeric digits
@GetMapping("/orders/{*path}") // Capture all remaining segments
Khi một URL có thể khớp với nhiều handler khác nhau, Spring giải quyết theo nguyên tắc ưu tiên cấu hình cụ thể nhất (most-specific match):
@GetMapping("/orders/latest") // Handler A: Literal exact match
@GetMapping("/orders/{id}") // Handler B: Dynamic path variable
Nếu client gửi request GET /orders/latest, Handler A sẽ luôn được chọn vì phân đoạn chuỗi tĩnh (literal segment) có độ ưu tiên cao hơn biến đường dẫn. Thứ tự phân cấp độ đặc hiệu từ cao xuống thấp: Literal > Regex > Path Variable > Wildcard * > Greedy **.
Quá trình đăng ký và tra cứu registry bên dưới diễn ra như thế nào?
Toàn bộ quá trình định tuyến được phân tách làm hai pha tách biệt:

- Pha khởi động (Startup Phase):
RequestMappingHandlerMappingquét toàn bộ các lớp có@RestController, phân tích các thuộc tính và xây dựng bảng bản đồRequestMappingInfo -> HandlerMethod. Nếu phát hiện hai method có cùng điều kiện khớp hoàn toàn, Spring sẽ ném ngay ngoại lệIllegalStateException. - Pha xử lý yêu cầu (Request Phase):
DispatcherServlettra cứu bảng bản đồ bằng phép so sánh băm $O(1)$, sắp xếp độ đặc hiệu và trả vềHandlerExecutionChainthích hợp.
Những lỗi sai kinh điển nào cần tránh khi định nghĩa Controller?
Dưới đây là các lỗi thường gặp trong quá trình phát triển API:
- Dùng
@Controllerthay vì@RestController: Quên khai báo@ResponseBodykhiến Spring chuyển giao dữ liệu choViewResolvertìm file template HTML, dẫn đến lỗi 500 Runtime. - Trùng lặp đường dẫn URL giữa các controller: Cố tình khai báo hai phương thức có cùng URL và HTTP method khiến ứng dụng bị crash ngay khi khởi động.
- Để dấu gạch chéo cuối ở class prefix: Đặt
@RequestMapping("/api/orders/")kết hợp@GetMapping("/{id}")sẽ vô tình tạo ra đường dẫn có hai dấu gạch chéo//không chuẩn mực.
Tóm tắt
@RestControllerlà meta-annotation kết hợp@Controllervà@ResponseBody, tối ưu cho việc xây dựng REST API.@ResponseBodychỉ định việc chuyển đổi trực tiếp Java object sang JSON thông quaHttpMessageConverter.- 5 shortcut annotation (
@GetMapping,@PostMapping...) giúp tăng tính an toàn lúc biên dịch và làm sáng tỏ ý định thiết kế. PathPatternParserhỗ trợ các biểu thức đường dẫn mạnh mẽ và luôn ưu tiên handler có mức độ đặc hiệu cao nhất.- Bảng định tuyến được tạo cố định lúc khởi động, đảm bảo ứng dụng phát hiện xung đột sớm theo nguyên lý fail-fast.
Tự kiểm tra
- Q1Tại sao Spring 4 giới thiệu annotation @RestController thay vì giữ nguyên cách viết @Controller kết hợp @ResponseBody?
- Q2Nếu lập trình viên vô tình dùng @Controller cho một REST API và trả về đối tượng OrderDto mà không có @ResponseBody, điều gì sẽ xảy ra?
- Q3Một ứng dụng có hai endpoint: GET /orders/latest và GET /orders/{id}. Khi client gửi request GET /orders/latest, handler nào sẽ được chọn?
- Q4Hai thuộc tính consumes và produces trong @RequestMapping lọc request dựa trên các header HTTP nào?
- Q5Điều gì xảy ra lúc ứng dụng khởi động nếu có hai controller khai báo trùng lặp hoàn toàn cùng một URL pattern và cùng HTTP method?
Bài tiếp theo: Content Negotiation, Versioning & CORS
Bài này có giúp bạn hiểu bản chất không?
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
URL Routing Pipeline: HandlerMapping Và PathPattern
Bài tiếpContent Negotiation, API Versioning Và CORS Spring
Lộ trình Junior Java Backend Developer
Chặng 15/21 · REST API với Spring MVC — bài 4/21 của chặng
Thảo luận & góp ý
Hỏi đáp về bài này