[Spring Boot 쇼핑몰] CRUD - User 클래스 ② - 장바구니 구현

개발자·2022년 1월 31일

Spring boot 쇼핑몰

목록 보기
9/14

이번에는 구매자의 기능을 구현해보려고 한다

장바구니 ( Cart ) 를 구현해 보려고 한다. 초기 설계를 다시보겠다.

장바구니를 구현하기 위해서 다음을 고려하였다.

  • Cart Entity, Cart_item Entity 생성
  • 한명의 User 가 한개의 Cart를 가지는 OneToOne Mapping
  • 한개의 Cart에 여러개의 Cart_item이 들어가는 OneToMany Mapping
  • 한개의 item이 여러개의 Cart_item에 들어가는 OneToMany Mapping

1. Entity 설계

  • domain 패키지 안에 cart와 cart_item 패키지를 생성

Cart.java

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Cart {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private int count; // 카트에 담긴 상품 개수

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="user_id")
    User user;

    @OneToMany(fetch = FetchType.EAGER)
    private List<Cart_item> cart_items = new ArrayList<>();

    @DateTimeFormat(pattern = "yyyy-mm-dd")
    private LocalDate createDate; // 날짜

    @PrePersist
    public void createDate(){
        this.createDate = LocalDate.now();
    }

    public static Cart createCart(User user){
        Cart cart = new Cart();
        cart.user = user;
        cart.count = 0;

        return cart;
    }

CartRepository.java

@Repository
public interface CartRepository extends JpaRepository<Cart,Integer> {
    Cart findByUserId(int userId);
}

Cart_item.java

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Entity
public class Cart_item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="cart_id")
    private Cart cart;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="item_id")
    private Item item;

    private int count; // 카트에 담긴 상품 개수


    @DateTimeFormat(pattern = "yyyy-mm-dd")
    private LocalDate createDate; // 날짜

    @PrePersist // DB에 INSERT 되기 직전에 실행. 즉 DB에 값을 넣으면 자동으로 실행됨
    public void createDate() {
        this.createDate = LocalDate.now();
    }

    public static Cart_item createCartItem(Cart cart,Item item,int count){
        Cart_item cartItem = new Cart_item();
        cartItem.setCart(cart);
        cartItem.setItem(item);
        cartItem.setCount(count);

        return cartItem;
    }

    public void addCount(int count){
        this.count += count;
    }
}

Cart_itemRepository.java

public interface Cart_itemRepository extends JpaRepository<Cart_item,Integer> {
    Cart_item findByCartIdAndItemId(int cartId, long itemId);
}

2. Service 설계

장바구니의 수행기능은 다음과 같다

  • User에게 장바구니 생성

  • 장바구니에 Item 추가하기

  • 장바구니 조회하기

  • 장바구니 Item 삭제하기

  • 장바구니 결제하기

CartService.java

User에게 장바구니 생성

public void createCart(User user){
        Cart cart = Cart.createCart(user);
        cartRepository.save(cart);
    }

장바구니에 Item 추가하기

@Transactional
    public void addCart(User user, Item item, int count){

        Cart cart = cartRepository.findByUserId(user.getId());

        // cart 가 비어있다면 생성.
        if(cart == null){
            cart = Cart.createCart(user);
            cartRepository.save(cart);
        }

        // cart_item 생성
        Cart_item cart_item = cart_itemRepository.findByCartIdAndItemId(cart.getId(),item.getId());

        // cart_item이 비어있다면 새로 생성.
        if(cart_item == null){
            cart_item = Cart_item.createCartItem(cart,item,count);
            cart_itemRepository.save(cart_item);
            cart.setCount(cart.getCount() + 1);
        }else{
            // 비어있지 않다면 그만큼 갯수를 추가.
            cart_item.addCount(count);
        }

    }

장바구니 조회하기

public List<Cart_item> userCartView(Cart cart){
        List<Cart_item> cart_items = cart_itemRepository.findAll();
        List<Cart_item> user_items = new ArrayList<>();

        for(Cart_item cart_item : cart_items){
            if(cart_item.getCart().getId() == cart.getId()){
                user_items.add(cart_item);
            }
        }

        return user_items;
    }

장바구니 Item 삭제하기

public void cartItemDelete(int id){
        cart_itemRepository.deleteById(id);
    }
    

장바구니 Item 전체삭제

public void cartDelete(int id){
        List<Cart_item> cart_items = cart_itemRepository.findAll(); // 전체 cart_item 찾기

        // 반복문을 이용하여 접속 User의 Cart_item 만 찾아서 삭제
        for(Cart_item cart_item : cart_items){
            if(cart_item.getCart().getUser().getId() == id){
                cart_item.getCart().setCount(cart_item.getCart().getCount() - 1);
                cart_itemRepository.deleteById(cart_item.getId());
            }
        }
    }

