[Springboot RestAPI] 2. 스토어 앱 DTO 문제 풀이

손영민's avatar
Aug 26, 2025
[Springboot RestAPI] 2. 스토어 앱 DTO 문제 풀이

1️⃣ 상품 목록 화면 DTO

✔️ 목적

모든 상품 리스트를 조회할 때 사용하는 DTO입니다. 간단히 id, name만 클라이언트에 응답합니다.

📦 DTO

@Data public class ProductDTO { private int id; private String name; public ProductDTO(Product product) { this.id = product.getId(); this.name = product.getName(); } }

🔸 변환 로직

// 1번 문제 : 상품 목록 화면!! // List<Product> -> List<ProductDTO> List<ProductDTO> productDTOs = new ArrayList<>(); for (Product p : products) { productDTOs.add(new ProductDTO(p)); } String ex01 = gson.toJson(productDTOs); System.out.println(ex01);

🔸 출력 JSON

[{"id":1,"name":"바지"},{"id":2,"name":"티"}]

2️⃣ 상품 상세 화면 + 옵션 리스트

✔️ 목적

특정 상품을 클릭했을 때, 해당 상품의 상세 정보와 함께 등록된 상품 옵션 리스트를 함께 조회합니다.
 

📦 DTO 구조

ProductDetailDTOProductOptionDTO 내부 클래스 포함
@Data public class ProductDetailDTO { private Integer productId; private String productName; List<ProductOptionDTO> options = new ArrayList<>(); public ProductDetailDTO(Product p, List<ProductOption> options) { this.productId = p.getId(); this.productName = p.getName(); for (ProductOption op : options) { this.options.add(new ProductOptionDTO(op)); } } @Data public class ProductOptionDTO { private int optionId; private String optionName; private int optionPrice; private int optionQty; public ProductOptionDTO(ProductOption op) { this.optionId = op.getId(); this.optionName = op.getName(); this.optionPrice = op.getPrice(); this.optionQty = op.getQty(); } } }

🔸 변환 로직

ProductDetailDTO productDetailDTO = new ProductDetailDTO(p2, p2Options); String ex02 = gson.toJson(productDetailDTO); System.out.println(ex02);

💬 예시 JSON

{ "productId":2, "productName":"티", "options":[ {"optionId":3,"optionName":"노랑티","optionPrice":1000,"optionQty":3}, {"optionId":4,"optionName":"하얀티","optionPrice":2000,"optionQty":5} ] }

3️⃣ 주문 옵션 상세 화면

✔️ 목적

특정 주문 옵션(예: 티셔츠 7개 주문)을 클릭했을 때, 해당 주문에 대한 상세 정보를 제공합니다.

📦 DTO

@Data public class TempDTO { private Integer orderId; private Integer productId; private Integer orderOptionId; private String orderOptionName; private Integer orderOptionQty; private Integer totalPrice; public TempDTO(OrderOption orderOption) { this.orderId = orderOption.getOrder().getId(); this.productId = orderOption.getProduct().getId(); this.orderOptionId = orderOption.getId(); this.orderOptionName = orderOption.getOptionName(); this.orderOptionQty = orderOption.getQty(); this.totalPrice = orderOption.getTotalPrice(); } }

🔸 변환 로직

java 복사편집 TempDTO tempDTO = new TempDTO(orOption4); String ex03 = gson.toJson(tempDTO); System.out.println(ex03);

💬 예시 JSON

{ "orderId":2, "productId":2, "orderOptionId":4, "orderOptionName":"노랑티", "orderOptionQty":7, "totalPrice":7000 }

4️⃣ 주문 상세 화면 (상품별 옵션 그룹화)

✔️ 목적

하나의 주문에 여러 상품이 있고, 각 상품별로 여러 주문 옵션이 있을 수 있을 때, 이를 상품 단위로 그룹화해서 보여주는 화면입니다. 총 주문 금액도 함께 응답합니다.

📦 DTO 구조

  • OrderDetailDTO
    • ProductDTO
      OrderOptionDTO

      📦 첫 번째 코드 - XY 클래스를 포함한 구조

@Data public class OrderDetailDTO { private Integer orderId; private List<X> products; private Integer totalPrice; public OrderDetailDTO(List<OrderOption> orderOptions) { this.orderId = orderOptions.get(0).getOrder().getId(); List<OrderOption> op1s = new ArrayList<>(); op1s.add(orderOptions.get(0)); op1s.add(orderOptions.get(1)); List<OrderOption> op2s = new ArrayList<>(); op2s.add(orderOptions.get(2)); X x1 = new X(op1s); X x2 = new X(op2s); List<X> xList = new ArrayList<>(); xList.add(x1); xList.add(x2); this.products = xList; this.totalPrice = 0; for (OrderOption op : orderOptions) { this.totalPrice += op.getTotalPrice(); } } @Data public class X { private Integer productId; private List<Y> orderOptions; public X(List<OrderOption> orderOptions) { this.productId = orderOptions.get(0).getProduct().getId(); List<Y> yList = new ArrayList<>(); for (OrderOption orderOption : orderOptions) { yList.add(new Y(orderOption)); } this.orderOptions = yList; } @Data public class Y { private Integer orderOptionId; private String orderOptionName; private Integer orderOptionQty; private Integer orderOptionTotalPrice; public Y(OrderOption orderOption) { this.orderOptionId = orderOption.getId(); this.orderOptionName = orderOption.getOptionName(); this.orderOptionQty = orderOption.getQty(); this.orderOptionTotalPrice = orderOption.getTotalPrice(); } } } }

