[스프링 로드맵] D-1. Validation 기본 - DTO 검증이 필요한 이유

2026. 1. 20. 16:00·백엔드

REST API를 만들다 보면 가장 먼저 부딪히는 문제가 있다.

  • 필수값을 안 보냈을 때는 어떻게 할 것인가?
  • 문자열 길이가 너무 길면?
  • 숫자인데 음수면?
  • 이런 요청을 그대로 서비스까지 보내도 되는가?

이 문제를 해결하기 위해 스프링에서는 컨트롤러 입구에서 요청 DTO를 검증하고, 문제가 있으면 비즈니스 로직으로 들어가기 전에 400(Bad Request) 로 차단하는 방식을 기본으로 사용한다.

이 글의 목표는 Validation이 “무엇이고”, “어디서”, “어떤 역할”을 하는지 흐름을 잡는 것이다.


0. Validation은 “어디에서” 하는가 (큰 그림)

먼저 위치부터 정리해야 한다.

Client(JSON 요청)
   ↓
Controller  ←  DTO + Validation (@Valid)
   ↓
Service     ←  비즈니스 규칙
   ↓
Repository
  • Validation은 컨트롤러 + DTO에서 수행
  • 서비스는 “검증이 끝난 값만 들어온다”는 전제로 동작

즉,

  • Validation = 입력값이 형식적으로 올바른가
  • Service 로직 = 업무 규칙상 가능한가

이렇게 역할이 분리된다.


1. Bean Validation이란 무엇인가

Bean Validation은 “값 검증 규칙을 어노테이션으로 선언하는 표준 방식”이다.

특징은 다음과 같다.

  • DTO 필드 위에 @NotBlank, @Min 같은 규칙을 붙인다
  • 컨트롤러에서 @Valid를 사용하면 스프링이 검증을 실행한다
  • 규칙을 위반하면 예외가 발생하고, 기본적으로 400 응답이 내려간다

핵심은 이거다.

검증 로직을 컨트롤러/서비스에 if문으로 흩뿌리지 않고, “입력 데이터 자체의 규칙”을 DTO에 모아둔다.


2. 왜 DTO에서 Validation을 하나

DTO는 외부 요청 데이터를 담는 객체다.

  • JSON 요청은 신뢰할 수 없다
  • 어떤 값이 올지 알 수 없다
  • 형식이 깨진 요청은 서비스까지 갈 필요가 없다

그래서 DTO는 다음 역할을 가진다.

  • 요청 데이터 구조 정의
  • 요청 데이터 형식 검증

즉 DTO + Validation은 👉 “이 요청은 최소한 말이 되는 입력인가?”를 판단하는 관문이다.


3. 의존성 설정 (@Valid가 동작하려면)

Spring Boot에서는 아래 스타터가 필요하다.

  • spring-boot-starter-validation

이 의존성이 있어야 @Valid와 Bean Validation 어노테이션이 동작한다.

(Spring Boot 3 기준으로는 Jakarta Validation 기반)


4. 요청 DTO 예시 (Shift 생성)

public record ShiftCreateRequest(

    @NotBlank(message = "근무처는 필수입니다.")
    @Size(max = 50, message = "근무처는 50자 이하여야 합니다.")
    String employerName,

    @NotNull(message = "시급은 필수입니다.")
    @Min(value = 9860, message = "시급이 너무 낮습니다.")
    Integer hourlyWage,

    @NotNull(message = "근무시간(분)은 필수입니다.")
    @Min(value = 1, message = "근무시간은 1분 이상이어야 합니다.")
    Integer minutesWorked
) {}

이 DTO는 다음을 보장한다.

  • 필수값이 빠지지 않았는가
  • 문자열 길이가 적절한가
  • 숫자 범위가 정상인가

👉 DB, 비즈니스 규칙과는 무관하게 “입력 데이터의 형태”만 검증한다.


5. 컨트롤러에서 Validation이 실행되는 흐름

@RestController
@RequestMapping("/api/shifts")
public class ShiftController {

    private final ShiftService shiftService;

    public ShiftController(ShiftService shiftService) {
        this.shiftService = shiftService;
    }

