스터디원 중에 한 분이 엔티티매퍼 알려주셔서 와 신세계다 이러고 쓰고 있었는데 예전 프로젝트들 까보니까 익숙하게 ModelMapper 쓰고 있었음...... 스프링 너무 간만인데다 어디 기록도 안 해두니까 다 까먹는다.
그런데 기존에 사용하던 ModelMapper는 modelMapper.map(ENTITY, DTO.Class)
형태로 사용할 때 리플렉션이 일어나서 MapStruct보다 성능이 떨어진다고 한다. 그래서 이번 프로젝트부터는 MapStruct를 사용하기로 했다. 알려주셔서 감사합니다.
mapstruct는 프로젝트를 빌드하면 mapstruct의 @Mapper가 달린 interface의 구현클래스를 자동으로 생성해 준다.
pom.xml
<properties>
<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
<org.projectlombok.lombok-mapstruct-binding.version>0.2.0</org.projectlombok.lombok-mapstruct-binding.version>
</properties>
<dependencies>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<!--lombok과 같이 사용할 경우-->
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId> <version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${org.projectlombok.ombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
properties로 mapstruct 버전 잡아주고, dependency 추가해주고, lombok과 같이 사용하기 위해 build plugin을 저 순서로 설정해줬다.
버전 업그레이드 되면서 이제는 둘이 호환이 잘 된다고 하는데 그래도 mapstruct와 lombok은 쉽게 충돌할 수 있는 친구들이니까 따로 신경 써 줘야 한다. 롬복 @Builder를 사용할 거라 lombok-mapstruct-bind도 넣어준다.
bind dependency를 넣어주지 않으면 mapstruct가 냅다 build만 가져다 써버려서 Impl클래스에 setter가 하나도 안 붙는다.
-> 빈 객체를 리턴하게 됨
mapstruct는 프로젝트를 빌드하면 mapstruct의 @Mapper가 달린 interface의 구현클래스를 자동으로 생성해 준다.
maven에서 빌드를 진행하기 위해 defaultGoal도 설정해 줬다.
이클립스 STS의 경우 클래스 생성위치를 메이븐이 못 잡는다. 때문에 위의 pom.xml에서 build>configuration 안에 따로 패스를 작성해줘야 한다. gradle의 경우 sourceSets로 설정해 주면 된다.
<sources>
<source>${project.build.directory}/generated-sources/annotations</source>
</sources>
Dto/Entity 준비
Dto를 Entity로 바꿔주는 함수를 작성할 건데 내 경우는 각각 대응되는 필드명이 같다.
MemberDtoMapper.java
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper
public interface MemberDtoMapper{
MemberDtoMapper INSTANCE = Mappers.getMapper(MemberDtoMapper.class);
Member toEntity(MemberSaveRequestDto requestDto);
}
이미 마이바티스 매퍼를 사용하고 있어서 bean이름이 겹치는 걸 방지하려고 MemberDtoMapper로 네이밍했다.
(MemberRepository는 JpaRepository가 이미 쓰고 있음...)
다음과 같이 본인클래스를 인스턴스로 설정해주고, Dto를 파라미터로 받아 Entity를 리턴하는 toEntity()를 선언해준다.
만일 파라미터와 반환타입에서 대응되는 필드 이름이 다르다면 메소드 위에 @Mapping(source = "dtoname", target = "entityname")
처럼 어노테이션을 달아주면 된다. (toEntity의 경우)
Generic Interface를 선언해서 각각 상속받게 하면 조금 더 편하게 쓸 수 있기는 한데 일단은 환경만 구성해 놓는 거라 일단 그냥 작성해줬다.
MemberDtoMapperImpl.java
Maven update-Maven Clean-Maven Build
빌드하면 이클립스 STS 기준 target/generated-sources/${본인패키지구조}/에 Impl클래스가 생긴다. 인텔리제이는 메이븐에서 인식해주는 경로로 잘 잡힌다.
MemberDtoMapperTest.java
@Slf4j
public class MemberDtoMapperTest {
@Test
public void toEntity() {
MemberSaveRequestDto requestDto = MemberSaveRequestDto.builder()
.name("test").tel("test").address("test").email("test").password("test")
.build();
Member member = MemberDtoMapper.INSTANCE.toEntity(requestDto);
assertEquals(member.getEmail(), "test");
}
}
toEntity()가 리턴한 Member객체에 Dto값이 제대로 들어가 있다.
만약 Impl이 만들어졌는데도 못 찾는다는 에러가 뜨면 pom.xml에 있는 source 경로 다시 확인해보고 업데이트클린빌드새로고침 반복하기......
잘 되던 게 어느날 갑자기 에러 뜨면 업데이트클린빌드새로고침하기......
이클립스는 메이븐이랑 SourceSet이 다른 거 같다던데 진짜 규정만 아니었어도 갈아탔다
+)
List 등의 Collection을 매핑해야 할 경우 제네릭으로 지정된 dto 자체에 대한 매핑부터 명시를 해줘야 한다.
빌드된 Mapper코드를 까 보면 Collection 타입을 매핑할 때는 foreach문 돌면서 target dto를 생성해버림
LIst<AuthDto>를 다른 dto로 매핑하고 싶을 경우 List<AuthDto>와 AuthDto에 대한 함수원형을 모두 작성해줘야 제대로 된 mapper가 생성된다.
'Web > Spring' 카테고리의 다른 글
[Spring] 빈 순환 참조 오류 (0) | 2022.01.16 |
---|---|
[Maven] QueryDSL 사용하기 (0) | 2022.01.02 |
[Mybatis/Pagination] PageHelper로 Paging처리하기 (0) | 2021.11.07 |
[Maven/Eclipse] 빌드 시 target/generated-sources 인식 못 하는 문제 (0) | 2021.11.07 |
[Maven] 최초 build시 잡아야 하는 configuration (0) | 2021.11.07 |
댓글