Spring Boot

[shop] 장바구니 구현하기2(장바구니 리스트, 수량 변경)

머리방울 2022. 10. 23. 14:58

1. 장바구니 리스트 

1) mapper

<mapper namespace="cartMapper">

<resultMap type="kh.study.shop.cart.vo.CartVO" id="cart">
<id column="CART_CODE" property="cartCode"/>
<result column="ITEM_CODE" property="itemCode"/>
<result column="MEMBER_ID" property="memberId"/>
<result column="CART_AMOUNT" property="cartAmount"/>
<result column="REG_DATE" property="regDate"/>
<result column="TOTAL_PRICE" property="totalPrice"/>

<!-- <association property="cateInfo" resultMap="adminMapper.cate"/> -->
<association property="itemList" resultMap="itemMapper.item"/>

<!-- itemVO를 가져오면 cateInfo, imgList 둘다 있기 때문에  -->
</resultMap>
<!-- 장바구니 리스트 -->
<select id="cartList" resultMap="cart">

SELECT CART_CODE
	 , S.ITEM_CODE
	 , CART_AMOUNT
	 , TO_CHAR(T.REG_DATE,'YYYY-MM-DD') AS REG_DATE
	 , TOTAL_PRICE
	 , CATE_NAME
	 , ITEM_NAME
	 , ATTACHED_NAME
	 , ITEM_PRICE
FROM ITEM_CATEGORY C, SHOP_ITEM S, ITEM_IMG G, SHOP_CART T
WHERE C.CATE_CODE = S.CATE_CODE
AND S.ITEM_CODE = T.ITEM_CODE
AND S.ITEM_CODE = G.ITEM_CODE
AND IS_MAIN = 'Y'
AND MEMBER_ID = #{memberId}
ORDER BY CART_CODE DESC

</select>
//장바구니 리스트
@Override
public List<CartVO> cartList(String memberId) {
    return sqlSession.selectList("cartMapper.cartList", memberId);
}

2. controller

장바구니 목록
@GetMapping("/cartList")
public String cartList(Authentication authentication, Model model) {

    //memberId 가져오기
    User user =  (User) authentication.getPrincipal();
    String memberId = user.getUsername();

    List<CartVO>list = cartService.cartList(memberId);
    model.addAttribute("cartList", list);

    //전체 총 가격 데이터
    int finalPrice = 0; 

    for(CartVO cart : list) {
        finalPrice = finalPrice + cart.getTotalPrice();
    }
    model.addAttribute("finalPrice", finalPrice);

    return "content/cart/cart_list";
}

3. html

