WEB JAVA SPRING/PROJECT

10. 장바구니 담기

sshhhh 2023. 9. 12. 17:06

장바구니 담기
장바구니 목록에서 주문하기

 

 

 

 

 

1.CartItemDto

/**
 * 상품 상세 페이지에서 장바구니에 담을 상품 아이디와 수량 전달받음
 */

package com.shop.dto;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;


@Getter @Setter
public class CartItemDto {

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

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

 

 

 

2.Cart

/*
 회원 한명당 1개의 장바구니를 가지므로
 처음 장바구니에 상품을 담을 때는 해당 회원의 장바구니를 생성할 것
 회원 엔티티를 파라미터로 받아서 장바구니 엔티티 생성
 */

public  static Cart createCart (Member member){
    Cart cart = new Cart();
    cart.setMember(member);
    return cart;
}

 

 

 

3.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 엔티티 찾음

Cart findByMemberId(Long memberID);

 

 

 

5.CartService

/**
 * 장바구니에 상품 담기
 */

@Service
@RequiredArgsConstructor
@Transactional
public class CartService {

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

    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 saveCartItem = //현재 상품이 장바구니에 이미 들어가있는지 조회
                cartItemRepository.findByCartIdAndItemId(cart.getId(), item.getId());

        if (saveCartItem != null) {//장바구니에 이미 있다면
            saveCartItem.addCount(cartItemDto.getCount()); //기존 수량에 현재 장바구니에 담을 수량만큼 더함
            return saveCartItem.getId();
        } else {//없다면
            //장바구니,상품엔티티,장바구니에 담을 수량을 이용해 CartItem 엔티티 생성
            CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
            cartItemRepository.save(cartItem); //장바구니에 들어갈 상품 저장

            return cartItem.getId();
        }

    }

 

 

 

 

 

6.CartController

//장바구니 관련 요청 처리

@Controller
@RequiredArgsConstructor
public class CartController {

    private final CartService cartService;

    @PostMapping(value = "/cart")
    public @ResponseBody
    ResponseEntity order(@RequestBody @Valid CartItemDto cartItemDto,
                         BindingResult bindingResult, Principal principal){ //Principal: 시큐리티,시스템을 사용하고자하는 사용자

        //CartItemDto 객체에 데이터 바인딩시 에러가 있는지 검사
        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); //결과값으로 생성된 장바구니 상품아이디와 요청이 성공했다는 http응답상태코드 반환
    }

 

 


itemDtl.html

//장바구니
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);
            }

        }
    });
}

 

 

<div th:if="${item.itemSellStatus == T(com.shop.constant.ItemSellStatus).SELL}" class="text-right">
    <button type="button" class="btn btn-light border border-primary btn-lg" onclick="addCart()">장바구니 담기</button>
    <button type="button" class="btn btn-primary btn-lg" onclick="order()">주문하기</button>
</div>

 

CartList.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layouts/layout1}">

<head>
    <meta name="_csrf" th:content="${_csrf.token}"/>
    <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>

