Study Web Development

2월 15일

이전으로

Servlet & JSP

9. MVC

mvcPage

프로젝트 생성 및 설정
  1. WEB-INF 폴더의 shop.properties 하단에 다음의 내용을 추가
/item/detail.do=kr.item.action.DetailAction
# 장바구니
/cart/write.do=kr.cart.action.WriteAction
/cart/list.do=kr.cart.action.ListAction
  1. table.sql 하단에 다음의 내용을 추가
/* 장바구니 */
CREATE TABLE zcart(
	cart_num NUMBER,
	item_num NUMBER NOT NULL,
	order_quantity NUMBER(7) NOT NULL,
	reg_date DATE NOT NULL,
	mem_num NUMBER NOT NULL,
	CONSTRAINT zcart_pk PRIMARY KEY (cart_num),
	CONSTRAINT zcart_fk1 FOREIGN KEY (item_num) REFERENCES zitem (item_num),
	CONSTRAINT zcart_fk2 FOREIGN KEY (mem_num) REFERENCES zmember (mem_num)
);

CREATE SEQUENCE zcart_seq;
Model
  1. 새 클래스 DetailAction 생성
package kr.item.action;

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

import kr.controller.Action;
import kr.item.dao.ItemDAO;
import kr.item.vo.ItemVO;
import kr.util.StringUtil;

public class DetailAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 상품 번호 반환
		int item_num = Integer.parseInt(request.getParameter("item_num"));
		
		ItemDAO dao = ItemDAO.getInstance();
		ItemVO item = dao.getItem(item_num);
		
		// 줄바꿈 처리
		item.setDetail(StringUtil.useBrNoHtml(item.getDetail()));
		
		request.setAttribute("item", item);
		
		// JSP 경로 반환
		return "/WEB-INF/views/item/user_detail.jsp";
	}

}
  1. src/main/java 오른쪽 클릭하고 새 패키지 kr.cart.action 생성 후 새 클래스 WriteAction 생성
package kr.cart.action;

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

import kr.cart.dao.CartDAO;
import kr.cart.vo.CartVO;
import kr.controller.Action;
import kr.item.dao.ItemDAO;
import kr.item.vo.ItemVO;

public class WriteAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		Integer user_num = (Integer)session.getAttribute("user_num");
		if(user_num==null) { // 로그인되어 있지 않은 경우
			return "redirect:/member/loginForm.do";
		}
		
		// 로그인되어 있는 경우
		request.setCharacterEncoding("UTF-8");
		
		CartVO cart = new CartVO();
		cart.setItem_num(Integer.parseInt(request.getParameter("item_num")));
		cart.setOrder_quantity(Integer.parseInt(request.getParameter("order_quantity")));
		cart.setMem_num(user_num);
		
		CartDAO dao = CartDAO.getInstance();
		CartVO cartItem = dao.getCart(cart);
		if(cartItem==null) { // 같은 회원 번호, 같은 상품 번호로 등록한 정보 미존재
			dao.insertCart(cart);
		}
		else { // 같은 회원 번호, 같은 상품 번호로 등록한 정보 존재
			ItemDAO itemDao = ItemDAO.getInstance();
			ItemVO item = itemDao.getItem(cartItem.getItem_num());
			int order_quantity = cartItem.getOrder_quantity() + cart.getOrder_quantity(); // 기존 카트에 저장된 수량과 새로 입력한 수량 합산
			
			if(item.getQuantity()<order_quantity) { // 상품 재고 수량보다 장바구니에 많이 담으면 오류
				request.setAttribute("notice_msg", "기존에 장바구니에 담은 상품입니다. 수량을 추가하면 재고가 부족합니다.");
				request.setAttribute("notice_url", request.getContextPath() + "/cart/list.do");
				return "/WEB-INF/views/common/alert_singleView.jsp";
			}
			
			// 같은 회원 번호, 같은 상품 번호로 등록한 정보가 존재할 때 업데이트
			cart.setOrder_quantity(order_quantity);
			dao.updateCartByItem_num(cart);
		}
		
		// JSP 경로 반환
		return "redirect:/cart/list.do";
	}
	
}
  1. 새 클래스 ListAction 생성
package kr.cart.action;

import java.util.List;

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

import kr.cart.dao.CartDAO;
import kr.cart.vo.CartVO;
import kr.controller.Action;

