관리 메뉴

거니의 velog

(6) 도서 쇼핑몰 만들기 6 본문

Java_Spring mini project 쇼핑몰

(6) 도서 쇼핑몰 만들기 6

Unlimited00 2023. 11. 25. 14:16

7. 장바구니 기능 구현하기

* 쇼핑몰에서 장바구니가 빠질 순 없다. 이번에는 상품을 담고 주문할 수 있는 장바구니 기능을 구현해 보자.


(1) 장바구니 테이블 생성

* 다음 그림은 장바구니 정보를 저장하는 테이블의 구조이다. 회원 ID와 상품 번호를 이용해 회원 정보 테이블과 상품정보 테이블을 동시에 참조하는 것을 볼 수 있다.


(2) 상품을 장바구니에 추가

* 그럼 상품 상세 페이지에서 원하는 상품을 장바구니에 추가하는 기능을 구현해 보자.

1. 매퍼 파일 cart.xml을 다음과 같이 준비한다.

2. 장바구니 CRUD 기능을 수행할 SQL문을 cart.xml에 작성한다. 상품 번호를 이용해 장바구니에 상품을 추가하지 전인지 혹은 이미 추가된 상품인지를 체크한다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.cart">
	<!-- 리절트 맵 정의 -->
	<resultMap id="cartResult" type="CartVO">
		<result property="cart_id" column="cart_id" />
		<result property="goods_id" column="goods_id" />
		<result property="member_id" column="member_id" />
		<result property="cart_goods_qty" column="cart_goods_qty" />
		<result property="creDate" column="creDate" />
	</resultMap>
	
	<resultMap id="goodsResult" type="GoodsVO">
		<result property="goods_id" column="goods_id" />
		<result property="goods_title" column="goods_title" />
		<result property="goods_writer" column="goods_writer" />
		<result property="goods_price" column="goods_price" />
		<result property="goods_publisher" column="goods_publisher" />

		<result property="goods_status" column="goods_status" />
		<result property="goods_sales_price" column="goods_sales_price" />
		<result property="goods_published_date" column="goods_published_date" />
		<result property="goods_total_page" column="goods_total_page" />
		<result property="goods_isbn" column="goods_isbn" />
		<result property="goods_delivery_price" column="goods_delivery_price" />
		<result property="goods_delivery_date" column="goods_delivery_date" />

		<result property="goods_fileName" column="fileName" />
		<result property="goods_sort" column="goods_sort" />
		<result property="goods_writer_intro" column="goods_writer_intro" />
		<result property="goods_contents_order" column="goods_contents_order" />
		<result property="goods_intro" column="goods_intro" />
	</resultMap>

	<select id="selectCartList"  parameterType="cartVO"  resultMap="cartResult"   >
	    <![CDATA[
		select cart_id, goods_id, member_id, cart_goods_qty, creDate 
		from t_shopping_cart 
		where member_id=#{member_id} 
		]]>
	</select>

	<select id="selectGoodsList" resultMap="goodsResult" parameterType="java.util.Map">
      <![CDATA[
          select g.*,d.fileName from t_shopping_goods g, t_goods_detail_image d
          where g.goods_id=d.goods_id
          and d.filetype='main_image'
           and g.goods_id in
      ]]>
		<foreach item="item" collection="list" open="(" separator="," close=")">
			#{item.goods_id}
		</foreach>
		order by g.goods_creDate desc
	</select>

	<!-- 장바구니 테이블에 추가하기 전에 그 상품 번호가 장바구니에 담겨 있는지 조회한다. -->
	<select id="selectCountInCart" resultType="String" parameterType="cartVO">
	    <![CDATA[
		    select decode(count(*), 0, 'false', 'true') from t_shopping_cart
			where goods_id=#{goods_id}
			  and member_id=#{member_id} 

    	]]>
	</select>

	<!-- 상품을 추가한다. -->
	<insert id="insertGoodsInCart" parameterType="cartVO">
	    <![CDATA[
		    	insert into t_shopping_cart(cart_id,
		    	                           goods_id,
		    	                           member_id)
		        				 values(#{cart_id},
    							        #{goods_id},
    							        #{member_id})
    	]]>
	</insert>

	<update id="updateCartGoodsQty" parameterType="cartVO">
	    <![CDATA[
			update t_shopping_cart
			       set cart_goods_qty=#{cart_goods_qty}
		 	       where member_id=#{member_id}
			        and goods_id=#{goods_id}
    	]]>
	</update>
	
	<delete id="deleteCartGoods" parameterType="int">
	    <![CDATA[
	      delete from t_shopping_cart
	      where cart_id=#{cart_id}
    	]]>
	</delete>
	
	<select id="selectMaxCartId" resultType="int">
	    <![CDATA[
			select nvl(max(cart_id), 0) + 1 from t_shopping_cart 
    	]]>
	</select>

</mapper>

3. 다음은 필요한 자바 클래스 파일들이다.

4. 상품을 장바구니에 추가하려면 우선 브라우저에서 전송된 상품 번호를 이용해 그 상품이 장바구니 테이블에 이미 추가된 상품인지 확인해야 한다. 그리고 장바구니에 없으면 상품 번호를 장바구니 테이블에 추가한다.

[CartControllerImpl.java]

package com.bookshop01.cart.controller;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.bookshop01.cart.service.CartService;
import com.bookshop01.cart.vo.CartVO;
import com.bookshop01.common.base.BaseController;
import com.bookshop01.goods.vo.GoodsVO;
import com.bookshop01.member.vo.MemberVO;

@Controller("cartController")
@RequestMapping(value = "/cart")
public class CartControllerImpl extends BaseController implements CartController {
	
	@Autowired
	private CartService cartService;
	@Autowired
	private CartVO cartVO;
	@Autowired
	private MemberVO memberVO;

	@RequestMapping(value = "/myCartList.do", method = RequestMethod.GET)
	public ModelAndView myCartMain(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);
		HttpSession session = request.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String member_id = memberVO.getMember_id();
		cartVO.setMember_id(member_id);
		Map<String, List> cartMap = cartService.myCartList(cartVO);
		session.setAttribute("cartMap", cartMap);// 장바구니 목록 화면에서 상품 주문 시 사용하기 위해서 장바구니 목록을 세션에 저장한다.
		// mav.addObject("cartMap", cartMap);
		return mav;
	}

	@RequestMapping(value = "/addGoodsInCart.do", method = RequestMethod.POST, produces = "application/text; charset=utf8")
	public @ResponseBody String addGoodsInCart(@RequestParam("goods_id") int goods_id, // 전송된 상품 번호를 받는다.
			HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		memberVO = (MemberVO) session.getAttribute("memberInfo");
		String member_id = memberVO.getMember_id();

		cartVO.setMember_id(member_id);
		// 카트 등록전에 이미 등록된 제품인지 판별한다.
		cartVO.setGoods_id(goods_id);
		cartVO.setMember_id(member_id);
		boolean isAreadyExisted = cartService.findCartGoods(cartVO); // 상품 번호가 장바구니 테이블에 있는지 조회한다.
		System.out.println("isAreadyExisted:" + isAreadyExisted);
		if (isAreadyExisted == true) { // 상품번호가 이미 장바구니 테이블에 있으면 이미 추가되었다는 메시지를 브라우저로 전송하고, 없으면 장바구니 테이블에 추가한다.
			return "already_existed";
		} else {
			cartService.addGoodsInCart(cartVO);
			return "add_success";
		}
	}

	@RequestMapping(value = "/modifyCartQty.do", method = RequestMethod.POST)
	public @ResponseBody String modifyCartQty(@RequestParam("goods_id") int goods_id,
			@RequestParam("cart_goods_qty") int cart_goods_qty, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		memberVO = (MemberVO) session.getAttribute("memberInfo");
		String member_id = memberVO.getMember_id();
		cartVO.setGoods_id(goods_id);
		cartVO.setMember_id(member_id);
		cartVO.setCart_goods_qty(cart_goods_qty);
		boolean result = cartService.modifyCartQty(cartVO);

		if (result == true) {
			return "modify_success";
		} else {
			return "modify_failed";
		}

	}

	@RequestMapping(value = "/removeCartGoods.do", method = RequestMethod.POST)
	public ModelAndView removeCartGoods(@RequestParam("cart_id") int cart_id, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		ModelAndView mav = new ModelAndView();
		cartService.removeCartGoods(cart_id);
		mav.setViewName("redirect:/cart/myCartList.do");
		return mav;
	}
	
}

