스프링부트 Enum 활용하기

10000DOO·2023년 3월 9일
1

YouHaveTo

목록 보기
7/12
post-thumbnail

프로젝트를 진행하면서 유저 등급, 게시글 카테고리, 예외 처리 문구 등등 상수값을 사용해야 되는 경우가 많이 있었습니다. 상수들을 테이블로 만들어 DB에 저장하고 FK로 연결하여 사용할 수 있는 방법이 있었지만 이런 방법은

1. 조회를 위해 매번 DB에 접근
2. 컴파일 불가능
3. 변경사항이 생기면 매번 DB 수정

위와 같은 문제점이 있습니다. 이러한 문제점을 해결하기 위해 Enum을 사용해보기로 했습니다.

📌 Enum 정의

Enum이란 Enumeration의 앞 글자로 열거라는 의미를 갖습니다. 관련이 있는 상수들의 집합입니다. 자바에서는 final로 String과 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값을 고정할 수 있습니다. 이렇게 고정된 값을 상수라고 합니다. 영어로는 constant입니다. 어떤 클래스가 상수만으로 작성되어 있으면 반드시 class로 선언할 필요는 없습니다. 이럴 때 class로 선언된 부분에 enum이라고 선언하면 이 객체는 상수의 집합이다. 라는 것을 명시적으로 나타냅니다.

📌 특징

1. 상수로 사용할 수 있다.

생성자는 private로 작성해야됩니다. Default 생성자 또한 private입니다.
사용하기 위해서는 BodyPart.Back 이런 식으로 작성해야됩니다.

public enum BodyPart {
    BACK, CHEST
}

2. 메서드를 정의할 수 있다.

enum 클래스는 상수와 함께 메서드를 정의할 수 있습니다. 이 메서드는 enum 상수와 관련된 동작을 수행하거나, enum 상수를 이용한 값을 반환할 수 있습니다.
BodyPart.BACK.getMessage() -> "등" 이러한 형식으로 사용할 수 있습니다.

@Getter
public enum BodyPart {
    BACK("등"),
    CHEST("가슴"),

    private final String message;

    BodyPart(String message) {
        this.message = message;
    }
}

3. 싱글톤 패턴.

enum 클래스는 싱글톤 패턴을 구현하는 데 사용됩니다. 이는 enum 클래스 내에서 정의된 상수가 애플리케이션 전체에서 단 하나의 인스턴스만 존재함을 보장하기 때문입니다.

📌 내부 API

values()

'values()' 메서드는 enum 클래스의 모든 상수를 배열 형태로 반환합니다.

BodyPart[] bodyParts = BodyPart.values();

valueOf()

'valueOf()' 메서드는 문자열로 표현된 상수 이름을 이용하여, 해당 상수의 참조(인스턴스)를 반환합니다. 만약 해당하는 상수가 없을 경우 IllegalArgumentException이 발생합니다.

BodyPart bodyPart = BodyPart.valueOf("BACK");

name()

'name()' 메서드는 상수의 이름을 문자열 형태로 반환합니다.

String name = BodyPart.BACK.name(); // "BACK"

ordinal()

'ordinal()' 메서드는 상수의 순서를 반환합니다. 첫 번째 상수는 0부터 시작합니다.

int ordinal = BodyPart.BACK.ordinal(); // 0

compareTo()

'compareTo()' 메서드는 해당 enum 상수와 다른 enum 상수를 비교합니다. 비교 결과는 순서에 따라 -1, 0, 1 중 하나의 값을 반환합니다.

int result = BodyPart.BACK.compareTo(BodyPart.CHEST); // -1

equals()

'equals()' 메서드는 해당 enum 상수와 다른 객체를 비교합니다. 비교 결과는 boolean 형태로 반환합니다.

boolean isEqual = BodyPart.BACK.equals(BodyPart.CHEST); // false

📌 사용 방법

📍 사용법1

아래와 같은 Enum 클래스가 있습니다.

public enum PostType {
    Q_AND_A, KNOWLEDGE, SHOW_OFF, COMPETITION, FREE
}

public enum WorkOutCategory {
    HEALTH, PILATES, YOGA, JOGGING, ETC
}

아래 보이는 것은 Enum을 사용해서 HTTP요청을 보내고 조건에 해당하는 게시글을 조회하는 것입니다.

Http요청 : http://localhost:8080/post?woryOutCategory=HEALTH,YOGA&username=10000DOO&page=0&size=2

@Data
public class PostListDto {

    private String username;
    private PostType postType;
    private WorkOutCategory workOutCategory;
    private String createdAt;
    private String title;
    private Long postId;
    private int mediaListCount;
    private int likeCount;
    private Long views;
    private Long commentCount;

    @Builder
    public PostListDto(String username, PostType postType, WorkOutCategory workOutCategory, String createdAt,
                       String title, int mediaListCount, int likeCount, Long views, Long commentCount, Long postId) {
        this.username = username;
        this.postType = postType;
        this.workOutCategory = workOutCategory;
        this.createdAt = createdAt;
        this.title = title;
        this.mediaListCount = mediaListCount;
        this.likeCount = likeCount;
        this.views = views;
        this.commentCount = commentCount;
        this.postId = postId;
    }
}