public class ListAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpSession session = request.getSession();
		Integer user_num = (Integer)session.getAttribute("user_num");
		if(user_num==null) { // 로그인되어 있지 않은 경우
			return "redirect:/member/loginForm.do";
		}
		
		CartDAO dao = CartDAO.getInstance();
		int all_total = dao.getTotalByMem_num(user_num);
		
		List<CartVO> list = null;
		if(all_total>0) {
			list = dao.getListCart(user_num);
		}
		
		request.setAttribute("list", list);
		request.setAttribute("all_total", all_total);
		
		// JSP 경로 반환
		return "/WEB-INF/views/cart/list.jsp";
	}

}
View
  1. item 폴더에 새 JSP 파일 user_detail.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품 상세</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.number.min.js"></script>
<script type="text/javascript">
	$(function() {
		// 장바구니 상품 담기 유효성 체크
		$('#item_cart').submit(function() {
			if($('#order_quantity').val()=='') {
				alert('수량을 입력하세요!');
				$('#order_quantity').focus();
				return false;
			}
		}); // end of submit
		
		// 주문 수량 변경
		$('#order_quantity').on('keyup mouseup', function() {
			if($('#order_quantity').val()=='') {
				$('#item_total_txt').text('총 주문 금액 : 0원');
				return;
			}
			if(Number($('#item_quantity').val()) < $('#order_quantity').val()) { // Number()를 씌우지 않으면 양쪽 다 문자열로 인식해서 비교가 제대로 되지 않음
				alert('수량이 부족합니다.');
				$('#order_quantity').val('');
				$('#item_total_txt').text('총 주문 금액 : 0원');
				return;
			}
			
			let total = $('#item_price').val() * $('#order_quantity').val();
			$('#item_total_txt').text('총 주문 금액 : ' + $.number(total) + '');
		}); // end of on
	});
</script>
</head>
<body>
<div class="page-main">
	<jsp:include page="/WEB-INF/views/common/header.jsp"/>
	<h2>상품 상세</h2>
	<c:if test="${item.status==1}">
	<div class="result-display">
		<div class="align-center">
			본 상품은 판매 중지되었습니다.
			<br>
			<input type="button" value="상품 목록" onclick="location.href='itemList.do';">
		</div>
	</div>
	</c:if>
	<c:if test="${item.status==2}">
	<h3 class="align-center">${item.name}</h3>
	<div class="item-image">
		<img src="${pageContext.request.contextPath}/upload/${item.photo2}" width="400">
	</div>
	<div class="item-detail">
		<form id="item_cart" action="${pageContext.request.contextPath}/cart/write.do" method="post">
			<input type="hidden" name="item_num" id="item_num" value="${item.item_num}">
			<input type="hidden" name="item_price" id="item_price" value="${item.price}">
			<input type="hidden" name="item_quantity" id="item_quantity" value="${item.quantity}">
			<ul>
				<li>
					가격 : <b><fmt:formatNumber value="${item.price}"/></b>
				</li>
				<li>
					재고 : <b><fmt:formatNumber value="${item.quantity}"/></b>
				</li>
				<c:if test="${item.quantity>0}">
				<li>
					<label for="order_quantity">구매 수량</label>
					<input type="number" name="order_quantity" id="order_quantity" min="1" max="${item.quantity}" class="quantity-width">
				</li>
				<li>
					<span id="item_total_txt">총 주문 금액 : 0원</span>
				</li>
				<li>
					<input type="submit" value="장바구니에 담기">
				</li>
				</c:if>
				<c:if test="${item.quantity<=0}">
				<li class="align-center">
					<span class="sold-out">품절</span>
				</li>
				</c:if>
			</ul>
		</form>
	</div>
	<hr size="1" noshade width="100%">
	<p>
		${item.detail}
	</p>
	</c:if>
</div>
</body>
</html>
  1. common 폴더에 새 JSP 파일 alert_singleView.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script type="text/javascript">
	alert('${notice_msg}');
	location.href = '${notice_url}';
