감 잃지말고 개발하기

[JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #3. 장바구니 목록 구현하기 본문

JSP/MVC

[JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #3. 장바구니 목록 구현하기

persii 2023. 5. 16. 17:47

세션을 이용해 사용자가 원하는 도서를 장바구니에 추가하고 이를 출력해 보며,

이와 더해 사용자가 입력한 배송지 정보를 쿠키로 생성해 출력하는 로직 기록하고자 한다.

 

저번 포스팅에서는 도서 상세 페이지에서 사용자가 장바구니 추가 버튼을 눌렀을 때 해당 도서가 세션 장바구니에 추가되는 로직을 구현해 보았다.

이번 포스팅에서는 세션에 저장된 장바구니를 화면에 출력하는 장바구니 페이지와 주문 페이지를 구현해 보도록 하겠다. 

 


♠ 프로젝트 전체 로직 흐름이 궁금하면 아래 포스팅을 참고하세요 ♠

 

2023.05.15 - [JSP/MVC] - [JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #1. 구현 흐름 정리하기

 

[JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #1. 구현 흐름 정리하기

세션을 이용해 사용자가 원하는 도서를 장바구니에 추가하고 이를 출력해 보며, 이와 더해 사용자가 입력한 배송지 정보를 쿠키로 생성해 출력하는 로직 기록하고자 한다. 개인 정보가 포함되

persimmon-ary-stepbystep.tistory.com


 

 

목표

 세션과 쿠키를 사용할 수 있다.

 

 

로직 흐름

  1. 도서를 장바구니에 추가한 후, 장바구니 아이콘을 클릭하면 장바구니 페이지 URL을 요청한다.
  2. 해당 컨트롤러에서 해당 URL을 매핑해 필요한 Action 클래스를 호출한다(BookFrontController.java).
  3. Action 클래스에서 
    • 세션을 확인한 후 세션에 저장된 장바구니 속성을 가져온다.
    • 장바구니 총금액을 계산한 후 request 객체에 속성으로 공유한다.
    • 이동할 페이지에 대한 설정을 한다(BookCartListAction.java).
  4. 장바구니 페이지로 이동한다. 장바구니 페이지에서 주문하기 버튼을 클릭하면 주문 페이지 URL을 요청한다(bookCartList.jsp).
  5. 해당 컨트롤러에서 해당 URL을 매핑해 필요한 Action 클래스를 호출한다(BookFrontController.java).
  6. Action 클래스에서
    • URL을 통해 건너온 세션 쿠키를 받아온다.
    • 세션을 확인한 후 세션에 저장된 장바구니 속성을 가져온다.
    • 장바구니 총금액을 계산한다.
    • 이동할 페이지에 대한 설정을 한다(BookShippingCheckOutAction.java).
  7. 화면이 이동한다.

 

 

로직 흐름 코드 및 실행화면

1. 장바구니 아이콘

장바구니 아이콘을 클릭하면 http://localhost:8090/bookCartList.ok 을 요청한다.

 

2. 컨트롤러(BookFrontController.java)

웹 브라우저에서 요청한 URL인 /bookCartList.ok에 해당하는 if문으로 들어오고 BookCartListAction 클래스의 execute() 메서드가 호출된다. 

 

기존 BookFrontController 클래스에 아래 코드를 추가한다.

// 장바구니 목록 페이지 요청
else if (command.equals("/bookCartList.ok")) {
    action = new BookCartListAction();
    try {
        forward = action.execute(req, resp);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

 

3. Action 클래스(BookCartListAction.java)

해당 클래스 전역에 세션이 공유되도록 HttpSession 객체를 전역 변수로 설정한다.

 

처리 흐름

  1. 세션에 저장된 장바구니 목록을 가져온다.
  2. 장바구니 총금액을 계산한 후 request 객체에 속성으로 공유한다.
  3. 이동할 페이지에 대한 설정을 한다.
    • 이동할 페이지 : /book/bookCartList.jsp
    • 이동할 방법 : forward

 

getCartList(HttpServletRequest req) 메서드

  • HttpServletRequest req
    • 해당 메서드는 세션 관련 작업을 하는 메서드이므로 클라에서 넘어온 HttpServletRequest 파라미터를 인자로 받아온다.
  • 처리 순서
    1. 장바구니 속성 확인을 위해 요청한 웹 브라우저의 세션을 확인한다.
      • 장바구니를 추가하는 서버 딴 로직에서 세션을 무조건 생성하도록 설정했으므로 getSession(false)로 한다.
    2. 세션이 있는 경우 세션에 저장되어 있는 장바구니 속성에 저장된 장바구니 목록을 리턴한다.
    3. 세션이 없는 경우 null을 리턴한다.
package action;

import java.net.URLEncoder;
import java.util.ArrayList;

import javax.security.auth.message.callback.PrivateKeyCallback.Request;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import vo.ActionForward;
import vo.Cart;

/** 장바구니 목록보기 요청을 처리하는 Action 클래스 */
public class BookCartListAction implements Action {

	private HttpSession session; 

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		req.setCharacterEncoding("UTF-8");

		/* 세션에 저장된 장바구니 목록을 ArrayList 타입의 객체로 반환하는 메서드 호출 */
		ArrayList<Cart> cartList = getCartList(req);

		/* 총금액 계산 */
		int totalMoney = 0; // 지불해야 하는 총금액
		int money = 0; // 장바구니 항목 하나에 대한 지불 금액

		if (cartList != null) {
			for (int i = 0; i < cartList.size(); i++) {
				money = cartList.get(i).getC_b_price() * cartList.get(i).getC_b_qty();
				totalMoney += money;
			}
		}

		/* 포워딩할 때 가져갈 정보 저장
		 * 총금액을 request 영역에 속성으로 공유
		 * .ok -> .jsp : forward
		 */
		req.setAttribute("totalMoney", totalMoney);

		ActionForward forward = new ActionForward();
		forward.setPath("/book/bookCartList.jsp");
		forward.setRedirect(false);

		return forward;
	}

	/** 세션에 저장된 장바구니 목록을 ArrayList 타입의 객체로 반환하는 메서드 */
	@SuppressWarnings("unchecked")
	public ArrayList<Cart> getCartList(HttpServletRequest req) {

		ArrayList<Cart> s_cartList = null;

		session = req.getSession(false);
		if (session != null) {
			// 세션이 생성되어 있는 경우
			s_cartList = (ArrayList<Cart>) session.getAttribute("cartList");
		}
        
		return s_cartList;
	}

}

 

4. 장바구니 페이지(bookCartList.jsp)

4-1.  장바구니 페이지

요청된 URL은 http://localhost:8090/bookCartList.ok 이다.

세션에 저장된 장바구니가 화면에 출력되는 걸 볼 수 있다.

주문하기 버튼을 클릭하면 주문 페이지로 이동한다.

장바구니 페이지

 

4-2.  장바구니 페이지 HTML

  • sessionScope.cartList : 세션에 저장된 장바구니 속성을 가져온다.
<c:if test="${sessionScope.cartList != null && sessionScope.cartList.size() > 0}">
  <table class="table" id="cart-table">
    <thead>
      <tr>
        <th scope="col">
          <input type="checkbox"/>
        </th>
        <th scope="col">Product</th>
        <th scope="col">Price</th>
        <th scope="col">Quantity</th>
        <th scope="col">Total</th>
      </tr>
    </thead>
    <tbody>
      <c:forEach var="cart" items="${sessionScope.cartList }" varStatus="status">
        <tr>
          <td>
            <input type="checkbox" id="remove" name="remove" value="${cart.c_b_id }" />
          </td>
          <td>
            <div>
              <div>
                <img src="${request.getContextPath() }/bookImage/${cart.c_b_image }" alt="${cart.c_b_name }" id="cartImage">
              </div>
              <div>
                <p>${cart.c_b_name }</p>
              </div>
            </div>
          </td>
          <td>
            <h5><i class="bi bi-currency-dollar"></i>${cart.c_b_price }</h5>
          </td>
          <td>
            <div>
              <a href="#">
                <i class="lnr lnr-chevron-up"></i>
              </a>
              <br>
              ${cart.c_b_qty }
              <br>
              <a href="#"> 
                <i class="lnr lnr-chevron-down"></i>
              </a>
            </div>
          </td>
          <td>
            <h5><i class="bi bi-currency-dollar"></i>${cart.c_b_qty * cart.c_b_price }</h5>
          </td>
        </tr>
      </c:forEach>
         
        <tr>
          <td>
            <h5>Subtotal</h5>
          </td>
          <td>
            <h5><i class="bi bi-currency-dollar"></i>${totalMoney }</h5>
          </td>
        </tr>
        <tr>
          <td>
            <div>
              <a class="gray_btn" href="${request.getContextPath() }/bookList.ok">쇼핑 계속하기</a>
              <a class="primary-btn" href="javascript:orderForm();">주문하기</a>
            </div>
          </td>
        </tr>
    </tbody>
  </table>
</c:if>
    
<c:if test="${sessionScope.cartList == null }">
  <h1>장바구니에 담은 책이 없습니다.</h1>
</c:if>

 

4-3.  주문하기 버튼 JS 코드

orderForm() 함수는 form 태그와 input 태그를 생성하고 이것을 서버에 전송하는 역할을 수행한다.

 

input 태그가 될 변수 $input에 세션 쿠키를 담아 서버로 보낼 것인데,

이 세션 쿠키는 사용자가 도서를 장바구니에 담았을 때 서버 딴에서 쿠키로 생성해 response 객체에 담아 공유한 세션 쿠키이다. 

이 세션 쿠키의 이름은 'c_session'이다.


♠ 장바구니 추가 서버 딴 로직(Action 클래스 참고) ♠

 

2023.05.15 - [JSP/MVC] - [JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #2. 장바구니 추가 구현하기

 

[JSP][MVC][Session] 세션을 이용한 도서 장바구니 구현하기 #2. 장바구니 추가 구현하기

세션을 이용해 사용자가 원하는 도서를 장바구니에 추가하고 이를 출력해 보며, 이와 더해 사용자가 입력한 배송지 정보를 쿠키로 생성해 출력하는 로직 기록하고자 한다. 저번 포스팅에서는

persimmon-ary-stepbystep.tistory.com


 

이 세션 쿠키를 스크립트에서 사용할 것인데, 이때 $.cookie() 함수를 사용할 것이다.

$.cookie()는 jquery로 브라우저에 저장되어 있는 쿠키를 가져오는 함수인데, 이를 사용하기 위해선 추가적인 API가 필요하다. 


♠ jQuery 플러그인 다운 사이트 ♠

 

https://plugins.jquery.com/cookie/

 

jQuery Cookie | jQuery Plugin Registry

jQuery Cookie by Klaus Hartl A simple, lightweight jQuery plugin for reading, writing and deleting cookies. Versions Version Date 1.4.1 Apr 27 2014 1.4.0 Oct 5 2013 1.3.1 Jan 25 2013 1.3.0 Jan 24 2013

plugins.jquery.com


<script>
  function orderForm() {
			
    var $form = $('<form>').attr({
	  action: '/bookShippingCheckOut.ok',
	  method: 'post'
	});

    var $input2 = $('<input>').attr({
	  type: 'hidden',
	  name: 'c_session',
	  value: $.cookie('c_session')
	});
			
	$form.append($input2);
	$form.appendTo('body'); // Append the form to the document body
	$form.submit();
			
  }
</script>

 

5. 컨트롤러(BookFrontController.java)

기존 BookFrontController 클래스에 아래 코드를 추가한다.

// 주문하기 페이지 요청
else if (command.equals("/bookShippingCheckOut.ok")) {
    action = new BookShippingCheckOutAction();
    try {
        forward = action.execute(req, resp);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

 

6. Action 클래스(BookShippingCheckOutAction.java)

package action;

import java.io.PrintWriter;
import java.util.ArrayList;

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

import vo.ActionForward;
import vo.Cart;

/** 장바구니 상품을 주문하는 요청을 처리하는 Action 클래스 */
public class BookShippingCheckOutAction implements Action {

	@Override
	public ActionForward execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {

		req.setCharacterEncoding("UTF-8");
		
		/* URL로 넘어온 파라미터 저장 */
		String c_session = req.getParameter("c_session");

		ArrayList<Cart> cartList = null;
		int totalMoney = 0;		// 지불해야 하는 총금액
		int money = 0;			// 장바구니 항목 하나에 대한 지불 금액
		
		/* 요청 파라미터와 비교해 세션에 저장된 장바구니 목록 가져오기 */
		HttpSession session = req.getSession(false);
		if(session != null) {
			// 세션이 생성되어 있는 경우
			if(session.getId().equals(c_session)) {
				// 브라우저의 세션Id와 세션쿠키가 동일한 경우(같은 브라우저의 경우)
				cartList = (ArrayList<Cart>) session.getAttribute("cartList");
				for(int i=0; i<cartList.size(); i++) {
					money = cartList.get(i).getC_b_price() * cartList.get(i).getC_b_qty();
					totalMoney += money;
				}
			} else {
				// 같은 세션Id 아닌 경우
				session.invalidate();
				
				resp.setCharacterEncoding("utf-8");
				PrintWriter out = resp.getWriter();
				out.print("<script>");
				out.print("alert('서로 다른 브라우저입니다.');");
				out.print("location.href='/bookShopMain.ok';");
				out.print("</script>");
				out.close();
			}
		} else {
			// 세션이 생성되지 않은 경우
			resp.setCharacterEncoding("utf-8");
			PrintWriter out = resp.getWriter();
			out.print("<script>");
			out.print("alert('잘못된 접근입니다.');");
			out.print("location.href='/bookShopMain.ok';");
			out.print("</script>");
			out.close();
		}
		
		/* 포워딩할 때 가져갈 정보 저장 
		 * 총금액을 request 영역에 속성으로 공유
		 * .ok -> .jsp : forward
		 * */
		req.setAttribute("totalMoney", totalMoney);
		
		ActionForward forward = new ActionForward();
		forward.setPath("/book/bookShippingCheckOut.jsp");
		forward.setRedirect(false);

		return forward;
	}
}

 

7. 이동된 페이지(주문 페이지)

장바구니에 담긴 도서 목록이 보라색 박스에 출력된 걸 확인할 수 있다.

주문 페이지

 

 


 

이렇게 장바구니 페이지와 주문 페이지를 구현해보았다.

다음 시간에는 주문 페이지에 배송 정보를 입력한 후 주문 확인 페이지로 이동하는 로직을 정리해 보도록 하겠다.

 

 

 끝.