엔티티와 DTO 변환시 여러가지 방법

haruceki·2025년 2월 12일

엔티티에는 민감한 데이터가 포함될 수 있으므로 필요한 데이터만 DTO로 변환하여 클라이언트에 전달하면 보안성과 효율성을 높일 수 있다.

1️⃣ toResponseDto() 메서드 사용

  • 엔티티 -> dto 변환 메서드
  • 사용이 쉽고 간결하나, 엔티티에 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();
}

2️⃣ DTO에서 fromEntity() 정적 메서드 사용

  • 엔티티가 DTO 변환을 신경쓰지 않으므로 객체의 역할이 분리된다.
  • 하지만 엔티티에서 변환 메서드를 직접 호출할 수 없다.

예시

@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);

3️⃣ ModelMapper 활용 (자동 매핑)

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);
    }
}

4️⃣ @Mapping을 활용한 MapStruct (컴파일 타임 변환)

  • MapStruct는 컴파일 타임에 변환 코드를 자동 생성하는 라이브러리 이다.
    그러므로 ModelMapper보다 성능이 뛰어나다.
    -> 대규모 프로젝트에 사용 가능

  • 추가 설정이 필요하고 프로젝트에 새 라이브러리를 추가해야하는 단점이 있다.

  • 의존성 추가 :
    implementation 'org.mapstruct:mapstruct:1.5.3.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final'

Mapper 인터페이스 생성

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 변환이 많을 때
profile
희망도 절망도 없이 매일 코딩을 한다.

0개의 댓글