Bean Validation과 고급 적용 전략
1️⃣ Bean Validation 이란?
- 검증 Annotation(@NotBlank, @Range 등) 사용
- 표준 스펙: jakarta.validation
- 구현체: Hibernate Validator
@Getter
public class SignUpDto {
@NotBlank(message = "이름은 필수입니다")
private String name;
@Range(min = 1, max = 120, message = "나이는 1~120 사이여야 합니다")
private Integer age;
}
@PostMapping("/signup")
public String save(@Validated @ModelAttribute SignUpDto dto, BindingResult bindingResult) { ... }
✅ @Validated vs @Valid
| 구분 |
설명 |
| @Valid |
Java 표준, 그룹 지정 불가 |
| @Validated |
Spring 제공, groups 기능 지원 |
✅ 객체 단위 오류 (ObjectError)
if (dto.getPrice() * dto.getCount() < 10000) {
bindingResult.reject("totalMin", new Object[]{10000}, "총액은 10000원 이상이어야 합니다");
}
2️⃣ 등록/수정 API 검증 조건 충돌 해결
방법 1. DTO 분리 (권장)
- ProductSaveRequest, ProductUpdateRequest 따로 만들기
방법 2. groups 기능 사용
public interface SaveCheck {}
public interface UpdateCheck {}
@NotBlank(groups = {SaveCheck.class, UpdateCheck.class})
@Range(min = 10, max = 10000, groups = SaveCheck.class)
@Validated(SaveCheck.class)
3️⃣ @ModelAttribute vs @RequestBody
| 항목 |
@ModelAttribute |
@RequestBody |
| 대상 |
Form, 쿼리 파라미터 |
JSON |
| 검증 범위 |
필드 단위 바인딩 |
객체 단위 바인딩 |
| 변환 실패 |
컨트롤러 호출 O |
컨트롤러 호출 X |
| BindingResult 사용 |
O |
O (단, 바인딩 성공 후만) |
4️⃣ 에러 메시지 처리
- 기본 메시지: @NotBlank(message = "이름을 입력하세요")
- 커스텀 메시지 처리: MessageSource 활용
- 공통 에러 포맷 필요 시: @ControllerAdvice로 전역 처리
요약
| 개념 |
키포인트 |
| Validation |
사용자 입력 검증은 UX + 보안 모두를 위한 필수 |
| BindingResult |
오류 수집 및 컨트롤러 진입 유지 가능 |
| Bean Validation |
간결한 Annotation 기반 검증 |
| ObjectError |
필드 외 조건 검증에 사용 |
| DTO 분리 / groups |
API별 검증 요구사항 충돌 해결 |
| @ModelAttribute vs @RequestBody |
바인딩 방식과 실패 시점이 다름 |