** 미리 방지 **
Order와 OrderItem Entity를 구현하고 실행하는데 에러가 났습니다.
[SQL Error] you have an error in your SQL Syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' order
간단한 에러였지만 실수할 수 있으니 주의해야겠습니다!!
오늘은 상품 주문 기능에 대해 다뤄보겠습니다. 상품 주문은 장바구니에서 할 수 있고 상품 상세 페이지에서 바로 구매할 수도 있습니다!
먼저 장바구니 상품 주문을 보겠습니다.
1. Order Entity와 OrderItem Entity를 생성합니다.
< Order >
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "orders")
public class Order {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;
  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "user_id")
  private User user; // 구매자
  @OneToMany(mappedBy = "order")
  private List<OrderItem> orderItems = new ArrayList<>();
  @DateTimeFormat(pattern = "yyyy-mm-dd")
  private LocalDate createDate; // 구매 날짜
  @PrePersist
  public void createDate() {
      this.createDate = LocalDate.now();
  }
  public void addOrderItem(OrderItem orderItem) {
      orderItems.add(orderItem);
      orderItem.setOrder(this);
  }
  public static Order createOrder(User user, List<OrderItem> orderItemList) {
      Order order = new Order();
      order.setUser(user);
      for (OrderItem orderItem : orderItemList) {
          order.addOrderItem(orderItem);
      }
      order.setCreateDate(order.createDate);
      return order;
  }
  public static Order createOrder(User user) {
      Order order = new Order();
      order.setUser(user);
      order.setCreateDate(order.createDate);
      return order;
  }
}
< OrderItem >
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="order_id")
    private Order order;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user; // 구매자
    private int itemId; // 주문 상품 번호
    private String itemName; // 주문 상품 이름
    private int itemPrice; // 주문 상품 가격
    private int itemCount; // 주문 상품 수량
    private int itemTotalPrice; // 가격*수량
    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="saleItem_id")
    private SaleItem saleItem; // 주문상품에 매핑되는 판매상품
    private int isCancel; // 주문 취소 여부 (0:주문완료 / 1:주문취소)
    // 장바구니 전체 주문
    public static OrderItem createOrderItem(int itemId, User user, CartItem cartItem, SaleItem saleItem) {
        OrderItem orderItem = new OrderItem();
        orderItem.setItemId(itemId);
        orderItem.setUser(user);
        orderItem.setItemName(cartItem.getItem().getName());
        orderItem.setItemPrice(cartItem.getItem().getPrice());
        orderItem.setItemCount(cartItem.getCount());
        orderItem.setItemTotalPrice(cartItem.getItem().getPrice()*cartItem.getCount());
        orderItem.setSaleItem(saleItem);
        return orderItem;
    }
    // 상품 개별 주문
    public static OrderItem createOrderItem(int itemId, User user, Item item, int count, Order order, SaleItem saleItem) {
        OrderItem orderItem = new OrderItem();
        orderItem.setItemId(itemId);
        orderItem.setUser(user);
        orderItem.setOrder(order);
        orderItem.setItemName(item.getName());
        orderItem.setItemPrice(item.getPrice());
        orderItem.setItemCount(count);
        orderItem.setItemTotalPrice(item.getPrice()*count);
        orderItem.setSaleItem(saleItem);
        return orderItem;
    }
}
2. Sale Entity와 SaleItem Entity를 생성합니다.
< Sale >
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class Sale {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="seller_id")
    private User seller; // 판매자
    @OneToMany(mappedBy = "sale")
    private List<SaleItem> saleItems = new ArrayList<>();
    private int totalCount; // 총 판매 개수
    public static Sale createSale(User seller) {
        Sale sale = new Sale();
        sale.setSeller(seller);
        sale.setTotalCount(0);
        return sale;
    }
}
< SaleItem >
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
public class SaleItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="sale_id")
    private Sale sale;
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "seller_id")
    private User seller; // 판매자
    private int itemId; // 주문 상품 번호
    private String itemName; // 주문 상품 이름
    private int itemPrice; // 주문 상품 가격
    private int itemCount; // 주문 상품 수량
    private int itemTotalPrice; // 가격*수량
    @OneToOne(mappedBy = "saleItem")
    private OrderItem orderItem; // 판매 상품에 매핑되는 주문 상품
    private int isCancel; // 판매 취소 여부 (0:판매완료 / 1:판매취소)
    @DateTimeFormat(pattern = "yyyy-mm-dd")
    private LocalDate createDate; // 날짜
    @PrePersist
    public void createDate(){
        this.createDate = LocalDate.now();
    }
    // 장바구니 전체 주문
    public static SaleItem createSaleItem(int itemId, Sale sale, User seller, CartItem cartItem) {
        SaleItem saleItem = new SaleItem();
        saleItem.setItemId(itemId);
        saleItem.setSale(sale);
        saleItem.setSeller(seller);
        saleItem.setItemName(cartItem.getItem().getName());
        saleItem.setItemPrice(cartItem.getItem().getPrice());
        saleItem.setItemCount(cartItem.getCount());
        saleItem.setItemTotalPrice(cartItem.getItem().getPrice()*cartItem.getCount());
        return saleItem;
    }
    // 상품 개별 주문
    public static SaleItem createSaleItem(int itemId, Sale sale, User seller, Item item, int count) {
        SaleItem saleItem = new SaleItem();
        saleItem.setItemId(itemId);
        saleItem.setSale(sale);
        saleItem.setSeller(seller);
        saleItem.setItemName(item.getName());
        saleItem.setItemPrice(item.getPrice());
        saleItem.setItemCount(count);
        saleItem.setItemTotalPrice(item.getPrice()*count);
        return saleItem;
    }
}
3. userCart.html 에서 구매 버튼을 생성합니다.
4. Controller에서 POST 처리를 합니다.
    // 장바구니 상품 전체 주문
    @Transactional
    @PostMapping("/user/cart/checkout/{id}")
    public String cartCheckout(@PathVariable("id") Integer id, @AuthenticationPrincipal PrincipalDetails principalDetails, Model model) {
        // 로그인이 되어있는 유저의 id와 주문하는 id가 같아야 함
        if(principalDetails.getUser().getId() == id) {
            User user = userPageService.findUser(id);
            // 유저 카트 찾기
            Cart userCart = cartService.findUserCart(user.getId());
            // 유저 카트 안에 있는 상품들
            List<CartItem> userCartItems = cartService.allUserCartView(userCart);
            // 최종 결제 금액
            int totalPrice = 0;
            for (CartItem cartItem : userCartItems) {
                // 장바구니 안에 있는 상품의 재고가 없거나 재고보다 많이 주문할 경우
                if (cartItem.getItem().getStock() == 0 || cartItem.getItem().getStock() < cartItem.getCount()) {
                    return "redirect:/main";
                }
                totalPrice += cartItem.getCount() * cartItem.getItem().getPrice();
            }
            int userCoin = user.getCoin();
            // 유저의 현재 잔액이 부족하다면
            if (userCoin < totalPrice) {
                return "redirect:/main";
            } else {
                // 유저 돈에서 최종 결제금액 빼야함
                user.setCoin(user.getCoin() - totalPrice);
                List<OrderItem> orderItemList = new ArrayList<>();
                for (CartItem cartItem : userCartItems) {
                    // 각 상품에 대한 판매자
                    User seller = cartItem.getItem().getSeller();
                    // 판매자 수익 증가
                    seller.setCoin(seller.getCoin() + (cartItem.getCount() * cartItem.getItem().getPrice()));
                    // 재고 감소
                    cartItem.getItem().setStock(cartItem.getItem().getStock() - cartItem.getCount());
                    // 상품 개별로 판매 개수 증가
                    cartItem.getItem().setCount(cartItem.getItem().getCount() + cartItem.getCount());
                    // sale, saleItem 에 담기
                    SaleItem saleItem = saleService.addSale(cartItem.getItem().getId(), seller.getId(), cartItem);
                    // order, orderItem 에 담기
                    OrderItem orderItem = orderService.addCartOrder(cartItem.getItem().getId(), user.getId(), cartItem, saleItem);
                    orderItemList.add(orderItem);
                }
                orderService.addOrder(user, orderItemList);
                // 장바구니 상품 모두 삭제
                cartService.allCartItemDelete(id);
            }
            model.addAttribute("totalPrice", totalPrice);
            model.addAttribute("cartItems", userCartItems);
            model.addAttribute("user", userPageService.findUser(id));
            return "redirect:/user/cart/{id}";
        } else {
            return "redirect:/main";
        }
    }
