Ràng buộc URL với phương thức xử lý
Annotation @RequestMapping(value = "/test/info", method = RequestMethod.GET) dùng để ánh xạ một phương thức trong Controller tới một URL cụ thể. Mặc định, nó chấp nhận cả yêu cầu GET và POST, nhưng có thể giới hạn bằng thuộc tính method. Tuy nhiên, các annotation chuyên biệt hơn như @GetMapping và @PostMapping thường được ưa chuộng hơn cho từng phương thức. Trong khi đó, @RequestMapping thường được dùng ở cấp lớp để định nghĩa tiền tố chung cho tất cả các endpoint bên trong.
Nhận tham số từ yêu cầu HTTP
Truyền tham số trực tiếp theo tên
Khi tên trường trong form HTML trùng với tên tham số trong phương thức Controller, Spring MVC sẽ tự động gán giá trị:
<form action="/user/submit" method="post">
<input name="account">
<input name="secret">
<input type="submit" value="Gửi">
</form>
@Controller
public class UserController {
@PostMapping("/submit")
@ResponseBody
public String handle(String account, String secret) {
// Xử lý logic
return "OK";
}
}
Spring MVC hỗ trợ chuyển đổi kiểu dữ liệu tự động (ví dụ: chuỗi số → Long). Tuy nhiên, nếu dữ liệu không hợp lệ (ví dụ: "xyz" → Long), hệ thống sẽ trả về lỗi 400 do không thể chuyển đổi.
Sử dụng @RequestParam
Khi tên tham số trên client không phù hợp với quy tắc đặt tên biến Java (ví dụ: user_name), hoặc khi cần xử lý dữ liệu phức tạp như mảng, danh sách, ta sử dụng @RequestParam:
@PostMapping("/apply")
@ResponseBody
public String processForm(
@RequestParam(value = "user_name", defaultValue = "Ẩn danh") String userName,
String course,
@RequestParam List<Integer> purpose
) {
System.out.println("Tên: " + userName);
System.out.println("Khóa học: " + course);
purpose.forEach(System.out::println);
return "Thành công";
}
Lưu ý: Khi dùng Map<String, String> để nhận toàn bộ tham số, các giá trị lặp (như checkbox nhiều lựa chọn) sẽ bị ghi đè — chỉ giữ lại giá trị đầu tiên. Do đó, nên dùng đối tượng DTO (Data Transfer Object) để đảm bảo toàn vẹn dữ liệu.
Xử lý JSON với @RequestBody
Khi frontend gửi dữ liệu dưới dạng JSON (thường gặp khi dùng Axios, Fetch API...), header Content-Type sẽ là application/json. Trong trường hợp này, Controller phải dùng @RequestBody để Spring MVC biết cần phân tích nội dung body thành đối tượng Java:
@PostMapping("/api/user")
@ResponseBody
public String createUser(@RequestBody User user) {
// Xử lý đối tượng user đã được deserialize từ JSON
return "Tạo thành công";
}
Ngược lại, với form HTML truyền thống (mặc định application/x-www-form-urlencoded), không cần @RequestBody khi dùng đối tượng DTO.
Gán giá trị cho thuộc tính đối tượng lồng nhau
Spring MVC hỗ trợ gán dữ liệu vào các đối tượng con thông qua cú pháp dấu chấm trong tên input:
<input name="credential.username">
<input name="credential.password">
<input name="profile.fullName">
<input name="profile.birthDate">
public class RegistrationForm {
private Credential credential = new Credential();
private Profile profile = new Profile();
}
public class Credential {
private String username;
private String password;
}
public class Profile {
private String fullName;
private Date birthDate;
}
Dữ liệu sẽ được ánh xạ chính xác vào các thuộc tính lồng nhau nhờ cơ chế data binding của Spring.
Trích xuất biến từ đường dẫn URL với @PathVariable
Annotation này cho phép lấy giá trị từ các đoạn động trong URL:
@GetMapping("/orders/{orderId}/items/{itemId}")
@ResponseBody
public String getItemDetail(
@PathVariable Long orderId,
@PathVariable("itemId") String productId
) {
return "Đơn hàng: " + orderId + ", Sản phẩm: " + productId;
}
Xử lý tham số kiểu ngày tháng
Chuyển đổi cục bộ với @DateTimeFormat
Áp dụng trực tiếp trên tham số hoặc thuộc tính đối tượng để chỉ định định dạng ngày:
@PostMapping("/events")
@ResponseBody
public String createEvent(
@DateTimeFormat(pattern = "yyyy-MM-dd") Date eventDate,
@RequestBody Event event
) {
// ...
}
Hoặc trong lớp DTO:
public class Event {
@DateTimeFormat(pattern = "dd/MM/yyyy")
private LocalDate startDate;
}
Cấu hình chuyển đổi toàn cục
Tạo converter tùy chỉnh:
public class StringToDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
if (source == null || source.trim().isEmpty()) return null;
try {
return new SimpleDateFormat("yyyy-MM-dd").parse(source);
} catch (ParseException e) {
throw new IllegalArgumentException("Không thể phân tích ngày: " + source);
}
}
}
Đăng ký trong file cấu hình Spring (XML):
<mvc:annotation-driven conversion-service="globalConversionService" />
<bean id="globalConversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.example.converter.StringToDateConverter" />
</set>
</property>
</bean>
Sau khi cấu hình, mọi tham số kiểu Date nhận chuỗi có định dạng yyyy-MM-dd sẽ được tự động chuyển đổi mà không cần annotation.