위의 코드는 DTO로 사용되는 클래스라 사용되지 않지만 Entity에서 사용되는 @Enumerated는 자바의 Enum타입을 Entity의 속성으로 사용할 수 있게 해줍니다.
EnumTpye에는 두가지가 존재합니다.
EnumType.ORDINAL : enum 순서 값을 DB에 저장
EnumType.STRING : enum 이름을 DB에 저장

{
    "status": 200,
    "data": {
        "postListDto": [
            {
                "username": "10000DOO",
                "postType": "SHOW_OFF",
                "workOutCategory": "HEALTH",
                "createdAt": "4일 전",
                "title": "테스트 게시글 입니다.",
                "postId": 1,
                "mediaListCount": 0,
                "likeCount": 0,
                "views": 5,
                "commentCount": null
            }
        ],
        "hasNext": false,
        "isFirst": true
    }
}

사용법1을 사용하여 상수를 Enum으로 사용했습니다.


📍 사용법2

아래 코드처럼 Enum 클래스를 작성할 수 있습니다.

@Getter
public enum ErrorCode {
   NOT_FOUND_LOGIN_ID("이미 존재하는 아이디입니다."),
   NOT_FOUND_EMAIL("이미 존재하는 이메일입니다."),
   NOT_FOUND_USERNAME("이미 존재하는 이름입니다."),
   BAD_CREDENTIALS_EXCEPTION("비밀번호가 틀렸습니다. 다시 시도해주세요."),
   INTERNAL_AUTHENTICATION_SERVICE_EXCEPTION("아이디가 틀렸습니다. 다시 시도해주세요."),
   AUTHENTICATION_EXCEPTION("로그인 실패입니다. 다시 시도해주세요."),
   NOT_FOUND_EXCEPTION_DIARY("존재하지 않는 다이어리입니다."),
   NOT_FOUND_EXCEPTION_POST("존재하지 않는 게시글입니다."),
   NOT_FOUND_EXCEPTION_MEDIA("존재하지 않는 미디어입니다."),
   NOT_FOUND_EXCEPTION_MEMBER("존재하지 않는 유저입니다."),
   NOT_FOUND_EXCEPTION_COMMENT("존재하지 않는 댓글입니다."),
   IO_FAIL_EXCEOPTION("파일 I/O 서버 오류입니다."),
   WRONG_CONTENT_TYPE("잘못된 Content-Type입니다."),
   NOT_EXIST_SAME_POST_IN_PARENT_AND_CHILD_COMMENT("원댓글과 같은 게시글에 존재하지 않습니다."),
   WRONG_TOKEN("잘못된 토큰입니다. 토큰 재발급이 불가능하니 다시 로그인 부탁드립니다."),
   NO_EXIST_TOKEN("존재하지 않는 토큰입니다. 토큰 재발급이 불가능하니 다시 로그인 부탁드립니다."),
   EXPIRED_TOKEN("토큰이 만료 되었습니다. 다시 로그인 해주세요."),
   NOT_LIKE_PRESSED("좋아요 정보가 없습니다."),
   ALREADY_PRESSED("이미 좋아요를 누르셨습니다."),
   DATE_FORMAT_EXCEPTION("날짜 형식 변환에 실패하였습니다."),
   NO_MATCHED_POST_TYPE("잘못된 게시글 타입입니다."),
   NO_MATCHED_EXERCISE_CATEGORY("잘못된 운동 카테고리입니다.");
   private final String message;

   ErrorCode(String message) {
       this.message = message;
   }
}

@Getter를 사용해서 각 인스턴스의 message 값을 가져와 사용할 수 있습니다.

Member findMember = memberRepository.findByUsername(SecurityUtil.getCurrentUsername())
                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.NOT_FOUND_EXCEPTION_MEMBER.getMessage()));

 Post findPost = postRepository.findNotDeletedById(writeCommentDto.getPostId())
                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.NOT_FOUND_EXCEPTION_POST.getMessage()));

프로젝트에서는 위와 같이 예외처리에서 에러메시지를 넣어주는데 사용했습니다.

//결과
{
    "status": 400,
    "error": "존재하지 않는 게시글입니다."
}
{
    "status": 400,
    "error": "존재하지 않는 유저입니다."
}

📌 좋았던 점

1. 상수를 문자열로 사용하는 것보다 관리가 편리합니다.
다른 곳에서 사용할 때 자동완성 가능, Enum 클래스에서만 변경하면 전부 반영, 컴파일 에러로 잘못된 점 확인 가능
2. 사용할 값을 제한할 수 있습니다.
3. 여러 클래스에서 재사용하기 쉽습니다.

📚 참고 자료

https://velog.io/@kyle/자바-Enum-기본-및-활용
https://velog.io/@yrc97/Spring-Java-Enum-활용하기-Enum-Code-API
https://lng1982.tistory.com/280
https://quantum-jumpin.tistory.com/18

profile
iOS 개발자 지망생 https://github.com/10000DOO

0개의 댓글