๊ฐ์ฒด ๊ฐ ๋งคํ์ ์ํ MapStruct ์ฌ์ฉ ๋ฐฉ๋ฒ
๊ธฐ์กด ํ๋ก์ ํธ์์ Dto Entity๋ฅผ ๋งคํํ ๋ model mapper ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์๋ค.
ํธํ๊ฒ ์ฌ์ฉํ ์ ์์์ง๋ง
๋ด๋ถ์ ์ผ๋ก ๋ฆฌํ๋ ์ ์ ์ด์ฉํ๊ธฐ ๋๋ฌธ์, ์ฑ๋ฅ ์ ๋ฌธ์ ๊ฐ ์๋ค.
์ด๋ฒ์๋ ๋ง์ด๋ค ์ถ์ฒํ๋ Map Struct๋ฅผ ์ฌ์ฉํด๋ดค๋ค.
์ ์ฉํ๋ฉด์ ์์ํ ๋ฌธ์ ๋ค์ด ์์๋๋ฐ, ๋ด๊ฐ ๊ฒช์ ๋ฌธ์ ์ ๋ค์ ๋ํ ํด๊ฒฐ ๋ฐฉ๋ฒ๋ค์ ์ ๋ฆฌํด๋ณด๊ฒ ๋ค.
https://mapstruct.org/documentation/dev/reference/html/
MapStruct 1.5.2.Final Reference Guide
If set to true, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, also showWarnings needs to be added due to a problem in the maven-compiler-plugin configuration.
mapstruct.org
=> ์์ ๋งํ๋ฉด Map Struct ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ฉด ๋๋ถ๋ถ์ ์ ์๊ฐ ์๋ค.
์์กด์ฑ ์ถ๊ฐ
implementation "org.mapstruct:mapstruct:1.5.2.Final"
compileOnly 'org.projectlombok:lombok'
annotationProcessor "org.mapstruct:mapstruct-processor:1.5.2.Final"
annotationProcessor 'org.projectlombok:lombok', "org.projectlombok:lombok-mapstruct-binding:0.2.0"
๋กฌ๋ณต๊ณผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ์ถฉ๋์ด ๋๋ค๊ณ ๋ ํ์ง๋ง, ์ต์ ๋ฒ์ ์์๋ ๊ทธ๋ฐ๊ฒ ์๋ค๊ณ ํ๋ค.
์ถฉ๋์ ํผํ๋ ค๋ฉด ๋กฌ๋ณต ์ ์ ์ถ๊ฐํ๋ฉด ๋๋ค.
Generic Mapper ์์ฑ
public interface GenericDtoMapper<D, E> {
D toDTO(E e);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateFromVO(D dto, @MappingTarget E entity);
}
public interface GenericEntityMapper<D, E> {
E toEntity(D d);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateFromVO(D dto, @MappingTarget E entity);
}
=> ๋จผ์ Entity ๋งคํผ์ Dto ๋งคํผ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ๋ค. ๋ชจ๋ ํ์ ์ ๋ฐ๊ธฐ ์ํด Generic์ ์ ์ฉ์์ผฐ๋ค.
@Mapper(componentModel = "spring")
public interface UserJoinMapper extends GenericEntityMapper<JoinRequestDto, User> {
}
=> @Mapper ์ ๋ ธํ ์ด์ ์ ํตํด MapStruct๊ฐ ๊ตฌ์ฒดํํ ๋งคํผ๋ฅผ ์ ์ํ๋ค.
=> ์ด๋ฐ ์์ผ๋ก ํ์ฅํด ๊ตฌ์ฒดํํ๋ฉด ๋๋ค.
=> componentModel ์ด๋ผ๋ ์ ๋ ธํ ์ด์ ์์ฑ์ ํตํด Spring Bean์ผ๋ก ๋ฑ๋กํด์ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
๋ฌธ์ ์
=> ์ผ๋ฐ์ ์ธ ํ๋๋ค์ ์ด๋ฆ์ด ๊ฐ๊ฑฐ๋ ํ๋ ค๋ @Mapping ์ ๋ ธํ ์ด์ ์ด๋ @ValueMapping์ผ๋ก ๊ฐ๋ฅํ๋ฐ,
์ฐธ์กฐ ํ์ ์ ํ๋๋ ๋งคํ์ ์ข ๋ ์ ๊ฒฝ์ ์จ์ค์ผ ํ๋ค.
@Mapping(target = "userId", source = "id")
@Override
DetailResponseDto toDTO(User user);
๊ฐ ๊ฐ์ฒด์ ํ๋ ์ด๋ฆ์ด ํ๋ฆด ๋ ๋งคํ ์ ๋ ธํ ์ด์ ํ์ฉ
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class DetailResponseDto {
private Long id;
private String name;
private String categoryName;
private Integer price;
private Integer quantity;
private String content;
@Setter
private String image;
}
๋งคํํ DTO
@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Product extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@JsonBackReference
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
private Integer price;
private Integer quantity;
private String content;
private String image;
@Enumerated(EnumType.STRING)
@Column(name = "product_status", nullable = false)
private ChickenStatus status;
๋งคํํ Entity
@Mapper(componentModel = "spring")
public interface ItemDetailMapper extends GenericDtoMapper<DetailResponseDto, Product> {
@Mapping(target = "categoryName", source = "product.category.categoryName.chickenName")
@Override
DetailResponseDto toDTO(Product product);
}
๋งคํ ์ธํฐํ์ด์ค ์ ์
์นดํ ๊ณ ๋ฆฌ๋ Enum ํ์ ์ด๊ธฐ ๋๋ฌธ์, DTO ๋งคํ ์ String์ผ๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค.
์์ค ๊ฐ์ฒด์ธ Product ์ํฐํฐ์ ํ์ ํ๋๋ค์. ์ฐ์ฐ์๋ฅผ ํ์ฉํด ์ง์ ์ ์ผ๋ก ๋งคํํ๋ค.
๋๋ต์ ์ผ๋ก ๋งคํ์ ๋ํ ๋ฌธ์ ๋ค์ ์ด๋ ๊ฒ ํด๊ฒฐํ ์ ์๋ค.