5. 상품 번호로 해당 상품의 개수를 조회한다. 상품 개수가 0이면 현재 등록된 상품이 없다는 것을 의미한다.

[CartServiceImpl.java]

package com.bookshop01.cart.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.bookshop01.cart.dao.CartDAO;
import com.bookshop01.cart.vo.CartVO;
import com.bookshop01.goods.vo.GoodsVO;

@Service("cartService")
@Transactional(propagation = Propagation.REQUIRED)
public class CartServiceImpl implements CartService {
	
	@Autowired
	private CartDAO cartDAO;

	public Map<String, List> myCartList(CartVO cartVO) throws Exception {
		Map<String, List> cartMap = new HashMap<String, List>();
		List<CartVO> myCartList = cartDAO.selectCartList(cartVO);
		if (myCartList.size() == 0) { // 카트에 저장된 상품이없는 경우
			return null;
		}
		List<GoodsVO> myGoodsList = cartDAO.selectGoodsList(myCartList);
		cartMap.put("myCartList", myCartList);
		cartMap.put("myGoodsList", myGoodsList);
		return cartMap;
	}

	public boolean findCartGoods(CartVO cartVO) throws Exception {
		return cartDAO.selectCountInCart(cartVO);
	} // 테이블에 추가하기 전에 동일한 상품 번호의 개수를 조회한다.

	public void addGoodsInCart(CartVO cartVO) throws Exception {
		cartDAO.insertGoodsInCart(cartVO);
	} // 장바구니에 추가한다.

	public boolean modifyCartQty(CartVO cartVO) throws Exception {
		boolean result = true;
		cartDAO.updateCartGoodsQty(cartVO);
		return result;
	}

	public void removeCartGoods(int cart_id) throws Exception {
		cartDAO.deleteCartGoods(cart_id);
	}

}

6. DAO 클래스에서는 다음과 같이 호출할 메서드를 구현한다.

[CartDAOImpl.java]

package com.bookshop01.cart.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.bookshop01.cart.vo.CartVO;
import com.bookshop01.goods.vo.GoodsVO;

@Repository("cartDAO")
public class CartDAOImpl implements CartDAO {
	
	@Autowired
	private SqlSession sqlSession;

	public List<CartVO> selectCartList(CartVO cartVO) throws DataAccessException {
		List<CartVO> cartList = (List) sqlSession.selectList("mapper.cart.selectCartList", cartVO);
		return cartList;
	}

	public List<GoodsVO> selectGoodsList(List<CartVO> cartList) throws DataAccessException {
		List<GoodsVO> myGoodsList;
		myGoodsList = sqlSession.selectList("mapper.cart.selectGoodsList", cartList);
		return myGoodsList;
	}

	public boolean selectCountInCart(CartVO cartVO) throws DataAccessException {
		String result = sqlSession.selectOne("mapper.cart.selectCountInCart", cartVO);
		return Boolean.parseBoolean(result);
	} // 이미 장바구니에 추가된 상품인지 조회한다.

