DB-> Entity, Entity->DB 자동 변환 (@Convert)
현재 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