설명

  • XY 클래스는 상품별로 주문 옵션을 그룹화하여 다루는 방식입니다.
  • 상품을 기준으로 여러 개의 주문 옵션을 그룹화하고, 각 주문 옵션의 세부 정보를 출력하는 구조입니다.
  • X 클래스는 상품을 나타내며, Y 클래스는 해당 상품에 대한 주문 옵션을 나타냅니다.
  • totalPrice는 주문 옵션을 하나씩 순회하면서 총합을 구합니다.

📦 두 번째 코드 - ProductDTOOrderOptionDTO를 이용한 구조

 
@Data public class OrderDetailDTO { private int orderId; private List<ProductDTO> products = new ArrayList<>(); private int sumPrice; public OrderDetailDTO(List<OrderOption> orderOptions) { this.orderId = orderOptions.get(0).getId(); // 중복이 제거된 상품 ids + 전체금액 계산 Set<Integer> productIds = new HashSet<>(); for (OrderOption orderOption : orderOptions) { productIds.add(orderOption.getProduct().getId()); this.sumPrice += orderOption.getTotalPrice(); } // 상품별 주문한 상품옵션 만들기 for (Integer productId : productIds) { List<OrderOption> selectedOptions = new ArrayList<>(); for (OrderOption orderOption : orderOptions) { if (productId == orderOption.getProduct().getId()) { selectedOptions.add(orderOption); } } ProductDTO productDTO = new ProductDTO(productId, selectedOptions); this.products.add(productDTO); } } @Data class ProductDTO { private int productId; private List<OrderOptionDTO> orderOptions = new ArrayList<>(); public ProductDTO(int productId, List<OrderOption> orderOptions) { this.productId = productId; for (OrderOption orderOption : orderOptions) { this.orderOptions.add(new OrderOptionDTO(orderOption)); } } @Data class OrderOptionDTO { private int orderOptionId; private String orderOptionName; private int orderQty; private int orderTotalPrice; public OrderOptionDTO(OrderOption orderOption) { this.orderOptionId = orderOption.getId(); this.orderOptionName = orderOption.getOptionName(); this.orderQty = orderOption.getQty(); this.orderTotalPrice = orderOption.getTotalPrice(); } } } }

설명

  • 두 번째 코드는 상품을 기준으로 주문 옵션을 그룹화하는 방식이지만, 첫 번째 코드와 비교하여 조금 더 명확하고 간결한 구조를 제공합니다.
  • ProductDTOProduct와 그에 해당하는 OrderOptionDTO들을 담고 있으며, 주문 옵션들의 정보를 분리하여 출력합니다.
  • totalPriceOrderOption을 순회하면서 모든 옵션의 총합을 구합니다.

📝 차이점

  • 첫 번째 코드에서는 **X*와 Y 클래스를 사용하여 상품과 주문 옵션을 분리한 반면, 두 번째 코드는 **ProductDTO*와 **OrderOptionDTO*를 사용하여 명확히 상품별 주문 옵션을 그룹화했습니다.
  • 첫 번째 코드에서는 상품을 그룹화할 때, 미리 옵션들을 수동으로 그룹화하는 과정이 포함되어 있으며, 두 번째 코드에서는 Set을 사용하여 중복을 제거하고, 상품별로 옵션들을 자동으로 그룹화하는 방식입니다.

🔸 변환 로직

List<OrderOption> or1Options = Arrays.asList(orOption1, orOption2, orOption3); OrderDetailDTO orderDetailDTO = new OrderDetailDTO(or1Options); String ex04 = gson.toJson(orderDetailDTO); System.out.println(ex04);

💬 예시 JSON

{ "orderId":1, "products":[ { "productId":1, "orderOptions":[ {"orderOptionId":1,"orderOptionName":"파란바지","orderQty":2,"orderTotalPrice":2000}, {"orderOptionId":2,"orderOptionName":"빨간바지","orderQty":2,"orderTotalPrice":4000} ] }, { "productId":2, "orderOptions":[ {"orderOptionId":3,"orderOptionName":"하얀티","orderQty":5,"orderTotalPrice":10000} ] } ], "sumPrice":16000 }
Share article

sson17