배경
프로젝트를 진행하면서 인스타그램의 Feed와 같은 기능을 구현중이었다. Feed에는 여러 장의 Image를 업로드할 수 있다. MultiPartFile로 전달 받은 Image들은 S3에 저장된 후 S3에 저장된 url을 String 값으로 반환한다.
이 ImageUrl들은 별도로 커스텀할 일이 없기 때문에 Entity로 만들 필요를 못느꼈다. 그래서 여러 개의 imageUrl을 하나의 컬럼에 저장할 수 있는 방법에 대해 알아보았고 Converter를 사용하는 방법을 알게되어서 정리한다.
구현
AttributeConverter는 JPA(Java Persistence API)에서 엔티티 클래스와 테이블 간 데이터 변환을 도와주는 인터페이스다.
JPA에서는 엔티티 클래스의 필드와 데이터베이스 테이블의 컬럼 간의 자료형이 일치하지 않는 경우가 종종 있다.
이런 경우에는 필드와 컬럼 간의 데이터 타입을 변환해주어야 하는데, 이때 AttributeConverter를 사용할 수 있다.
AttributeConverter는 다음 두 개의 메서드를 가지고 있다.
- public Y convertToDatabaseColumn(X attribute): 엔티티 필드에서 데이터베이스 컬럼으로 데이터를 변환한다.
- public X convertToEntityAttribute(Y dbData): 데이터베이스 컬럼에서 엔티티 필드로 데이터를 변환한다.
StringListConverter
StringListConverter 클래스는 AttributeConverter 인터페이스를 구현해서, 문자열로 된 리스트를 데이터베이스 컬럼에 저장하기 위한 문자열로 변환하거나, 데이터베이스에서 읽어온 문자열을 리스트로 변환하도록 했다.
ObjectMapper는 Jackson 라이브러리에서 제공하는 클래스로, JSON 데이터와 Java 객체 사이의 변환을 담당한다. 이 코드에서는 ObjectMapper를 이용하여 List을 문자열로, 문자열을 List로 변환할 수 있다.
@Slf4j
public class StringListConverter implements AttributeConverter<List<String>, String> {
private static final ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
// DB에 저장 될 때 사용
@Override
public String convertToDatabaseColumn(List<String> attribute) {
try {
return mapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
log.debug("StringListConverter.convertToDatabaseColumn exception occur attribute: {}", attribute.toString());
throw new BusinessLogicException(ExceptionCode.UNABLE_TO_CONVERT_LIST_TO_STRING);
}
}
// DB의 데이터를 Object로 매핑할 때 사용
@Override
public List<String> convertToEntityAttribute(String dbData) {
try {
return mapper.readValue(dbData, List.class);
} catch (IOException e) {
log.debug("StringListConverter.convertToEntityAttribute exception occur dbData: {}", dbData);
throw new BusinessLogicException(ExceptionCode.UNABLE_TO_CONVERT_STRING_TO_LIST);
}
}
}
DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES 옵션은 ObjectMapper가 JSON 데이터를 Java 객체로 역직렬화할 때, JSON 데이터에 존재하지 않는 속성이 Java 객체에 정의된 경우 무시하고 객체를 생성할 수 있도록 해준다.
DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES 옵션은 ObjectMapper가 JSON 데이터를 Java 객체로 역직렬화할 때, JSON 데이터에 null 값이 포함된 기본형(primitive type) 필드에 대해서 예외를 발생시키지 않도록 하는 옵션이다. 옵션을 false로 설정하면 null 값으로 들어온 필드는 0, false 등의 기본값을 사용한다.
convertToDatabaseColumn 메서드는 JPA에서 DB에 저장하기 전에 List을 문자열로 변환해주고,
convertToEntityAttribute 메서드는 DB에서 읽어온 문자열을 다시 List 형태로 변환해준다.
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Feed extends BaseTimeEntity {
...
@Convert(converter = StringListConverter.class)
private List<String> imageUrls = new ArrayList<>();
...
}
}
'JPA' 카테고리의 다른 글
JPA - 연관 관계를 위한 불필요한 select 줄이기(getReferenceById()) (0) | 2024.11.18 |
---|---|
Querydsl - Expressions클래스로 select에서 상수 사용하는 법 (1) | 2024.11.14 |
Spring Data JPA - 외래키(Foreign Key)를 복합 기본키(Composite Primary Key)로 사용하기 (1) | 2024.11.08 |
JPA - Querydsl를 사용해 DTO 받는 방법 (0) | 2023.03.02 |
Spring Data JPA - Auditing으로 생성일, 수정일 자동화하는 법 (0) | 2022.12.02 |