⚔️ Bean Validation의 충돌
- 등록, 수정 API에서 각각 다른 Validation이 적용된다면?
🧩 문제 상황: Validation 충돌
📌 요구 사항 요약
| 항목 | 등록 API 요구 사항 | 수정 API 요구 사항 |
|---|---|---|
id | 없어도 됨 (DB 자동 생성) | 반드시 필요 (@PathVariable) |
name | null/빈값/공백 ❌ | 동일 |
price | 10~10000 사이 | 제한 없음 |
count | 1~999 | 동일 |
💣 발생 문제
등록과 수정이 같은 DTO 클래스를 공유하면,
상황에 따라 다른 검증 조건을 적용하기 어려움
예: 등록 시에는 @Range(min=10)을 적용하고 싶지만, 수정 시에는 제외하고 싶을 때 충돌 발생
🚀 기본 해결 방법
SaveRequestDto, UpdateRequestDto 따로 사용groups 기능 사용🗂️
groups
1. DTO를 분리
ProductSaveRequestDtoProductUpdateRequestDto2. groups 기능 사용 (선택적)
✍ 그룹 인터페이스 정의
public interface SaveCheck {}
public interface UpdateCheck {}
🧑💻 DTO 클래스에서 groups 지정
@Data
public class ProductRequestDtoV2 {
@NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
private String name;
@NotNull
@Range(min = 10, max = 10000, groups = SaveCheck.class) // 저장 전용
private Integer price;
@NotNull
@Range(min = 1, max = 999)
private Integer count;
}
📟 컨트롤러에서 그룹 지정
@PostMapping("/v2/product")
public String save(
@Validated(SaveCheck.class) @ModelAttribute ProductRequestDtoV2 dto
)
@PutMapping("/v2/product/{id}")
public String update(
@PathVariable Long id,
@Validated(UpdateCheck.class) @ModelAttribute ProductRequestDtoV2 dto
)
⚖️ groups VS DTO 분리
| 비교 항목 | groups 사용 | DTO 분리 |
|---|---|---|
| 코드 수 | 줄어듦 | 약간 증가 |
| 가독성 | 떨어짐 (복잡한 조건 많아질수록) | 높음 |
| 유지보수 | 어렵고 실수 위험 ↑ | 명확하고 안정적 |
| 실무 활용도 | 제한적 | 매우 높음 ✅ |
| 장점 | 하나의 클래스에서 다양한 조건 대응 | API 단위로 명확한 책임 분리 |
🧪 실습 예시 비교
1. 단일 DTO로 저장/수정 처리 → 실패 위험
@Range를 등록 API에만 써야 하는데, 수정 API에도 적용됨2. groups로 문제 해결 → 성공
SaveCheck.class에만 @Range 지정🔍 @Validated vs @Valid
| 항목 | @Validated | @Valid |
|---|---|---|
| 제공자 | Spring 전용 | Java 표준 |
| groups 지원 | ✅ 지원함 | ❌ 미지원 |
| 사용 예시 | @Validated(SaveCheck.class) | @Valid |
| 대표 예외 | ConstraintViolationException | MethodArgumentNotValidException |
→ ⚠️ groups 기능을 사용하고 싶다면 무조건 @Validated를 사용해야 함