프로젝트/Todak(Fidocs)
[ Todak ] MapStruct 사용
무으리
2024. 9. 12. 10:33
// mapstruct를 사용하기 위한 의존선 라이브러리
implementation "org.mapstruct:mapstruct:1.5.3.Final"
// Mapstruct로 각 데이터 매퍼의 클래스를 생성하기 위해 Annotation-processor 를 추가해 주어야함
annotationProcessor "org.mapstruct:mapstruct-processor:1.5.3.Final"
// Lombok 과 Mapstruct 충돌을 없애기 위해 어노테이션 프로세서를 선언해줘야함.
// 이를 하지 않으면 Lombok과 호출 순서에서 충돌이 있을 수 있다.
// -> Mapstruct 가 Lombok의 getter, setter ,builder 를 사용하기 때문
annotationProcessor "org.projectlombok:lombok-mapstruct-binding:0.2.0"
만약 build 에러가 나면 위와 같은 의존성을 추가해 주어야 한다.

DtoMapper 가 없으면 만들어 주자.
package com.padaks.todaktodak.common.dto;
import com.padaks.todaktodak.reservation.domain.Reservation;
import com.padaks.todaktodak.reservation.dto.ReservationSaveReqDto;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
// Mapper 어노테이션을 붙이면 MapStruct 가 자동으로 DtoMapper 구현체를 생성해준다.
@Mapper(componentModel = "spring")
public interface DtoMapper {
// 매퍼 클래스에서 DtoMapper 를 찾을수 있도록 하는 코드.
// instance를 생성해 주어야 매퍼에 대한 접근이 가능.
DtoMapper INSTANCE = Mappers.getMapper(DtoMapper.class);
// Reservation(Entity의 파일명) Entity에 ReservationSaveReqDto 의 값을 매핑해 주겠다.
Reservation toReservation(ReservationSaveReqDto reservationSaveReqDto);
}
다음과 같이 스크립트를 짜주는데 맨 밑의 줄만 추가해주면 된다.

그리고 서비스 에서
- Reservation reservation = dtoMapper.toReservation(dto); 를 적어주기만 하면
dtoMapper 가 Mapping 을 해준다.

이거는 Member 의 Mapper
만약 수동으로 매핑해 주어야 하는 것이 있다면 다음과 같이 soucre 와 target 으로 지정해주면 된다.
그리고 따로 매핑을 제외하고 싶은 변수는 ignore = true 로 해주어서 제외해 주면된다.
source : 매개변수로 받아온 변수명
target : 목표가 되는 Dto 또는 Entity 의 변수명

위와 같이 입력하면

실행하는 순간 DtoMapperImpl 에 위 사진과 같이 builder 가 작성된다.
Reservation 은 ReservationSaveReqDto 와 매핑이 된다. => 이때 ignore 된 ReservationSaveReqDto 의 ID는 매핑 X
source 와 target 으로 지정해준 hospital 객체는 reservation의 hospital 과 매핑된다.
또한 MapStruct 가 자동으로 매핑하지 못하거나, 복잡한 매핑 로직은 default 로 수동으로 매핑해서 구현할 수 있다.

다음은 reservation 의 dtoMapper 이다.
package com.padaks.todaktodak.common.dto;
import com.padaks.todaktodak.hospital.domain.Hospital;
import com.padaks.todaktodak.reservation.domain.Reservation;
import com.padaks.todaktodak.reservation.domain.ReserveType;
import com.padaks.todaktodak.reservation.dto.*;
import com.padaks.todaktodak.reservation.domain.ReservationHistory;
import com.padaks.todaktodak.review.domain.Review;
import com.padaks.todaktodak.review.dto.ReviewSaveReqDto;
import org.mapstruct.Builder;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
// Mapper 어노테이션을 붙이면 MapStruct 가 자동으로 DtoMapper 구현체를 생성해준다.
@Mapper(componentModel = "spring", builder = @Builder(disableBuilder = false))
public interface DtoMapper {
// 매퍼 클래스에서 DtoMapper 를 찾을수 있도록 하는 코드.
// instance를 생성해 주어야 매퍼에 대한 접근이 가능.
DtoMapper INSTANCE = Mappers.getMapper(DtoMapper.class);
@Mapping(target = "hospital", source = "hospital")
@Mapping(target = "id", ignore = true)
Reservation toReservation(ReservationSaveReqDto reservationSaveReqDto, Hospital hospital);
CheckListReservationReqDto toListReservation(Reservation reservation);
// default 를 통해 수동 매핑을 구현,
// MapStruct가 자동으로 매핑하지 못하거나, 복잡한 매핑 로직을 수행하고자 할 때 사용.
default ReserveType resTypeToReserveType(ResType resType) {
if (resType == null) {
return null;
}
switch (resType) {
case Immediate:
return ReserveType.Immediate;
case Scheduled:
return ReserveType.Scheduled;
default:
throw new IllegalArgumentException("Unknown ResType: " + resType);
}
}
@Mapping(source = "hospitalId", target = "hospitalId")
ReservationHistory toReservationHistory(Reservation reservation, Long hospitalId);
ReservationSaveResDto toReservationSaveResDto(Reservation reservation);
CheckHospitalListReservationResDto toHospitalListReservation(Reservation reservation);
RedisDto toRedisDto(Reservation reservation);
}