Nhận dữ liệu từ request
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
API cần biết client muốn gì: sản phẩm số mấy, tìm theo tên nào, tạo sản phẩm với tên và giá bao nhiêu. Dữ liệu đó nằm ở ba chỗ trong request. Bài này chỉ cách nhận cả ba vào tham số của handler method.
Khái niệm
🔗 Binding tham số (argument binding): cơ chế Spring tự lấy dữ liệu trong request và gán vào tham số của handler method.
| Nguồn | Ví dụ trong request | Annotation |
|---|---|---|
| Route | /api/products/5 |
@PathVariable |
| Query string | ?name=pen&maxPrice=10000 |
@RequestParam |
| Body (JSON) | { "name": "Pen", "price": 5000 } |
@RequestBody |
Mỗi tham số ghi rõ annotation cho biết nó lấy từ đâu. Riêng object trong
body, thiếu @RequestBody thì Spring không đọc JSON vào object đó.
Ví dụ
// ProductsController.java
package com.shop.api;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
class ProductsController {
@GetMapping("/{id}")
public String getById(@PathVariable int id) {
return "Sản phẩm " + id;
}
@GetMapping("/search")
public String search(
@RequestParam String name,
@RequestParam long maxPrice) {
return "Tìm " + name
+ ", giá tối đa " + maxPrice;
}
@PostMapping
public Product create(
@RequestBody Product product) {
return product;
}
}
// Product.java
package com.shop.api;
class Product {
private String name = "";
private long price;
public String getName() { return name; }
public long getPrice() { return price; }
public void setName(String name) {
this.name = name;
}
public void setPrice(long price) {
this.price = price;
}
}getById(@PathVariable int id):idtrùng tên với{id}trong route nên lấy từ URL.search(...):@RequestParamlấynamevàmaxPricetừ query string?name=...&maxPrice=....create(@RequestBody Product product): đọc body JSON thành objectProduct.- Spring tự đổi chuỗi trong URL thành
int,long. Đổi không được thì trả lỗi 400.
Thử ngay
Giữ các file cũ, thay ProductsController.java và Product.java theo phần
Ví dụ, rồi chạy lại server. Gọi hai request GET:
curl -i "http://localhost:5000/api/products/5"
curl -i "http://localhost:5000/api/products/search?name=pen&maxPrice=10000"Để gửi POST, tạo file product.json:
{ "name": "Pen", "price": 5000 }Rồi gửi file đó làm body:
curl -i -X POST http://localhost:5000/api/products -H "Content-Type: application/json" -d @product.jsonĐoán trước khi chạy: field name của Product là private. Method
create có nhận được tên sản phẩm không?
Xem kết quả
HTTP/1.1 200
Content-Type: application/json
{"name":"Pen","price":5000}Có. Spring tạo Product bằng constructor không tham số, rồi gọi setName,
setPrice theo tên trường trong JSON. Method trả lại đúng object vừa nhận.
Tên trường phải khớp cả hoa thường. JSON viết "Name" thì không có setter
nào khớp, trường đó bị bỏ qua và name giữ giá trị rỗng.
Lỗi hay gặp
Gửi chữ vào tham số số. id là int mà URL lại là chữ, Spring không
đổi được và trả về 400.
// SAI — "abc" không phải số, nhận về 400 Bad Request
GET /api/products/abc// ĐÚNG
GET /api/products/5Quên header Content-Type. Không có -H, curl gửi body với kiểu của
form (application/x-www-form-urlencoded). Server không đọc kiểu này như
JSON và trả về 415 Unsupported Media Type.
# SAI — thiếu -H "Content-Type: application/json"
curl -i -X POST http://localhost:5000/api/products -d @product.json# ĐÚNG
curl -i -X POST http://localhost:5000/api/products -H "Content-Type: application/json" -d @product.jsonTóm tắt
- Spring tự gán dữ liệu request vào tham số của handler method.
- Dữ liệu đến từ route (
@PathVariable), query string (@RequestParam) hoặc body JSON (@RequestBody). - Object trong body cần
@RequestBody, tên trường JSON phải khớp tên getter, setter. - Gửi JSON phải có header
Content-Type: application/json.
Tự kiểm tra
0/3 câuMethod có @GetMapping("/{orderId}/lines") và tham số @PathVariable int orderId, @RequestParam int page. Gọi GET /api/orders/7/lines?page=2 thì orderId và page bằng bao nhiêu?
Client gửi thông tin đơn hàng mới gồm nhiều trường. Dữ liệu này nên đặt ở đâu trong request?
POST body JSON đúng, nhưng server trả 415 Unsupported Media Type. Nguyên nhân khả dĩ nhất?