노션으로 다시 돌아갔습니다 😅

DTO 유효성 검증 (Validation) - (1)

by mignon25

유효성 검증을 위한 의존 라이브러리 추가

// build.gradle

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

 

 

유효성 검증 대상 및 제약 사항 확인 - MemberPostDto

// MemberPostDto

@Getter
public class MemberPostDto {

    private String email;
    private String name;
    private String phone;
    
}

위와 같은 DTO 객체의 멤버 변수에 대해 다음과 같은 제약 사항이 존재한다고 가정해보자.

 

<MemberPostDto 유효성 검증 제약 사항>

  • email (이메일 주소)
    • 값이 비어있지 않거나(null X) 공백이 아니어야 한다. 
    • 유효한 이메일 주소 형식이어야 한다.
  • name (이름)
    • 값이 비어있지 않거나(null X) 공백이 아니어야 한다.
  • phone (휴대폰 번호)
    • 값이 비어있지 않거나(null X) 공백이 아니어야 한다.
    • 010-xxx-xxxx 또는 010-xxxx-xxxx 의 형식의 문자열이어야 한다.  

 

 

Validation 적용하기 

javax.validation.constraints 에 정의된 애너테이션 및 커스텀 애너테이션을 통해 validation을 적용할 수 있다. 

1. MemberPostDto 에 Validation 적용

// MemberPostDto

@Getter
public class MemberPostDto {

	@NotBlank
    @Email
    private String email;
    
    @NotBlank(message = "이름은 공백이 아니어야 합니다.")
    private String name;
    
    @Pattern(regexp = "^010-\\d{3,4}-\\d{4}$",
    		message = "휴대폰 번호는 010으로 시작하는 11자리 숫자와 '-'로 구성되어야 합니다.")
	private String phone;
    
}

@NotBlank

  • null 값, 공백(""), 스페이스(" ") 모두 허용하지 않는다.
  • 유효성 검증에 실패하면 에러 메세지가 콘솔에 출력된다.

@Email

  • 유효한 이메일 주소인지 검증
  • 유효성 검증에 실패하면 내장된 디폴트 에러 메세지가 콘솔에 출력된다.
  • (주의) 최상위 도메인이 빠진 aaa@bbbb 같은 형태도 유효성 검증에 통과된다.
    => 필요하다면 추가적인 조건을 지정해줄 것. (정규 표현식 또는 커스텀 애너테이션)

@Pattern

  • 휴대폰 번호의 형식을 정규 표현식을 통해 검증

 

<그 밖의 Validation 애너테이션들 >

Jakarta Bean Validation : 표준 스펙에서 지원하는 유효성 검증을 위한 내장 애너테이션

@Range(min = 10000, max = 50000)

  • null 허용
  • 원하는 범위를 최소값과 최대값을 통해 지정할 수 있다.

@Positive, @PositiveOrZero

  • null 허용
  • 양수 또는 0이상의 수 허용

@Min(10), @Max(10)

  • null 허용
  • 최소값 및 최대값 지정

<정규 표현식 예시>

regexp = "^\\S+(\\s?\\S+)*$"

- 문자열의 처음은 무조건 공백이 아닌 문자
- 이후 ((공백 문자 0개 또는 1개)(공백이 아닌 문자 1개 이상)) 패턴이 0개 이상 온다. 
  • ^ : 문자열의 시작
  • \\S : 공백이 아닌 문자
  • + : 바로 앞의 패턴 1개 이상
  • () : 그룹화
  • \\s : 공백 문자
  • ? : 바로 앞 패턴 0개 또는 1개
  • \\S+ : 공백이 아닌 문자 1개 이상
  • ()* : * 앞의 패턴 0개 이상
  • $ : 문자열의 끝

 

2. Controller에서 Validation 적용 설정

Dto 클래스 앞에 @Valid 추가
@RestController
@RequestMapping("/v1/coffees")
public class CoffeeController {

    @PostMapping
    public ResponseEntity postCoffee(@Valid @RequestBody CoffeePostDto coffeePostDto) {

        return new ResponseEntity<>(coffeePostDto, HttpStatus.CREATED);
    }
    
    ...
    
}

 

 

쿼리 파라미터 및 @Pathvariable 에 대한 유효성 검증

1. Controller 의 클래스 레벨에 @Validated 추가

2. 검증할 쿼리 파라미터 또는 @Pathvaiable 애너테이션 뒤에 원하는 validation annotation 추가

@RestController
@RequestMapping("/v1/coffees")
@Validated // 추가
public class CoffeeController {

    @PatchMapping("/{coffee-id}")
    public ResponseEntity patchCoffee(
            @PathVariable("coffee-id") @Positive long coffeeId, // 추가
            @Valid @RequestBody CoffeePatchDto coffeePatchDto) {

        return new ResponseEntity<>(coffeePatchDto, HttpStatus.OK);
    }

	...
}
  • @Validated
  • @PathVariable("coffee-id") @Positive long coffeeId, 

 

 

Custom Validator 를 사용한 유효성 검증

1. Custom Validor 를 사용하기 위한 Custom Annotation 정의
2. 정의한 Custom Annotation 에 바인딩되는 Custom Validator 구현
3. 유효성 검증이 필요한 DTO 클래스의 멤버 변수에 Custom Annotation 추가

1. Custom Annotation 정의

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {NotSpaceValidator.class}) // (1)
public @interface NotSpace {

    String message() default "공백이 아니어야 합니다"; // (2)
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    
}
  • (1) : 바인딩되는 Validator 클래스
  • (2) : 애너테이션 추가시 별도로 message를 정의하지 않았을 때 유효성 검증 실패 시, 디폴트로 표시하는 메세지 

2. Custom Validator 구현

public class NotSpaceValidator implements ConstraintValidator<NotSpace, String> { 

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value == null || StringUtils.hasText(value);
    }
}
  • CustomValidator를 구현하기 위해서는 ConstraintValidator 인터페이스를 구현해야 한다. 
  • ConstraintValidator<NotSpace, String> 
    • NotSpace : CustomValidator와 매핑된 Custom Annotation
    • String : Custom Annotation 으로 검증할 대상 멤버변수의 타입
  • value의 타입도 검증 대상 멤버변수 타입으로 일치시켜준다. 
  • isValid() 메서드에 유효성 검증 로직 구현

3. 유효성 검증을 위해 Custom Annotation 추가

@Getter
public class MemberPatchDto {
    private long memberId;

    @NotSpace(message = "회원 이름은 공백이 아니어야 합니다") // (1)
    private String name;

    @Pattern(regexp = "^010-\\d{3,4}-\\d{4}$",
            message = "휴대폰 번호는 010으로 시작하는 11자리 숫자와 '-'로 구성되어야 합니다")
    private String phone;
    
}

 

 

블로그의 정보

Mignon'S Dev Log

mignon25

활동하기