[Spring] @Constraint로 커스텀 벨리데이션 만들기

2022. 12. 7. 12:02Web/spring-boot

1. @Constraint

  • 해당 어노테이션을 사용하면, 사용자가 원하는 Constraint와 Validation을 만들어 이를 적용할수있다.
  • 도메인 모델에서 부여되는 제약조건을 생성하기 위해 쓰인다.

2. 예시

@Constraint(validatedBy = GenderValidator.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidGender {
    String message() default "올바른 성별을 입력해주세요";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  • validatedBy라는 이름의 속성을 하나 가지고 있으며, 이 속성의 타입은 ConstraintValidator를 타입 파라미터로 가지는 Class 배열인 것을 알 수 있습니다. (GenderValidator에 대해서는 아래에서 자세히 알아보도록 하겠습니다.)
  • target 은 ElementType.FIELD (도메인모델의 필드), ElementType.PARAMETER (컨트롤러단의 파라미터) 등으로 사용된다
  • Retention은 런타임과정에서 사용하겠다는 뜻이다.
  • message
    • 제약조건 위배 시 생성할 에러메시지를 정의합니다.
    • 국제화를 위해 resource bundle key로 작성할 것을 추천합니다.
    • 이 때, resource bundle key는 FQCN 뒤에 ".message"를 작성하는 컨벤션을 따르는 것을 추천합니다.
      • Jakarta Bean Validation에 내장된 제약조건들은 모두 위 컨벤션을 따릅니다.
  • groups
    • 유효성 검증을 수행할 그룹을 지정합니다.
    • 기본값은 empty array이어야 합니다.
    • 그룹이 지정되지 않을 경우, Default 그룹이 지정됩니다.
  • payload
    • 유효성 검증을 수행하는 클라이언트가 사용할 수 있는 메타 데이터를 지정합니다.
    • 기본값은 empty array이어야 합니다.
    • API 자체에서 사용되지는 않습니다.
    • 메타 데이터 지정을 위해 문자열 기반의 값을 사용하는 것보다 Payload를 구현하는 클래스를 이용하는 것이 보다 쉽고, type-safe합니다.
// GenderValidator.java

public class GenderValidtor implements ConstraintValidator<ValidGender, String>{

    @Override
    public boolean isValid(String gender, ConstraintValidatorContext context) {
        try {
            Gender.valueOf(gender.toUpperCase()); 
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
  • ConstrainValidator <어노테이션, 검증할 변수타입> 상속받아 벨리데이션 내용을 구체적으로 명시해준다.
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class CreateUserReqDto {
        @Email(message = "올바른 이메일을 입력해주세요")
        private String email;

        private String password;

        @ValidGender(message = "올바른 성별을 입력해주세요") <-- CustomValidator
        private Gender gender;
    }
  • 사용할 변수에 어노테이션을 선언해주고 Controller에서 @Valid 어노테이션을 선언함으로서 공통적으로 벨리데이션 처리할수있다.