Spring

MapStruct 란?

728x90

Mapstruct 란 클래스간 변환을 쉽게 하기 위해 등장한 라이브러리다

 

 

- DTO, Entity

: DTO 란 Data Transfer Object 를 말하며, 계층간 데이터 전송을 위해 만든 Bean 을 의미한다

Entity 란 DB 의 테이블과 매핑시키기 위한 자바 객체를 의미한다

 

Entity 에 정의해둔 필드변수 외에도 별도로 어떤 값을 유저로 부터 받아와야 한다거나 혹은 Entity 에는 없는 필드를 리턴시켜줘야 할때, DTO 를 이용하는데, 이런 작업을 가능하게하려면, Entity 와 DTO 간에 매핑과정이 필요하다

 

 

- maven 을 이용하는 경우

: maven 을 이용하는 경우 의존성 주입을 다음과 같이 해줘야 한다

 

pom.xml

    <dependencies>
 
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
 
        <!-- mapstruct -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok-mapstruct-binding</artifactId>
            <version>0.2.0</version>
        </dependency>
 
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>0.2.0</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
cs

위와 같이 lombok 과 같이 쓰는 경우 mapstruct 라이브러리와 같이 연동하려면, <build> 부분에 lombok-mapstruct-binding 을 넣어줘야 한다.

 

 

 

- 예제

: 예를들어, 어떤 커뮤니티 사이트를 만든다고 가정하고, 작성할 글의 카테고리 관련한 API 를 만든다고 했을때, Entity 와 DTO 를 다음과 같이 구성했다고 하자

 

- Entity

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Category {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
 
    @NotBlank(message = "Category name is required !")
    private String name;
 
    @NotBlank(message = "Description is required !")
    private String description;
 
    @OneToMany(fetch = FetchType.LAZY)
    private List<Post> posts;
 
    private Instant createdDate;
 
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}
 
cs

 

- DTO

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CategoryDto {
    private Long id;
    private String name;
    private String description;
    private Integer postCount;
}
cs

 

Entity 클래스엔, 필드 변수가 id, name, description, posts, createdDate, user 가 있지만,

DTO 클래스에는, id, name, description, postCount 로 구성되어 있다

 

두 클래스의 필드 변수가 서로 일치하지 않으므로, mapper 인터페이스를 선언해야 한다

 

- mapper interface

@Mapper(componentModel = "spring")
public interface CategoryMapper {
 
    @Mapping(target = "postCount", expression = "java(mapPosts(category.getPosts()))")
    CategoryDto mapCategoryToDto(Category category);
 
    default Integer mapPosts(List<Post> postCount) {
        return postCount.size();
    }
 
    @InheritInverseConfiguration
    @Mapping(target = "posts", ignore = true)
    @Mapping(target = "createdDate", expression = "java(java.time.Instant.now())")
    Category mapDtoToCategory(CategoryDto categoryDto);
}
cs

 

첫번째 메소드인 mapCategoryToDto 는 엔티티 클래스를 입력 받아서 DTO 로 변환시키는 작업을 하고

두번째 메소드는 그 반대로 DTO 를 엔티티로 변환시키는 역할을 맡고 있다

 

각 필드를 매핑시킬때는, @Mapping 어노테이션을 쓰고, target 은 매핑될 타겟 클래스의 타겟 필드 변수이름을 말하고

expression 은 어떤 값으로 넣을지에 대한 자바 구문을 넣는 속성값을 의미한다

그리고 여기엔 나와있지 않지만, source 라는 것도 있으며, target 과 매핑될 소스 객체의 소스 필드 변수이름을 의미한다

 

 

 

 

 

 

 

- References)

1. DTO, VO, DAO : genesis8.tistory.com/214

2. mapstruct : mapstruct.org/

728x90

'Spring' 카테고리의 다른 글

Spring Cloud 와 Microservice 란  (0) 2021.07.01
Swagger 를 통한 REST API 문서화  (0) 2021.04.30
Lombok 이란?  (0) 2021.03.29
Spring Boot - Spring Data REST  (0) 2021.03.25
Spring Boot - DAO  (0) 2021.03.24