TroubleShooting & Study/SpringBoot

[Annotation] 유효성 검사 어노테이션 여러 개를 합칠 수 있을까? (feat. Custom Annotation, Validation)

DH_0518 2024. 11. 3. 23:25

 Untitled 개발 이후, 회사의 다른 서비스를 만들면서 하나의 계정으로 회사의 모든 서비스들을 이용할 수 있으면 유저들이 편할 것 같다는 생각을 했다. 그래서 대표님게 SSO(Single Sign On)을 건의했고, 그렇게 통합 인증 서버를 만들게 되었다.

 

통합 인증 서버는 앞으로 회사의 모든 서비스들에서 트래픽이 몰릴 것이므로 좀 더 단단하게 만들고 싶었고, 이전에는 사용하지 않았던 Validation을 적용해보기로 했다.

 

 

 

 

 

Validation

 

 

 

 먼저 Spring Validation은 @RequestBody, @RequestParam, @PathVariable에 대해 유효성 검증을 수행하고, 유효하지 않는 데이터인 경우 Exception을 발생시키는 라이브러리이다

 내가 제일 먼저 적용한 API는 '이메일 중복 확인' 기능이다. 이메일 중복 확인의 경우 Email 형식에 맞는지 검사하는 @Email 어노테이션, 값이 비어있거나 null인지를 검사하는 @NotEmpty, 설정한 길이 미만/초과를 검사하는 @Size를 사용한다

 

수정 전

 사진을 보면 알 수 있겠지만, 단순히 하나의 RequestParam을 받는데  @Email, @NotEmpty, @Size를 모두 사용하다보니 코드가 길어지고 가독성이 현저히 떨어진다.

 따라서 Validation을 수행하는 세 개의 어노테이션을 하나의 어노테이션으로 쓸 수 있다면 이런 부분을 해결할 수 있을 것이다

 

 

해결한 코드를 먼저 보고 지나가자

수정 후

 

 

 

 

 

 

 

 

Custom Annotation 만들기

 

 

 

그렇다면 이제 어떻게 Custom Annotation을 만드는지 확인해보고, 내가 만든 @EmailValidation을 확인한 후 글을 마무리 하겠다

 

 

Custom Annotation 구성

: Annotation의 구성은 다음과 같다

@Target({ElementType.[적용대상]})
@Retention(RetentionPolicy.[정보가 유지되는 시점])
public @interface '어노테이션 이름'{
  public '타입' '멤버이름()' default '기본값';
  ...
}

 

 

Custom Annotation 규칙

  1. 지정 가능한 메타 어노테이션은 다음과 같다
    • @Target: 해당 어노테이션이 적용되는 대상
      • PACKAGE: 패키지
      • TYPE: 타입
      • ANNOTATION_TYPE: 어노테이션 타입
      • CONSTRUCTOR: 생성자
      • FIELD: 멤버 변수
      • LOCAL_VARIABLE: 지역 변수
      • METHOD: 메서드
      • PARAMETER: 전달 인자
      • TYPE_PARAMETER: 전달 인자 타입
      • TYPE_USE: 타입
    • @Retention: 해당 어노테이션의 생명주기를 설정
      • SOURCE: 컴파일 전까지 유효
      • CLASS: 컴파일러가 클래스를 참조할 때까지 유효
      • RUNTIME: 런타임 시기에도 JVM에 의해 참조가 가능(리플렉션)
    • @Documented: 해당 어노테이션을 JavaDoc에 포함시킨다
    • @Inherited: 어노테이션의 상속을 가능하도록 설정
    • @Repeatable: 해당 어노테이션을 연속적으로 선언할 수 있음, Java 8부터 지원
  2. 타입은 '@interface' 여야 한다
  3. 필드의 접근자는 public이거나 default여야 한다
  4. 필드에서 가능한 타입은 다음과 같다
    • (원시 타입) byte, short, char, int, float, double, boolean
    • (참조 타입) String
    • Enum
    • Class
    • Annotation

 

 

 

 

Sample

 

 

 

내가 Validation을 적용하기 위한 'EmailValidation' 어노테이션의 구조는 다음과 같다

  • @Email, @NotEmpty, @Size
    • Validation을 진행할 어노테이션
  • @Documented, @Target, @Retention
    • 문서화 여부, 적용 대상, 생명주기를 설정하는 메타 어노테이션
  • @Constraint
    • 커스텀 검증 어노테이션에서 검증 로직을 정의하는 역할. '검증 어노테이션'임을 선언하는 것이므로, 필수로 들어가야 한다
    • 'ConstraintValidator' 인터페이스를 구현한 클래스를 지정해야 한다
    • 만약 빈값 '{}' 을 지정했다면, @Constraint가 적용된 어노테이션들의 내부 검증 로직을 사용한다
      ex) @Email, @NotEmpty, @Size ...
  • message, groups, payload
    • 세 가지 필드는 커스텀 검증 어노테이션에서 표준 규약으로 사용되는 필드이다
    • message: 기본 검증 메시지를 정의하는 필드로, 없으면 검증 실패시 오류 메시지를 설정하지 못한다. 필수
    • groups: 검사를 수행할 그룹을 정의한다. 없다면 모든 검증이 동일한 그룹으로 처리되어 상황에 맞게 검증을 나눌 수 없다. 필수
    • payload: 검증 실패 시 추가적인 메타데이터를 전달할 때 사용하는 필드. 없다면 메타데이터를 활용할 수 없다. 선택사항이다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Reference

 

Spring Annotation의 원리와 Custom Annotation 만들어보기

‼️ Spring Annotation의 원리와 Custom Annotation 만들어보기

donghyeon.dev

 

[Java] 어노테이션 (+커스텀 어노테이션 만들기)

자바 어노테이션에 대한 간략한 이해와 커스텀 어노테이션 만들어서 사용하는 법을 araboza

velog.io