728x90
Spring에서 DTO 유효성 검사
스프링에서는 DTO를 받을 때 기본적으로 제공하는 유효성 검사를 사용합니다. 그러나 기본 유효성 검사 외에 모든 유효성을 만족시키기에는 부족할 수 있습니다. 이를 해결하기 위해 필요에 따라 커스텀 어노테이션을 만들어 사용할 수 있습니다.
커스텀 어노테이션의 필요성
- DTO 내에서의 유효성 검증: 기본적으로 제공되는 유효성 검사로는 충분하지 않을 수 있습니다. 예를 들어, 여러 필드를 동시에 검사해야 하는 경우 @AssertTrue와 같은 방법을 사용할 수 있지만, 이는 코드 가독성을 저하시킬 수 있습니다.
- 추상화: 커스텀 어노테이션을 사용하면 유효성 검사 로직을 추상화하여 재사용성과 가독성을 높일 수 있습니다.
커스텀 어노테이션을 만들기 전 알아야 할 어노테이션
1. @Target
- @Target은 어노테이션이 적용될 수 있는 대상을 지정합니다. 설정할 수 있는 값은 ElementType enum으로 정의되어 있습니다.
- ElementType.FIELD: 필드에 적용
- ElementType.METHOD: 메서드에 적용
- ElementType.TYPE: 클래스, 인터페이스, 열거형에 적용
- ElementType.PARAMETER: 매개변수에 적용
- ElementType.CONSTRUCTOR: 생성자에 적용
- ElementType.LOCAL_VARIABLE: 지역 변수에 적용
- ElementType.ANNOTATION_TYPE: 다른 어노테이션에 적용
예시
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) // 필드에 적용
public @interface MyFieldAnnotation {
}
@Target(ElementType.METHOD) // 메서드에 적용
public @interface MyMethodAnnotation {
}
@Target(ElementType.TYPE) // 클래스에 적용
public @interface MyClassAnnotation {
}
2. @Retention
- @Retention은 어노테이션이 언제까지 유지될지를 지정합니다. 설정할 수 있는 값은 RetentionPolicy enum으로 정의되어 있습니다.
- RetentionPolicy.SOURCE: 컴파일 타임에만 유지
- RetentionPolicy.CLASS: 컴파일된 클래스 파일에 포함되지만, JVM에 로드될 때는 존재하지 않음
- RetentionPolicy.RUNTIME: 실행 중에도 유지 (JVM에 로드되고 리플렉션을 통해 접근 가능)
예시
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.SOURCE) // 컴파일 타임에만 유지
public @interface MySourceAnnotation {
}
@Retention(RetentionPolicy.CLASS) // 클래스 파일에 포함되지만 런타임에 존재하지 않음
public @interface MyClassAnnotation {
}
@Retention(RetentionPolicy.RUNTIME) // 실행 중에도 유지
public @interface MyRuntimeAnnotation {
}
3. @Constraint 설명
- @Constraint 어노테이션은 커스텀 유효성 검증 어노테이션을 정의할 때 사용됩니다.
- 이 어노테이션을 사용하여 해당 커스텀 어노테이션이 검증할 클래스를 지정합니다. 검증 클래스는 ConstraintValidator 인터페이스를 구현해야 합니다.
- 검증 클래스에서는 커스텀 어노테이션의 규칙을 정의하고, 어떤 필드가 유효한지를 판단하는 로직을 구현합니다.
- 유효성 검증을 위한 커스텀 어노테이션을 만들 때 필수적으로 사용하는 어노테이션입니다.
@Constraint(validatedBy = MyValidator.class) // MyValidator 유효성 검증을 담당
public @interface CustomAnnotation {
}
결합된 예시
어노테이션을 정의할 때 @Target과 @Retention을 함께 사용할 수 있습니다.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 메서드에 적용
@Retention(RetentionPolicy.RUNTIME) // 실행 중에도 유지
public @interface MyAnnotatedMethod {
String value();
}
인자 설정하기
groups
- 의미: 검증 그룹을 정의합니다. 여러 검증을 그룹으로 묶어 특정 상황에서만 적용할 수 있습니다. 예를 들어, 사용자 등록과 수정 시에 각각 다른 검증 그룹을 적용하고 싶을 때 유용합니다.
payload
- 의미: 이 어노테이션에 대한 추가 메타데이터를 담을 수 있는 필드입니다. 일반적으로 사용자가 이 값을 통해 검증 로직을 확장할 수 있도록 합니다. 특정 검증 요구 사항에 따라 추가 정보를 제공할 수 있습니다.
추가 설명
- groups와 payload는 일반적으로 커스텀 검증 로직에서 사용되는 고급 기능입니다. 특히 groups를 활용하면, 여러 상황에 따라 다른 검증 로직을 적용할 수 있어 유연한 검증이 가능합니다.
간단한 커스텀 어노테이션 만들기: CustomEmailAnnotation
아래는 간단한 커스텀 이메일 어노테이션 @CustomEmail을 정의하는 예시입니다.
1. 커스텀 어노테이션 정의
CustomEmail.java
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Constraint(validatedBy = EmailValidator.class) // 유효성 검증을 담당할 클래스 지정
@Target({ElementType.FIELD, ElementType.METHOD}) // 필드와 메서드에 적용
@Retention(RetentionPolicy.RUNTIME) // 실행 중에도 유지
// @NotBlank // 이것도 custom 어노테이션에서 사용이 가능합니다.
// @Size(min = 1, max = 100) // 이것도 가능합니다.
public @interface CustomEmail {
String message() default "유효한 이메일 주소가 아닙니다."; // 기본 오류 메시지
String regexp() default "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z]{2,}$"; // 기본 정규 표현식
Class<?>[] groups() default {}; // 그룹 정보
Class<? extends Payload>[] payload() default {}; // 추가 정보
}
2. 유효성 검증 로직
EmailValidator.java
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class EmailValidator implements ConstraintValidator<CustomEmail, String> {
private String regexp;
@Override
public void initialize(CustomEmail constraintAnnotation) {
this.regexp = constraintAnnotation.regexp();
}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
boolean result = Pattern.matches(regexp, email); // 정규 표현식 수정
return result;
}
}
3. DTO에서 사용하기
이제 @CustomEmail 어노테이션을 DTO에 적용할 수 있습니다.
UserRegistrationRequest.java
import jakarta.validation.constraints.NotBlank;
public class UserRegistrationRequest {
@NotBlank(message = "이메일은 필수입니다.")
@CustomEmail(message = "유효한 이메일 주소를 입력하세요.")
private String email;
}
이렇게 간단한 커스텀 어노테이션을 정의하고 사용할 수 있습니다. 이를 통해 코드의 가독성을 높이고 재사용성을 증가시킬 수 있습니다.
728x90
'Spring Boot' 카테고리의 다른 글
[Spring Boot] JPA 연관 관계 설정하기 (1) | 2024.10.10 |
---|---|
[Spring Boot] MySQL 연결하기 (3) | 2024.10.05 |
[Spring Boot] Validation AssertTrue/False 사용법 (1) | 2024.10.03 |
[Spring Boot] "Validation(유효성)"검증 실패 처리: 클라이언트에게 적절한 오류 메시지 보내는 방법" (3) | 2024.10.03 |
[Spring Boot] DAO, DTO, VO 차이 (0) | 2024.09.30 |