[Spring] Bean Validation (3)

이연우·2025년 7월 26일

TIL

목록 보기
52/100

⚔️ Bean Validation의 충돌

  • 등록, 수정 API에서 각각 다른 Validation이 적용된다면?

🧩 문제 상황: Validation 충돌

  • 요구 사항
    • 상품
      • id (식별자)
      • name (이름)
      • price (가격)
      • count (재고)
    • 상품 등록 API
      • 식별자 값은 필수가 아님
      • name은 null, “”, “ “을 허용하지 않음
      • price는 10 ~ 10000 사이의 숫자로 생성
      • count는 1 ~ 999 사이의 숫자로 생성
    • 상품 수정 API
      • 식별자 값이 필수
      • name은 null, “”, “ “을 허용하지 않음
      • price는 무제한으로 허용
      • count는 1 ~ 999 사이의 숫자로 생성

📌 요구 사항 요약

항목등록 API 요구 사항수정 API 요구 사항
id없어도 됨 (DB 자동 생성)반드시 필요 (@PathVariable)
namenull/빈값/공백 ❌동일
price10~10000 사이제한 없음
count1~999동일

💣 발생 문제

  • 등록과 수정이 같은 DTO 클래스를 공유하면,
    상황에 따라 다른 검증 조건을 적용하기 어려움

  • 예: 등록 시에는 @Range(min=10)을 적용하고 싶지만, 수정 시에는 제외하고 싶을 때 충돌 발생

🚀 기본 해결 방법

  1. 저장할 Object를 직접 사용하지 않고 SaveRequestDto, UpdateRequestDto 따로 사용
  2. Bean Validation의 groups 기능 사용

🗂️ groups

1. DTO를 분리

  • 등록용: ProductSaveRequestDto
  • 수정용: ProductUpdateRequestDto
    → 가장 명확하고 직관적인 방법
    → 실무에서도 자주 사용됨

2. 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 단위로 명확한 책임 분리
  • 💡 실무에서는 대부분 DTO 분리 방식 선호
    → 특히 등록/수정 폼이 다른 경우가 많기 때문

🧪 실습 예시 비교
1. 단일 DTO로 저장/수정 처리 → 실패 위험

  • @Range를 등록 API에만 써야 하는데, 수정 API에도 적용됨
  • 결국 price 제한이 의도와 다르게 적용

2. groups로 문제 해결 → 성공

  • SaveCheck.class에만 @Range 지정
  • 수정에서는 해당 검증 생략

🔍 @Validated vs @Valid

항목@Validated@Valid
제공자Spring 전용Java 표준
groups 지원✅ 지원함❌ 미지원
사용 예시@Validated(SaveCheck.class)@Valid
대표 예외ConstraintViolationExceptionMethodArgumentNotValidException

→ ⚠️ groups 기능을 사용하고 싶다면 무조건 @Validated를 사용해야 함

0개의 댓글