Jin's Dev Story

[스프링 부트 쇼핑몰 프로젝트 with JPA] 14. 장바구니 담기 본문

Web & Android/스프링 부트 쇼핑몰 프로젝트 with JPA

[스프링 부트 쇼핑몰 프로젝트 with JPA] 14. 장바구니 담기

woojin._. 2023. 10. 16. 20:00
이 내용은 스프링 부트 쇼핑몰 프로젝트 with JPA 책을 학습한 내용입니다.

1. CartItemDto

  • 제품 상세 페이지에서 장바구니에 담을 상품 Id 와 수량을 전달 받을 DTO 객체 생성
@Getter
@Setter
public class CartItemDto {

    @NotNull(message = "상품 아이디는 필수 입력 값입니다.")
    private Long itemId;  // 상품 아이디

    @Min(value = 1, message = "최소 1개 이상 담아주세요.")
    private int count;  // 상품 수량

}

2. Cart Entity

  • 회원 한 명당 1개의 장바구니를 갖으므로 처음 장바구니에 상품을 담을 때는 해당 회원의 장바구니를 생성해야함
  • 멤버를 파라미터로 받아서 장바구니를 생성하는 static 메소드 추가
// 회원의 장바구니 생성
    public static Cart createCart(Member member) {
        Cart cart = new Cart();
        cart.setMember(member);

        return cart;
    }

3. CartItem Entity

  • 장바구니에 담을 CartItem 객체를 생성하는 메소드 추가
  • 장바구니에 담겨 있는 상품을 또 장바구니로 담았을 경우 수량을 증가시키는 메소드 추가
// 장바구니에 담을 상품 엔티티를 생성하는 메소드
    public static  CartItem createCartItem(Cart cart, Item item, int count) {
        CartItem cartItem = new CartItem();
        cartItem.setCart(cart);
        cartItem.setItem(item);
        cartItem.setCount(count);

        return cartItem;
    }

    // 장바구니에 담을 수량을 증가시켜 주는 메소드
    public void addCount(int count) {
        this.count += count;
    }

4. CartRepository

  • 현재 로그인한 유저의 장바구니(Cart)를 찾기 위해서 쿼리 메소드 추가
public interface CartRepository extends JpaRepository<Cart, Long> {

    // 현재 로그인한 회원의 Cart 엔티티를 찾기 위한 메소드
    Cart findByMemberId(Long memberId);

}

5. CartItemRepository

  • 상품이 장바구니에 들어있는지 조회하는 쿼리 메소드 추가
public interface CartItemRepository extends JpaRepository<CartItem, Long> {
    CartItem findByCartIdAndItemId(Long cartId, Long itemId);
}

6. CartService 생성

  • 유저의 장바구니가 존재하지 않다면 생성
  • 장바구니 안에 해당 상품이 존재한다면 수량을 증가시키고, 그렇지 않다면 추가
@Service
@RequiredArgsConstructor
@Transactional
public class CartService {

    private final ItemRepository itemRepository;
    private final MemberRepository memberRepository;
    private final CartRepository cartRepository;
    private final CartItemRepository cartItemRepository;
    private final OrderService orderService;

    public Long addCart(CartItemDto cartItemDto, String email) {
        Item item = itemRepository.findById(cartItemDto.getItemId()).orElseThrow(EntityNotFoundException::new);
        Member member = memberRepository.findByEmail(email);

        Cart cart = cartRepository.findByMemberId(member.getId());
        if(cart == null) {
            cart = Cart.createCart(member);
            cartRepository.save(cart);
        }

        CartItem savedCartItem = cartItemRepository.findByCartIdAndItemId(cart.getId(), item.getId());

        if(savedCartItem != null) {
            savedCartItem.addCount(cartItemDto.getCount());
            return savedCartItem.getId();
        } else {
            CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
            cartItemRepository.save(cartItem);

            return cartItem.getId();
        }
    }

7. CartController 생성

  • 제품 상세 페이지에서 넘어온 CartItemDto 객체와 email 을 파라미터로 CartService.addCart() 메소드를 수행
@Controller
@RequiredArgsConstructor
public class CartController {

    private final CartService cartService;

    @PostMapping("/cart")
    public @ResponseBody ResponseEntity order(@RequestBody @Valid CartItemDto cartItemDto, BindingResult bindingResult, Principal principal) {

        if(bindingResult.hasErrors()) {
            StringBuilder sb = new StringBuilder();
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            for(FieldError fieldError : fieldErrors) {
                sb.append(fieldError.getDefaultMessage());
            }
            return new ResponseEntity<String> (sb.toString(), HttpStatus.BAD_REQUEST);
        }

        String email = principal.getName();
        Long cartItemId;

        try {
            cartItemId = cartService.addCart(cartItemDto, email);
        } catch (Exception e) {
            return new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);
    }

8. 제품 상세 페이지 장바구니 담기

  • "장바구니 담기" 버튼을 누르면 수행되는 Ajax 코드
function addCart(){
      var token = $("meta[name='_csrf']").attr("content");
      var header = $("meta[name='_csrf_header']").attr("content");

      var url = "/cart";
      var paramData = {
        itemId : $("#itemId").val(),
        count : $("#count").val()
      };

      var param = JSON.stringify(paramData);

      $.ajax({
        url      : url,
        type     : "POST",
        contentType : "application/json",
        data     : param,
        beforeSend : function(xhr){
          /* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
          xhr.setRequestHeader(header, token);
        },
        dataType : "json",
        cache   : false,
        success  : function(result, status){
          alert("상품을 장바구니에 담았습니다.");
          location.href='/';
        },
        error : function(jqXHR, status, error){

          if(jqXHR.status == '401'){
            alert('로그인 후 이용해주세요');
            location.href='/members/login';
          } else{
            alert(jqXHR.responseText);
          }

        }
      });
    }
  • "장바구니 담기" 버튼을 누르면 Ajax 코드 수행되게 설정
<button type="button" class="btn btn-light border border-primary btn-lg" onclick="addCart()">장바구니 담기</button>