	public void insertGoodsInCart(CartVO cartVO) throws DataAccessException {
		int cart_id = selectMaxCartId();
		cartVO.setCart_id(cart_id);
		sqlSession.insert("mapper.cart.insertGoodsInCart", cartVO);
	} // 장바구니에 추가한다.

	public void updateCartGoodsQty(CartVO cartVO) throws DataAccessException {
		sqlSession.insert("mapper.cart.updateCartGoodsQty", cartVO);
	}

	public void deleteCartGoods(int cart_id) throws DataAccessException {
		sqlSession.delete("mapper.cart.deleteCartGoods", cart_id);
	}

	private int selectMaxCartId() throws DataAccessException {
		int cart_id = sqlSession.selectOne("mapper.cart.selectMaxCartId");
		return cart_id;
	}

}

7. 마지막으로 상품 상세 페이지에서 장바구니를 표시할 JSP 파일을 준비한다.

8. 상품 상세 페이지에서 장바구니를 클릭하면 Ajax를 이용해 상품 번호를 컨트롤러로 전송한다. 그러면 결괏값에 따라 알림창을 표시한다.

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8" 	isELIgnored="false"%>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<c:set var="goods" value="${goodsMap.goodsVO}" />
<c:set var="imageList" value="${goodsMap.imageList }" />
<%
     //치환 변수 선언합니다.
      pageContext.setAttribute("crcn", "\r\n"); //개행문자
      pageContext.setAttribute("crcn" , "\n"); //Ajax로 변경 시 개행 문자 
      pageContext.setAttribute("br", "<br/>"); //br 태그
%>
<html>

<head>
    <style>
        #layer {
            z-index: 2;
            position: absolute;
            top: 0px;
            left: 0px;
            width: 100%;
        }

        #popup {
            z-index: 3;
            position: fixed;
            text-align: center;
            left: 50%;
            top: 45%;
            width: 300px;
            height: 200px;
            background-color: #ccffff;
            border: 3px solid #87cb42;
        }

        #close {
            z-index: 4;
            float: right;
        }
    </style>
    <script type="text/javascript">
        function add_cart(goods_id) {
            $.ajax({
                type: "post",
                async: false, //false인 경우 동기식으로 처리한다.
                url: "${contextPath}/cart/addGoodsInCart.do",
                data: {
                    goods_id: goods_id

                }, // Ajax를 이용해 장바구니에 추가할 상품 번호를 전송한다.
                success: function(data, textStatus) {
                	
                    //alert(data);
                    //	$('#message').append(data);
                    if (data.trim() == 'add_success') {
                        imagePopup('open', '.layer01');
                    } else if (data.trim() == 'already_existed') {
                        alert("이미 카트에 등록된 상품입니다.");
                    } // 장바구니에 추가하면 알림창을 표시한다.

                },
                error: function(data, textStatus) {
                    alert("에러가 발생했습니다." + data);
                },
                complete: function(data, textStatus) {
                    //alert("작업을완료 했습니다");
                }
            }); //end ajax	
        }

        function imagePopup(type) {
            if (type == 'open') {
                // 팝업창을 연다.
                jQuery('#layer').attr('style', 'visibility:visible');

                // 페이지를 가리기위한 레이어 영역의 높이를 페이지 전체의 높이와 같게 한다.
                jQuery('#layer').height(jQuery(document).height());
            } else if (type == 'close') {

                // 팝업창을 닫는다.
                jQuery('#layer').attr('style', 'visibility:hidden');
            }
        }

        function fn_order_each_goods(goods_id, goods_title, goods_sales_price, fileName) {
            var _isLogOn = document.getElementById("isLogOn");
            var isLogOn = _isLogOn.value;

            if (isLogOn == "false" || isLogOn == '') {
                alert("로그인 후 주문이 가능합니다!!!");
            }


            var total_price, final_total_price;
            var order_goods_qty = document.getElementById("order_goods_qty");

            var formObj = document.createElement("form");
            var i_goods_id = document.createElement("input");
            var i_goods_title = document.createElement("input");
            var i_goods_sales_price = document.createElement("input");
            var i_fileName = document.createElement("input");
            var i_order_goods_qty = document.createElement("input");

            i_goods_id.name = "goods_id";
            i_goods_title.name = "goods_title";
            i_goods_sales_price.name = "goods_sales_price";
            i_fileName.name = "goods_fileName";
            i_order_goods_qty.name = "order_goods_qty";

            i_goods_id.value = goods_id;
            i_order_goods_qty.value = order_goods_qty.value;
            i_goods_title.value = goods_title;
            i_goods_sales_price.value = goods_sales_price;
            i_fileName.value = fileName;

            formObj.appendChild(i_goods_id);
            formObj.appendChild(i_goods_title);
            formObj.appendChild(i_goods_sales_price);
            formObj.appendChild(i_fileName);
            formObj.appendChild(i_order_goods_qty);

            document.body.appendChild(formObj);
            formObj.method = "post";
            formObj.action = "${contextPath}/order/orderEachGoods.do";
            formObj.submit();
        }
    </script>
</head>

