• Home
  • About
    • GreenteaPIE photo

      GreenteaPIE

      GreenteaPIE's Development Story.

    • Learn More
    • Email
    • Github
    • Youtube
  • Posts
    • All Posts
    • All Tags
  • Projects

8 - DB Spring 장바구니

18 May 2023

Reading time ~7 minutes

사용한 플랫폼 : Spring, Oracle

1. 장바구니 담기

com.db.model 에 CartVO 추가

package com.db.model;

import java.sql.Timestamp;

import lombok.Data;

@Data
public class CartVO {
	private int cartnum;
	private String userid;
	private int num;
	private String psize;
	private int quantity;
	private int price;
	private Timestamp orderdate;
	private int result;
}

Product table에 상품의 고유 가격이 있지만, 할인율이 임의로 설정된 상품이나 Auction(경매)에 임의로 정해질 가격이 기존의 상품 가격과 달라지기 때문에 price 컬럼을 따로 저장할 수 있게 추가 해 주었다.

ProductController.java 에 추가

	// 장바구니에 상품 추가
	@PostMapping("/addCart")
	@ResponseBody
	public ResponseEntity<?> addCartPOST(String userid, CartVO cart, HttpServletRequest request, HttpSession session)
			throws Exception {

		productService.addCart(cart); // 장바구니 추가 쿼리 실행

		return ResponseEntity.ok("Success");
	}

상품디테일 페이지에서 Ajax를 사용해 비동기로 장바구니 추가 메서드를 작동 시기위해 @ResponseBody 어노테이션을 사용한다.

ResponseEntity<?> 는 자바의 제네릭 타입을 사용하여 응답 본문의 내용을 자유롭게 표현할 수 있다. ? 는 다양한 종류 데이터를 반환 할 수 있기때문에 사용하였다.

ProductMapper.java 에 추가

	// 장바구니 상품 추가
	public CartVO addCart(CartVO cart);

ProductService.java 에 추가

	// 장바구니 상품 추가
	public CartVO addCart(CartVO cart) throws Exception;

ProductServiceImpl.java 에 추가

	@Override
	public CartVO addCart(CartVO cart) throws Exception {

		return productmapper.addCart(cart);

	}