</script>
  1. views 폴더의 하위 폴더로 cart 생성 후 새 JSP 파일 list.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>장바구니</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
	$(function() {
		// 장바구니 상품 주문 수량 변경
		$('.cart-modify').on('click', function() {
			let input_quantity = $(this).parent().find('input[name="order_quantity"]');
			if(input_quantity.val()=='') {
				alert('수량을 입력하세요!');
				input_quantity.focus();
				return;
			}
			
			if(input_quantity.val()<1) {
				alert('상품의 최소 수량은 1입니다.');
				input_quantity.val(input_quantity.attr('value'));
				return;
			}
			
			// ajax 처리
			$.ajax({
				url:'modifyCart.do',
				type:'post',
				data:{
					cart_num:$(this).attr('data-cartnum'),
					item_num:$(this).attr('data-itemnum'),
					order_quantity:input_quantity.val()
				},
				dataType:'json',
				cache:false,
				timeout:30000,
				success:function(param) {
					if(param.result=='logout') {
						alert('로그인 후 사용하세요!');
					}
					else if(param.result=='noSale') {
						alert('판매 중지되었습니다.');
						location.href = 'list.do'; // 화면 갱신
					}
					else if(param.result=='noQuantity') {
						alert('상품의 수량이 부족합니다.');
						location.href = 'list.do'; // 화면 갱신
					}
					else if(param.result=='success') {
						alert('담은 수량이 수정되었습니다.');
						location.href='list.do'; // 화면 갱신
					}
					else {
						alert('수정시 오류 발생!');
					}
				},
				error:function() {
					alert('네트워크 오류 발생!');
				}
			}); // end of ajax
		}); // end of on
		
		// 장바구니 상품 삭제
		$('.cart-delete').on('click', function() {
			$.ajax({
				url:'deleteCart.do',
				type:'post',
				data:{cart_num:$(this).attr('data-cartnum')},
				dataType:'json',
				cache:false,
				timeout:30000,
				success:function(param) {
					if(param.result=='logout') {
						alert('로그인 후 사용하세요!');
					}
					else if(param.result=='success') {
						alert('선택하신 상품을 삭제했습니다.');
						location.href = 'list.do'; // 화면 갱신
					}
					else {
						alert('삭제시 오류 발생!');
					}
				},
				error:function() {
					alert('네트워크 오류 발생!');
				}
			}); // end of ajax
		}); // end of on
	});
</script>
</head>
<body>
<div class="page-main">
	<jsp:include page="/WEB-INF/views/common/header.jsp"/>
	<h2>장바구니</h2>
	<c:if test="${empty list}">
	<div class="result-display">
		장바구니에 담은 상품이 없습니다.
	</div>
	</c:if>
	<c:if test="${!empty list}">
	<form id="cart_order" method="post" action="${pageContext.request.contextPath}/order/orderForm.do">
		<table>
			<tr>
				<th>상품명</th>
				<th>수량</th>
				<th>상품 가격</th>
				<th>합계</th>
			</tr>
			<c:forEach var="cart" items="${list}">
			<tr>
				<td>
					<a href="${pageContext.request.contextPath}/item/detail.do?item_num=${cart.item_num}">
						<img src="${pageContext.request.contextPath}/upload/${cart.item.photo1}" width="80">
						${cartitem.name}
					</a>
				</td>
				<td class="align-center">
					<c:if test="${cart.item.status==1 or cart.item.quantity<cart.order_quantity}">[판매 중지]</c:if>
					<c:if test="${cart.item.status!=1 or cart.item.quantity>=cart.order_quantity}">
					<input type="number" name="order_quantity" value="${cart.order_quantity}" min="1" max="99999" class="quantity-width">
					<br>
					<input type="button" value="변경" class="cart-modify" data-cartnum="${cart.cart_num}" data-itemnum="${cart.item_num}">
					</c:if>
				</td>
				<td class="align-center"><fmt:formatNumber value="${cart.item.price}"/></td>
				<td class="align-center">
					<fmt:formatNumber value="${cart.sub_total}"/><br>
					<input type="button" value="삭제" class="cart-delete" data-cartnum="${cart.cart_num}">
				</td>
			</tr>
			</c:forEach>
			<tr>
				<td colspan="3" class="align-right"><b>총 구매 금액</b></td>
				<td class="align-center"><fmt:formatNumber value="${all_total}"/></td>
			</tr>
		</table>
		<div class="align-center">
			<input type="submit" value="구매하기">
		</div>
	</form>
	</c:if>
</div>
</body>
</html>
  1. common 폴더의 header.jsp에서 <c:if test="${!empty user_num}"> 태그 사이에 다음의 내용을 추가
		<a href="${pageContext.request.contextPath}/cart/list.do">장바구니</a>
자바빈
  1. src/main/java 오른쪽 클릭하고 새 패키지 kr.cart.vo 생성 후 새 클래스 CartVO 생성
package kr.cart.vo;

import java.sql.Date;

import kr.item.vo.ItemVO;

public class CartVO {
	private int cart_num;
	private int item_num;
	private int order_quantity;
	private Date reg_date;
	private int mem_num;
	private int sub_total;
	
	private ItemVO item;
	
