Validation
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
Client gửi sản phẩm tên rỗng, giá âm. Nếu API cứ thế lưu vào thì dữ liệu hỏng từ đầu. Validation chặn dữ liệu sai trước khi handler method chạy.
Khái niệm
✅ Validation: bước kiểm tra dữ liệu client gửi lên có hợp lệ không trước khi xử lý.
🔖 Bean Validation: bộ annotation chuẩn của Java gắn lên trường của DTO để khai báo quy tắc, ví dụ @NotBlank, @Positive.
| Annotation | Quy tắc |
|---|---|
@NotBlank |
bắt buộc có, chuỗi không được rỗng |
@Size(max = 100) |
chuỗi tối đa 100 ký tự |
@Positive |
số lớn hơn 0 |
@Min(1), @Max(10) |
số nằm trong khoảng |
@Email |
đúng định dạng email |
Ví dụ
// ProductsController.java
package com.shop.api;
import jakarta.validation.*;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/products")
class ProductsController {
@PostMapping
public ResponseEntity<String> create(
@Valid @RequestBody
CreateProductRequest request) {
return ResponseEntity.ok(
"Đã tạo " + request.name());
}
}
// CreateProductRequest.java
package com.shop.api;
import jakarta.validation.constraints.*;
record CreateProductRequest(
@NotBlank(message = "Tên không được trống")
@Size(max = 100)
String name,
@Positive(message = "Giá phải lớn hơn 0")
long price) {
}- Quy tắc nằm ngay trên từng trường của DTO, trong package
jakarta.validation.constraints. @Validbảo Spring kiểm tra DTO trước khi gọi method. Sai quy tắc thì trả 400, method không chạy.messageđặt câu báo lỗi riêng thay cho câu mặc định.
Thử ngay
Giữ các file cũ, thay ProductsController.java và
CreateProductRequest.java theo phần Ví dụ, rồi chạy lại server. Tạo file
product.json với dữ liệu sai:
{ "name": "", "price": -5 }Rồi gửi:
curl -i -X POST http://localhost:5000/api/products -H "Content-Type: application/json" -d @product.jsonĐoán trước khi chạy: method có chạy tới dòng return ResponseEntity.ok(...)
không, và response báo mấy lỗi?
Xem kết quả
HTTP/1.1 400
Content-Type: application/json
{"timestamp":"2026-09-29T04:12:00.819Z","status":400,"error":"Bad Request","path":"/api/products"}Method không chạy. Spring chặn từ trước và trả 400. Body mặc định không kể
lỗi nào, nhưng log của server ghi đủ: Validation failed ... with 2 errors,
mỗi lỗi kèm tên trường và câu báo lỗi như "Tên không được trống".
Muốn body có danh sách lỗi, thêm dòng
spring.web.error.include-binding-errors=always vào
application.properties.
Lỗi hay gặp
Tự kiểm tra bằng if trong từng method. Quy tắc bị chép rải rác, sửa một
chỗ dễ quên chỗ khác.
// SAI — quy tắc nằm trong method, phải chép lại ở PUT
// ItemsController.java
package com.shop.api;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/items")
class ItemsController {
@PostMapping
public ResponseEntity<String> create(
@RequestParam String name) {
if (name.isBlank()) {
return ResponseEntity.badRequest()
.body("Tên không được trống");
}
return ResponseEntity.ok(name);
}
}Đặt quy tắc thành annotation trên DTO thì mọi method dùng DTO đó đều được kiểm tra.
// ĐÚNG — quy tắc nằm trên DTO
// ItemsController.java
package com.shop.api;
import jakarta.validation.*;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/items")
class ItemsController {
@PostMapping
public ResponseEntity<String> create(
@Valid @RequestBody
CreateItemRequest request) {
return ResponseEntity.ok(request.name());
}
}
// CreateItemRequest.java
package com.shop.api;
import jakarta.validation.constraints.*;
record CreateItemRequest(
@NotBlank(message = "Tên không được trống")
String name) {
}Quên @Valid. Annotation trên DTO vẫn còn đó, nhưng không có gì bảo
Spring kiểm tra, nên dữ liệu sai vẫn lọt vào method.
Tóm tắt
- Validation chặn dữ liệu sai trước khi method chạy.
- Khai báo quy tắc bằng annotation trên DTO:
@NotBlank,@Positive,@Size. @Validtrước tham số bật bước kiểm tra, sai thì Spring trả 400.- Dùng
messageđể có câu báo lỗi dễ hiểu cho người dùng.
Tự kiểm tra
0/3 câuDTO có trường @Min(1) @Max(10) int quantity, tham số trong controller có @Valid. Client gửi quantity = 0. Chuyện gì xảy ra?
Muốn email của khách hàng vừa bắt buộc vừa đúng định dạng. Gắn annotation nào?
Quy tắc validation nên đặt ở đâu?