-
Spring Boot 시리즈 8편 – 입력값 검증 전략: @Valid부터 도메인 중심 유효성 설계까지개발/Spring Boot 2025. 4. 24. 08:00
Spring Boot에서 @Valid를 활용한 입력값 검증부터 커스텀 Validator, 도메인 기반 유효성 설계까지 실무 중심으로 정리했습니다. 예외 처리 통합 전략도 포함됩니다.
Spring Boot 시리즈 8편 – 입력값 검증 전략: @Valid부터 도메인 중심 유효성 설계까지
REST API에서 입력값 유효성 검증은 단순히 올바른 형식을 검사하는 것을 넘어,
비즈니스 로직을 보호하고, 클라이언트의 예측 가능한 에러 응답을 보장하는 중요한 첫 관문입니다.이번 글에서는 @Valid와 Bean Validation 기본 사용법부터,
복잡한 검증 로직을 도메인 내부로 이동시키고,
필요한 경우 Validator 클래스를 직접 커스터마이징하는 전략까지 단계별로 설명합니다.
🧱 1. 기본 검증 구조 – DTO + @Valid
1️⃣ DTO에 검증 애노테이션 적용
public class RegisterUserRequest { @NotBlank(message = "이름은 필수입니다.") private String name; @Email(message = "이메일 형식이 아닙니다.") @NotBlank(message = "이메일은 필수입니다.") private String email; @Size(min = 4, max = 20, message = "비밀번호는 4~20자 사이여야 합니다.") private String password; }
- Bean Validation(Jakarta Validation) 기반으로 제공
- @NotBlank, @Email, @Size, @Pattern 등 기본 제약조건을 조합하여 사용
2️⃣ Controller에서 @Valid 적용
@PostMapping("/api/users") public ResponseEntity<ApiResponse<Void>> register(@Valid @RequestBody RegisterUserRequest request) { userService.register(request); return ResponseEntity.ok(ApiResponse.success()); }
- @Valid 사용 시 자동으로 유효성 검사가 수행되며, 실패 시 MethodArgumentNotValidException 발생
❌ 2. 검증 실패 시 예외 처리 통합
@ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ApiResponse<List<FieldErrorResponse>>> handleValidationException(MethodArgumentNotValidException ex) { List<FieldErrorResponse> errors = ex.getBindingResult().getFieldErrors().stream() .map(err -> new FieldErrorResponse(err.getField(), err.getDefaultMessage())) .toList(); return ResponseEntity.badRequest().body(ApiResponse.fail("C001", "유효성 검사 실패", errors)); }
- FieldErrorResponse 클래스는 각 필드별 오류를 클라이언트에게 명확하게 전달합니다.
- 응답 형식은 7편에서 다룬 ApiResponse<T> 구조와 일관성 있게 유지합니다.
🔁 3. 커스텀 유효성 검사 – 직접 Validator 만들기
예시: 중복 이메일 방지 @EmailNotRegistered
1️⃣ 애노테이션 정의
@Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EmailNotRegisteredValidator.class) public @interface EmailNotRegistered { String message() default "이미 등록된 이메일입니다."; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2️⃣ Validator 구현
@Component public class EmailNotRegisteredValidator implements ConstraintValidator<EmailNotRegistered, String> { private final UserRepository userRepository; public EmailNotRegisteredValidator(UserRepository userRepository) { this.userRepository = userRepository; } @Override public boolean isValid(String value, ConstraintValidatorContext context) { return value != null && !userRepository.existsByEmail(value); } }
3️⃣ DTO에 적용
public class RegisterUserRequest { @EmailNotRegistered private String email; }
- Repository 의존성이 필요한 검증도 깔끔하게 구성할 수 있습니다.
- 코드 재사용성과 명확성이 모두 높아집니다.
🧠 4. 도메인 내부 유효성 검증 전략
복잡한 비즈니스 조건은 DTO가 아니라 도메인 객체 내부에서 검증하는 것이 바람직합니다.
예시: User 엔티티 내부에서 검증
@Entity public class User { public void changePassword(String current, String newPassword) { if (!this.password.equals(current)) { throw new BusinessException(ErrorCode.INVALID_PASSWORD); } this.password = newPassword; } }
- 비밀번호 일치 여부, 가입 자격 조건, 정책 기반 유효성 등은 도메인 책임
- Entity가 스스로 자신의 유효한 상태를 유지하도록 설계
✅ 5. 실무 적용 전략 정리
구분 적용 위치 설명
형식 검증 DTO, @Valid JSON 역직렬화 전후 기본 조건 확인 외부 의존 검증 커스텀 Validator DB 조회, 외부 API 의존 검증 정책 기반 검증 Domain 객체 비즈니스 규칙, 상태 전이 조건 등 공통 오류 처리 GlobalExceptionHandler MethodArgumentNotValidException, BindException 등 처리
🧪 테스트 전략
검증 대상 테스트 방식
기본 검증 (@Valid) 컨트롤러 통합 테스트 (MockMvc or RestAssured) 커스텀 Validator 단위 테스트 (스프링 컨텍스트 없이 가능) 도메인 유효성 도메인 단위 테스트, 상태 전이 테스트
✅ 마무리 요약
항목 핵심 내용
검증 도구 @Valid, @NotBlank, @Size, 커스텀 애노테이션 실패 처리 @ExceptionHandler(MethodArgumentNotValidException) 고급 설계 DB 기반 검증은 Validator로, 정책 검증은 도메인 내부에 응답 통일 ApiResponse<T> 구조로 에러 응답 포함 테스트 책임 분리된 계층마다 명확한 테스트 전략 수립
📌 다음 편 예고
Spring Boot 시리즈 9편: 로그인 및 인증 처리 전략 – JWT 기반 인증 흐름 구현과 보안 고려사항
LIST'개발 > Spring Boot' 카테고리의 다른 글
Spring Boot 시리즈 10편 – Spring Security로 인가 처리 확장: 권한 기반 API 보호 전략 (0) 2025.04.25 Spring Boot 시리즈 9편 – 로그인 및 인증 처리 전략: JWT 기반 인증 흐름과 보안 설계 (0) 2025.04.24 Spring Boot 시리즈 7편 – API 응답 구조 표준화 전략: 성공과 실패를 구분하는 통일 설계 (0) 2025.04.23 Spring Boot 시리즈 6편 – Swagger를 활용한 API 문서 자동화 전략 (0) 2025.04.23 Spring Boot 고급 시리즈 10편 – 멀티 모듈 아키텍처 전략: 실무 서비스 구조 분리 가이드 (0) 2025.04.23