	public int getCart_num() {
		return cart_num;
	}
	public void setCart_num(int cart_num) {
		this.cart_num = cart_num;
	}
	public int getItem_num() {
		return item_num;
	}
	public void setItem_num(int item_num) {
		this.item_num = item_num;
	}
	public int getOrder_quantity() {
		return order_quantity;
	}
	public void setOrder_quantity(int order_quantity) {
		this.order_quantity = order_quantity;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
	public int getMem_num() {
		return mem_num;
	}
	public void setMem_num(int mem_num) {
		this.mem_num = mem_num;
	}
	public int getSub_total() {
		return sub_total;
	}
	public void setSub_total(int sub_total) {
		this.sub_total = sub_total;
	}
	
	public ItemVO getItem() {
		return item;
	}
	public void setItem(ItemVO item) {
		this.item = item;
	}
}
DAO
  1. src/main/java 오른쪽 클릭하고 새 패키지 kr.cart.dao 생성 후 새 클래스 CartDAO 생성
package kr.cart.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import kr.cart.vo.CartVO;
import kr.item.vo.ItemVO;
import kr.util.DBUtil;

public class CartDAO {
	// 싱글턴 패턴
	private static CartDAO instance = new CartDAO();
	public static CartDAO getInstance() {
		return instance;
	}
	private CartDAO() {}
	
	// 장바구니 등록
	public void insertCart(CartVO cart) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "INSERT INTO zcart (cart_num, item_num, order_quantity, reg_date, mem_num) "
				+ "VALUES (zcart_seq.NEXTVAL, ?, ?, SYSDATE, ?)";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, cart.getItem_num());
			pstmt.setInt(2, cart.getOrder_quantity());
			pstmt.setInt(3, cart.getMem_num());
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch (Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(null, pstmt, conn);
		}
	}
	
	// 회원 번호(mem_num)별 총 구입액
	public int getTotalByMem_num(int mem_num) throws Exception {
		int total = 0;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "SELECT SUM(sub_total) FROM (SELECT c.mem_num, c.order_quantity * i.price AS sub_total "
				+ "FROM zcart c JOIN zitem i ON c.item_num=i.item_num) WHERE mem_num=?";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, mem_num);
			// SQL문을 실행해서 결과 행을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			if(rs.next()) {
				total = rs.getInt(1);
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(rs, pstmt, conn);
		}
		
		return total;
	}
	
	// 장바구니 목록
	public List<CartVO> getListCart(int mem_num) throws Exception {
		List<CartVO> list = null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "SELECT * FROM zcart c JOIN zitem i ON c.item_num=i.item_num "
				+ "WHERE c.mem_num=? ORDER BY i.item_num ASC";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, mem_num);
			// SQL문을 실행해서 결과 행들을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			list = new ArrayList<CartVO>();
			while(rs.next()) {
				CartVO cart = new CartVO(); 
				cart.setCart_num(rs.getInt("cart_num"));
				cart.setItem_num(rs.getInt("item_num"));
				cart.setOrder_quantity(rs.getInt("order_quantity"));
				cart.setMem_num(rs.getInt("mem_num"));
				
				ItemVO item = new ItemVO();
				item.setName(rs.getString("name"));
				item.setPrice(rs.getInt("price"));
				item.setPhoto1(rs.getString("photo1"));
				item.setQuantity(rs.getInt("quantity"));
				item.setStatus(rs.getInt("status"));
				
				// ItemVO를 CartVO에 저장
				cart.setItem(item);
				
				// sub_total 연산하기
				cart.setSub_total(cart.getOrder_quantity() * item.getPrice());
				
				list.add(cart);
			}		
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(rs, pstmt, conn);
		}
		
		return list;
	}
	
	// 장바구니 상세
	public CartVO getCart(CartVO cart) throws Exception {
		CartVO cartSaved = null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "SELECT * FROM zcart WHERE item_num=? AND mem_num=?";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, cart.getItem_num());
			pstmt.setInt(2, cart.getMem_num());
			// SQL문을 실행해서 결과 행을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			if(rs.next()) {
				cartSaved = new CartVO();
				cartSaved.setCart_num(rs.getInt("cart_num"));
				cartSaved.setItem_num(rs.getInt("item_num"));
				cartSaved.setOrder_quantity(rs.getInt("order_quantity"));
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(rs, pstmt, conn);
		}
		
		return cartSaved;
	}
	
	// 장바구니 수정
	public void updateCart(CartVO cart) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "UPDATE zcart SET order_quantity=? WHERE cart_num=?";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, cart.getOrder_quantity());
			pstmt.setInt(2, cart.getCart_num());
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(null, pstmt, conn);
		}
	}
	
	// 장바구니 회원 번호별 수정
	public void updateCartByItem_num(CartVO cart) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션 할당
			conn = DBUtil.getConnection();
			// SQL문 작성
			sql = "UPDATE zcart SET order_quantity=? WHERE item_num=? AND mem_num=?";
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, cart.getOrder_quantity());
			pstmt.setInt(2, cart.getItem_num());
			pstmt.setInt(3, cart.getMem_num());
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			DBUtil.executeClose(null, pstmt, conn);
		}
	}
	
	// 장바구니 삭제
	
}

다음으로