<body>
    <hgroup>
        <h1>컴퓨터와 인터넷</h1>
        <h2>국내외 도서 &gt; 컴퓨터와 인터넷 &gt; 웹 개발</h2>
        <h3>${goods.goods_title }</h3>
        <h4>${goods.goods_writer} &nbsp; 저| ${goods.goods_publisher}</h4>
    </hgroup>
    <div id="goods_image">
        <figure>
            <img alt="HTML5 &amp; CSS3" src="${contextPath}/thumbnails.do?goods_id=${goods.goods_id}&fileName=${goods.goods_fileName}">
        </figure>
    </div>
    <div id="detail_table">
        <table>
            <tbody>
                <tr>
                    <td class="fixed">정가</td>
                    <td class="active"><span>
                            <fmt:formatNumber value="${goods.goods_price}" type="number" var="goods_price" />
                            ${goods_price}원
                        </span></td>
                </tr>
                <tr class="dot_line">
                    <td class="fixed">판매가</td>
                    <td class="active"><span>
                            <fmt:formatNumber value="${goods.goods_price*0.9}" type="number" var="discounted_price" />
                            ${discounted_price}원(10%할인)
                        </span></td>
                </tr>
                <tr>
                    <td class="fixed">포인트적립</td>
                    <td class="active">${goods.goods_point}P(10%적립)</td>
                </tr>
                <tr class="dot_line">
                    <td class="fixed">포인트 추가적립</td>
                    <td class="fixed">만원이상 구매시 1,000P, 5만원이상 구매시 2,000P추가적립 편의점 배송 이용시 300P 추가적립</td>
                </tr>
                <tr>
                    <td class="fixed">발행일</td>
                    <td class="fixed">
                        <c:set var="pub_date" value="${goods.goods_published_date}" />
                        <c:set var="arr" value="${fn:split(pub_date,' ')}" />
                        <c:out value="${arr[0]}" />
                    </td>
                </tr>
                <tr>
                    <td class="fixed">페이지 수</td>
                    <td class="fixed">${goods.goods_total_page}쪽</td>
                </tr>
                <tr class="dot_line">
                    <td class="fixed">ISBN</td>
                    <td class="fixed">${goods.goods_isbn}</td>
                </tr>
                <tr>
                    <td class="fixed">배송료</td>
                    <td class="fixed"><strong>무료</strong></td>
                </tr>
                <tr>
                    <td class="fixed">배송안내</td>
                    <td class="fixed"><strong>[당일배송]</strong> 당일배송 서비스 시작!<br> <strong>[휴일배송]</strong>
                        휴일에도 배송받는 Bookshop</TD>
                </tr>
                <tr>
                    <td class="fixed">도착예정일</td>
                    <td class="fixed">지금 주문 시 내일 도착 예정</td>
                </tr>
                <tr>
                    <td class="fixed">수량</td>
                    <td class="fixed">
                        <select style="width: 60px;" id="order_goods_qty">
                            <option>1</option>
                            <option>2</option>
                            <option>3</option>
                            <option>4</option>
                            <option>5</option>
                        </select>
                    </td>
                </tr>
            </tbody>
        </table>
        <ul>
            <li><a class="buy" href="javascript:fn_order_each_goods('${goods.goods_id }','${goods.goods_title }','${goods.goods_sales_price}','${goods.goods_fileName}');">구매하기 </a></li>
            
            <%-- 장바구니를 클릭하면 추가할 상품 번호를 함수로 전달한다. --%>
            <li><a class="cart" href="javascript:add_cart('${goods.goods_id }')">장바구니</a></li>
            
            <li><a class="wish" href="#">위시리스트</a></li>
        </ul>
    </div>
    <div class="clear"></div>
    <!-- 내용 들어 가는 곳 -->
    <div id="container">
        <ul class="tabs">
            <li><a href="#tab1">책소개</a></li>
            <li><a href="#tab2">저자소개</a></li>
            <li><a href="#tab3">책목차</a></li>
            <li><a href="#tab4">출판사서평</a></li>
            <li><a href="#tab5">추천사</a></li>
            <li><a href="#tab6">리뷰</a></li>
        </ul>
        <div class="tab_container">
            <div class="tab_content" id="tab1">
                <h4>책소개</h4>
                <p>${fn:replace(goods.goods_intro,crcn,br)}</p>
                <c:forEach var="image" items="${imageList }">
                    <img src="${contextPath}/download.do?goods_id=${goods.goods_id}&fileName=${image.fileName}">
                </c:forEach>
            </div>
            <div class="tab_content" id="tab2">
                <h4>저자소개</h4>
                <p>
                <div class="writer">저자 : ${goods.goods_writer}</div>
                <%-- fn:replace 함수를 이용해 저자 소개에 포함된 crcn(개행문자)을 br태그로 대체한다. --%>
                <p>${fn:replace(goods.goods_writer_intro,crcn,br) }</p>
            </div>
            <div class="tab_content" id="tab3">
                <h4>책목차</h4>
                <%-- 마찬가지로 상품 목차에 포함된 crcn(개행문자)을 br 태그로 대체한다. --%>
                <p>${fn:replace(goods.goods_contents_order,crcn,br)}</p>
            </div>
            <div class="tab_content" id="tab4">
                <h4>출판사서평</h4>
                <%-- 상품 목차에 포함된 crcn(개행문자)을 br 태그로 대체한다. --%>
                <p>${fn:replace(goods.goods_publisher_comment ,crcn,br)}</p>
            </div>
            <div class="tab_content" id="tab5">
                <h4>추천사</h4>
                <%-- 상품 추천평에 포함된 crcn(개행문자)을 br 태그로 대체한다. --%>
                <p>${fn:replace(goods.goods_recommendation,crcn,br) }</p>
            </div>
            <div class="tab_content" id="tab6">
                <h4>리뷰</h4>
            </div>
        </div>
    </div>
    <div class="clear"></div>
    <div id="layer" style="visibility: hidden">
        <!-- visibility:hidden 으로 설정하여 해당 div안의 모든것들을 가려둔다. -->
        <div id="popup">
            <!-- 팝업창 닫기 버튼 -->
            <a href="javascript:" onClick="javascript:imagePopup('close', '.layer01');"> <img src="${contextPath}/resources/image/close.png" id="close" />
            </a> <br />
            <font size="12" id="contents">장바구니에 담았습니다.</font><br>
            <form action='${contextPath}/cart/myCartList.do'>
                <input type="submit" value="장바구니 보기">
            </form>
