Spring/스프링 이론

스프링부트를 이용한 유효성 검사(feat. Validation)

블로그 주인장 2023. 11. 22.

유효성 검사

어플리케이션의 비즈니스 로직이 올바르게 동작하려면 데이터를 사전 검증하는 작업이 필요합니다.

이를 '유효성 검사' 또는 '데이터 검증' 이라고 부르는데 이를 알아보겠습니다.


일반적인 어플리케이션 유효성 검사


문제점

  1. 계층별로 진행하는 유효성 검사는 검증 로직이 각 클래스별로 분산되어 있어서 관리하기가 어렵다
  2. 검증 로직 이외로 중복이 많아 여러 곳에 유사한 기능의 코드가 존재할 수 있다.
  3. 검증해야할 값이 많다면 검증하는 코드가 길어져서 코드가 복잡하고 가독성이 떨어진다.

 

문제 해결 방법

  1. 이를 해결하기 위해서 자바에서는 Bean Validation 이라는 데이터 유효성 검사 프레임워크를 제공한다.
  2. Bean Validation
    • 어노테이션을 통해 다양한 데이터를 검증하는 기능
    • 유효성 검사를 위한 로직을 DTO 같은 도메인 모델과 묶어서 각 계층에서 사용하면서 검증 자체를 도메인 모델에 얹는 방식으로 수행한다는 의미이다.
    • 어노테이션을 사용한 검증 방식이기 때문에 코드의 간결함도 유지할 수 있다.

 

Hibernate Validator


  • Hibernate Validator는 Bean Validation 명세의 구현체이다.
  • 스프링부트에서는 Hibernate Validator를 유효성 검사 표준으로 채택하여 사용하고 있다.
  • JSR-303 명서의 구현체로써, 도메인 모델에서 어노테이션을 통한 필드값 검증을 도와준다.

 

의존성 추가


Maven(pom.xml)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

gradle(build.gradle)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-validation'
}​

 

 

스프링부트의 유효성 검사


  • 유효성 검사는 각 계층으로 데이터가 넘어오는 시점에 해당 데이터에 대한 검사를 실시한다.
  • 스프링부트에서는 계층 간 데이터 전송을 대체로 DTO 객체를 활용하고 있기 때문에 유효성 검사를 DTO 객체를 대상으로 수행하는 것이 일반적이다.

 

[예시] ValidRequestDto 클래스

@Data
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ValidRequestDto {
    @NotBlank
    String name;

    @Email
    String email;
    
    @Pattern(regexp = "^01(?:0|1|[6-9])[.-]?(\\d{3}|\\{4})[.-]?(\\d{4})$")
    String phoneNumber;
    
    @Min(value = 20) @Max(value = 40)
    int age;
    
    @Size(min = 0, max = 40)
    String description;
    
    @Positive
    int count;
    
    @AssertTrue
    boolean booleanCheck;
}

 

문자열 검증

  • @Null : null 값만 허용한다.
  • @NotNull : null을 허용하지 않는다. [","] 는 허용한다.
  • @NotEmpty : null, ""을 허용하지 않는다. [" "]는 허용한다.
  • @NotBlank : null, "", " " 모두 허용하지 않는다.

최대값/최소값 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @DemicalMax(value = "$numberString") : $numberString 보다 작은 값을 허용한다.
  • @DemicalMin(value = "$numberString") : $numberString 보다 큰 값을 허용한다.
  • @Min(value = $number) : $number 이상의 값을 허용한다.
  • @Max(value = $number) : $number 이하의 값을 허용한다.

값의 범위 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @Positive : 양수를 허용한다.
  • @PositiveOrZero : 0을 포함한 양수를 허용한다.
  • @Negative : 음수를 허용한다.
  • @NegativeOrZero : 0을 포함한 음수를 허용한다.

시간에 대한 검증

  • Date, LocalDate, LocalDateTime 등의 타입을 지원한다.
  • @Future : 현재보다 미래의 날짜를 허용한다.
  • @FutureOrPresent : 현재를 포함한 미래의 날짜를 허용한다.
  • @Past : 현재보다 과거의 날짜를 허용한다.
  • @PastOrPresent : 현재를 포함한 과거의 날짜를 허용한다.

이메일 검증

  • @Email : 이메일 형식을 검사한다. "" 는 허용한다.

자릿수 범위 검증

  • BigDecimal, BigInteger, int, long 등의 타입을 지원한다.
  • @Digits(integer = $number1, fraction = $number2): $number1의 정수 자릿수와 $number2의 소수 자릿수를 허용

Boolean 검증

  • @AssertTrue : true인지 체크한다. null 값은 체크하지 않는다.
  • @AssertFalse : false인지 체크한다. null 값은 체크하지 않는다.

문자열 길이 검증

  • @Size(min = $number1, max = $number2) : $number1 이상 $number2 이하의 범위를 허용한다.

정규식 검증

  • @Pattern(regexp = "$expression") : 정규식을 검사한다. 정규식은 자바의 java.util.regex.Pattern 패키지 컨벤션을 따른다.

 

[예시] ValidationController 클래스

@RestController
@RequestMapping("/validation")
public class ValidationController {

    private final Logger LOGGER = LoggerFactory.getLogger(ValidationController.class);

    @PostMapping("/valid")
    public ResponseEntity<String> checkValidationByValid(
            @Valid @RequestBody ValidRequestDto validRequestDto) {
        LOGGER.info(validRequestDto.toString());
        return ResponseEntity.status(HttpStatus.OK).body(validRequestDto.toString());
    }
}

 

[예시] Swagger를 이용한 데이터 테스트

  • 유효성 검사를 통과하면 200(ok), 통과하지 못하면 400(Bad_Request) 발생

 

[예시] 정규식 가이드

  • 정규식(Regular Expression)
    • 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식이다.
    • 전화번호, 주민등록번호, 이메일과 같이 특정 형식의 값을 검증해야할 때 이용할 수 있다.
  • 정규식의 요소
    1. ^ : 문자열의 시작
    2. $ : 문자열의 종료
    3. . : 임의의 한 문자
    4. * : 앞 문자가 없거나 무한정 많다.
    5. + : 앞 문자가 하나 이상
    6. ? : 앞 문자가 없거나 하나가 존재
    7. \d : 숫자 [0-9]와 동일하게 취급 
    8. 그 외의 경우 : 예시사이트1 , 예시사이트2
반응형

댓글