엔티티에는 민감한 데이터가 포함될 수 있으므로 필요한 데이터만 DTO로 변환하여 클라이언트에 전달하면 보안성과 효율성을 높일 수 있다.
public ProductResponseDto toResponseDto() {
return new ProductResponseDto(
this.id,
this.name,
this.description,
this.price,
this.quantity
);
}
public ProductResponseDto getProductById(Long id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("상품을 찾을 수 없습니다."))
return product.toResponseDto();
}
@Getter
@AllArgsConstructor
public class ProductResponseDto {
private Long id;
private String name;
private String description;
private int price;
private int quantity;
public static ProductResponseDto fromEntity(Product product) {
return new ProductResponseDto(
product.getId(), product.getName(), product.getDescription(),
product.getPrice(), product.getQuantity()
);
}
}
Product product = productRepository.findById(id).orElseThrow();
ProductResponseDto dto = ProductResponseDto.fromEntity(product);
ModelMapper 라이브러리를 사용할 경우 엔티티와 DTO 간 필드명이 같을 경우 자동으로 변환할 수 있다.
gradle 의존성(implementation 'org.modelmapper:modelmapper:3.1.1')을 추가 필요
자동 변환이라 코드가 깔끔함
필드명이 다를 경우 수동 설정 필요
작은 프로젝트에서는 오버킬일 수 있음
import org.modelmapper.ModelMapper;
@Service
public class ProductService {
private final ProductRepository productRepository;
private final ModelMapper modelMapper;
public ProductService(ProductRepository productRepository, ModelMapper modelMapper) {
this.productRepository = productRepository;
this.modelMapper = modelMapper;
}
public ProductResponseDto getProductById(Long id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("상품을 찾을 수 없습니다."));
return modelMapper.map(product, ProductResponseDto.class);
}
}
MapStruct는 컴파일 타임에 변환 코드를 자동 생성하는 라이브러리 이다.
그러므로 ModelMapper보다 성능이 뛰어나다.
-> 대규모 프로젝트에 사용 가능
추가 설정이 필요하고 프로젝트에 새 라이브러리를 추가해야하는 단점이 있다.
의존성 추가 :
implementation 'org.mapstruct:mapstruct:1.5.3.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ProductMapper {
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);
ProductResponseDto toDto(Product product);
}
Product product = productRepository.findById(id).orElseThrow();
ProductResponseDto dto = ProductMapper.INSTANCE.toDto(product);
| 방법 | 장점 | 단점 | 추천 상황 |
|---|---|---|---|
| toResponseDto() 메서드 | 간단하고 직관적 | 엔티티 역할이 모호해질 수 있음 | 작은 프로젝트, 빠르게 개발할 때 |
DTO에서 fromEntity() 사용 | 엔티티 역할이 깔끔함 | 변환 호출이 필요함 | 엔티티와 DTO를 분리하고 싶을 때 |
| ModelMapper 사용 | 자동 변환 가능, 코드가 간결함 | 필드명이 다르면 문제 발생 | 필드명이 거의 동일한 경우 |
| MapStruct 사용 | 성능이 가장 좋음, 컴파일 타임 변환 | 추가 설정 필요 | 대규모 프로젝트에서 DTO 변환이 많을 때 |