</body>

</html>
<input type="hidden" name="isLogOn" id="isLogOn" value="${isLogOn}" />

9. 다음은 실행 결과이다. 로그인 후 상품 상세 페이지에서 장바구니를 클릭한다.

- http://localhost/bookshop01/goods/goodsDetail.do?goods_id=354

10. 장바구니에 없는 상품이면 장바구니에 추가된다.

11. 반면에 이미 장바구니에 추가된 상품이면 "이미 카트에 등록된 상품입니다." 라는 알림창이 나타난다.


(3) 장바구니 목록 보기

* '장바구니 목록 보기'는 상품을 장바구니에 추가한 후 또는 상단의 장바구니 메뉴를 클릭했을 때 장바구니에 담긴 상품 목록을 보여주는 기능이다.

1. 장바구니 테이블에 담긴 상품 번호에 대해 in 연산자와 <foreach> 태그를 이용해 상품 정보를 조회한 후 장바구니 페이지에 표시하도록 card.xml을 편집한다.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
	PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.cart">

	<!-- 장바구니 정보를 저장할 resultMap이다. -->
	<resultMap id="cartResult" type="CartVO">
		<result property="cart_id" column="cart_id" />
		<result property="goods_id" column="goods_id" />
		<result property="member_id" column="member_id" />
		<result property="cart_goods_qty" column="cart_goods_qty" />
		<result property="creDate" column="creDate" />
	</resultMap>
	
	<!-- 장바구니 페이지를 표시할 상품 정보를 저장할 resultMap이다. -->
	<resultMap id="goodsResult" type="GoodsVO">
		<result property="goods_id" column="goods_id" />
		<result property="goods_title" column="goods_title" />
		<result property="goods_writer" column="goods_writer" />
		<result property="goods_price" column="goods_price" />
		<result property="goods_publisher" column="goods_publisher" />

		<result property="goods_status" column="goods_status" />
		<result property="goods_sales_price" column="goods_sales_price" />
		<result property="goods_published_date" column="goods_published_date" />
		<result property="goods_total_page" column="goods_total_page" />
		<result property="goods_isbn" column="goods_isbn" />
		<result property="goods_delivery_price" column="goods_delivery_price" />
		<result property="goods_delivery_date" column="goods_delivery_date" />

		<result property="goods_fileName" column="fileName" />
		<result property="goods_sort" column="goods_sort" />
		<result property="goods_writer_intro" column="goods_writer_intro" />
		<result property="goods_contents_order" column="goods_contents_order" />
		<result property="goods_intro" column="goods_intro" />
	</resultMap>

	<!-- 모든 장바구니 정보를 조회한다. -->
	<select id="selectCartList"  parameterType="cartVO"  resultMap="cartResult"   >
	    <![CDATA[
		select cart_id, goods_id, member_id, cart_goods_qty, creDate 
		from t_shopping_cart 
		where member_id=#{member_id} 
		]]>
	</select>

	<!-- 장바구니 테이블에 등록된 상품 번호를 이용해 상품 정보를 조회한다. -->
	<select id="selectGoodsList" resultMap="goodsResult" parameterType="java.util.Map">
      <![CDATA[
          select g.*,d.fileName from t_shopping_goods g, t_goods_detail_image d
          where g.goods_id=d.goods_id
          and d.filetype='main_image'
           and g.goods_id in
      ]]>
		<foreach item="item" collection="list" open="(" separator="," close=")">
			#{item.goods_id}
		</foreach>
		order by g.goods_creDate desc
	</select>

2. 자바 클래스를 구현하자. CartControllerImpl 클래스에서는 조회한 장바구니 목록과 상품 정보 목록을 Map에 저장한다. 그리고 장바구니 목록을 표시하는 페이지에서 상품을 주문할 경우에 대비해 상품 정보를 미리 세션에 바인딩한다.

@Controller("cartController")
@RequestMapping(value = "/cart")
public class CartControllerImpl extends BaseController implements CartController {
	
	@Autowired
	private CartService cartService;
	@Autowired
	private CartVO cartVO;
	@Autowired
	private MemberVO memberVO;

	@RequestMapping(value = "/myCartList.do", method = RequestMethod.GET)
	public ModelAndView myCartMain(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String viewName = (String) request.getAttribute("viewName");
		ModelAndView mav = new ModelAndView(viewName);
		HttpSession session = request.getSession();
		MemberVO memberVO = (MemberVO) session.getAttribute("memberInfo");
		String member_id = memberVO.getMember_id();
		cartVO.setMember_id(member_id);
		Map<String, List> cartMap = cartService.myCartList(cartVO); // 장바구니 페이지에 표시할 상품 정보를 조회한다.
		session.setAttribute("cartMap", cartMap);// 장바구니 목록 화면에서 상품 주문 시 사용하기 위해서 장바구니 목록을 세션에 저장한다.
		// mav.addObject("cartMap", cartMap);
		return mav;
	}

3. Service 클래스를 구현한다. 고객이 장바구니 담기를 클릭하면 장바구니 테이블에는 해당 상품의 상품 번호만 저장된다. 따라서 장바구니 페이지에 상품 정보를 같이 표시하려면 장바구니 테이블에 저장된 상품 번호를 이용해 상품 정보를 따로 조회한 후 장바구니 페이지로 전달해서 표시해야 한다. Service 클래스에서는 회원 ID로 상품 번호를 조회한 후 이를 이용해 다시 상품 상세 정보를 조회한다. 그리고 조회한 장바구니 정보와 상품 정보를 Map에 각각 저장한 후 컨트롤러로 반환한다.

@Service("cartService")
@Transactional(propagation = Propagation.REQUIRED)
public class CartServiceImpl implements CartService {
	