장바구니 결제하기

@Transactional
    public void cartPayment(int id){
        List<Cart_item> cart_items = cart_itemRepository.findAll(); // 전체 cart_item 찾기
        List<Cart_item> userCart_items = new ArrayList<>();
        User buyer = userRepository.findById(id).get();

        // 반복문을 이용하여 접속 User의 Cart_item만 찾아서 저장
        for(Cart_item cart_item : cart_items){
            if(cart_item.getCart().getUser().getId() == buyer.getId()){
                userCart_items.add(cart_item);
            }
        }

        // 반복문을 이용하여 접속 User의 Cart_item 만 찾아서 삭제
        for(Cart_item cart_item : userCart_items){
            // 재고 변경
            int stock = cart_item.getItem().getStock(); // 현재 재고를 변수에 저장
            stock = stock - cart_item.getCount(); // 저장된 변수를 결제한 갯수만큼 빼준다
            cart_item.getItem().setStock(stock); // 재고갯수 변경

            // 금액 처리
            User seller = cart_item.getItem().getUser();
            int cash = cart_item.getItem().getPrice(); // 아이템 가격을 변수에 저장
            buyer.setMoney(cash * -1);
            seller.setMoney(cash);
        }
    }

3. Controller 설계

Cart 또한 User의 기능중 하나이므로 UserPageController.java에 추가하여 구현하도록 하였다.

Service에서 설계한 기능인 5가지 기능을 View 단계에서 처리하도록한다.

UserPageController.java

내 장바구니 조회

    @GetMapping("/user/{id}/cart")
    public String myCartPage(@PathVariable("id") Integer id,Model model,@AuthenticationPrincipal PrincipalDetails principalDetails){
        // 로그인 User == 접속 User
        if(principalDetails.getUser().getId() == id){
            // User의 장바구니를 가져온다.
            Cart cart = principalDetails.getUser().getCart();
            // 장바구니의 아이템을 가져온다.

            List<Cart_item> cart_items = cartService.userCartView(cart);

            int totalPrice = 0;
            for(Cart_item cart_item : cart_items){
                totalPrice += ( cart_item.getItem().getPrice() * cart_item.getCount());
            }

            model.addAttribute("cart_itemList",cart_items);
            model.addAttribute("totalPrice",totalPrice);
            model.addAttribute("user",userPageService.findUser(id));

            return "/cart/cart";
        }else{
            return "redirect:/main";
        }
    }

특정 상품 장바구니에 추가

@PostMapping("/user/{id}/cart/{itemId}")
    public String myCartAdd(@PathVariable("id") Integer id,@PathVariable("itemId") Long itemId,int count){
        User user = userPageService.findUser(id);
        Item item = itemService.itemView(itemId);

        cartService.addCart(user,item,count);

        return "redirect:/item/view/{itemId}";
    }

특정 상품 장바구니에서 삭제

@GetMapping("/user/{id}/cart/{cart_itemId}/delete")
    public String myCartDelete(@PathVariable("id") Integer id, @PathVariable("cart_itemId") int cart_itemId, @AuthenticationPrincipal PrincipalDetails principalDetails){
        User user = userPageService.findUser(id);
        user.getCart().setCount(user.getCart().getCount() - 1);
        cartService.cartItemDelete(cart_itemId);

        return "redirect:/user/{id}/cart";
    }

결제 페이지

@PostMapping("/user/{id}/cart/checkout")
    public String myCartPayment(@PathVariable("id") Integer id, Model model){
        User user = userPageService.findUser(id);
        cartService.cartPayment(id); // 결제처리
        cartService.cartDelete(id); // 장바구니 비우기

        return "redirect:/main";
    }

4. View

  • 물품 담기 전
  • 물품 담은 후

5. 마무리

장바구니를 구현하면서 가장 어려웠던 점은
OneToOne, OneToMany, ManyToOne 맵핑을 하는것을 자세하게 모르는 점이었다. 이러한 점은 나중에 따로 공부하여 블로그에 올리도록 하려한다.

내가 쇼핑몰에서 사용하던 장바구니를 의외로 손쉽게 구현 할 수 있는것 같았다.
물론 FrontEnd단에서 장바구니 화면을 구현하는것이 어려웠지만 부트스트랩을 이용하여 할 수 있었다.

다음에는 장바구니를 통해 구매하기를 누르면 주문이 들어가는것을 구현하려한다.

3개의 댓글

comment-user-thumbnail
2022년 4월 1일

저 혹시 jsp도 알 수 있을까요?

2개의 답글