들어가면서
자주 사용하는 특별한 유효성 검사 로직을 분리해서 관리하고 싶을 때! 커스텀 유효성 어노테이션을 만들면 유용하다.
가독성도 향상되어서 코드를 읽기가 좋아지는 효과도 있어서 커스텀 유효성 검사를 구현하는 방법을 알게되어서 너무 좋았다!
커스텀 유효성 어노테이션을 만들기 위한 절차는 2가지가 있다.
- 커스텀 어노테이션 만들기
- 커스텀 로직 판별기 만들기
필요한 클래스 만들기
비밀번호를 검사하는 유효성을 구현하고 싶은 경우를 예시로 삼아서 설명하겠다.
우선 구현하고자 하는 클래스를 만들자!
public @interface Password {}
public class PasswordValidator{}
1. 커스텀 어노페이션 만들기
유효성 검사할 대상을 상대로 사용할 어노테이션을 만들자.
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface Password {
String message() default "비밀번호는 최소 8자 이상, 15자 이하이며 알파벳 소문자(a-z), 숫자(0~9)로 구성되어야 합니다.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
위의 예제 로직을 설명하면...
- 사용할 대상은 메소드와 필드로 선정하고 런타임에서도 필요하기 때문에 런타임으로 정책을 설정했다.
- 구현한 커스텀 어노테이션의 제약을 구현하는 클래스로는 PasswordValidator.class 로 지정하여 커스텀할 로직을 넣어주었다.
- message()를 통해서 실패시 표시할 메시지를 커스텀할 수 있다.
- groups() 는 스프링에서 제공하는 @Validated를 사용할 때, 유용한 속성이다.
- payload()는 밸리데이션 클라이언트가 사용하는 메타데이터를 전달하기 위해서 사용된다.
groups?
동일한 객체를 사용하는 로직 A, B가 있을 때, A에서는 객체의 일부만 검증하고 싶고 B에서는 모두 검증하고 싶다면 어떻게 구현을 해야할까?
새로운 클래스를 생성해서 A, B로 분리하는 방법이 있겠지만 이 경우에는 동일한 데이터를 나타내는 객체가 2개가 생기는 것이기 때문에 중복이다.
이러한 경우에 group를 사용해서 유효성을 실행하는 경우를 나타내는 것이 좋다.
public record Dto(
@NotNull(groups = {A.class, B.class}) String test1,
@NotNull(groups = {B.class}) String test2
){}
public void sampleMethodA(@Validated(A.class) Dto dto)();
public void sampleMethodB(@Validated(B.class) Dto dto)();
2. 커스텀 로직 판별기 만들기
비밀번호의 제약을 검사하는 판별기 클래스를 구현하려면 ConstraintValidator
를 상속받아서 구현한다.
제네릭 타입으로 유효성 어노테이션과 사용할 대상의 타입을 주어서 상속받는다.
public class PasswordValidator implements ConstraintValidator<Password, String> {
private static final Pattern pattern = Pattern.compile("^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$");
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
if (password == null) return false;
if (password.length() < 8 || password.length() > 15) return false;
return pattern.matcher(password).matches();
}
}
예제에서는 정규식으로 비밀번호에 사용되는 문자를 검사하고 길이는 따로 검사하는 식으로 로직을 구현했다.
사용하기
여기까지 준비가 되었다면 이제는 @Notnull
과 같은 유효성 어노테이션과 같이 사용을 하면 커스텀 유효성 검사 구현을 적용할 수 있는 것이다!
Reference
'spring' 카테고리의 다른 글
테스트 코드에서 @Transactional 을 통한 롤백 사용시 주의점 (2) | 2023.12.04 |
---|---|
Spring 메일 전송기능 구현하기 (3) | 2023.12.01 |
Springdoc을 이용해서 Swagger API 만들기 (0) | 2023.11.03 |
Spring Rest docs 와 Swagger 장점만 골라서 사용하기 (0) | 2023.10.28 |
RestTemplate을 통해서 API 호출하기 (0) | 2023.10.13 |