5. cartService, orderService, saleService에서 로직을 각각 구현합니다.
< cartService >
    // 장바구니 아이템 전체 삭제 -> 매개변수는 유저 id
    public void allCartItemDelete(int id) {
        // 전체 cartItem 찾기
        List<CartItem> cartItems = cartItemRepository.findAll();
        // 반복문을 이용하여 해당하는 User 의 CartItem 만 찾아서 삭제
        for(CartItem cartItem : cartItems){
            if(cartItem.getCart().getUser().getId() == id) {
                cartItem.getCart().setCount(0);
                cartItemRepository.deleteById(cartItem.getId());
            }
        }
    }
< orderService >
    // 장바구니상품주문
    @Transactional
    public OrderItem addCartOrder(int itemId, int userId, CartItem cartItem, SaleItem saleItem) {
        User user = userPageService.findUser(userId);
        OrderItem orderItem = OrderItem.createOrderItem(itemId, user, cartItem, saleItem);
        orderItemRepository.save(orderItem);
        return orderItem;
    }
< saleService >
    // 판매내역에 저장 (장바구니 전체 주문)
    @Transactional
    public SaleItem addSale (int itemId, int sellerId, CartItem cartItem) {
        User seller = userPageService.findUser(sellerId);
        Sale sale = saleRepository.findBySellerId(sellerId);
        sale.setTotalCount(sale.getTotalCount()+cartItem.getCount());
        saleRepository.save(sale);
        SaleItem saleItem = SaleItem.createSaleItem(itemId, sale, seller, cartItem);
        saleItemRepository.save(saleItem);
        return saleItem;
    }
이렇게 하면 장바구니의 상품 주문이 성공적으로 끝납니다!!
구매자는 이제 다양한 상품을 장바구니에 담아놓고, 한 번에 주문 할 수 있습니다!