개발은 재밌어야 한다
article thumbnail

Spring Boot 애플리케이션을 개발할 때 입력 값의 유효성을 검증하는 것은 중요한 과정입니다. 이를 위해 자주 사용하는 어노테이션 중 하나가 Bean Validation에서 제공하는 @NotNull, @NotEmpty, @NotBlank입니다. 이 글에서는 각 어노테이션의 차이점과 사용법을 예제와 함께 알아보겠습니다.


@NotNull, @NotEmpty, @NotBlank란?

이 세 가지 어노테이션은 Java Bean Validation API(javax.validation.constraints)에서 제공되며, 주로 Spring Boot의 유효성 검사 과정에서 사용됩니다.
각각의 동작 방식은 다음과 같습니다.

어노테이션설명대상 타입

@NotNull 값이 null이 아니어야 합니다. 모든 객체 타입
@NotEmpty 값이 null이 아니고, 빈 문자열 또는 컬렉션이 아님 문자열, 컬렉션, 배열 등
@NotBlank 값이 null이 아니고, 공백만 포함하지 않아야 함 문자열 타입

각 어노테이션의 동작 원리

@NotNull

  • 검증 조건: 값이 null인지 여부만 검사합니다.
  • 사용 예: 필수 입력 값이 반드시 존재해야 할 때 사용.
import javax.validation.constraints.NotNull;

public class UserRequest {
    @NotNull(message = "사용자 이름은 필수 입력 값입니다.")
    private String name;
}
 
  • 테스트 케이스:
    • 입력: name = null → 검증 실패.
    • 입력: name = "" → 검증 성공 (빈 문자열 허용).

@NotEmpty

  • 검증 조건: 값이 null이 아니고, 비어 있지 않은 경우("" 또는 empty collection)만 통과합니다.
  • 사용 예: 문자열이 비어 있지 않아야 하거나, 리스트나 배열에 값이 반드시 존재해야 할 때 사용.
  •  
import javax.validation.constraints.NotEmpty;

public class UserRequest {
    @NotEmpty(message = "취미 목록은 비어 있을 수 없습니다.")
    private List<String> hobbies;
}
  • 테스트 케이스:
    • 입력: hobbies = null → 검증 실패.
    • 입력: hobbies = [] → 검증 실패.
    • 입력: hobbies = ["Reading", "Cooking"] → 검증 성공.

@NotBlank

  • 검증 조건: 값이 null이 아니고, 공백 문자(" ", "\t")만 포함하지 않아야 합니다.
  • 사용 예: 문자열이 공백만 포함해서는 안 되는 경우 사용.
import javax.validation.constraints.NotBlank;

public class UserRequest {
    @NotBlank(message = "비밀번호는 공백만으로 구성될 수 없습니다.")
    private String password;
}
  • 테스트 케이스:
    • 입력: password = null → 검증 실패.
    • 입력: password = "" → 검증 실패.
    • 입력: password = " " → 검증 실패.
    • 입력: password = "abc123" → 검증 성공.

차이점 비교

어노테이션null 값 허용빈 문자열 허용 ("")공백 문자만 허용 (" ")

@NotNull
@NotEmpty
@NotBlank
  • @NotNull은 null만 체크하므로 빈 값("")이나 공백(" ")은 허용됩니다.
  • @NotEmpty는 빈 값("")이나 비어 있는 컬렉션도 허용하지 않습니다.
  • @NotBlank는 공백 문자만 포함된 경우도 허용하지 않습니다.

사용 방법

의존성 추가

Spring Boot에서는 기본적으로 Bean Validation API가 포함되어 있습니다. 만약 필요하다면 spring-boot-starter-validation 의존성을 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
컨트롤러에서 사용

유효성 검사를 적용하려면 DTO 클래스에 어노테이션을 추가하고, 컨트롤러 메서드에서 @Valid 또는 @Validated를 사용합니다.

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @PostMapping
    public String createUser(@RequestBody @Valid UserRequest request) {
        return "User created with name: " + request.getName();
    }
}
 

DTO 클래스

각 어노테이션을 적절히 사용해 유효성 검사를 적용합니다.

 
import javax.validation.constraints.NotNull;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotBlank;

public class UserRequest {

    @NotNull(message = "이름은 필수 입력 값입니다.")
    private String name;

    @NotEmpty(message = "취미 목록은 비어 있을 수 없습니다.")
    private List<String> hobbies;

    @NotBlank(message = "비밀번호는 공백만으로 구성될 수 없습니다.")
    private String password;

    // Getters and Setters
}

에러 메시지 처리

Spring Boot에서는 기본적으로 유효성 검증 실패 시 에러 메시지를 반환합니다. 이를 커스터마이징하려면 @ControllerAdvice를 사용합니다.

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
                errors.put(error.getField(), error.getDefaultMessage()));
        return errors;
    }
}

유의 사항

  1. 컬렉션과 배열
    • @NotBlank는 컬렉션이나 배열에는 사용할 수 없습니다. 이 경우 @NotEmpty를 사용하세요.
  2. 성능 고려
    • 큰 데이터 구조에 대해 검증을 수행할 경우, 필요하지 않은 곳에서 어노테이션을 남발하면 성능 문제가 발생할 수 있습니다.
  3. 상황에 맞는 선택
    • 값만 존재하면 되는 경우: @NotNull
    • 빈 값이 허용되지 않는 경우: @NotEmpty
    • 공백도 허용되지 않는 경우: @NotBlank
profile

개발은 재밌어야 한다

@ghyeong

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!