코드 그라데이션
shop 구현 (17) 장바구니에서 상품 주문하기 본문
@PostMapping(value = "/cart/orders")
public @ResponseBody ResponseEntity orderCartItem(@RequestBody CartOrderDto cartOrderDto, Principal principal){
System.out.println(cartOrderDto.getCartItemId());
List<CartOrderDto> cartOrderDtoList = cartOrderDto.getCartOrderDtoList();
if(cartOrderDtoList == null || cartOrderDtoList.size() == 0){ // 카트 주문 상품이 없으면 실행
return new ResponseEntity<String>("주문할 상품을 선택해주세요.",HttpStatus.FORBIDDEN);
}
for(CartOrderDto cartOrder : cartOrderDtoList){ //Cart에 담긴 item 시킬 수 있는 권한이 있는지 확인
if(!cartService.validateCartItem(cartOrder.getCartItemId(), principal.getName())){
return new ResponseEntity<String>("주문 권한이 없습니다.",HttpStatus.FORBIDDEN);
}
}
Long orderId = cartService.orderCartItem(cartOrderDtoList, principal.getName());
return new ResponseEntity<Long>(orderId,HttpStatus.OK);
}
이건 장바구니에 있는 아이템을 조회하는 메서드
DTO를 받아서 DTO를 검증.
Long orderId = cartService.orderCartItem(cartOrderDtoList, principal.getName()); 요기가 사실상 주문 로직.
원래 검증은 @Valid, BindingResult, if문 @Max/@Min 같은 4가지 조합으로 했는데, 왜 여기 (DTO 검증로직)에서는 if문만 가지고 하는가?
사실 일관성을 이용해서 전자의 방법을 사용하는 게 논리적으로는 맞다.
Valid로 하는 게 한계가 있다.
=> 어노테이션으로 표현할 수 있는 부분만 할 수 있다.
예를 들면 검색기능에서 날짜를,
startDate를 2023년 10월 10일, endDate를 2022년 10월 10일로 해놔버렸으면.
잘못 설정한 것.(선후관계 나타내는 경우)
아니면 검증 로직을 반드시 남겨야 하는 상황인 경우
어노테이션으로 하기에는 빈 틈이 존재한다.
역할을 최대한 분리하는 게 좋다고 했다.
즉, if(cartOrderDtoList == null || cartOrderDtoList.size() == 0){ // 카트 주문 상품이 없으면 실행
return new ResponseEntity<String>("주문할 상품을 선택해주세요.",HttpStatus.FORBIDDEN);
}
for(CartOrderDto cartOrder : cartOrderDtoList){ //Cart에 담긴 item 시킬 수 있는 권한이 있는지 확인
if(!cartService.validateCartItem(cartOrder.getCartItemId(), principal.getName())){
return new ResponseEntity<String>("주문 권한이 없습니다.",HttpStatus.FORBIDDEN);
}
이 검증 로직도 여기에 붙여놓는 게 아니라 다른 곳에 만들어놓고, 불러다 쓰게 만드는 게 더 맞다.
검증도 여러번 다양한 곳에서 쓸 것이니 반복
서비스 부분 코드
public Long orderCartItem(List<CartOrderDto> cartOrderDtoList, String email){
List<OrderDto> orderDtoList = new ArrayList<>();
for(CartOrderDto cartOrderDto : cartOrderDtoList){
CartItem cartItem = cartItemRepository.findById(cartOrderDto.getCartItemId())
.orElseThrow(EntityExistsException::new); //카트 아이템을 추출
OrderDto orderDto = new OrderDto(); // 주문 객체생성
orderDto.setItemId(cartItem.getItem().getId());
orderDto.setCount(cartItem.getCount());
orderDtoList.add(orderDto); // 주문리스트 추가
}
Long orderId = orderService.orders(orderDtoList, email); //주문 실행
for(CartOrderDto cartOrderDto : cartOrderDtoList){
CartItem cartItem = cartItemRepository.findById(cartOrderDto.getCartItemId())
.orElseThrow(EntityExistsException::new);
cartItemRepository.delete(cartItem); // 카트에 있는 상품 지웁니다.
}
return orderId;
}
카트 오더 디티오로부터 오더 디티오를 만들려고 하는 상황
Long orderId = orderService.orders(orderDtoList, email); //주문 실행
이걸 보면 주문을 장바구니에서 하나, 상품페이지에서 하나 동일한 주문
이건 결국 내가 얼마나 order를 다른데 불필요하게 의존하지 않고 가져다 쓸 수 있느냐.
어디서 오든 형식만 맞춰줘서 처리하게 만들면 된다는 이야기.
이렇게 설계를 하는게 order는 변하지 않으니까 일관성을 유지할 수 있다는 장점.
주문은 카트가 들어갈 필요가 없고, order만 들어가면 된다.
주문 완료 이후에
cartItemRepository.delete(cartItem); // 카트에 있는 상품 지웁니다.
그런데 주문 완료되고 그 아이템을 제거하는 과정에서 예외가 발생하면?
트랜잭션이 어노테이션으로 달려 있으므로 위 코드 전체가 롤백이 되면서, 주문이 안 된 상태로 들어가게 되고, 그대로 남아있는다.
아까 봤듯이 예외 발생하지 않게 처리하려면
cartItemRepository.deleteById(cartId); 하면 된다.
public Long orders(List<OrderDto> orderDtoList, String email){
Member member = memberRepository.findByEmail(email);
List<OrderItem> orderItemList = new ArrayList<>(); //주문상품리스트 객체 생성
for(OrderDto orderDto : orderDtoList){
Item item = itemRepository.findById(orderDto.getItemId()).orElseThrow(EntityNotFoundException::new);
OrderItem orderItem = OrderItem.createOrderItem(item,orderDto.getCount());
orderItemList.add(orderItem); 주문상품리스트에 추가
}
Order order = Order.createOrder(member, orderItemList); // 주문 생성
orderRepository.save(order); // order 데이터베이스에 적재
return order.getId();
}
이거 왜 필요하는지는 잘 모르겠다.
굳이 바꾸자면
List<OrderItem> orderItemList = new ArrayList<>(); //주문상품리스트 객체 생성
여기서 계속 새로 객체를 만들지 말고, 만드는 역할을 따로 밖에서 하고,
여기서는
orders(List<OrderItem> orderItems, String email) {}
이렇게 디자인하는게 낫다.
이렇게 되면 다 밖에서 해주는 것이므로, order나 orders나 분리할 필요가 없다.
'Spring > SpringShop' 카테고리의 다른 글
shop 구현 (18) 상품 삭제하기 (0) | 2023.07.25 |
---|---|
shop 구현 (16) 장바구니 담기, 장바구니에 내역 조회 (0) | 2023.07.24 |
shop 구현 (15) 주문 취소하기 (0) | 2023.07.22 |
shop 구현 (14) 주문 이력 조회 (0) | 2023.07.22 |
shop 구현 (13) 주문 기능 구현 (0) | 2023.07.21 |