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>