![[Java] 26. Stream API (2) - DTO 변환과 컬렉션 처리](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BJava%255D%252026.%2520Stream%2520API%2520%282%29%2520-%2520DTO%2520%25EB%25B3%2580%25ED%2599%2598%25EA%25B3%25BC%2520%25EC%25BB%25AC%25EB%25A0%2589%25EC%2585%2598%2520%25EC%25B2%2598%25EB%25A6%25AC%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3Djay0628&w=3840&q=75)
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);
얕은 복사 예시
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);
문제 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);
문제 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);
전체 결과
[{"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}동적으로 만들기

- 상품의 총 그룹이 몇개인지 알아야 됨
- orOption 각각이 가지고 있는 productId를 찾아서 distinct해야 됨 → hashset 쓰면 됨
- pId가 1인거 - 1, 1 / pId가 2인거 - 2


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