<div class="row justify-content-center mt-4">
	
 <div class="col-11">

 <table class="table align-middle">
  <colgroup>
     <col width="5%">
     <col width="5%">
     <col width="15%">
     <col width="30%">
     <col width="15%">
     <col width="15%">
     <col width="15%">
  </colgroup>
  <thead>
     <tr>
        <td><input type="checkbox" id="checkAll"></td>
        <td>No</td>
        <td colspan="2">상품 정보</td>
        <td>수량</td>
        <td>가격</td>
        <td>등록일</td>
     </tr>
  </thead>
  <tbody>
   <th:block th:each="cart, status : ${cartList}">
     <tr>
        <td><input type="checkbox" class="chk" th:value="${cart.cartCode}" 
        th:data-item-code="${cart.itemList.itemCode}" checked></td>
        <td>
            <span th:text="${#lists.size(cartList) - status.index}"></span>

        </td>  <!-- 전체개수 - index -->
        <td> <img th:src="|@{/image/}${cart.itemList.imgList[0].attachedName}|" 
        width="100px" height="100px"></td>
        <td>
            [<span th:text="${cart.itemList.cateInfo.cateName}"></span>]
             <span th:text="${cart.itemList.itemName}"></span> 
        </td>
        <td>
            <div class="input-group mb-3">
              <input type="text" class="form-control amountInput" aria-describedby="button-addon2" 
              th:value="${cart.cartAmount}" th:data-origin-amount="${cart.cartAmount}">
              <button class="btn btn-outline-primary" type="submit" id="button-addon2"
              th:onclick="updateCnt(this);">변경</button>
            </div>

        </td>
        <td>
            [[${cart.itemList.itemPrice}]] * [[${cart.cartAmount}]]		      	
          <div class="totalPriceDiv" th:data-total-price ="${cart.totalPrice}">
            [[${#numbers.formatCurrency(cart.totalPrice)}]]
          </div>
        </td>
        <td th:text="${cart.regDate}"></td>
     </tr>
 </th:block>
  </tbody>
 </table>
     
     <div class="row mt-4" >
      <div class="col mb-3">
         <div class="row" style="margin-right: 10px;">
            <div class="offset-9 col-1 text-center" style=" height: 2.5rem;
            font-size: 1.2rem; padding-top: 0.2rem; border-bottom: 1.5px solid; color: block;">
             TotalPrice   
            </div>
            <div class="col-2 text-end" style="border-bottom: 1.5px solid; 
            padding-top: 0.2rem; height: 2.5rem; font-size: 1.1rem;">
               <span th:text="${#numbers.formatCurrency(finalPrice)}" id="finalPriceSpan"></span>
            </div>
         </div>
     </div>
     </div>

 <div class="row mt-3 mb-4" style="margin-left: 720px;">
  <div class="col" > 
     <form action="" method="post" id="cartForm">
        <input type="hidden" name="cartCodes" value="">
     </form>
        <button type="button" class="btn btn-outline-dark" th:onclick="deleteBuy(this);"> 
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box2-heart" viewBox="0 0 16 16">
        <path d="M8 7.982C9.664 6.309 13.825 9.236 8 13 2.175 9.236 6.336 6.31 8 7.982Z"/>
        <path d="M3.75 0a1 1 0 0 0-.8.4L.1 4.2a.5.5 0 0 0-.1.3V15a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V4.5a.5.5 0 0 0-.1-.3L13.05.4a1 1 0 0 0-.8-.4h-8.5Zm0 
            1H7.5v3h-6l2.25-3ZM8.5 4V1h3.75l2.25 3h-6ZM15 5v10H1V5h14Z"/>
        </svg>선택삭제</button>
		</div>
		
      <div class="col">
        <button type="button" class="btn btn-outline-dark" th:onclick="deleteBuy(this);"> 
        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box2-heart" viewBox="0 0 16 16">
        <path d="M8 7.982C9.664 6.309 13.825 9.236 8 13 2.175 9.236 6.336 6.31 8 7.982Z"/>
        <path d="M3.75 0a1 1 0 0 0-.8.4L.1 4.2a.5.5 0 0 0-.1.3V15a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1V4.5a.5.5 0 0 0-.1-.3L13.05.4a1 1 0 0 0-.8-.4h-8.5Zm0 
                1H7.5v3h-6l2.25-3ZM8.5 4V1h3.75l2.25 3h-6ZM15 5v10H1V5h14Z"/>
        </svg>선택구매</button>
	</div>
     </div>
    </div>
  </div>
<script type="text/javascript" th:src="@{/js/cart/cart_list.js}"></script>
</div>

 

2. 장바구니 수량변경

1) mapper

<!-- 장바구니 수량변경 -->
<update id="changeCnt">
UPDATE SHOP_CART
SET CART_AMOUNT = #{cartAmount}
  , TOTAL_PRICE = (SELECT ITEM_PRICE 
	               FROM SHOP_ITEM
	 			   WHERE ITEM_CODE = (SELECT ITEM_CODE 
                                          		FROM SHOP_CART
                                         	 	WHERE CART_CODE = #{cartCode}))*#{cartAmount}

WHERE CART_CODE = #{cartCode}

</update>
//장바구니 상품수량 변경
@Override
public void changeCnt(CartVO cartVO) {
    sqlSession.update("cartMapper.changeCnt", cartVO);
}

 

2) controller

장바구니 수량 변경
@PostMapping("/changeCnt")
@ResponseBody
public void changeCnt(CartVO cartVO) {
    cartService.changeCnt(cartVO);
}

3) html

 <td>
    <div class="input-group mb-3">
      <input type="text" class="form-control amountInput" aria-describedby="button-addon2"
      th:value="${cart.cartAmount}" th:data-origin-amount="${cart.cartAmount}">
      <button class="btn btn-outline-primary" type="submit" id="button-addon2"
      th:onclick="updateCnt(this);">변경</button>
    </div>
</td>

 

4) js

장바구니 수량 변경 모달창(this 사용)
function updateCnt(selectedTag){
			
    모달창 소스
    const modal = new bootstrap.Modal('#changeAmountModal');
    모달 보여주기
    modal.show();

   수량 데이터	
   const cartAmount = selectedTag.closest('td').querySelector('.amountInput').value;	

   cartCode
   const cartCode = selectedTag.closest('tr').querySelector('input[type="checkbox"]').value;

    모달 확인 버튼의 data-cart-code, data-cart-amount 속성값을 수량을 변경하고자 하는 데이터로

    document.querySelector('#updateAmountBtn').dataset.cartCode = cartCode;
    document.querySelector('#updateAmountBtn').dataset.cartAmount = cartAmount;

    기존 장바구니 수량을 취소버튼으로 전달
    const originAmount = selectedTag.closest('td').querySelector('.amountInput').dataset.originAmount;
    document.querySelector('#cancelBtn').dataset.originAmount = originAmount;

}


수량 변경 버튼 클릭 후 나타나는 모달창의 확인버튼 클릭
function changeCnt(){

const cartCode = document.querySelector('#updateAmountBtn').dataset.cartCode;
const cartAmount = document.querySelector('#updateAmountBtn').dataset.cartAmount;

$.ajax({
   url: '/cart/changeCnt', //요청경로
    type: 'post',
    data:{'cartCode':cartCode,'cartAmount':cartAmount}, //필요한 데이터

    success: function(result) {

        모달창 소스
        const modal = new bootstrap.Modal('#updateCntModal');

        모달 보여주기
        modal.show();

        수량 변경
        for(const chk of chks){

            if(chk.value == cartCode){
                chk.closest('tr').querySelector('.amountInput').dataset.originAmount = 	cartAmount;

            }
        }


        //다른 방법 모달창 하나로 실행 후 모달창 닫기
        //위에서 선언을 한 후(const modal = new bootstrap.Modal('#updateCntModal');)
        // modal.hide();
        // modal.show(); 모달 사용 시

        //장바구니 상품에 대한 수량 및 가격 갱신
    },
    error: function(){
       alert('실패');
    }
 });

}

수량 변경 팝업에서 취소버튼 클릭 시
function rollbackAmount(selectedTag){

    모든 체크박스를 돌면서 cartCode값을 가져온다.
    수량을 rollback 시켜야 하는 cartCode랑 비교

    const selectedCartCode = document.querySelector('#updateAmountBtn').dataset.cartCode;

    const originAmount =  document.querySelector('#cancelBtn').dataset.originAmount;

    for(const chk of chks){
        if(chk.value == selectedCartCode){
            chk.closest('tr').querySelector('.amountInput').value = originAmount; 
        }
    }
	
}

5) controller

