SpringBoot

DB-> Entity, Entity->DB 자동 변환 (@Convert)

se0nghyun2 2023. 5. 14. 12:02

현재 DB에는 도서의 상태를 나타내는 같이 state 컬럼이 있습니다.

 

각 상태값과 그에 대한 설명은 아래와 같습니다.

  • 0 - 대출 가능
  • 1 - 대출 불가

 

Book엔티티

엔티티 조회 시 상태 값 그대로( 0,1 ) 로 조회됩니다.

문제 1) 모르는 사람이 봤을 땐 이 상태값이 어떤 의미를 알기가 어려웠습니다.

문제 2) 앞단으로 응답하는 ResponseDTO엔 상태값이 아닌 상태에 대한 설명 이 매핑되어 응답되길 원했습니다.

 

목표

1. 앞단 ResponseDTO에는 상태값이 아닌 상태설명 을 매핑
2. 모르는 이가 봐도 어떤 값인지 명확한 표현
3. 상태 추가 시 OCP 원칙 준수 

 

 

BookSate 

책상태를 나타내는 BookSate Enum클래스 생성

@Getter
public enum BookState {
    RENTING_AVAILABLE("0","대출 가능"),
    RENTING_NOT_AVAILABLE("1","대출 불가");

    private String state;
    private String desc;

    BookState(String state,String desc) {
        this.state=state;
        this.desc = desc;
    }

}

 

 

리팩토링 전)

Enum클래스에 상태값을 상태설명으로 변환하는 메소드(convertStateToDesc)를 선언하였습니다.

Entity -> ResponseDto 변환할 때 해당 메소드를 통해 상태 설명으로 변환하여 매핑되도록 구현했었습니다.

 

BookState 

public static String convertStateToDesc(String state){
        if(state == "1"){
            BookState state = BookState.RENTING_NOT_AVAILABLE;
            return state.getDesc();
        } else{
            BookState state = BookState.RENTING_AVAILABLE;
            return state.getDesc();
      }
}

그런데 문제가 보입니다.

만약 상태값이 추가된다면??????

  • 2 - 대출불가(도서 예약중)

아래처럼 if/else문을 추가하여 OCP 위배한 채 수정해야 합니다.

public static String convertStateToDesc(String state){
        if(state.equals("0")){
            BookState state = BookState.RENTING_NOT_AVAILABLE_BY_LOAN;
            return state.getDesc();
        } else if(state.equals("1")){
            BookState state = BookState.RENTING_AVAILABLE;
            return state.getDesc();
        }else{
        	BookState state = BookState.RENTING_NOT_AVAILABLE_BY_RESERVATION;
            return state.getDesc();
        }
}

 


 

따라서 이 방식은 사용하지 않고 어떻게 해결할지  고민하던 중 @Convert 어노테이션을 알게 되었습니다.

참고) https://techblog.woowahan.com/2600/

 

 

리팩토링)

Book엔티티

필드의 타입을 Enum클래스 타입으로 정의하며, @Convert 내 BookStateConvert를 인자로 줍니다.

 

 

BookState

public static BookState ofBookState(String state){
    return Arrays.stream(BookState.values())
            .filter(v->v.getState().equals(state))
            .findAny()
            .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 상태값 입니다." + state ));
}

전달받은 DB상 데이터(state)를 Bookstate로 변환하는 메소드

 

 

BookStateConverter

public class BookStateConverter implements AttributeConverter<BookState,String> {

    //ENUM -> DB데이터 변환 (ex: "대출 불가"->"0")
    @Override
    public String convertToDatabaseColumn(BookState attribute) {
        return attribute.getState();
    }

    //DB데이터 -> ENUM으로 변환 (ex: "0"->"대출 불가")
    @Override
    public BookState convertToEntityAttribute(String dbData) {
        return BookState.ofBookState(dbData);
    }
}

위를 통하여

  •  DB  -> 엔티티 = String -> Enum 변환
  •  엔티티 -> DB = Enum -> String 변환 

그리고 새로운 상태값 추가 시 아래처럼 해당 상태값에 대하여 추가만 하면 됩니다.

public enum BookState {
    RENTING_AVAILABLE("0","대출 가능"),
    RENTING_NOT_AVAILABLE("1","대출 불가(대여중)"),
    RENTING_NOT_AVAILABLE("2","대출 불가(예약)");

 

SearchBookResponseDTO

@Getter
public class SearchBookResponseDTO {
    private BookId bookId;
	...
    private String state;




    public SearchBookResponse(Book entity){
        this.bookId= entity.getBookId();
        ...
        this.state = entity.getState().getDesc();
    }

}

 

결과

 

목표 달성

1. 앞단 ResponseDTO에는 상태값이 아닌 상태설명 을 매핑 -> @Convert 로 개선
2. 모르는 이가 봐도 어떤 값인지 명확한 표현 ->Enum클래스 로 개선
3. 상태 추가 시 OCP 유지 -> @Convert 로 개선

 

 


참고)

https://techblog.woowahan.com/2527/

 

Java Enum 활용기 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한 형제들에서 결제/정산 시스템을 개발하고 있는 이동욱입니다. 이번 사내 블로그 포스팅 주제로 저는 Java Enum 활용 경험을 선택하였습니다. 이전에 개인 블로그에 E

techblog.woowahan.com