	@Autowired
	private CartDAO cartDAO;

	public Map<String, List> myCartList(CartVO cartVO) throws Exception {
		Map<String, List> cartMap = new HashMap<String, List>();
		List<CartVO> myCartList = cartDAO.selectCartList(cartVO); // 장바구니 페이지에 표시할 장바구니 정보를 조회한다.
		if (myCartList.size() == 0) { // 카트에 저장된 상품이 없는 경우 null을 반환한다.
			return null;
		}
		List<GoodsVO> myGoodsList = cartDAO.selectGoodsList(myCartList); // 장바구니 페이지에 표시할 상품 정보를 조회한다.
		cartMap.put("myCartList", myCartList);
		cartMap.put("myGoodsList", myGoodsList);
		return cartMap; // 장바구니 정보와 상품 정보를 cardMap에 저장하여 반환한다.
	}

4. DAO 클래스는 다음과 같다.

package com.bookshop01.cart.dao;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;

import com.bookshop01.cart.vo.CartVO;
import com.bookshop01.goods.vo.GoodsVO;

@Repository("cartDAO")
public class CartDAOImpl implements CartDAO {
	
	@Autowired
	private SqlSession sqlSession;

	public List<CartVO> selectCartList(CartVO cartVO) throws DataAccessException {
		List<CartVO> cartList = (List) sqlSession.selectList("mapper.cart.selectCartList", cartVO);
		return cartList;
	}

	public List<GoodsVO> selectGoodsList(List<CartVO> cartList) throws DataAccessException {
		List<GoodsVO> myGoodsList;
		myGoodsList = sqlSession.selectList("mapper.cart.selectGoodsList", cartList);
		return myGoodsList;
	}

	public boolean selectCountInCart(CartVO cartVO) throws DataAccessException {
		String result = sqlSession.selectOne("mapper.cart.selectCountInCart", cartVO);
		return Boolean.parseBoolean(result);
	} // 이미 장바구니에 추가된 상품인지 조회한다.

	public void insertGoodsInCart(CartVO cartVO) throws DataAccessException {
		int cart_id = selectMaxCartId();
		cartVO.setCart_id(cart_id);
		sqlSession.insert("mapper.cart.insertGoodsInCart", cartVO);
	} // 장바구니에 추가한다.

	public void updateCartGoodsQty(CartVO cartVO) throws DataAccessException {
		sqlSession.insert("mapper.cart.updateCartGoodsQty", cartVO);
	}

	public void deleteCartGoods(int cart_id) throws DataAccessException {
		sqlSession.delete("mapper.cart.deleteCartGoods", cart_id);
	}

	private int selectMaxCartId() throws DataAccessException {
		int cart_id = sqlSession.selectOne("mapper.cart.selectMaxCartId");
		return cart_id;
	}

}

5. 마지막으로 JSP를 구현하자. 컨트롤러에서 세션에 바인딩한 장바구니 목록과 상품 목록을 이용해 장바구니 페이지를 구현해 보자.

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"
	isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<c:set var="myCartList" value="${cartMap.myCartList}" />
<c:set var="myGoodsList" value="${cartMap.myGoodsList}" />

<c:set var="totalGoodsNum" value="0" /> <!-- 주문 개수 -->
<c:set var="totalDeliveryPrice" value="0" /> <!-- 총 배송비 -->
<c:set var="totalDiscountedPrice" value="0" /> <!-- 총 할인금액 -->

<head>
    <script type="text/javascript">
        function calcGoodsPrice(bookPrice, obj) {
            var totalPrice, final_total_price, totalNum;
            var goods_qty = document.getElementById("select_goods_qty");
            //alert("총 상품금액"+goods_qty.value);
            var p_totalNum = document.getElementById("p_totalNum");
            var p_totalPrice = document.getElementById("p_totalPrice");
            var p_final_totalPrice = document.getElementById("p_final_totalPrice");
            var h_totalNum = document.getElementById("h_totalNum");
            var h_totalPrice = document.getElementById("h_totalPrice");
            var h_totalDelivery = document.getElementById("h_totalDelivery");
            var h_final_total_price = document.getElementById("h_final_totalPrice");
            if (obj.checked == true) {
                //	alert("체크 했음")

                totalNum = Number(h_totalNum.value) + Number(goods_qty.value);
                //alert("totalNum:"+totalNum);
                totalPrice = Number(h_totalPrice.value) + Number(goods_qty.value * bookPrice);
                //alert("totalPrice:"+totalPrice);
                final_total_price = totalPrice + Number(h_totalDelivery.value);
                //alert("final_total_price:"+final_total_price);

            } else {
                //	alert("h_totalNum.value:"+h_totalNum.value);
                totalNum = Number(h_totalNum.value) - Number(goods_qty.value);
                //	alert("totalNum:"+ totalNum);
                totalPrice = Number(h_totalPrice.value) - Number(goods_qty.value) * bookPrice;
                //	alert("totalPrice="+totalPrice);
                final_total_price = totalPrice - Number(h_totalDelivery.value);
                //	alert("final_total_price:"+final_total_price);
            }

            h_totalNum.value = totalNum;

            h_totalPrice.value = totalPrice;
            h_final_total_price.value = final_total_price;

            p_totalNum.innerHTML = totalNum;
            p_totalPrice.innerHTML = totalPrice;
            p_final_totalPrice.innerHTML = final_total_price;
        }

