![[Springboot RestAPI] 2. 스토어 앱 DTO 문제 풀이](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BSpringboot%2520RestAPI%255D%25202.%2520%25EC%258A%25A4%25ED%2586%25A0%25EC%2596%25B4%2520%25EC%2595%25B1%2520DTO%2520%25EB%25AC%25B8%25EC%25A0%259C%2520%25ED%2592%2580%25EC%259D%25B4%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3Dsson17&w=2048&q=75)
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 구조
ProductDetailDTO
→ ProductOptionDTO
내부 클래스 포함@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 구조
@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();
}
}
}
}
설명
X
와Y
클래스는 상품별로 주문 옵션을 그룹화하여 다루는 방식입니다.
- 상품을 기준으로 여러 개의 주문 옵션을 그룹화하고, 각 주문 옵션의 세부 정보를 출력하는 구조입니다.
X
클래스는 상품을 나타내며,Y
클래스는 해당 상품에 대한 주문 옵션을 나타냅니다.
totalPrice
는 주문 옵션을 하나씩 순회하면서 총합을 구합니다.
📦 두 번째 코드 - ProductDTO
와 OrderOptionDTO
를 이용한 구조
@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();
}
}
}
}
설명
- 두 번째 코드는 상품을 기준으로 주문 옵션을 그룹화하는 방식이지만, 첫 번째 코드와 비교하여 조금 더 명확하고 간결한 구조를 제공합니다.
ProductDTO
는Product
와 그에 해당하는OrderOptionDTO
들을 담고 있으며, 주문 옵션들의 정보를 분리하여 출력합니다.
totalPrice
는OrderOption
을 순회하면서 모든 옵션의 총합을 구합니다.
📝 차이점
- 첫 번째 코드에서는 **
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