[Java] 26. Stream API (2) - DTO 변환과 컬렉션 처리

김주희's avatar
Apr 27, 2025
[Java] 26. Stream API (2) - DTO 변환과 컬렉션 처리
spring은 내부의 jackson 라이브러리 → gson 없어도 json으로 출력 가능하다
 
문제 1번
깊은 복사
@Data public class ProductDTO { // 깊은 복사 private int id; private String name; // 바꿀 대상을 한꺼번에 통으로 넣는다 -> setter가 아닌 생성자를 써야됨 // setter는 상태를 변경 public ProductDTO(Product product) { this.id = product.getId(); this.name = product.getName(); } }
// 1번 문제 : 상품 목록 화면 // List<Product> -> List<ProductDTO> : 깊은 복사 // 옮기고 싶은 애의 크기만큼 돌아야 된다. List<ProductDTO> productDTOs = new ArrayList<>(); // iterate -> 처음부터 full scan = for Each (중간부터 불가) for (Product p : products) { // for(int i=0;i<productDTOs.size();i++) -> 크기 제어하고 싶은 경우 productDTOs.add(new ProductDTO(p)); } String ex01 = gson.toJson(productDTOs); System.out.println(ex01);
notion image
 
얕은 복사 예시
new된 heap은 하나이고 p1,p3 모두 같은 걸 가리킨다.
Product p3 = p1;
 
 
문제2번
DTO 만들때 누구의 id인지 적어주는 것이 좋다. (항상 flat할 수 없으므로)
내부 클래스를 만들때에는 그 친구 이름에DTO를 붙임
 
필드에서 리스트를 new 하면 생성자 내부에서 new할 필요 없음
필드명에는 dto 안붙이는게 낫다
@Data public class ProductDetailDTO { private Integer productId; private String productName; // 필드에서 리스트를 new 하면 생성자 내부에서 new할 필요 없음 // 필드명에는 dto 안붙이는게 좋다. 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(); } } }
// 2번 문제 : 상품 상세 화면 (p2) // Product(p2, p2Options) -> ProductDetail ProductDetailDTO productDetailDTO =new ProductDetailDTO(p2,p2Options); String ex02 = gson.toJson(productDetailDTO); System.out.println(ex02);
notion image
 
 
 
문제 3번
order(주문번호)에 orderOption이 여러개가 아니라 하나밖에 없는 경우
// 3번 문제만을 위한 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(); // Lazy Loading (조인 안했다면) this.orderOptionId = orderOption.getId(); this.orderOptionName = orderOption.getOptionName(); this.orderOptionQty = orderOption.getQty(); this.totalPrice = orderOption.getTotalPrice(); } }
// 3번 문제 : 주문 확인 상세 화면 (or2) - orOption4 // 틀렸음 : TempDTO 담기 TempDTO tempDTO = new TempDTO(orOption4); String ex03 = gson.toJson(tempDTO); System.out.println(ex03);
notion image
 
문제 4번
주문번호 1번 안에 옵션이 3개임 - 상품 1번에 옵션 2개 엮여 있고, 상품 2번에 옵션 1개 엮여 있음
 
상품1 : 반스 신발 - a (270
- b (230
상품2 : 나이키 신발 - c (XL
 
구매내역보기 하면 a,b,c가 다 보여야 됨
상품 구분 없이 뿌리게 되면 상품명이 중복되게 뿌려짐
1
a - 270 - 반스
b - 230 - 반스
c - XL - 나이키
1
[a - 270 ] - 반스
[b - 230 ] -
[c - XL ] - 나이키
 
a,b,c 3개를 그룹핑해야 됨
(DB에서 그룹핑한다고 해결 안됨→ 같은 애들로 묶어서 세로 연산할때 쓰는 거임 본질은 그룹을 묶는게 아니라 세로연산임! → squash)
 
상품1과 상품2의 컬렉션을 따로 만들어야 된다!
 
 
외부 클래스로 만들면 복잡해지므로 내부 클래스로 만드는게 좋다 (모든 언어가 내부 클래스 지원X)
 
orderOptions에 orderOption 3개 받음
상품번호 기준으로 박스 2개 만들어짐
@Data public class OrderDetailDTO { private Integer orderId; private List<X> products; private Integer totalPrice; public OrderDetailDTO(List<OrderOption> orderOptions) { // p1(orOption1, orOption2), p2(orOption3) this.orderId = orderOptions.get(0).getOrder().getId(); // 이것도 동적으로 List<OrderOption> op1s = new ArrayList<>(); // for문 돌려서 1,1,2를 동적으로 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(); } } } }
// 4번 문제 : 주문 확인 상세 화면 (or1) // p1(orOption1, orOption2), p2(orOption3) -> OrderDetailDTO OrderDetailDTO orderDetailDTO = new OrderDetailDTO(or1Options); String ex04 = gson.toJson(orderDetailDTO); System.out.println(ex04);
notion image
 
전체 결과
[{"id":1,"name":"바지"},{"id":2,"name":"티"}] {"productId":2,"productName":"티","options":[{"optionId":3,"optionName":"노랑티","optionPrice":1000,"optionQty":3},{"optionId":4,"optionName":"하얀티","optionPrice":2000,"optionQty":5}]} {"orderId":2,"productId":2,"orderOptionId":4,"orderOptionName":"노랑티","orderOptionQty":7,"totalPrice":7000} {"orderId":1,"products":[{"productId":1,"orderOptions":[{"orderOptionId":1,"orderOptionName":"파란바지","orderOptionQty":2,"orderOptionTotalPrice":2000},{"orderOptionId":2,"orderOptionName":"빨간바지","orderOptionQty":2,"orderOptionTotalPrice":4000}]},{"productId":2,"orderOptions":[{"orderOptionId":3,"orderOptionName":"하얀티","orderOptionQty":5,"orderOptionTotalPrice":10000}]}],"totalPrice":16000}
 
 

동적으로 만들기

notion image
 
  1. 상품의 총 그룹이 몇개인지 알아야 됨
    1. orOption 각각이 가지고 있는 productId를 찾아서 distinct해야 됨 → hashset 쓰면 됨
      1. notion image
    2. pId가 1인거 - 1, 1 / pId가 2인거 - 2
      1. notion image
public class OrderDetailDTO { private int orderId; private List<ProductDTO> products = new ArrayList<>(); private int sumPrice; public OrderDetailDTO(List<OrderOption> orderOptions) { // p1(orOption1, orOption2), p2(orOption3) 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(); } } } }
Share article

jay0628