JPA @Convert를 이용하여 Entity와 DB간 형변환

ChangSol·2024년 3월 28일

간혹가다 개발 시 객체의 타입과 DB의 타입을 다르게해야 하는 경우가 발생한다.

필자는 아래와 상황에 봉착했었다.

고객의 생년월일을 암호화 X -> 암호화 O 로 변경해야 하는 상황
객체의 타입을 수정해야 되나라는 생각이었지만, 좀 더 좋은 방법이 없을까 하다가 전에 사용했던 Convert 방식이 생각이 났다.

따라서 Convert 방식 하나로 손쉽게 Entity <-> DB 를 변환할 수 있다.
다만 형변환 리소스가 증가하는 부분이니 꼭 필요한 경우에만 사용하길 권장한다.

기존 Entity는 다음과 같이 심플하게 진행을 했었다.

[기존]

@Getter
@MappedSuperclass
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SuperBuilder
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseUser extends BaseDomainWithId {
	...

	/**
	 * 고객 생년월일
	 */
	@Comment("고객 생년월일")
	private LocalDate birth;
}
2024-03-28 14:01:59.129 DEBUG 25620 --- [nio-8080-exec-5] org.hibernate.SQL                        : 
    insert 
    into
        USERS
        (BIRTH, ...) 
    values
        (?, ...)
2024-03-28 14:01:59.129 TRACE 25620 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [DATE] - [2024-03-28]
...

[변경]

Entity에 @Convert를 이용하기 위해서 AttributeConverter Interface를 상속받은 Converter Class를 생성한다.

  1. @Converter annotation
  2. AttributeConverter<객체타입, 디비타입> implements
@Converter
@Component // 암호화 컴포넌트 사용을 위한 Bean 처리
@RequiredArgsConstructor
public class LocalDateSecurityAttributeConverter implements AttributeConverter<LocalDate, String> {

	private final DamoComponent damoComponent;

	@Override
	public String convertToDatabaseColumn(LocalDate attribute) {
		if (attribute == null) {
			return null;
		} else {
			// 암호화 처리
			return damoComponent.encrypt(attribute.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
		}
	}

	@Override
	public LocalDate convertToEntityAttribute(String dbData) {
		if (dbData == null) {
			return null;
		} else {
			// 복호화 처리
			return LocalDate.parse(damoComponent.decrypt(dbData), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		}
	}
}

위 Converter는 DB 삽입 시 암호화 컴포넌트로 암호화를 하여 String으로 형변환되어 삽입되며, DB 조회 시 암호화 컴포넌트로 복호화를 하여 LocalDate로 형변환 되는 컨버터이다.

이제 Entity에 컨버터를 적용하도록 변경한다.

@Getter
@MappedSuperclass
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SuperBuilder
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseUser extends BaseDomainWithId {
	...

	/**
	 * 고객 생년월일
	 */
	@Comment("고객 생년월일")
	@Convert(converter = LocalDateSecurityAttributeConverter.class)
	@Column(columnDefinition = "CHAR(24)")
	private LocalDate birth;
}
2024-03-28 14:22:43.271 DEBUG 2036 --- [nio-8080-exec-6] org.hibernate.SQL                        : 
    insert 
    into
        USER_CI
        (BIRTH, ...) 
    values
        (?, ...)
2024-03-28 14:22:43.272 TRACE 2036 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [gwKRRTXS9DOsUPiEsaYQdA==]
...

이제 DB는 암호화가 잘 되어서 들어가고 조회 시 컨버터를 통하여 복호화를 하여 암/복호화가 지저분한 소스 없이 어노테이션으로 깔끔하게 진행되는 것을 볼 수 있다.

해당 부분은 권장사항이 아니며, 무조건 Entity<->DB 간 형변환이 일어나야하는 경우만 추천한다.

profile
Back-End Developer

0개의 댓글