        function modify_cart_qty(goods_id, bookPrice, index) {
            //alert(index);
            var length = document.frm_order_all_cart.cart_goods_qty.length;
            var _cart_goods_qty = 0;
            if (length > 1) { //카트에 제품이 한개인 경우와 여러개인 경우 나누어서 처리한다.
                _cart_goods_qty = document.frm_order_all_cart.cart_goods_qty[index].value;
            } else {
                _cart_goods_qty = document.frm_order_all_cart.cart_goods_qty.value;
            }

            var cart_goods_qty = Number(_cart_goods_qty);
            //alert("cart_goods_qty:"+cart_goods_qty);
            //console.log(cart_goods_qty);
            $.ajax({
                type: "post",
                async: false, //false인 경우 동기식으로 처리한다.
                url: "${contextPath}/cart/modifyCartQty.do",
                data: {
                    goods_id: goods_id,
                    cart_goods_qty: cart_goods_qty
                },

                success: function(data, textStatus) {
                    //alert(data);
                    if (data.trim() == 'modify_success') {
                        alert("수량을 변경했습니다!!");
                    } else {
                        alert("다시 시도해 주세요!!");
                    }

                },
                error: function(data, textStatus) {
                    alert("에러가 발생했습니다." + data);
                },
                complete: function(data, textStatus) {
                    //alert("작업을완료 했습니다");

                }
            }); //end ajax	
        }

        function delete_cart_goods(cart_id) {
            var cart_id = Number(cart_id);
            var formObj = document.createElement("form");
            var i_cart = document.createElement("input");
            i_cart.name = "cart_id";
            i_cart.value = cart_id;

            formObj.appendChild(i_cart);
            document.body.appendChild(formObj);
            formObj.method = "post";
            formObj.action = "${contextPath}/cart/removeCartGoods.do";
            formObj.submit();
        }

        function fn_order_each_goods(goods_id, goods_title, goods_sales_price, fileName) {
            var total_price, final_total_price, _goods_qty;
            var cart_goods_qty = document.getElementById("cart_goods_qty");

            _order_goods_qty = cart_goods_qty.value; //장바구니에 담긴 개수 만큼 주문한다.
            var formObj = document.createElement("form");
            var i_goods_id = document.createElement("input");
            var i_goods_title = document.createElement("input");
            var i_goods_sales_price = document.createElement("input");
            var i_fileName = document.createElement("input");
            var i_order_goods_qty = document.createElement("input");

            i_goods_id.name = "goods_id";
            i_goods_title.name = "goods_title";
            i_goods_sales_price.name = "goods_sales_price";
            i_fileName.name = "goods_fileName";
            i_order_goods_qty.name = "order_goods_qty";

            i_goods_id.value = goods_id;
            i_order_goods_qty.value = _order_goods_qty;
            i_goods_title.value = goods_title;
            i_goods_sales_price.value = goods_sales_price;
            i_fileName.value = fileName;

            formObj.appendChild(i_goods_id);
            formObj.appendChild(i_goods_title);
            formObj.appendChild(i_goods_sales_price);
            formObj.appendChild(i_fileName);
            formObj.appendChild(i_order_goods_qty);

            document.body.appendChild(formObj);
            formObj.method = "post";
            formObj.action = "${contextPath}/order/orderEachGoods.do";
            formObj.submit();
        }

        function fn_order_all_cart_goods() {
            //	alert("모두 주문하기");
            var order_goods_qty;
            var order_goods_id;
            var objForm = document.frm_order_all_cart;
            var cart_goods_qty = objForm.cart_goods_qty;
            var h_order_each_goods_qty = objForm.h_order_each_goods_qty;
            var checked_goods = objForm.checked_goods;
            var length = checked_goods.length;


            //alert(length);
            if (length > 1) {
                for (var i = 0; i < length; i++) {
                    if (checked_goods[i].checked == true) {
                        order_goods_id = checked_goods[i].value;
                        order_goods_qty = cart_goods_qty[i].value;
                        cart_goods_qty[i].value = "";
                        cart_goods_qty[i].value = order_goods_id + ":" + order_goods_qty;
                        //alert(select_goods_qty[i].value);
                        console.log(cart_goods_qty[i].value);
                    }
                }
            } else {
                order_goods_id = checked_goods.value;
                order_goods_qty = cart_goods_qty.value;
                cart_goods_qty.value = order_goods_id + ":" + order_goods_qty;
                //alert(select_goods_qty.value);
            }

            objForm.method = "post";
            objForm.action = "${contextPath}/order/orderAllCartGoods.do";
            objForm.submit();
        }
    </script>
</head>

<body>
    <table class="list_view">
        <tbody align=center>
            <tr style="background:#33ff00">
                <td class="fixed">구분</td>
                <td colspan=2 class="fixed">상품명</td>
                <td>정가</td>
                <td>판매가</td>
                <td>수량</td>
                <td>합계</td>
                <td>주문</td>
            </tr>