<!-- 사용자 스크립트 추가 -->
<th:block layout:fragment="script">

    <script th:inline="javascript">

        $(document).ready(function(){ //주문할 상품 체크,해제
            $("input[name=cartChkBox]").change( function(){
                getOrderTotalPrice();
            });
        });


        function getOrderTotalPrice(){ //총주문 금액 구하기
            var orderTotalPrice = 0;
            $("input[name=cartChkBox]:checked").each(function() {
                var cartItemId = $(this).val();
                var price = $("#price_" + cartItemId).attr("data-price");
                var count = $("#count_" + cartItemId).val();
                orderTotalPrice += price*count; //가격*수량
            });

            $("#orderTotalPrice").html(orderTotalPrice+'원');
        }

        function changeCount(obj){ //수량변경시 상품금액 변경
            var count = obj.value;
            var cartItemId = obj.id.split('_')[1];
            var price = $("#price_" + cartItemId).data("price");
            var totalPrice = count*price;
            $("#totalPrice_" + cartItemId).html(totalPrice+"원");
            getOrderTotalPrice();
            updateCartItemCount(cartItemId, count);
        }

        function checkAll(){ //전체 체크,해제
            if($("#checkall").prop("checked")){
                $("input[name=cartChkBox]").prop("checked",true);
            }else{
                $("input[name=cartChkBox]").prop("checked",false);
            }
            getOrderTotalPrice();
        }

        function updateCartItemCount(cartItemId, count){
            var token = $("meta[name='_csrf']").attr("content");
            var header = $("meta[name='_csrf_header']").attr("content");

            var url = "/cartItem/" + cartItemId+"?count=" + count;

            $.ajax({
                url      : url,
                type     : "PATCH", //부분업데이트
                beforeSend : function(xhr){
                    /* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
                    xhr.setRequestHeader(header, token);
                },
                dataType : "json",
                cache   : false,
                success  : function(result, status){
                    console.log("cartItem count update success");
                },
                error : function(jqXHR, status, error){

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

                }
            });
        }

        function deleteCartItem(obj){
            var cartItemId = obj.dataset.id;
            var token = $("meta[name='_csrf']").attr("content");
            var header = $("meta[name='_csrf_header']").attr("content");

            var url = "/cartItem/" + cartItemId;

            $.ajax({
                url      : url,
                type     : "DELETE",
                beforeSend : function(xhr){
                    /* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
                    xhr.setRequestHeader(header, token);
                },
                dataType : "json",
                cache   : false,
                success  : function(result, status){
                    location.href='/cart';
                },
                error : function(jqXHR, status, error){

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

                }
            });
        }

        function orders(){
            var token = $("meta[name='_csrf']").attr("content");
            var header = $("meta[name='_csrf_header']").attr("content");

            var url = "/cart/orders";

            var dataList = new Array();
            var paramData = new Object();

            $("input[name=cartChkBox]:checked").each(function() {
                var cartItemId = $(this).val();
                var data = new Object();
                data["cartItemId"] = cartItemId;
                dataList.push(data);
            });

            paramData['cartOrderDtoList'] = dataList;

            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='/orders';
                },
                error : function(jqXHR, status, error){

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

                }
            });
        }

    </script>

</th:block>

<!-- 사용자 CSS 추가 -->
<th:block layout:fragment="css">
    <style>
        .content-mg{
            margin-left:25%;
            margin-right:25%;
            margin-top:2%;
            margin-bottom:100px;
        }
        .repImgDiv{
            margin-right:15px;
            margin-left:15px;
            height:auto;
        }
        .repImg{
            height:100px;
            width:100px;
        }
        .fs18{
            font-size:18px
        }
        .fs24{
            font-size:24px
        }
    </style>
</th:block>

<div layout:fragment="content" class="content-mg">

    <h2 class="mb-4">
        장바구니 목록
    </h2>

    <div>

        <table class="table">
            <colgroup>
                <col width="15%"/>
                <col width="70%"/>
                <col width="15%"/>
            </colgroup>
            <thead>
            <tr class="text-center">
                <td>
                    <input type="checkbox" id="checkall" onclick="checkAll()"> 전체선택
                </td>
                <td>상품정보</td>
                <td>상품금액</td>
            </tr>
            </thead>
            <tbody>
            <tr th:each="cartItem : ${cartItems}">
                <td class="text-center align-middle">
                    <input type="checkbox" name="cartChkBox" th:value="${cartItem.cartItemId}">
                </td>
                <td class="d-flex">
                    <div class="repImgDiv align-self-center">
                        <img th:src="${cartItem.imgUrl}" class = "rounded repImg" th:alt="${cartItem.itemNm}">
                    </div>
                    <div class="align-self-center">
                        <span th:text="${cartItem.itemNm}" class="fs24 font-weight-bold"></span>
                        <div class="fs18 font-weight-light">
                            <span class="input-group mt-2">
                                <span th:id="'price_' + ${cartItem.cartItemId}"
                                      th:data-price="${cartItem.price}"
                                      th:text="${cartItem.price} + '원'" class="align-self-center mr-2">
                                </span>
                                <input type="number" name="count" th:id="'count_' + ${cartItem.cartItemId}"
                                       th:value="${cartItem.count}" min="1"
                                       onchange="changeCount(this)" class="form-control mr-2" >
                                <button type="button" class="close" aria-label="Close">
                                    <span aria-hidden="true" th:data-id="${cartItem.cartItemId}" onclick="deleteCartItem(this)">&times;</span>
                                </button>
                            </span>
                        </div>
                    </div>
                </td>
                <td class="text-center align-middle">
                    <span th:id="'totalPrice_' + ${cartItem.cartItemId}"
                          name="totalPrice" th:text="${cartItem.price * cartItem.count} + '원'">
                    </span>
                </td>
            </tr>
            </tbody>
        </table>

        <h2 class="text-center">
            총 주문 금액 : <span id="orderTotalPrice" class="text-danger">0원</span>
        </h2>

        <div class="text-center mt-3">
            <button type="button" class="btn btn-primary btn-lg" onclick="orders()">주문하기</button>
        </div>

    </div>

</div>

</html>