[Spring] Custom Annotation

HOJUN·2024년 6월 8일

Backend - Spring

목록 보기
11/34

Custom Annotation

전화번호 입력 검증을 했었는데, 정규식을 외우고 있을 수는 없지 않을까 ?
우리나라 전화번호는 000-0000-0000으로 다 같을테니까 어노테이션을 만들어보자.

public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String>

ConstraintValidator는 데이터 혹은 클래스의 검증 시점을 비즈니스로직 수행 전, 즉 controller 진입 전 검증을 하므로 일관성 있는 응답이 가능하다.

해당 단계에서 Exception이 발생하면 ControllerAdvice를 구현함으로써 대처할 수 있겠다.

private String regexp;

    @Override
    public void initialize(PhoneNumber constraintAnnotation) {
        this.regexp = constraintAnnotation.regexp();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        boolean result = Pattern.matches(regexp, value);
        return result;
    }

isValid 메소드에서 검증을 하는데 regexp에 입력된 정규식에 기반하는 검증을 수행한다.

그럼 자동으로 value가 입력된 값이 될 것이다.

@Constraint(validatedBy = {PhoneNumberValidator.class})
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PhoneNumber {
    String message() default "핸드폰 번호 양식에 맞지 않습니다. ex)000-0000-0000";

    String regexp() default "^\\d{2,3}-\\d{3,4}-\\d{4}$";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

물론 정규식을 안 쓸 수는 없지만, 이렇게 어노테이션을 만들어 놓으면 다시 쓸 일이 없지 않겠는가.

1. @Target(ElementType.FIELD)

매개변수 ElementType으로 옵션이 여러가지가 있는데, 어노테이션을 붙일 수 있는 대상을 지정한다. 링크텍스트
데이터의 body의 클래스 필드인 phoneNumber이므로 FIELD를 사용한다.

2. @Retention(RetentionPolicy.RUNTIME)

실제 유지되는 범위의 정책이라고 해야되겠다.
런타임에 검증하도록 RUNTIME을 사용한다.
CLASS와 SOURCE가 존재하는데, 대충 어떤 범위인지 예상할 수 있을 것이다.

3. @Constraint(validatedBy = {PhoneNumberValidator.class})

유효성을 검증하는 로직을 가져온다.
앞서 작성했던 isValid 메소드가 여기서 사용된다.

@PhoneNumber
private String phoneNumber;

원래 작성했던 패턴을 어노테이션 하나로 정리했다.
정규식 한 번 쓰면 될까 생각할 수 있지만 아무래도 만들어놓고 재사용하면 되는 것 아니겠는가

0개의 댓글