[Servlet] 장바구니 기능 구현

ByeolGyu·2024년 5월 28일

Servlet

목록 보기
2/2

✔ 장바구니 기능 구현

▷ Shop

ProductDTO

  • 변수 설정

  • 디폴트 생성자

  • 상품 정보를 모두 받는 생성자 설정

  • 이 외 Setter & Getter, toString, hashCode(),
    객체가 동일한 인스턴스인지 확인하는 equals 메서드
    새로운 객체를 형성하고, 현재 객체의 속성값을 사용해 초기화 하는 clone메서드 구현

ProductDAOImpl 전체 코드

  • ProductDAO 인터페이스를 상속받음
package org.comstudy.day06.shop;

import java.util.ArrayList;
import java.util.List;

public class ProductDAOImpl implements ProductDAO {
	private static final List<ProductDTO> productList;
	private static int seq;
	static {
		productList = new ArrayList<ProductDTO>();  // productList 초기화
		productList.add(new ProductDTO(1, "냉장고", 300, "삼성", 0));
		productList.add(new ProductDTO(2, "세탁기", 100, "LG", 0));
		productList.add(new ProductDTO(3, "선풍기", 30, "삼성", 0));
		productList.add(new ProductDTO(4, "컴퓨터", 160, "ASUS", 0));
		productList.add(new ProductDTO(5, "테레비", 200, "LG", 0));
		productList.add(new ProductDTO(6, "에어컨", 250, "케리어", 0));
		seq = 7;
	}
	
	// CRUD (입력, 출력, 검색, 수정, 삭제)
	@Override
	public void insert(ProductDTO dto) {  // 상품 번호 설정 및 상품 목록에 추가
		dto.setSeq(seq++);
		productList.add(dto);
	}
	
	@Override
	public List<ProductDTO> selectAll() {  // 모든 상품 조회
		return productList;
	}
	
	private int findIndex(int seq) { // 상품 번호 인덱스 반환
		int idx = -1;
		for(int i=0; i<productList.size(); i++) {
			if(productList.get(i).getSeq() == seq) {
				idx = i;
				break;
			}
		}
		return idx;
	}
	
	@Override
	public ProductDTO findBySeq(int seq) { // 상품 번호로 상품 조회
		ProductDTO product = null;
		int i = findIndex(seq);
		if(i != -1) {
			product = productList.get(i);
		}
		
		return product;
	}
	
	@Override
	public void update(ProductDTO dto) {  // 상품 정보 수정
		int i = findIndex(dto.getSeq()); // 인덱스 번호 찾아서
		if(i != -1) {
			productList.set(i, dto);	// 수정
		}
	}
	
	@Override
	public void delete(ProductDTO dto) {  // 상품 삭제
		int i = findIndex(dto.getSeq());
		if(i != -1) {
			productList.remove(i);
		}
	}
}

ShopController 전체 코드

