MapStruct 사용하기

By | 2021년 1월 25일
Table of Content

MapStruct 사용하기

MapStruct 를 이용하면 DTO – Entity 간 매핑을 간편하게 할 수 있고, 더불어 Entity 업데이트 코드를 매우 간단하게 줄일 수 있다.

annotationProcessor 의 순서가 중요하다. mapstruct-processor 가 나중에 있어야 정상 작동한다.

다른 사람들은 mapstruct-processor 가 먼저 있어야 한다고 하는데 본인은 아래 설정이 작동했다.

의존성 추가

dependencies {
    // ......
    implementation 'org.mapstruct:mapstruct:1.4.1.Final'
    compileOnly 'org.projectlombok:lombok'
    compileOnly 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
    annotationProcessor 'org.projectlombok:lombok'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.1.Final'
    // ......
}

DTO – Entity 생성

DTO 와 Entity 의 필드명을 1:1 로 일치시켜야 코딩이 편해집니다.

@Setter, @Getter, @NoArgsConstructor 가 추가되어 있는지 항상 확인한다. 에러의 95% 가 에너테이션 누락이다.

@Setter
@Getter
@NoArgsConstructor
@Entity
public class Brands extends BaseTimeEntity implements Persistable<String> {

    @Id
    private String brandId;

    @NotNull
    @Column(length = 32)
    private String partnerId;

    @NotNull
    @Column(length = 128)
    private String brandName;

    @NotNull
    @ColumnDefault("Y")
    @Column(length = 1)
    private String useyn = "Y";

    public Brands(String brandId) {
        this.brandId = brandId;
    }

    @Override
    public String getId() {
        return brandId;
    }

    @Override
    public boolean isNew() {
        return getRegdate() == null;
    }
}
@Getter
@Setter
@NoArgsConstructor
public class BrandsDto extends BaseTimeDto implements Serializable {

    @ApiModelProperty(example = "conitale")
    private String brandId;

    @ApiModelProperty(example = "conitale")
    private String partnerId;

    @ApiModelProperty(example = "코니테일")
    private String brandName;

    @ApiModelProperty(example = "Y")
    private String useyn;
}

GenericMapper 생성

DTO – Entity 간 필드명을 동일하게 생성한 경우 수동 매핑을 아예 안해도 된다.

updateFromDto() 는 Entity 업데이트시 값이 null 이 아닌 값만 업데이트 하도록 할 수 있다.

public interface GenericMapper<D, E> {

    D toDto(E e);
    E toEntity(D d);

    @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
    void updateFromDto(D dto, @MappingTarget E entity);
}

Mapper 생성

상속만으로 코딩이 끝난다. 필드명이 다르면 하나 하나 수동으로 매핑해야 한다.

@Mapper(componentModel = "spring")
public interface BrandsMapper extends GenericMapper<BrandsDto, Brands> {

//    @Override
//    @Mapping(source = "name", target = "modelName")
//    @Mapping(source = "color", target = "modelColor")
//    BrandsDto toDto(Brands brands);
}

Service 생성

update 가 매우 간단해진다.

@Service
public class BrandsService {

    private final BrandsMapper mapper = Mappers.getMapper(BrandsMapper.class);

    // ......

    public void update(String id, BrandsDto d) {

        Brands e = get(id, true);
        updateFromDto(d, e);
        repository.save(e);
    }

    public D select(String id) {
        return toDto(get(id, true));
    }

    protected BrandsDto toDto(Brands brands) {
        return mapper.toDto(brands);
    }

    protected Brands toEntity(BrandsDto e) {
        return mapper.toEntity(e);
    }

    protected void updateFromDto(BrandsDto dto, Brands brands) {
        mapper.updateFromDto(dto, brands);
    }
}

답글 남기기