장바구니 수량 변경
@PostMapping("/changeCnt")
@ResponseBody
public void changeCnt(CartVO cartVO) {

    cartService.changeCnt(cartVO);
}

6) html (모달창)

<!--  상품 수량 변경 시 모달창  -->
<div class="modal fade" id="changeAmountModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body">
      	<div class="row mb-3" >
	      	<div class="col text-center">
	      	  수량을 변경하시겠습니까?
	      	</div>
      	</div>
      	
       <div class="row">
       	<div class="col text-center">
       		<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal"
       		style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: 3rem; --bs-btn-font-size: 1rem;"
       		th:onclick="changeCnt();" data-cart-code="" data-cart-amount="" id="updateAmountBtn">확인</button>
       
       		<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal" th:onclick="rollbackAmount();"
       		style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: 3rem; --bs-btn-font-size: 1rem;" data-origin-amount="" id="cancelBtn">취소</button>
       	</div>
       </div>
      </div>
    </div>
  </div>
</div>		
		
<!--  상품 수량 변경 후 모달창  -->
<div class="modal fade" id="updateCntModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body">
      	<div class="row mb-3" >
	      	<div class="col text-center">
	      	  수량이 변경되었습니다.
	      	</div>
      	</div>
       <div class="row">
       	<div class="col text-center">
       		<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal"
       		style="--bs-btn-padding-y: .25rem; --bs-btn-padding-x: 3rem; --bs-btn-font-size: 1rem;">확인</button>
       	</div>
       </div>
      </div>
    </div>
  </div>
</div>