유효성 검사를 위한 커스텀 애너테이션 구현하기

후투티·2025년 4월 21일

잊지마!

목록 보기
14/20

리뷰를 작성하면서 별점을 부여하는 기능을 구현했다.
그런데 별점은 0.5점 단위로 주는 게 좀 더 좋을 듯하여 유효성 검사를 추가해주기로 했다.
FE쪽에서 0.5 단위로 보여줄 수 있다고 하셨지만
BE쪽에서 유효성 검사를 처리해두는 게 좋겠다고 판단하여 진행하게 되었다.

일단은 최솟값은 0이 아니라 0.5로 두고 싶기 때문에
DTO쪽에 @Min(value=0.5)로 두려고 했다.
하지만 @Min과 @Max는 int 값만 허용하기 때문에
double 값인 0.5로 설정하면 컴파일 에러가 났다.

이를 해결하기 위해서는 (소수점 이하를 포함하여 검증하기 위해서)
@DecimalMin(value = "0.5"), @DecimalMax(value ="5.0") 이렇게 하는 방법도 있으나,

유효성 검사로 0.5 단위만 허용하는
내가 만든 RatingValid라는 이름의 커스텀 Validator를 사용할 수 있다.


ConstraintValidator<A, T> 를 구현한 RatingValidator 클래스 만들기

여기서 A는 애너테이션의 타입이고, T는 검사할 값의 타입이다.
애너테이션은 RatingValid로 이름을 정하고, 0.5 단위이기 때문에 Double로 타입을 적었다.

반환값으로는 0.5 이상, 5.0 이하의 값이면서, 0.5단위로만 값을 받았는지 여부를boolean으로 받도록 했다.
(rating == null 이 조건은 내 서비스 내에서는 리뷰 수정시 별점은 수정하지 않을 수도 있게 한 거라 이건 각자의 서비스에 따라 달라지는 조건이다.)


커스텀 애너테이션 RatingValid 만들기

만드는 방법은 아래와 같다.
https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraint

@Contraint

단어 그대로 강제하는 기능을 가진 애너테이션이라는 것을 표시한 것이다.
그리고 실제 검증 로직은 (validatedBy = RatingValidator.class)에 따라
RatingValidator 클래스에서 한다는 뜻이다.
이로써 @RatingValid를 넣으면 유효성 검사를 할 수 있게 된다.

@Target({ElementType.FIELD, ElementType.PARAMETER})

이건 어디에 이 애너테이션을 붙일 수 있는지 정하는 것이다.
DTO에서 멤버변수에 붙이기 위해서 ElementType.FIELD를,
Controller에서 파라미터에 붙이기 위해서 ElementType.PARAMETER를 붙여준 것이다.

Retention(RetnionPolicy.RUNTIME)

요거는 Contraint에 들어가보니 되어 있길래따라 적어줬다.
찾아보니 스프링이 구동중이어야 유효성 검사가 실행되는 것이기 때문이라고 한다.

@interface

나만의 애테이션을 만들거야. 그것의 이름은! _ _ _

String message() default "어쩌구저쩌구"

유효성 검사에 실패하면 나올 에러 메시지를 적는 곳이다.

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

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

이것들은 실제로 사용되는 부분은 아니다.
하지만 Bean Validation(= Java 표준 유효성 검사)에서
커스텀 제약 조건 애너테이션을 만들 때 message 뿐만 아니라
groupg(), payload()를 필수로 작성해야 한다고 한다.
그래서 안 쓰더라도 형식 맞추기 용도로라도 정의를 해 놓아야 하는 부분이다.
기본값으로 {} 이렇게 비워두면 된다.


이렇게 유효성 검사를 하도록 애너테이션을 만들어두면 잊지말고
Controller에서 @RequestBody만 적는 게 아니라 @Valid를 적어줘야 한다..!

profile
모르는 건 모른다고 하는 사람

0개의 댓글