스프링 부트의 엔티티(Entity) 클래스의 DTO 클래스로의 변환에 대한 고찰

유동재·2024년 4월 6일
0

Spring Boot

목록 보기
4/7
post-thumbnail

장바구니 조회와 같은 GET 요청을 클라이언트가 서버에게 보낼 때, 서버가 해당 요청에 대한 응답으로 Entity 객체가 아닌 DTO 객체를 반환하는 것이 보안적으로도 성능적으로도 우수하다.

왜냐하면,
보안적으로는 Entity 객체를 그대로 반환시켜버리는 것은 사실상 데이터 베이스의 구조를 그대로 다 보여주는 것이기 때문이고,
성능적으로는 DTO가 아닌 Entity 객체를 그대로 반환시켜버리면 지연 로딩 문제가 발생할 수도 있기 때문이다. 추가적으로 DTO는 필요한 정보만을 담는 것이 가능하다는 것도 이유 중 하나일 것이다.

그래서 프로젝트를 진행할 때 항상 Entity가 아닌, DTO 객체를 반환시키다 보니, 해당 작업이 반복적으로 꽤나 빈번하게 요구되었다.


해당 작업을 수행하는 방법으로 대표적으로 세 가지를 사용해보았다.

  1. 먼저 아래와 같이 일반적으로 로직이 구현되는 서비스 클래스에서 그때 그때 setter 메서드를 사용하여 변환을 해주는 방식이다.
public CartDto getCartDto(Long cartId) {
    Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new NotFoundException("Cart not found"));
    CartDto cartDto = new CartDto();
    cartDto.setId(cart.getId());
    cartDto.setUserId(cart.getUserId());
    cartDto.setItems(cart.getItems());
    return cartDto;
}

  1. 두 번째로는 Entity 클래스에서 일반적으로 EntityToDto와 같은 이름을 가진 메서드를 만들어서 사용하는 방식이다.
// 장바구니 Entity 클래스
public class Cart {
	// ...
    // Entity → DTO 메서드 정의
    public CartDto cartToDto() {
        CartDto cartDto = new CartDto();
        cartDto.setId(this.getId());
        cartDto.setUserId(this.getUserId());
        cartDto.setItems(this.getItems());
        return cartDto;
    }
}


	// ...
    // 서비스 클래스 내부의 메서드
  	public CartDto getCartDto(Long cartId) {
        Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new NotFoundException("장바구니에 물품이 존재하지 않습니다."));
        return cart.cartToDto();
  	}
}	

  1. 마지막으로는 modelMapper 라는 라이브러리를 아래와 같이 스프링 빈으로 등록하고 사용하는 방식이다.
// 새로운 클래스를 정의하여, 스프링 빈으로 주입
@Configuration
public class ModelMapperConfig {
    
    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}

// ...
// 서비스 클래스 내부에 존재하는 메서드
    public CartDto getCartDto(Long cartId) {
        Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new RuntimeException("Cart not found"));
        return modelMapper.map(cart, CartDto.class);
    }
}

처음에는 ModelMapper와 같은 라이브러리를 사용하는 방식이 최선의 방식이라고 생각했다.
그러나 프로젝트를 진행하던 와중, ModelMapper는 기본적으로 이름 기반 매핑을 수행하기 때문에, 이름이 다른 필드는 자동으로 매핑되지 않는다는 단점을 맞닥뜨리게 되었다. 이런 상황에서는 추가적인 설정이 필요하며, 이는 ModelMapper의 유연성과 강력함에도 불구하고 고려해야 할 단점이라는 생각이 들었다.

그렇기 때문에 그때 그때 상황에 맞는 방식을 사용하는 유연한 사고가 갖춰야할 중요한 역량 중 하나라고 생각한다. 나는 1번 방식은 가독성이 떨어진다고 생각하여 굳이 사용하지 않을 것 같고, 기본적으로는 3번, 즉 ModelMapper를 사용하되, 그때그때 2번 방식을 채택하여 사용할 것 같다.

profile
풀 스택이 되기 위해 노력하는 개발자입니다!

0개의 댓글

관련 채용 정보