            <c:choose>
                <c:when test="${ empty myCartList }">
                    <tr>
                        <td colspan=8 class="fixed">
                            <strong>장바구니에 상품이 없습니다.</strong>
                        </td>
                    </tr>
                </c:when>
                <c:otherwise>
                    <tr>
                        <form name="frm_order_all_cart">
                        	<%-- 장바구니에 등록된 상품 번호로 조회한 상품 목록을 표시한다. --%>
                            <c:forEach var="item" items="${myGoodsList }" varStatus="cnt">
                            	<%-- 장바구니에 담긴 상품 수량을 표시하기 위해 변수를 설정한다. --%>
                                <c:set var="cart_goods_qty" value="${myCartList[cnt.count-1].cart_goods_qty}" />
                                <c:set var="cart_id" value="${myCartList[cnt.count-1].cart_id}" />
                                <td><input type="checkbox" name="checked_goods" checked value="${item.goods_id }" onClick="calcGoodsPrice(${item.goods_sales_price },this)"></td>
                                <td class="goods_image">
                                    <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id }">
                                        <%-- 상품의 이미지를 표시한다. --%>
                                        <img width="75" alt="" src="${contextPath}/thumbnails.do?goods_id=${item.goods_id}&fileName=${item.goods_fileName}" />
                                    </a>
                                </td>
                                <td>
                                    <h2>
                                    	<%-- 상품 이름을 표시한다. --%>
                                        <a href="${contextPath}/goods/goodsDetail.do?goods_id=${item.goods_id }">${item.goods_title }</a>
                                    </h2>
                                </td>
                                <td class="price"><span>${item.goods_price }원</span></td>
                                <td>
                                    <strong>
                                        <fmt:formatNumber value="${item.goods_sales_price*0.9}" type="number" var="discounted_price" />
                                        ${discounted_price}원(10%할인)
                                    </strong>
                                </td>
                                <td>
                                    <input type="text" id="cart_goods_qty" name="cart_goods_qty" size=3 value="${cart_goods_qty}"><br>
                                    <a href="javascript:modify_cart_qty(${item.goods_id },${item.goods_sales_price*0.9 },${cnt.count-1 });">
                                        <img width=25 alt="" src="${contextPath}/resources/image/btn_modify_qty.jpg">
                                    </a>
                                </td>
                                <td>
                                    <strong>
                                        <fmt:formatNumber value="${item.goods_sales_price*0.9*cart_goods_qty}" type="number" var="total_sales_price" />
                                        ${total_sales_price}원
                                    </strong>
                                </td>
                                <td>
                                    <a href="javascript:fn_order_each_goods('${item.goods_id }','${item.goods_title }','${item.goods_sales_price}','${item.goods_fileName}');">
                                        <img width="75" alt="" src="${contextPath}/resources/image/btn_order.jpg">
                                    </a><br>
                                    <a href="#">
                                        <img width="75" alt="" src="${contextPath}/resources/image/btn_order_later.jpg">
                                    </a><br>
                                    <a href="#">
                                        <img width="75" alt="" src="${contextPath}/resources/image/btn_add_list.jpg">
                                    </A><br>
                                    <a href="javascript:delete_cart_goods('${cart_id}');""> 
						   <img width=" 75" alt="" src="${contextPath}/resources/image/btn_delete.jpg">
                                    </a>
                                </td>
                    </tr>
                    <c:set var="totalGoodsPrice" value="${totalGoodsPrice+item.goods_sales_price*0.9*cart_goods_qty }" />
                    <c:set var="totalGoodsNum" value="${totalGoodsNum+1 }" />
                    </c:forEach>

        </tbody>
    </table>

    <div class="clear"></div>
    </c:otherwise>
    </c:choose>
    <br>
    <br>

    <table width=80% class="list_view" style="background:#cacaff">
        <tbody>
            <tr align=center class="fixed">
                <td class="fixed">총 상품수 </td>
                <td>총 상품금액</td>
                <td> </td>
                <td>총 배송비</td>
                <td> </td>
                <td>총 할인 금액 </td>
                <td> </td>
                <td>최종 결제금액</td>
            </tr>
            <tr cellpadding=40 align=center>
                <td id="">
                    <p id="p_totalGoodsNum">${totalGoodsNum}개 </p>
                    <input id="h_totalGoodsNum" type="hidden" value="${totalGoodsNum}" />
                </td>
                <td>
                    <p id="p_totalGoodsPrice">
                        <fmt:formatNumber value="${totalGoodsPrice}" type="number" var="total_goods_price" />
                        ${total_goods_price}원
                    </p>
                    <input id="h_totalGoodsPrice" type="hidden" value="${totalGoodsPrice}" />
                </td>
                <td>
                    <img width="25" alt="" src="${contextPath}/resources/image/plus.jpg">
                </td>
                <td>
                    <p id="p_totalDeliveryPrice">${totalDeliveryPrice }원 </p>
                    <input id="h_totalDeliveryPrice" type="hidden" value="${totalDeliveryPrice}" />
                </td>
                <td>
                    <img width="25" alt="" src="${contextPath}/resources/image/minus.jpg">
                </td>
                <td>
                    <p id="p_totalSalesPrice">
                        ${totalDiscountedPrice}원
                    </p>
                    <input id="h_totalSalesPrice" type="hidden" value="${totalSalesPrice}" />
                </td>
                <td>
                    <img width="25" alt="" src="${contextPath}/resources/image/equal.jpg">
                </td>
                <td>
                    <p id="p_final_totalPrice">
                        <fmt:formatNumber value="${totalGoodsPrice+totalDeliveryPrice-totalDiscountedPrice}" type="number" var="total_price" />
                        ${total_price}원
                    </p>
                    <input id="h_final_totalPrice" type="hidden" value="${totalGoodsPrice+totalDeliveryPrice-totalDiscountedPrice}" />
                </td>
            </tr>
        </tbody>
    </table>
    <center>
        <br><br>
        <a href="javascript:fn_order_all_cart_goods()">
            <img width="75" alt="" src="${contextPath}/resources/image/btn_order_final.jpg">
        </a>
        <a href="#">
            <img width="75" alt="" src="${contextPath}/resources/image/btn_shoping_continue.jpg">
        </a>
        <center>
            </form>

6. 다음은 실행 결과이다. 상품 상세 페이지에서 상품들을 장바구니에 담은 후 장바구니 보기를 클릭한다.

7. 화면 상단 메뉴의 장바구니를 클릭해도 장바구니에 담긴 상품 목록을 볼 수 있다.