Table of Content
MapStruct 사용하기
MapStruct
를 이용하면 DTO – Entity 간 매핑을 간편하게 할 수 있고, 더불어 Entity 업데이트 코드를 매우 간단하게 줄일 수 있습니다.
의존성 추가
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 Brand extends BaseTimeEntity implements Persistable<String> {
@Id
private String brandId;
private String partnerId;
private String brandName;
private String useyn = "Y";
public Brand(String brandId) {
this.brandId = brandId;
}
@Override
public String getId() {
return brandId;
}
@Override
public boolean isNew() {
return getRegdate() == null;
}
}
@Getter
@Setter
@NoArgsConstructor
public class BrandResponseDto {
private String brandId;
private String partnerId;
private String brandName;
private String useyn;
private LocalDateTime regdate;
private LocalDateTime lastupdate;
}
RequestDto
에는 insert/update 할 데이타만 남겨놓습니다.
@Getter
@Setter
@NoArgsConstructor
public class BrandCreateRequestDto {
private String partnerId;
private String brandName;
}
@Getter
@Setter
@NoArgsConstructor
public class BrandUpdateRequestDto {
private String brandName;
private String useyn;
}
GenericMapper 생성
DTO – Entity 간 필드명을 동일하게 생성한 경우 수동 매핑을 아예 안해도 됩니다.
updateFromDto()
는 Entity 업데이트시 값이 null 이 아닌 값만 업데이트 하도록 할 수 있습니다.
public interface GenericMapper<D, E> {
D toDto(E e);
List<D> toDto(List<E> e);
void updateFromDto(D dto, @MappingTarget E entity);
}
@Mapper(
componentModel = "spring",
unmappedTargetPolicy = ReportingPolicy.IGNORE,
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
)
public interface BrandMapper extends GenericMapper<BrandDto, Brand> {
}
Service 생성
update
가 매우 간단해집니다.
@Service
public class BrandService {
private final BrandMapper mapper = Mappers.getMapper(BrandMapper.class);
// ......
@Transactional
public ResponseEntity<?> create(BrandCreateRequestDto dto) {
Brand entity = new Brand();
converter.updateFromDto(dto, entity);
return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, converter.toDto(repository.save(entity))));
}
@Transactional
public ResponseEntity<?> update(String brandId, BrandUpdateRequestDto dto) {
Optional<Brand> brand = repository.findById(brandId);
assert brand.isPresent();
converter.updateFromDto(dto, brand.get());
repository.save(brand.get());
return ResponseEntity.ok(new ApiResponseMessage(ResponseCode.OK));
}
public ResponseEntity<?> get(String brandId) {
Optional<Brand> brand = repository.findById(brandId);
assert brand.isPresent();
return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, converter.toDto(brand.get())));
}
public ResponseEntity<?> search(SearchBrandRequestDto dto) {
Page<BrandResponseDto> dtos = repository.search(dto).map(converter::toDto);
return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, dtos));
}
}
뜬금없는 오류발생
이따금 Mapper 관련 오류가 뜬금없이 발생합니다.
이럴땐 grable build clean 후 다시 실행하면 정상적으로 실행됩니다.