ProductMapper.xml 에 추가

	<!-- 장바구니 상품 추가 -->
	<select id="addCart" resultType="com.db.model.CartVO">

		insert into cart(cartnum,
		userid, num, psize, quantity, price)
		values (cart_seq.nextval,
		#{userid}, #{num}, #{psize}, #{quantity},
		#{price})

	</select>

productDetail.jsp 에 스크립트 추가

<script>
		function validateForm() {
			var psize = $('input[name="psize"]:checked').val();
			if (!psize) {
				alert("사이즈를 선택해주세요");
				return false;
			}

			// form data
			var formData = $("form[name='addcart']").serialize();

			// AJAX request
			$.ajax({
				type : "POST",
				url : "/product/addCart",
				data : formData,
				success : function(response) {
					alert("장바구니에 추가되었습니다.");
					location.reload(); // 페이지 새로 고침
				},
				error : function(xhr, status, error) {
					alert("장바구니에 추가하는 데 실패했습니다.");
					location.reload(); // 페이지 새로 고침
				}
			});
			return false;
		}
	</script>

장바구니 추가 메소드를 실행하고 해당 페이지를 새로고침 한다.

2. 장바구니 뱃지 숫자 표기

ProductController.java 에 추가

	// 장바구니 뱃지 상품 개수
	@GetMapping("/countCartAjax")
	@ResponseBody
	public String countCartAjax(String userid) throws Exception {
		return String.valueOf(productService.countCart(userid));
	}

ProductMapper.java 에 추가

	// 장바구니 상품 갯수 불러오기
	public int countCart(String userid);

ProductService.java 에 추가

	// 장바구니 상품 갯수 불러오기
	public int countCart(String userid) throws Exception;

ProductServiceImpl.java 에 추가

	@Override
	public int countCart(String userid) throws Exception {

		return productmapper.countCart(userid);
	}

ProductMapper.xml 에 추가

	<!-- 장바구니 상품 갯수 불러오기 -->
	<select id="countCart" resultType="int" parameterType="String">
		SELECT
		COUNT(*) FROM cart WHERE userid = #{userid} and result ='1'
	</select>

result = ‘1’ 은 아직 결제를 진행 하지 않은 상태이다.

결제 시 result 가 0으로 바뀌어 장바구니 페이지나 뱃지에 나오지 않게 만든다.

3. 나의 장바구니 불러오기

ProductController.java 에 추가

	// 나의 장바구니
	@GetMapping("/myCart")
	public String myCartGET(String userid, HttpServletRequest request, HttpSession session) throws Exception {

		ArrayList<CartVO> clist = productService.getCartList(userid); // userid로 장바구니 리스트 불러오기
		request.setAttribute("clist", clist);

		ArrayList<ProductVO> plist = productService.getAllProduct(); // 모든 상품 가져오기
		request.setAttribute("plist", plist);

		return "/product/cart";

	}

Cart table의 num(상품 번호)와 Product table 의 num이 FK로 연결 되어있어, 모든 상품 리스트를 불러온 후 장바구니의 num과 일치할 경우 장바구니 페이지에 해당 상품의 정보도 함께 출력해준다.

ProductMapper.java 에 추가

	// 장바구니 리스트 불러오기
	public ArrayList<CartVO> getCartList(String userid);

	// 모든 상품 정보 불러오기
	public ArrayList<ProductVO> getAllProduct();

ProductService.java 에 추가

	// 장바구니 리스트 불러오기
	public ArrayList<CartVO> getCartList(String userid) throws Exception;

	// 모든 상품 정보 불러오기
	public ArrayList<ProductVO> getAllProduct() throws Exception;

ProductServiceImpl.java 에 추가

	@Override
	public ArrayList<CartVO> getCartList(String userid) throws Exception {

		return productmapper.getCartList(userid);
	}

	@Override
	public ArrayList<ProductVO> getAllProduct() throws Exception {

		return productmapper.getAllProduct();
	}

ProductMapper.xml 에 추가

	<!-- 장바구니 리스트 불러오기 -->
	<select id="getCartList" resultType="com.db.model.CartVO">
		SELECT *
		FROM cart
		WHERE
		userId=#{userid} AND result='1'
		ORDER BY orderDate DESC
	</select>
	
		<!-- 모든 상품정보 불러오기 -->
	<select id="getAllProduct" resultType="com.db.model.ProductVO">

		select * from product

	</select>

cart.jsp 추가

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<style>
td .delhidden {
	width: 100px
}

.delhide:hover .delhidden {
	display: block;
}

.delhide .delhidden {
	display: none;
}
</style>
<jsp:include page="../header.jsp"></jsp:include>
<body>
	<hr>
	<!-- Page Header Start -->
	<div class="container bg-secondary mb-3" style="max-width: 800px;">
		<div class="d-flex flex-column align-items-center justify-content-center" style="min-height: 200px">
			<h1 class="font-weight-semi-bold text-uppercase mb-3">Shopping Cart</h1>
			<div class="d-inline-flex">
				<p class="m-0">
					<a href="/">Home</a>
				</p>
			</div>
		</div>
	</div>
	<!-- Page Header End -->
	<!-- Cart Start -->
	<div class="container-fluid pt-5">
		<div class="row px-xl-5">
			<div class="col-lg-8 table-responsive mb-5">
				<table class="table table-bordered text-center mb-0" id="cartTable">
					<thead class="bg-secondary text-dark">
						<tr>
							<th>Products</th>
							<th>Size</th>
							<th>Price</th>
							<th>Quantity</th>
							<th>Total</th>
							<!-- 								<th>Remove</th> -->
						</tr>
					</thead>
					<tbody class="align-middle">
						<c:choose>
							<c:when test="${clist.size()==0}">
								<tr>
									<td class="align-middle" colspan="7">
										<h3>장바구니가 비었습니다.</h3>
									</td>
								</tr>
							</c:when>
							<c:otherwise>
								<c:forEach var="cart" items="${clist}">
									<!-- 장바구니 cartVO -->
									<tr class="delhide">
										<c:forEach var="product" items="${plist }">
											<!-- 상품리스트 -->
											<c:if test="${cart.num == product.num}">
												<c:if test="${cart.result == 1}">
													<!--상품리스트품번과 장바구니 번호가 일치할 때  -->
													<td class="align-middle">
														<div class="d-flex align-items-center">
															<img src="../resources/img/${product.imgUrl}" alt="productImg" style="width: 55px; margin-right: 5px;">
															<div class="text-left">
																<a href='/product/productDetail?num=${product.num}&pname=${product.pname}'>${product.pname}</a>
															</div>
														</div>
													</td>
													<td class="align-middle"><c:choose>
															<c:when test='${cart.psize  =="S" }'>S</c:when>
															<c:when test='${cart.psize  =="M" }'>M</c:when>
															<c:when test='${cart.psize  =="L" }'>L</c:when>
															<c:when test='${cart.psize  =="XL" }'>XL</c:when>
															<c:when test='${cart.psize  =="XS" }'>XS</c:when>
															<c:when test='${cart.psize  =="XXL" }'>XXL</c:when>
															<c:when test='${cart.psize  =="Free" }'>Free</c:when>
														</c:choose></td>
													<td class="align-middle"><fmt:setLocale value="ko_KR" /> <fmt:formatNumber type="currency" value="${cart.price}" currencySymbol="₩" /></td>
													<td class="align-middle">
														<div class="input-group quantity mx-auto" style="width: 120px;">
															<div class="input-group-btn">
																<button class="btn btn-primary btn-minus" onclick="decreaseQuantity(${cart.cartnum})">
																	<i class="fa fa-minus"></i>
																</button>
															</div>
															<input type="text" style="height: 38.5px;" name="quantity" class="form-control form-control-sm bg-secondary text-center" value="${cart.quantity}" id="quantity-${cart.cartnum}" readonly>
															<div class="input-group-btn">
																<button class="btn btn-primary btn-plus" onclick="increaseQuantity(${cart.cartnum})">
																	<i class="fa fa-plus"></i>
																</button>
															</div>
															<c:set var="totalPrice" value="${cart.price * cart.quantity}" />
															<c:set var="subprice" value="${subprice + totalPrice}" />
														</div>
													</td>
													<td class="align-middle"><fmt:setLocale value="ko_KR" /> <fmt:formatNumber type="currency" value="${cart.price * cart.quantity}" currencySymbol="₩" /></td>
												</c:if>
											</c:if>
										</c:forEach>
									</tr>
								</c:forEach>
							</c:otherwise>
						</c:choose>
					</tbody>
				</table>
			</div>
			<div class="col-lg-4">
				<div class="card border-secondary mb-5">
					<div class="card-header bg-secondary border-0">
						<h4 class="font-weight-semi-bold m-0">Cart Summary</h4>
					</div>
					<div class="card-body">
						<div class="d-flex justify-content-between mb-3 pt-1">
							<h6 class="font-weight-medium">Subtotal</h6>
							<h6 class="font-weight-medium" id="subPrice">
								<fmt:setLocale value="ko_KR" />
								<fmt:formatNumber type="currency" value="${subprice}" currencySymbol="₩" />
							</h6>
						</div>
						<div class="d-flex justify-content-between">
							<h6 class="font-weight-medium">Shipping</h6>
							<h6 class="font-weight-medium">
								<strong style="font-size: 20px">Free</strong>
							</h6>
						</div>
					</div>
					<div class="card-footer border-secondary bg-transparent">
						<div class="d-flex justify-content-between mt-2">
							<h5 class="font-weight-bold">Total</h5>
							<h5 class="font-weight-bold" id="subPrice">
								<fmt:setLocale value="ko_KR" />
								<fmt:formatNumber type="currency" value="${subprice}" currencySymbol="₩" />
							</h5>
						</div>
						<c:if test="${clist.size()!=0}">
							<a href="#">
								<input type="button" class="btn btn-block btn-primary my-3 py-3" value="Proceed To Checkout">
							</a>
						</c:if>
						<c:if test="${clist.size()==0}">
							<a href="#" onclick="alert('주문할 상품이 없습니다.'); return false;">
								<input type="button" class="btn btn-block btn-primary my-3 py-3" value="Proceed To Checkout">
							</a>
						</c:if>
					</div>
				</div>
			</div>
		</div>
	</div>
	<!--Cart End -->
	<hr>
</body>
<jsp:include page="../footer.jsp"></jsp:include>
</html>

불러온 장바구니의 리스트가 비어있다면 결제 페이지로 넘어가지 않게 한다.

_config.yml

header.jsp 에 수정

<div class="col-lg-3 col-6 text-right">
				<c:if test="${user != null}">
					<div id="cart-badge">
						<a href="/product/myCart?userid=${user.userid}" class="btn border">
							<i class="fas fa-shopping-cart text-primary"></i>
							<span class="badge"></span>
						</a>
					</div>
				</c:if>
				<c:if test="${user == null}">
					<a class="btn border" onclick="alert('로그인 후에 이용이 가능합니다.'); return false;">
						<i class="fas fa-shopping-cart text-primary"></i>
						<span class="badge"></span>
					</a>
				</c:if>
			</div>

로그인이 안되어 있을 땐 장바구니 버튼이 작동되지 않게 만든다.

4. 장바구니 수량 증가 및 감소 & 삭제

Cart table에 저장된 quantity(수량)의 값이 보이는 값이 아니라 실제 서버에서 수량의 변동까지 저장 시키고, 따로 삭제 버튼을 만들어 삭제 하는것이 아닌 수량을 1미만으로 조정하려 할 때 장바구니에서 해당 상품을 삭제 시키게 만든다.

해당 버튼들 또한 Ajax를 이용하여 해당 페이지에서 비동기로 작동 시키게 만든다.

ProductController.java 에 추가

	// 장바구니 수량 감소
	@PostMapping("/quantityMinus")
	public ResponseEntity<String> decreaseQuantity(@RequestParam("cartnum") int cartnum) throws Exception {
		productService.decreaseQuantity(cartnum);
		return ResponseEntity.ok("Success");
	}

	// 장바구니 수량 증가
	@PostMapping("/quantityPlus")
	@ResponseBody
	public ResponseEntity<String> increaseQuantity(@RequestParam("cartnum") int cartnum) throws Exception {
		productService.increaseQuantity(cartnum);
		return ResponseEntity.ok("Success");
	}

	// 장바구니 상품 삭제
	@PostMapping("/deleteCart")
	@ResponseBody
	public ResponseEntity<String> cartDelete(@RequestParam("cartnum") int cartnum) throws Exception {
		productService.cartDelete(cartnum);
		return ResponseEntity.ok("Success");
	}

ProductMapper.java 에 추가

	// 장바구니 수량 감소
	public int decreaseQuantity(int cartnum);

	// 장바구니 수량 증가
	public int increaseQuantity(int cartnum);

	// 장바구니 상품 삭제
	public int cartDelete(int cartnum);

ProductService.java 에 추가

	// 장바구니 수량 감소
	public int decreaseQuantity(int cartnum) throws Exception;

	// 장바구니 수량 증가
	public int increaseQuantity(int cartnum) throws Exception;

	// 장바구니 상품 삭제
	public int cartDelete(int cartnum) throws Exception;

ProductServiceImpl.java 에 추가

	@Override
	public int decreaseQuantity(int cartnum) throws Exception {

		return productmapper.decreaseQuantity(cartnum);
	}

	@Override
	public int increaseQuantity(int cartnum) throws Exception {

		return productmapper.increaseQuantity(cartnum);
	}

	@Override
	public int cartDelete(int cartnum) throws Exception {

		return productmapper.cartDelete(cartnum);
	}

ProductMapper.xml 에 추가

	<!-- 장바구니 수량감소 -->
	<update id="decreaseQuantity">

		update cart SET quantity = quantity - 1
		where cartnum
		= #{carnum}

	</update>

	<!-- 장바구니 수량증가 -->
	<update id="increaseQuantity">

		update cart SET quantity = quantity + 1
		where cartnum
		= #{carnum}

	</update>

	<!-- 장바구니 상품삭제 -->
	<delete id="cartDelete">

		delete from cart where cartnum=#{cartnum}

	</delete>

cart.jsp 에 스크립트 추가

<script>
  function increaseQuantity(cartnum) {
    $.ajax({
      url: "/product/quantityPlus",
      method: "POST",
      data: {cartnum: cartnum},
      success: function (response) {
        console.log(response);
        location.reload(); // 페이지 새로 고침
      },
      error: function (error) {
        console.error(error);
      }
    });
  }
  function decreaseQuantity(cartnum) {
	    var currentQuantity = $("#quantity-" + cartnum).val();
	    if (currentQuantity <= 1) {
	      if (confirm("최소 수량 입니다.\n해당 상품을 장바구니에서 삭제 하시겠습니까?")) {
	        $.ajax({
	          url: "/product/deleteCart",
	          method: "POST",
	          data: {cartnum: cartnum},
	          success: function (response) {
	            console.log(response);
	            location.reload(); // 페이지 새로 고침
	          },
	          error: function (error) {
	            console.error(error);
	          }
	        });
	      } else {
	        return;
	      }
	    } else {
	      $.ajax({
	        url: "/product/quantityMinus",
	        method: "POST",
	        data: {cartnum: cartnum},
	        success: function (response) {
	          console.log(response);
	          location.reload(); // 페이지 새로 고침
	        },
	        error: function (error) {
	          console.error(error);
	        }
	      });
	    }
	  }
</script>

프로젝트 주소



projectjavajspOraclecssHTMLBootStrapAPIJQueryJavaScriptSpringFrameWork Share Tweet +1