게으른 완벽주의자의 개발자 도전기
[shop]장바구니에서 구매하기 버튼 클릭하여 구매하기(closest, parentElement) 본문
<사진출처 yes24>
장바구니에서 체크박스를 이용하여 선택구매를 클릭했을 때
1) 구매하기 진행 2) 구매이력 남기기 3) 장바구니에서 해당 상품 삭제를 진행하고자 한다.
상세페이지에서 구매하기 버튼 클릭과 다른점은 한가지 상품이 아닌
다양한 상품을 한 번에 구매한다는 점이다.
1. mapper 쿼리 작성
1) 구매하기
<insert id="cartBuy">
INSERT INTO SHOP_BUY(
MEM_ID
, BUY_CODE
, TOTAL_PRICE
) VALUES (
#{memId}
, #{buyCode}
, #{totalPrice}
)
</insert>
2)구매이력
구매이력에서는 무슨 상품을 샀는지 내역이 들어간다.
이때 내역에는 상품코드, 가격, 이름 등등의 다양한 정보가 들어간다.
이런 정보를 한 번에 넣을 수 있는 것이 List이다.
BuyDTO에 List<BuyDetailDTO> buyDetailList 만들고, getter와 setter를 만든다
<insert id="insertCartDetail">
INSERT INTO BUY_DETAIL
(BUY_DETAIL_CODE
, ITEM_CODE
, BUY_CNT
, BUY_CODE
)
buyDTO.getBuyDetailList()가 실행될 수 있게 컬렉션을 사용하겠다.
<foreach collection="buyDetailList" item="buyDetailDTO" separator="UNION ALL" index="i">
(buyDetailList에서 하나를 꺼냈을 때 buyDetailDTO라고 할 것이고
하나의 쿼리가 끝나면 UNION ALL로 연결할 것이고, 인덱스를 사용할 것이다)
★SELECT문에 |LPAD(#{i}+1, 2, 0)로 인덱스를 추가한 이유는
쿼리가 끝나면 UNION ALL로 연결되기 때문에 인덱스를 추가하지 않으면
BUY_DETAIL_CODE는 계속 같은 수로 머무르게 된다.
즉, SELECT |LPAD(#{1, 2, 0) FROM DUAL
UNION ALL
SELECT |LPAD(#{1, 2, 0) FROM DUAL
첫번째 SELECT문에서도 1 두번째 SELECT 문에서도 1이 나오게 되는 것이다.
그래서 인덱스로 LPAD(#{i}+1 1, 2, 3 순차적으로 나오게 만든 것이다.
SELECT #{buyDetailDTO.buyDetailCode} ||'_'||LPAD(#{i}+1, 2, 0) (두자리만 나온다는 가정 )
, #{buyDetailDTO.itemCode}
, #{buyDetailDTO.buyCnt}
, #{buyDetailDTO.buyCode}
FROM DUAL
</foreach>
</insert>
3) BUY_CODE 조회
<select id="selectBuyCode" resultType="String">
SELECT 'BUY_' || LPAD(NVL(MAX(TO_NUMBER(SUBSTR(BUY_CODE,5))),0)+1, 3, 0)
FROM SHOP_BUY
</select>
4) 상품 장바구니에서 삭제
장바구니에는 CART_CODE가 하나가 아닌 여러개가 있다.
이때 사용할 수 있는 것이 LIST이다.
cartDTO에 LIST<String>cartCodeList를 만들고,
getter와 setter를 만들어준다.(cartCode 하나를 출력하기에 변수String)
또한, in(A, B, C)를 활용해서 충족되는 데이터만 삭제하도록 한다.
<delete id="deleteCarts">
DELETE SHOP_CART
WHERE CART_CODE IN
<foreach collection="cartCodeList" item="cartCode" open="(" close=")" separator=", ">
#{cartCode}
</foreach>
</delete>
2.인터페이스 메소드 작성
세가지 작업의 트랜잭션이 완벽하게 수행되면 커밋하도록 설정하였다.
@Override
public void cartBuy(BuyDTO buy, CartDTO cart) {
try {
장바구니 구매하기
sqlSession.insert("buyMapper.cartBuy", buy);
구매이력
sqlSession.insert("buyMapper.insertCartDetail", buy);
구매한 상품은 장바구니에서 삭제
sqlSession.delete("cartMapper.deleteCarts", cart);
// 커밋
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
}
}
3. JS
1) jsp
<td><input data-cart-code ="bbb"
data-cartcode="${cart.cartCode }"
type="checkbox" class="chk" value="${cart.itemCode}"></td>
<form action="insertBuys.buy" method="post">
( name=자바로 데이터 가져갈려고 id= js에서 쓸려고)
<input type="hidden" id="totalPrice" value="" name="totalPrice">
<input type="hidden" id="itemCode" value="" name="itemCode">
<input type="hidden" id="buyCnt" value="" name="buyCnt">
<input type="hidden" id="cartCode" value="" name="cartCode">
</form>
<input type="button" value="선택구매" onclick="goBuy();">
2) JS
i) 데이터 위치 지정하기
아래와 같은 boardList가 있다고 생각하자
<tr>
<td>첫번째 메뉴</td>
<td>두번째 메뉴</td>
<td> 세번째 메뉴</td>
<td>네번째 메뉴</td>
<td> 다섯번째 메뉴</td>
</tr>
1) parentElement 사용하기
첫번째 메뉴라는 문자열의 부모태그는 <td>이다.
- > boardList.parentElement
<td>의 부모인 <tr>로 가고자 한다.
- > boardList.parentElement.parentElement
- children[ ] : 자식태그(배열)
- previousElementSibling : 이전 형제(같은 <td>)
- nextElementSibling : 다음 형제 찾아감 (<td>)
5번째 자식인 다섯번째 메뉴 찾기 (배열은 0이 1이니까)
boardList.parentElement.parentElement.children[4].innerText
-> tr 입장에서 td들은 자식이기 때문에 td의 다섯번째 자식(children[4])
2) closest
closest() : 가장 가까운 상위 태그를 찾아 감
5번째 자식인 다섯번째 메뉴 찾기
boardList.closest('tr').children[4].innerText;
function goBuy(){
const checkedCnt = document.querySelectorAll('.chk:checked').length;
let totalPrice = 0;
let itemCodes = '';
let buyCnts = '';
let cartCodes ='';
체크박스에 선택한 상품이 없을 때
if(checkedCnt ==0){
alert('선택한 상품이 없습니다.');
return;
(return 작성하여 if문 정지시킴)
}
체크된 상품의 totalPrice 총가격 가져 오겠다
const checkedBoxes = document.querySelectorAll('.chk:checked');
for(const checkBox of checkedBoxes){
const price = checkBox.closest('tr').children[5].innerText;
totalPrice는 숫자 0 들어갔으니 연산을 위해 price를 같은 인수로 바꾼다
totalPrice = totalPrice + parseInt(price);
itemCode가져오기(input태그에서 value값으로 가져옴)
const itemCode = checkBox.value;
itemCodes = itemCodes + itemCode +',';
buyCnt 가져오기
const buyCnt = checkBox.closest('tr').children[4].innerText;
buyCnts = buyCnts + buyCnt + ',';
cartCode 가져오기 (data-cartcode)
const cartCode = checkBox.dataset.cartcode;
cartCodes = cartCodes + cartCode + ',';
}
총가격
document.querySelector('#totalPrice').value = totalPrice;
아이템코드
document.querySelector('#itemCode').value = itemCodes.substr(0, itemCodes.length -1);
구매수량
document.querySelector('#buyCnt').value = buyCnts.substr(0, buyCnts.length -1);
장바구니 상품 삭제 (value는 input태그에 넣을 값)
document.querySelector('#cartCode').value = cartCodes.substr(0, cartCodes.length -1);
버튼 누르면 form태그 실행
document.querySelector('form[action="insertBuys.buy"]').submit();
}
4. CONTROLLER
else if(command.equals("/insertBuys.buy")) {
int totalPrice = Integer.parseInt(request.getParameter("totalPrice"));
String itemCodes = request.getParameter("itemCode");
String buyCnts = request.getParameter("buyCnt");
String cartCodes = request.getParameter("cartCode");
배열로 받아온 데이터 split 사용하여 , 제거
String[] itemCodeArr = itemCodes.split(",");
String[] cartCodeArr = cartCodes.split(",");
String[] buyCntArrString = buyCnts.split(",");
(문자열로 받아오니까 정수로 바꿔줌)
int[] buyCntArr = new int[buyCntArrString.length];
for(int i=0 ; i< buyCntArr.length; i++) {
buyCntArr[i]= Integer.parseInt(buyCntArrString[i]);
}
구매코드 출력
String buyCode = buyService.selectBuyCode();
구매자 ID
HttpSession session = request.getSession();
MemberDTO loginInfo = (MemberDTO) session.getAttribute("loginInfo");
String memId = loginInfo.getMemId();
BuyDTO buy = new BuyDTO();
buy.setTotalPrice(totalPrice);
buy.setBuyCode(buyCode);
buy.setMemId(memId);
장바구니에서는 몇개를 구매할 지 모르기 때문에 List를 사용한다.
List<BuyDetailDTO> buyDetailList = new ArrayList<>();
또한, 데이터 몇개 들어올 지 모르기 때문에 for문으로 한 줄씩 넣어줌
(itemCodeArr 또는 buyCntArr 중 하나로 for문을 만든다)
for(int i =0 ; i < itemCodeArr.length; i++) {
한 아이템 당 데이터 넣을 객체
BuyDetailDTO buyDetailDTO = new BuyDetailDTO();
buyDetailDTO.setItemCode(itemCodeArr[i]);
buyDetailDTO.setBuyCnt(buyCntArr[i]);
buyDetailDTO.setBuyCode(buyCode);
buyDetailDTO.setBuyDetailCode(buyCode);
위 내용을 List에 추가
buyDetailList.add(buyDetailDTO)
}
★cartCode 담는 방법은 2가지가 있다.
1. List를 만들어 foreach문으로 담기
1)cartCode 담을 통 만들기
List<String>cartCodeList = new ArrayList<>();
2) foreach문
for(String cartCode : cartCodeArr) {
cartCodeList.add(cartCode);
}
2. 배열을 List로 변환
List<String> cartCodeList = Arrays.asList(cartCodeArr);
장바구니에 담긴 상품목록 삭제
CartDTO cart = new CartDTO();
cart.setCartCodeList(cartCodeList);
구매이력 입력
buy.setBuyDetailList(buyDetailList);
insert 진행
buyService.cartBuy(buy, cart);
'Js' 카테고리의 다른 글
[SHOP] 장바구니 선택한 상품 삭제하기( js로 form태그 실행, dataSet) (0) | 2022.08.28 |
---|---|
[shop] 상품 상세페이지에서 구매하기 (0) | 2022.08.28 |
[shop]장바구니 체크박스 (js event 활용하기) (0) | 2022.08.22 |