    @PostMapping
    public ResponseEntity<Void> create(
            @RequestBody @Valid ShiftCreateRequest req
    ) {
        shiftService.create(req);
        return ResponseEntity.status(201).build();
    }
}

실제 흐름은 다음 순서다.

  1. 클라이언트가 JSON 요청을 보낸다
  2. 스프링이 JSON을 DTO로 바인딩한다 (@RequestBody)
  3. @Valid가 붙어 있으면 Bean Validation 실행
  4. 규칙 위반 시 예외 발생
  5. 컨트롤러 메서드는 실행되지 않고 400 응답 반환

중요한 포인트: 검증에 실패하면 서비스는 호출되지 않는다.


6. 검증 실패 시 응답은 어떻게 처리되나

기본 동작은 다음과 같다.

  • 상태 코드: 400 Bad Request
  • 바디: 검증 실패 정보 포함

응답 포맷을 커스터마이징하는 방법은 전역 예외 처리(@ControllerAdvice) 단계에서 다룬다.

지금 단계에서는

  • 검증이 어디서 실행되는지
  • 실패하면 어디에서 차단되는지

이 두 가지만 이해하면 충분하다.


7. 자주 헷갈리는 포인트 정리

(1) @NotNull vs @NotBlank

  • @NotNull → null만 막음
  • @NotBlank → null + 빈 문자열 + 공백 문자열 모두 막음

👉 문자열 필수값은 @NotBlank가 기본

 

(2) int 대신 Integer를 쓰는 이유

  • int는 null을 표현할 수 없다
  • “값이 안 왔다”를 검증하려면 Integer + @NotNull이 적절하다

(3) @Valid는 어디에 붙이나

  • 요청 DTO를 받을 때 컨트롤러 메서드 파라미터에 붙인다
@RequestBody @Valid ShiftCreateRequest req

8. Entity에도 Validation을 붙일 수 있나?

기술적으로는 가능하다.

  • @Entity 필드에도 Bean Validation 어노테이션을 붙일 수 있다
  • JPA 동작 시 검증이 실행되도록 설정할 수도 있다

다만 현재 학습 단계에서는 다음처럼 역할을 분리하는 것이 좋다.

  • DTO: 요청 데이터 검증
  • Entity: 도메인 상태와 관계 표현

그래서 이 단계에서는

👉 Entity에 Validation은 다루지 않고,

👉 DTO + 컨트롤러 검증 흐름에 집중한다.


9. 한 문장 요약

Validation은 DTO에 규칙을 선언하고, 컨트롤러에서 @Valid로 실행하여 형식이 잘못된 요청을 서비스 진입 전에 차단하기 위한 장치다.

'백엔드' 카테고리의 다른 글

[스프링 로드맵] E-1. 전역 예외 처리 기본 - 응답을 하나로 묶는 이유  (1) 2026.01.20
[스프링 로드맵] D-2. Validation 응답 설계 - BindingResult vs 예외 처리  (0) 2026.01.20
[스프링 로드맵] C-3. Repository 실전 - JpaRepository가 해주는 것들  (1) 2026.01.19
[스프링 로드맵] C-2. 엔티티 설계 - @Entity와 기본 생성자의 의미  (0) 2026.01.19
[스프링 로드맵] C-1. JPA 큰 그림 - JPA vs Hibernate vs Spring Data JPA  (0) 2026.01.19
'백엔드' 카테고리의 다른 글
  • [스프링 로드맵] E-1. 전역 예외 처리 기본 - 응답을 하나로 묶는 이유
  • [스프링 로드맵] D-2. Validation 응답 설계 - BindingResult vs 예외 처리
  • [스프링 로드맵] C-3. Repository 실전 - JpaRepository가 해주는 것들
  • [스프링 로드맵] C-2. 엔티티 설계 - @Entity와 기본 생성자의 의미
samsam031
samsam031
samsam031 님의 블로그 입니다.
  • samsam031
    samsam031 님의 블로그
    samsam031
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 디지털포렌식
      • 드림핵 문제풀이
      • 대외활동
      • 개발 실습
      • 컴퓨터 보안
      • 클라우드
      • 자격증
      • 자연어처리
      • 백엔드
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
samsam031
[스프링 로드맵] D-1. Validation 기본 - DTO 검증이 필요한 이유
상단으로

티스토리툴바