package org.comstudy.day06.shop;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/shop/*")
public class ShopController extends HttpServlet {
	
	private String viewName = ""; 				
	private String prefix = "/WEB-INF/views/";  // JSP 파일의 경로를 저장
	private String suffix = ".jsp";				// JSP 파일의 확장자 저장
	
	ProductDAO dao = new ProductDAOImpl();		// DAO  객체 생성
		
	// 리다이렉트 또는 포워딩 결정 메서드
	protected void dispatcher(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		if(viewName.indexOf("redirect:") == 0) { 			// 뷰 이름에 "redirect:"가 포함되어 있으면 Redirect
			response.sendRedirect(viewName.substring("redirect:".length())); 
		} else {
			String path = prefix + viewName + suffix; 		//JSP 파일의 경로 생성
			RequestDispatcher view = request.getRequestDispatcher(path); // RequestDispatcher 객체 생성
			view.forward(request, response); // 포워딩 
		}
	}
	
	// process : doGet()doPost() 통합 처리하는 메서드
	protected void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		req.setCharacterEncoding("UTF-8");
		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html; charset=UTF-8");
		
		// urlPattern 만들기
		String reqUri = req.getRequestURI();
		String ctxPath = req.getContextPath();
		int beginIndex = ctxPath.length();
		String urlPattern = reqUri.substring(beginIndex);
		
		System.out.println("Url Pattern : " + urlPattern);
				
		
		// <POST 방식>
		if("POST".equals(req.getMethod() ) ) {
			// 상품 등록, 수정, 삭제 등의 기능
		//<Get 방식>
		} else {
			if("/shop/list.do".equals(urlPattern)) {
				List<ProductDTO> pList = (List<ProductDTO>)dao.selectAll(); // 모든 상품 목록 가져옴
				req.setAttribute("pList", pList);							// 요청 객체에 상품 목록 속성 설정
				viewName = "shop/productList";
			} else if("/shop/cart.do".equals(urlPattern)) {
				// 상품 seq, 수량을 파라미터로 전달 받고
				// 목록에서 seq를 찾아서 해당 상품의 객체를 장바구니 목록에 저장
				// 장바구니 목록은 session에 바인딩 하고 장바구니 목록 뷰 보여줌
				viewName = "shop/cartList";
			} else if("/shop/detail.do".equals(urlPattern)) {
				int seq = Integer.parseInt(req.getParameter("seq")); // 상품 번호 파라미터 추출
				ProductDTO product = dao.findBySeq(seq); 			 // 상품 번호에 해당하는 상품 정보 가져옴
				req.setAttribute("product", product);				 // 요청 객체에 상품 정보 속성 설정
				viewName = "shop/productDetail";
			} else if ("/shop/cart_add.do".equals(urlPattern)) {
		        // 요청 파라미터로부터 상품 번호와 수량을 가져옴
		        int seq = Integer.parseInt(req.getParameter("seq")); // 상품 번호 파라미터 추출
		        int ea = Integer.parseInt(req.getParameter("ea"));	// 수량 파라미터 추출

		        
		        // 요청된 상품 번호에 해당하는 상품 조회
		        ProductDTO product = dao.findBySeq(seq);
		        ProductDTO newProduct = (ProductDTO) product.clone();	// 상품 정보 복제해서 newPoduct에 넣기
		        newProduct.setEa(ea); // 상품 수량 설정

		        // 세션에서 장바구니 목록을 가져옴.
		        HttpSession session = req.getSession(); // 현재 요청의 세션 객체 가져옴
		        List<ProductDTO> cart = (List<ProductDTO>) session.getAttribute("cart"); // 세션에서 장바구니 목록 가져옴
		        if (cart == null) { 			
		            cart = new ArrayList<>();	// 장바구니가 비어있는 경우 새로운 장바구니 목록 생성
		        }

		        // 장바구니에 이미 동일한 상품이 존재하는지 확인
		        // 동일 상품이 있으면 수량을 증가
		        // 동일 상품 없으면 새로운 상품 추가
		        boolean samething = false; 
		        for (ProductDTO item : cart) { // 장바구니 목록 순회
		            if (item.getSeq() == newProduct.getSeq()) { // 같은 상품이 있을때
		                item.setEa(item.getEa() + newProduct.getEa()); // 더함
		                samething = true; // 같은 상품 있음
		                break; 
		            }
		        }

		        if (!samething) { // 같은 상품 없을 때
		            cart.add(newProduct);
		        }

		        // 장바구니 목록을 세션에 다시 저장
		        session.setAttribute("cart", cart);

		        // 장바구니 페이지로 리다이렉트
		        viewName = "redirect:cart.do";
		        
		    } else if("/shop/cart_remove.do".equals(urlPattern)) {
				int seq = Integer.parseInt(req.getParameter("seq"));

				HttpSession session = req.getSession();
				List<ProductDTO> cart = (List<ProductDTO>)session.getAttribute("cart"); // 세션 안에 있는지 확인
				
				if(cart != null) {
					//seq가 일치하는 index를 cartList에서 찾아서 제거
					int index = cart.indexOf(new ProductDTO(seq));
					if(index != -1) {
						cart.remove(index);
					}
				}
				viewName = "redirect:cart.do";
			}
		}

        dispatcher(req, resp); // 포워딩
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		process(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		process(req, resp);
	}
}

▷ 장바구니 기능

장바구니 목록 생성 (ShopController)

장바구니 목록에 추가하기 (ShopController)

장바구니 상품 삭제하기 (ShopController)

상품 상세보기(productDetail.jsp)

addCartFn()

  • 장바구니에 상품 추가할 때 호출
  • 선택한 상품 번호와 수량을 가져와서 장바구니에 추가하는 url 생성 및 리다이렉트

productDetail.jsp 전체 코드

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
	</head>
	<body>
		<h1> 상품 상세보기 </h1>
		<table width="500" border="1">
			<tr>
				<th>번호</th><td>${product.seq}</td>
			</tr>
			<tr>
				<th>상품명</th><td>${product.title}</td>
			</tr>
			<tr>
				<th>가격</th><td>${product.price}</td>
			</tr>
			<tr>
				<th>메이커</th><td>${product.maker}</td>
			</tr>
			<tr>
				<th>수량</th>
				<td>
					<select id="ea">
						<option value="1">1</option> 
						<option value="2">2</option> 
						<option value="3">3</option> 
						<option value="4">4</option> 
						<option value="5">5</option> 
					</select>
				</td>
			</tr>
			
		</table>
		
		<script>
			function addCartFn(element){
				var seq = element.dataset.seq;
			    var ea = document.getElementById("ea").value;
			    var url = "cart_add.do?seq=" + seq + "&ea=" + ea;
				console.log(url);
				window.location.href = url;
			}
		</script>
		
		
		<a href="list.do">상품 목록</a>
		<a href="cart.do">장바구니 목록</a>
		<button data-seq="${product.seq}" onclick="addCartFn(this)">장바구니에 추가</button>
	</body>
</html>

장바구니 리스트(cartList.jsp)

jstl 사용하기
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 를 통해 사용선언

  • JSP 파일에서 JSTL 태그 사용 가능하게 됨
  • ${}을 사용하여 데이터를 효율적으로 표현 가능
  • <c:if>, <c:forEach> 등을 사용해 조건부나 반복문 생성 가능함
  • {empty}는 JSTL EL에서 사용되는 표현식 중 하나,
    test={empty}를 통해 비어 있으면 true를 반환하고, 비어있지 않으면 false를 반환
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@page import="org.comstudy.day06.shop.ProductDTO"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>장바구니 목록</title>
<script>
		function removeCartFn(btn) {
			var seq = btn.dataset.seq;
			var url = "cart_remove.do?seq=" + seq;
			location.href = url;
		}
</script>
</head>
<body>
<%
int eaTotal = 0;
int priceTotal = 0;
%>
    <h1>장바구니 목록</h1>
    <c:if test="${empty cart}">
        <p>장바구니에 상품이 없습니다.</p>
    </c:if>
    
    <c:if test="${not empty cart}">
	    <table border="1" width="500">
	        <thead>
	            <tr>
	                <th>상품 번호</th>
	                <th>상품명</th>
	                <th>메이커</th>
	                <th>수량</th>
	                <th>가격</th>
	                <th>삭제</th>
	            </tr>
	        </thead>
	        <tbody>
	            <c:forEach var="item" items="${cart}">
	            <%
	            ProductDTO item = (ProductDTO) pageContext.findAttribute("item");
	            if (item != null) {
	                eaTotal += item.getEa();
	                priceTotal += item.getPrice() * item.getEa();
	            %>
	                <tr>
	                    <td>${item.seq}</td>
	                    <td>${item.title}</td>
	                    <td>${item.maker}</td>
	                    <td>${item.ea}</td>
	                    <td>${item.price * item.ea}</td>
	                    <td><button data-seq="${item.seq}" onclick="removeCartFn(this)">장바구니에서 제거</button></td>
	                </tr>
	            <%
	            }
	            %>
	            </c:forEach>
	        </tbody>
	        <tfoot>
		        <tr>
			        <th colspan="3">합 계</th>
			        <td><%=eaTotal %></td>
			        <td><%=priceTotal %></td>
			        <td><button>구매하기</button></td>
		        </tr>
	        </tfoot>
	    </table>
	</c:if>
    <a href="list.do">상품 목록으로 돌아가기</a>
</body>
</html>
profile
ByeolGyu

0개의 댓글