JAVA

model mapping 라이브러리 Mapstruct

91cm 2021. 7. 8. 23:02

 

Mapstruct란?

모델간 맵핑을 쉽게 해주는 라이브러이다    ex) entity <-> dto

-컴파일 시점에 맵핑클래스를 생성함(그래서 매우 좋음 바로바로 확인가능)

-ModelMapper 보다 맵핑 성능이 훨씬 좋음

 

 

1.  라이브러리 추가

mapstruct만 추가해주면된다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
	implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:2.1.1.RELEASE'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	annotationProcessor "org.mapstruct:mapstruct-processor:1.3.1.Final"
	runtimeOnly 'com.h2database:h2'
	
    // mapstruct!! 추가
	implementation 'org.mapstruct:mapstruct:1.3.1.Final'
        
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

 

 

2. 예제 DTO , Entity 생성

2-1 DTO

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@ToString
@Getter @Setter
@NoArgsConstructor // 기본생성자 필수!
@AllArgsConstructor // 테스트코드 작성을 위해 추가
public class UserDto {

    private String nameModel;

    private int ageModel;

    private String addrModel;

}

 

2-2 Entity  

실제 Entity로 만들진 않았지만, Entity 역할을 하는 model로 테스트 진행 예정

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@ToString
@Getter @Setter
@NoArgsConstructor // 기본 생성자 필수!
@AllArgsConstructor // 테스트코드 작성을 위해 추가
public class User {

    private String name;

    private int age;

    private String addr;

}

 

 

3. mapper 인터페이스 생성*중요

source : 맵핑시킬 멤버 필드명

target : 맵핑되어질 멤버 필드명

ignor : 해당 멤버필드는 맵핑하지 않음

 

참고 : 멤버 필드명이 양쪽이 모두 같다면 속성명시는 생략가능.

 

import com.example.test.test.dto.UserDto;
import com.example.test.test.dto.User;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;


@Mapper // mapstruct를 사용하기 위해 선언
public interface UserMapper {
	
    //UserMapper를 상속받아 구현체가 작성됨 , build 폴더가보면 확인가능. UserMapperImpl이 생성됨
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); 
	
    // Entity를 DTO로 맵핑 
    @Mapping(source = "name", target ="nameModel")
    @Mapping(source = "age", target ="ageModel")
    @Mapping(source = "addr", target ="addrModel")
    UserDto userEntityToUserDto(User user);
	
    // DTO를 Entity로 맵핑
    @Mapping(source = "nameModel", target = "name")
    @Mapping(source = "ageModel", target = "age")
    @Mapping(source = "addrModel", target = "addr")
    User userDtoToUserEntity(UserDto userDto);
	
    // 특정 컬럼을 제외하고 맵핑 (ignore속성)
    @Mapping(target ="addr", ignore = true)
    @Mapping(target = "name" , source = "nameModel")
    @Mapping(target = "age" , source = "ageModel")
    User userDtoToEntityAndIgnore(UserDto userDto);

}

 

4. 테스트 코드 작성

import com.example.test.test.dto.User;
import com.example.test.test.dto.UserDto;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;


class UserMapperTest {

    @Test
    public void DTO를_Entity로_맵핑() {
        UserDto userDto = new UserDto("민", 20, "서울");

        User user = UserMapper.INSTANCE.userDtoToUserEntity(userDto);

        System.out.println(">>>>> userDto = " + userDto);
        System.out.println(">>>>> user = " + user);

        Assertions.assertEquals("민", user.getName());
        Assertions.assertEquals(20, user.getAge());
        Assertions.assertEquals("서울", user.getAddr());
    }

    @Test
    public void Entity를_DTO로_맵핑() {
        User user = new User("민", 20, "서울");

        UserDto userDto = UserMapper.INSTANCE.userEntityToUserDto(user);

        System.out.println(">>>>> user = " + user);
        System.out.println(">>>>> userDto = " + userDto);

        Assertions.assertEquals("민", userDto.getNameModel());
        Assertions.assertEquals(20, userDto.getAgeModel());
        Assertions.assertEquals("서울", userDto.getAddrModel());
    }

    @Test
    public void 주소필드는_무시하고_맵핑() {
        UserDto userDto = new UserDto("민", 20, "서울");

        User user = UserMapper.INSTANCE.userDtoToEntityAndIgnore(userDto);

        System.out.println(">>>>> userDto = " + userDto);
        System.out.println(">>>>> user = " + user);

        Assertions.assertEquals("민", user.getName());
        Assertions.assertEquals(20, user.getAge());
        Assertions.assertEquals(null, user.getAddr());
    }

}

 

5.결과 성공