์• ์ •์ฝ”๋”ฉ ๐Ÿ’ป

WEB/JAVA 2022.03.16 ๋Œ“๊ธ€ 0๊ฐœ Joana

[MapStruct] ๋‚ด๊ฐ€ ์ฐพ์•„ ์“ฐ๋ ค๊ณ  ์ •๋ฆฌํ•œ ๊ธ€

 

๐Ÿƒ‍โ™‚๏ธ ๊ณ„์†ํ•ด์„œ ์—…๋ฐ์ดํŠธ ํ•˜๊ธฐ ๐Ÿƒ‍โ™‚๏ธ

 

1. ๊ณต์‹๋ฌธ์„œ

2. ์™œ ์‚ฌ์šฉํ• ๊นŒ?

3. ๋™์ž‘๋ฐฉ์‹

4. ์˜์กด์„ฑ

5. Mapper Inteface ์ž‘์„ฑ

6. Mapper ๊ตฌํ˜„์ฒด ์‚ดํŽด๋ณด๊ธฐ

 

 

 

 

๊ณต์‹๋ฌธ์„œ

 

https://mapstruct.org/documentation/stable/reference/pdf/mapstruct-reference-guide.pdf

 

 

 

MapStruct ์™œ ์‚ฌ์šฉํ• ๊นŒ?

 

๋ณดํ†ต DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์„œ๋น„์Šค๋‹จ์—์„œ ๋กœ์ง์„ ์„ค๊ณ„ ํ•˜๊ธฐ ์œ„ํ•ด Entity -> Dto , Dto -> Entity ์ž‘์—…์„ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด๋Ÿฌํ•œ Mapping ์ž‘์—…์„ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งŽ์ด ์กด์žฌํ•œ๋‹ค ๊ทธ์ค‘ ์•„๋ž˜์˜ ๋งํฌ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด MapStruct ํผํฌ๋จผ์Šค๊ฐ€ ๋น ๋ฅธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

https://www.baeldung.com/java-performance-mapping-frameworks

 

 

๋™์ž‘๋ฐฉ์‹

 

์‚ฌ์šฉ์ž๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์„ ์ƒ์„ฑํ•˜๊ณ  ๋งตํ•‘ ๊ด€๋ จ ์„ค์ •์„ ํ•ด์ฃผ๋ฉด ์ปดํŒŒ์ผํ•˜๋Š”๋™์•ˆ MapStruct๊ฐ€ ๋‚ด๋ถ€ ๊ตฌํ˜„์ฒด์—์„œ setter๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ๋งตํ•‘ํ•œ๋‹ค.

 

 

์˜์กด์„ฑ

 

Maven

...
<properties>
    <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
</properties>
...
<dependencies>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>${org.mapstruct.version}</version>
    </dependency>
</dependencies>
...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source> <!-- depending on your project -->
                <target>1.8</target> <!-- depending on your project -->
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>${org.mapstruct.version}</version>
                    </path>
                    <!-- other annotation processors -->
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

 

Gradle

dependencies {
    ...
    implementation 'org.mapstruct:mapstruct:1.4.2.Final'
 
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}

 

 Mapper Inteface ์ž‘์„ฑ

public class OrderDto{
    private int itemCount;
    private ItemStatus itemStatus;
    private Brand brand;
}
public class Orders{
    private long id;
    private ItemList itemList;
    private Brand brand;
}
public class Brand{
    private Long id;
    private String name;
    private Stirng tel;
}
@Mapper(uses = {BrandMapper.class})
public interface OrderMapper {

  OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);
 
  @Mapping(target = "brand", source = "brand")
  @Mapping(target = "itemCount", source = "itemList", qualifiedByName = "itemCount")
  @Mapping(target = "itemStatus", source = "itemList.status")
  OrderDto toDto(Orders orders);

  List<OrderDto> toListDto(List<Orders> orders);
  
  @Named("itemCount")
  default int itemCount(List<ItemList> itemList){
  return (int) itemList.stream()
  			.map(itemList::getItemId)
  			.distinct()
  			.count();
  }


}

 

 

Orders Entity -> OrderDto ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ์ž‘์—…์ด๋‹ค 

 

@Mapper(uses = {BrandMapper.class})

- OrderDto ์•ˆ์— Brand ํ•„๋“œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— BrandMapper ๋„ ๋งŒ๋“ค์–ด์ค€ ๋‹ค์Œ์— ํฌํ•จ์‹œ์ผœ์ค˜์•ผํ•œ๋‹ค.

๋ฐ‘์— ๊ตฌํ˜„์ฒด ์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์„ค๋ช…ํ•˜๊ฒ ์Œ

 

- Orders ์— id ์™€ OrderDto ์— id ๋Š” ํ•„๋“œ๋ช…์ด ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ @Mapping ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ๋งตํ•‘๋œ๋‹ค.

๊ทธ ์™ธ์— ํ•„์š”ํ•œ ํ•„๋“œ๋Š” @Mapping์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค

 

- Dto์— ์žˆ๋Š” ItemStatus ๋Š” Orders์˜ itemList์˜ status๋กœ ๋งตํ•‘ํ•œ๋‹ค.

 

@Mapping(target = "itemCount", source = "itemList", qualifiedByName = "itemCount")
@Named("itemCount")

- Dto๋กœ ๋ณ€ํ™˜์ค‘์— ๊ณ„์‚ฐ์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ ๋”ฐ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ๋นผ์ค๋‹ˆ๋‹ค -> ๊ตฌํ˜„์ฒด ์ƒ์„ฑ์‹œ ์ œ์™ธํ•˜๊ณ  ์ƒ์„ฑํ•จ. ํ•ด๋‹น ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

 

 

Mapper ๊ตฌํ˜„์ฒด ์‚ดํŽด๋ณด๊ธฐ

 

์–ด๋–ค์‹์œผ๋กœ ์ž‘์„ฑํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ฐพ์•„๊ฐ€๋ณด๋ฉด ๋œ๋‹ค. ์˜ˆ์‹œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค

(Interface ์ž‘์„ฑ ํ›„ target/generated-sources-annotaions ๋ฅผ rebuild ํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค) 

๋‚˜๋Š” ๊ธฐ๋ณธ์ƒ์„ฑ์ž, Setter ๊ฐ€ ์•„๋‹Œ Builder ๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์–ด์žˆ๋‹ค.

public class OrderMapperImpl implements OrderMapper {

    private final BrandMapper brandMapper = Mappers.getMapper( BrandMapper.class );

	@Override
    public OrderDto toDto(Orders orders) {
        if ( orders == null ) {
            return null;
        }

        OrderDtoBuilder orderDto = OrderDto.builder();

        orderDto.brand( brandMapper.toDto( brandMapper.toDto(orders) ) );
        orderDto.itemCount( itemCount( orders.getItemList() ) );
        orderDto.status( itemStatus( orders ) );
        
        
    private ItemStatus itemStatus(Orders orders) {
        if ( orders == null ) {
            return null;
        }
        ItemList itemList = orders.getItemList();
        if ( itemList == null ) {
            return null;
        }
        ItemStatus itemStatus = goodsReceipt.getItemStatus();
        if ( itemStatus == null ) {
            return null;
        }
        return itemStatus;
    }
    

        return orderDto.build();
        }
 }

 

 

 

 

 

๋ฐ˜์‘ํ˜•