| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
- java테스트
- Array
- Java
- ArrayList
- 자바문법
- SpringBoot
- input
- 문자열
- IntelliJ
- 스프링부트
- string
- Eclipse
- list
- 정규식
- math
- 배열
- vscode
- 인텔리제이
- 테스트자동화
- javascript
- Visual Studio Code
- 자바스크립트
- 자바
- 단위테스트
- js
- html
- HashMap
- CSS
- junit
- junit5
- Today
- Total
어제 오늘 내일
[Spring Boot] 사용자의 입력은 믿지 마세요! 유효성 검사(Validation) 정복하기 (@Valid vs @Validated) 본문
[Spring Boot] 사용자의 입력은 믿지 마세요! 유효성 검사(Validation) 정복하기 (@Valid vs @Validated)
hi.anna 2026. 3. 11. 07:22"이메일 형식이 아닙니다.", "비밀번호는 8자 이상이어야 합니다."
회원가입 할 때 이런 메시지 많이 보셨죠? 프론트엔드에서도 막을 수 있지만, 백엔드에서의 검증은 필수입니다. (해커들은 프론트엔드를 우회해서 요청을 보내니까요!)
오늘은 if문 도배 없이, 어노테이션 몇 개로 깔끔하게 데이터를 검증하는 Bean Validation을 알아보겠습니다.
1. 의존성 추가부터! (build.gradle)
Spring Boot 2.3 버전 이상부터는 별도의 라이브러리를 추가해야 합니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
2. DTO에 규칙 정하기 (어노테이션의 마법)
데이터를 받는 객체(DTO)에 "이 필드는 어떤 규칙을 지켜야 해!"라고 딱지(Annotation)를 붙여줍니다.
@Getter
public class MemberRequestDto {
@NotBlank(message = "이름은 필수입니다.") // null, "", " " 모두 허용 안 함!
private String name;
@Email(message = "이메일 형식이 올바르지 않습니다.")
private String email;
@Min(value = 18, message = "18세 이상만 가입 가능합니다.")
private int age;
}
💡 면접 단골 질문: @NotNull vs @NotEmpty vs @NotBlank 차이점?
문자열(String) 검증할 때 가장 헷갈리는 3대장입니다. 확실히 정리해 드릴게요.
| 어노테이션 | null | ""(빈 문자열) | " " (공백) | 추천 상황 |
| @NotNull | X | O | O | 숫자, 객체 등 |
| @NotEmpty | X | X | O | 리스트, 배열 등 |
| @NotBlank | X | X | X | String (문자열) |
꿀팁: 문자열 입력받을 땐 고민하지 말고 그냥
@NotBlank쓰세요.
사용자가 스페이스바만 눌러서 가입하는 걸 막아줍니다.
3. 컨트롤러에서 검사 시작! (@Valid)
규칙을 정했으니, 이제 검사하라고 시켜야겠죠? 컨트롤러의 파라미터 앞에 @Valid만 붙이면 끝입니다.
@PostMapping("/signup")
public ResponseEntity<String> signup(@Valid @RequestBody MemberRequestDto request) {
// 1. 요청이 들어오면 @Valid가 DTO를 검사합니다.
// 2. 문제가 있으면? -> 여기서 즉시 에러 발생! (메서드 실행 안 됨)
memberService.signup(request);
return ResponseEntity.ok("가입 성공");
}
4. 에러는 어디서 잡나요? (MethodArgumentNotValidException)
@Valid 검사에 실패하면 MethodArgumentNotValidException이라는 긴 이름의 예외가 발생 합니다.
지난 포스팅에서 배운 @RestControllerAdvice 기억나시죠? 거기서 잡으면 됩니다!
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
// 에러가 난 필드와 메시지를 쏙쏙 뽑아서 맵에 담기
ex.getBindingResult().getAllErrors().forEach(c -> errors.put(((FieldError) c).getField(), c.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
}
결과 (클라이언트가 받는 응답):
{
"name": "이름은 필수입니다.",
"email": "이메일 형식이 올바르지 않습니다."
}
5. 심화: @Valid vs @Validated 차이가 뭔가요?
@Valid: 자바 표준 스펙(JSR-303)입니다. 가장 기본적으로 쓰입니다.@Validated: 스프링이 제공하는 기능입니다. 그룹(Groups) 기능을 사용할 수 있습니다.
"그룹 기능이 뭐죠?"
회원가입 할 때는 id가 없어야 하고(Null), 정보 수정 할 때는 id가 필수(NotNull)여야 한다면?
하나의 DTO를 쓰면서 상황에 따라 검증 로직을 다르게 적용하고 싶을 때 @Validated를 씁니다. (하지만 실무에서는 복잡해서 DTO를 분리하는 것을 더 추천합니다!)
마치며
오늘의 핵심 요약입니다.
- Validation 라이브러리를 추가한다.
- DTO에
@NotBlank,@Email등의 규칙을 붙인다. - 컨트롤러 파라미터에
@Valid를 붙여 검사를 수행한다. - 발생한 예외는 전역 핸들러에서 깔끔하게 처리한다.
이제 여러분의 서버는 잘못된 데이터로부터 안전합니다!
다음 포스팅에서는 Spring Boot 데이터 접근 기술의 꽃: JPA와 영속성 컨텍스트(Persistence Context)에 대해 알아보겠습니다. 드디어 DB 이야기네요!
도움이 되셨다면 좋아요와 댓글 부탁드립니다! 😊
