본문 바로가기

웹 개발/쇼핑몰 프로젝트(개인)

쇼핑몰 만들기(13)-고객 페이지(구매확정, 리뷰 기능, pw히스토리 테이블 생성)

728x90

이번에는 고객이 구매를 확정하는 기능,

리뷰를 작성하는 기능을 구현하고자한다.

또한 비밀번호를 변경 할 경우 이전에 사용했던 비밀번호를 관리하기위해(이전에 사용했던 pw 사용못하게 하는 등) pw히스토리 테이블을 만들고 만들었던 기능을 좀 변경하도록 하겠다

 

리뷰를 작성하기 위해 따로 리뷰 테이블을 생성한다.

리뷰 테이블의 기본키를 주문 테이블의 주문 번호로 설정해서, 주문 번호 하나당 리뷰 하나를 작성 할 수 있도록 한다.

그리고 상품 상세페이지에 들어갈때 해당 리뷰도 같이 출력하게 할것이다

 

아래는 리뷰 테이블을 생성한 것이다.

orders_no는 주문테이블의 기본키이고 리뷰테이블에서는 기본키이자 외래키이다.

리뷰테이블

 

리뷰 테이블을 생성했으니 구매확정 기능을 통해 구매확정을 하고, 리뷰를 작성하는 기능을 구현하겠다.

 

updateCustomerOrdersState.jsp

<%@page import="shop.dao.OrdersDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	// 요청 값
	String ordersNo = request.getParameter("ordersNo");

	System.out.println("updateCustomerOrdersState - ordersNo = " + ordersNo);
	
	// 주문 번호가 null일 경우(페이지 바로 접속 시)
	if(ordersNo == null) {
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
		return;
	}
%>

<%
	// 구매확정으로 주문 상태 변경하기
	String updateState = "구매확정";
	int updateOrdersStateRow = OrdersDAO.updateOrdersState(ordersNo, updateState);
	
	// 주문 상태 변경 디버깅
	System.out.println("updateCustomerOrdersState - updateOrdersStateRow = " + updateOrdersStateRow);
	
	response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
%>

 

해당 상품의 ordersNo를 요청값으로 받는다.

구매확정으로 주문의 상태를 변경시키기 위해 OrdersDAO의 updateOrdersState()메서드를 사용한다.

주문상태를 변경 시킨 후 고객의 주문목록으로 redirect했다.

이로서 구매확정 기능은 끝이다.

 

구매확정 하기

다음으로 리뷰 작성 기능을 구현하겠다.

 

리뷰 작성 버튼을 클릭하면

리뷰 작성 폼으로 이동한다.

리뷰 작성 페이지

insertCustomerReviewForm.jsp

<%@page import="shop.dao.OrdersDAO"%>
<%@page import="java.util.HashMap"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	// 요청 값
	String ordersNo = request.getParameter("ordersNo");

	// 디버깅
	System.out.println("customerReviewForm - ordersNo = " + ordersNo);
	
	// 주문 번호가 null일 경우 주문 목록으로 이동
	if(ordersNo == null) {
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
		return;
	}
%>
<%
	// 해당 주문번호의 상품 정보 가져오기
	HashMap<String, Object> ordersOne = OrdersDAO.selectOrdersOneByEmp(ordersNo);
	
%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>리뷰 작성</title>
	<link href="/shop/css/w3.css" rel="stylesheet" type="text/css">
	<link href="/shop/css/bootstrap.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="row">
<!-- 메인 메뉴 -->
<jsp:include page="/customer/inc/customerMenu.jsp"></jsp:include>

	<div class="col"></div>

	<div class="col-5">
		<div class="w3-border w3-round" style="margin-top: 20px;">
			<div class="w3-container w3-dark-grey " style="padding: 10px;">
				<h1>후기 작성</h1>
			</div>	
			
			<div class="w3-card-4" style="padding-top: 15px;">
				<form class="w3-container" action="/shop/customer/review/insertCustomerReviewAction.jsp" method="post">
					
					<!-- 상품의 정보 일부분 -->
					<div>
						<label>상품명</label>
						<input class="w3-input" type="text" name="goodsTitle" value="<%=ordersOne.get("goodsTitle")%>" readonly="readonly">
						<div style="border-bottom: 1px solid #ccc;">
							<img alt="" src="/shop/upload/<%=ordersOne.get("imgName")%>" width="200px">
						</div>
					</div>
						<input type="hidden" value="<%=ordersNo%>" name="ordersNo">

						<!-- 고객 리뷰 작성 부분 -->
					<div>
						<label>별점을 매겨주세요</label>
						
						<div class="score-star">
							<input type="radio" id="5-score" name="reviewScore" value="5" required="required">
							<label for="5-score" class="score">&#9733;</label>
							
							<input type="radio" id="4-score" name="reviewScore" value="4" >
							<label for="4-score" class="score">&#9733;</label>
							
							<input type="radio" id="3-score" name="reviewScore" value="3" >
							<label for="3-score" class="score">&#9733;</label>
							
							<input type="radio" id="2-score" name="reviewScore" value="2" >
							<label for="2-score" class="score">&#9733;</label>
							
							<input type="radio" id="1-score" name="reviewScore" value="1" >
							<label for="1-score" class="score">&#9733;</label>
						</div>
						
					</div>
					
					<div>
						<label>리뷰 내용</label>
						<textarea class="w3-input" rows="5" cols="50" name="reviewContent" required="required"></textarea>
					</div>
					
					<div style="text-align: center; margin: 10px auto;">
						<button class="btn btn-outline-secondary" style="width: 60%; margin: 0 auto;" type="submit">리뷰 작성하기</button>
					</div>
				</form>
			</div>
		</div>
	</div>
	
	<div class="col"></div>
</div>
</body>
</html>

 

해당 주문번호 하나당 리뷰하나를 작성하므로

ordersNo를 요청값으로 받는다.

해당 주문의 상품 정보 일부분을 가져와 보여주기 위해 OrdersDAO의 selectOrdersOneByEmp()메서드를 사용한다.

별점과 내용을 작성한 후 리뷰 작성버튼을 누르면 

insertCustomerReviewAction으로 요청값을 보낸다

 

insertCustomerReviewAction.jsp

<%@page import="shop.dao.OrdersDAO"%>
<%@page import="shop.dao.ReviewDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	request.setCharacterEncoding("UTF-8");

	// 요청 값
	String ordersNo = request.getParameter("ordersNo");
	String reviewScore = request.getParameter("reviewScore");
	String reviewContent = request.getParameter("reviewContent");

	// 주문 번호가 null일 경우 주문 목록으로 이동
	if(ordersNo == null) {
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
		return;
	}
	
	// 요청 값 디버깅
	System.out.println("customerReviewAction - ordersNo = " + ordersNo);
	System.out.println("customerReviewAction - reviewScore = " + reviewScore);
	System.out.println("customerReviewAction - reviewContent = " + reviewContent);
%>

<%
	// 리뷰 작성하기
	int insertReviewRow = ReviewDAO.insertReview(Integer.parseInt(ordersNo), Integer.parseInt(reviewScore), reviewContent);
	
	// 리뷰 작성 쿼리 실행됐을 경우
	if(insertReviewRow == 1 ) {
		System.out.println("customerReviewAction - insertReviewRow = " + insertReviewRow);
		
		// 주문 상태 변환
		String updateState = "리뷰완료";
		int updateStateRow = OrdersDAO.updateOrdersState(ordersNo, updateState);	
		// 디버깅
		System.out.println("customerReviewAction - updateStateRow = " + updateStateRow);
		
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");	
		return;
	} else {
		// 쿼리 실행 실패
		response.sendRedirect("/shop/customer/orders/customerOrdersForm.jsp?ordersNo=" + ordersNo);
		return;
	}
	
	
%>

 

ordersNo, reviewScore, reviewContent를 요청 값으로 받는다.

ReviewDAO의 insertReview메서드를 통해 리뷰 테이블에 insert쿼리를 날린다.

insert쿼리가 정상 실행됐다면 주문 상태를 리뷰 완료로 변경시키는 메서드 또한 실행한다.

해당 매서드까지 모두 실행됐을 경우 고객의 주문목록으로 redirect하면 리뷰 작성 기능도 구현 완료이다.

리뷰 작성 후 주문 목록

다음은 고객이 해당 주문에 작성한 리뷰를 페이지 하나에 볼 수 있게하는 리뷰 상세보기 페이지이다.

 

customerReviewOne.jsp

<%@page import="shop.dao.GoodsDAO"%>
<%@page import="java.util.HashMap"%>
<%@page import="shop.dao.ReviewDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	// 요청 값
	String ordersNo = request.getParameter("ordersNo");
	// 디버깅
	System.out.println("customerReviewOne - ordersNo = " + ordersNo);
		
	// 요청 값 null일 경우 메인페이지 redirect
	if(ordersNo == null) {
		response.sendRedirect("/shop/customer/goods/customerGoodsList.jsp");
		return;
	}
%>
<%
	// 작성된 리뷰 가져오기
	HashMap<String, Object> reviewOne = ReviewDAO.selectReviewOne(Integer.parseInt(ordersNo));

	// 작성된 리뷰의 상품 정보 가져오기
	HashMap<String, Object> goodsInfo = GoodsDAO.selectGoodsInfo((String)reviewOne.get("goodsNo"));
%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>작성한 리뷰 보기</title>
	<link href="/shop/css/w3.css" rel="stylesheet" type="text/css">
	<link href="/shop/css/bootstrap.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="row">
<!-- 메인 메뉴 -->
<jsp:include page="/customer/inc/customerMenu.jsp"></jsp:include>

	<div class="col"></div>

	<div class="col-5">
		<div class="w3-border w3-round" style="margin-top: 20px;">
			<div class="w3-container w3-dark-grey " style="padding: 10px;">
				<h1>작성한 리뷰 보기</h1>
			</div>	
			
			<div class="w3-card-4" style="padding-top: 15px;">
				<form class="w3-container" action="/shop/customer/review/deleteCustomerReviewForm.jsp" method="post">
					
					<!-- 상품의 정보 일부분 -->
					<div>
						<label>상품명</label>
						<input class="w3-input" type="text" name="goodsTitle" value="<%=goodsInfo.get("goodsTitle")%>" readonly="readonly">
						<div style="border-bottom: 1px solid #ccc;">
							<img alt="" src="/shop/upload/<%=goodsInfo.get("imgName")%>" width="200px">
						</div>
					</div>
						<input type="hidden" value="<%=ordersNo%>" name="ordersNo">

					<!-- 고객 리뷰 작성 부분 -->
					<div>
						<label>별점</label>
						
						<div class="score-star-read">
							<%
								for(int i = 5; i >= 1; i--) {
									if(i > (int)(reviewOne.get("score"))) {
							%>
										<input type="radio" id="<%=i %>-score" value="<%=i %>" disabled="disabled" style="text-decoration: none;">
										<label for="<%=i %>-score" class="score">&#9733;</label>
										
							<%
									} else {
							%>
										<input type="radio" id="<%=i %>-score" value="<%=i %>" checked="checked">
										<label for="<%=i %>-score" class="score">&#9733;</label>
							<%		
									}
								}
							%>
							
						</div>
						
					</div>
					
					<div>
						<label>리뷰 내용</label>
						<textarea class="w3-input" rows="5" cols="50" name="reviewContent" readonly="readonly"><%=reviewOne.get("content")%></textarea>
					</div>
					
					<div style="text-align: center; margin: 10px auto;">
						<button class="btn btn-outline-secondary" style="width: 60%; margin: 0 auto;" type="submit">리뷰 삭제하기</button>
					</div>
				</form>
			</div>
		</div>
	</div>
	
	<div class="col"></div>
</div>
</body>
</html>

 

ordersNo를 요청값으로 받아 해당 주문 번호를 통해 리뷰를 가져올것이다.

ReviewDAO의 selectReviewOne메서드로 리뷰테이블에서 해당 주문번호의 리뷰를 가져오고,

GoodsDAO의 selectGoodsInfo 메서드를 통해 해당 상품의 정보를 가져온다(리뷰 상세보기 페이지에서 상품도 보여주기 위해)

가져온 데이터들을 페이지에 뿌려주면 끝이다!

다음은 리뷰를 삭제할 수 있도록 하겠다.

 

deleteCustomerReviewForm.jsp

<%@page import="java.util.HashMap"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	// loginCutomer 세션 변수 가져오기
	HashMap<String, Object> loginCustomerMember = (HashMap<String, Object>)(session.getAttribute("loginCustomer"));	
	// 로그인 돼있는 고객의 id
	String customerId = (String)loginCustomerMember.get("customerId");
	
	// 요청 값
	String ordersNo = request.getParameter("ordersNo");
	// 디버깅
	System.out.println("deleteCustomerReviewForm - ordersNo = " + ordersNo);
	
	// 주문 번호가 null일 경우 주문 목록으로 이동
	if(ordersNo == null) {
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
		return;
	}
%>
<%
	// msg 출력
	String msg = request.getParameter("msg");
%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>리뷰 삭제</title>
	<link href="/shop/css/w3.css" rel="stylesheet" type="text/css">
	<link href="/shop/css/bootstrap.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="row">
<!-- 메인 메뉴 -->
<jsp:include page="/customer/inc/customerMenu.jsp"></jsp:include>

	<div class="col"></div>

	<div class="col-4">
		<div style="text-align: center;">
			<%
				if(msg != null) {
			%>
					<%=msg %>
			<%
				}
			%>
		</div>
		<div class="w3-border w3-round" style="margin-top: 20px;">
			<div class="w3-container w3-dark-grey" style="padding: 10px;">
				<h1>리뷰 삭제하기</h1>
			</div>	
			
			<div class="w3-card-4" style="padding: 5%;">
				<form class="w3-container" action="/shop/customer/review/deleteCustomerReviewAction.jsp" method="post">
					<div>
						리뷰를 삭제하시려면 ID와 PW를 입력해주세요:(
					</div>
					<input type="hidden" name="ordersNo" value="<%=ordersNo%>">
					<div style="margin-top: 20px;">
						<label>ID</label>
						<input class="w3-input" type="text" name="customerId" value="<%=customerId %>" readonly="readonly">
					</div>
					
					<div>
						<label>PW</label>
						<input class="w3-input" type="password" name="customerPw" required="required">
					</div>
							
					<div style="text-align: center; margin: 10px auto;">
						<button class="btn btn-outline-secondary" type="submit">리뷰 삭제하기</button>
					</div>
				</form>
			</div>
		</div>
	</div>
	
	<div class="col"></div>
</div>
</body>
</html>

 

 

loginCustomer 세션변수를 가져온다.(리뷰 삭제를 하기위해 id, pw를 입력해야하는데, id의 경우 다른 사람 id를 입력하게하면 안되기때문에)

그리고 id,pw를 입력하고 리뷰 삭제를 누르면 

deleteCustomerReviewAction으로 이동한다.

 

deleteCustomerReviewAction.jsp

<%@page import="shop.dao.OrdersDAO"%>
<%@page import="shop.dao.ReviewDAO"%>
<%@page import="java.net.URLEncoder"%>
<%@page import="shop.dao.CustomerDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file ="/customer/inc/customerCommonSessionCheck.jsp" %>
<%
	// 요청 값
	String customerId = request.getParameter("customerId");
	String customerPw = request.getParameter("customerPw");
	String ordersNo = request.getParameter("ordersNo");
	
	// 디버깅
	System.out.println("deleteCustomerReviewAction - customerId = " + customerId);
	System.out.println("deleteCustomerReviewAction - customerPw = " + customerPw);
	System.out.println("deleteCustomerReviewAction - ordersNo = " + ordersNo);
	
	// 해당 jsp 바로 실행했을 경우
	if(customerId == null && customerPw == null) {
		response.sendRedirect("/shop/customer/review/deleteCustomerReviewForm.jsp");
		return;
	}
%>

<%
	// 회원정보 일치 검증
	boolean canDeleteCustomer = CustomerDAO.checkCustomerIdPw(customerId, customerPw);

	// 회원 정보 일치할 경우
	if(canDeleteCustomer) {
		// 리뷰 삭제
		int deleteCustomerReviewRow = ReviewDAO.deleteReview(ordersNo);	
		
		// 리뷰 삭제 시 주문상태 다시 구매확정으로 변경(리뷰 작성 가능하도록)
		String updateState = "구매확정";
		OrdersDAO.updateOrdersState(ordersNo, updateState);
		
		// 리뷰삭제 디버깅
		System.out.println("deleteCustomerReviewAction - deleteCustomerReviewRow = " + deleteCustomerReviewRow);
		
		response.sendRedirect("/shop/customer/orders/customerOrdersList.jsp");
	} else {
		// 회원 정보 일치하지 않을 경우
		String msg = URLEncoder.encode("리뷰 삭제에 실패헀습니다. 다시 입력 해주세요", "UTF-8");
		response.sendRedirect("/shop/customer/review/deleteCustomerReviewForm.jsp?msg=" + msg);
		return;
	}
	
	
%>

 

 

customerId, customerPw, ordersNo를 요청값으로 받는다.

 

일단 CustomerDAO의 checkCustomerIdPw메서드로 고객 테이블에 해당 고객이 존재하는지 확인한다.

해당 고객이 존재하다면

ReviewDAO의 deleteReview메서드로 리뷰를 삭제한다.

리뷰를 삭제하면 주문상태는 다시 구매확정으로 변경되고, 해당 주문에 대해서는 리뷰를 다시 작성할 수 있도록 해준다.

 

이렇게 고객 리뷰기능이 모두 구현됐다

리뷰 삭제 후 

다음은 고객의 pw 히스토리 테이블을 만들었다.

 

고객 pw 히스토리 테이블
변경된 고객의 테이블

pw 히스토리 테이블은 고객이 pw를 변경할 때 이전에 사용했던 pw는 사용할 수 없도록 하기위해 만들었다.

또한 고객의 테이블에 원래 pw가 있었으나, pw 히스토리 테이블과 조인하여 가장 최신에 만들어진 pw를 사용하면 되므로pw 컬럼을 제거하였다.

 

 

쇼핑몰 만들기(10)-고객 페이지(상품 상세페이지, 고객 마이페이지(회원정보 수정 및 탈퇴)

쇼핑몰 만들기(9)-고객 페이지(쇼핑몰 메인페이지) 쇼핑몰 만들기(8)-고객 페이지 쇼핑몰 만들기(7)-카테고리 관리 쇼핑몰 만들기(6)-상품 관리(상품 수정, 삭제) 쇼핑몰 만들기(5)-상품 관리 쇼핑몰

broad-backend.tistory.com

if(newCustomerPw.equals(newCustomerPwCheck) && !newCustomerPw.equals("") && newCustomerPw != null) {
		// 새 비밀번호가 pw history에 있는지 확인
		boolean canUsePw = CustomerDAO.checkCustomerPwHistory(customerId, newCustomerPw);
		// 디버깅
		System.out.println("updateCustomerAction - canUsePw = " + canUsePw);
		// 새비밀번호 사용 가능하면
		if(canUsePw) {
			// 고객 비밀번호 히스토리 테이블에 데이터 추가
			int changeCustomerPwRow = CustomerDAO.insertCustomerPw(customerId, newCustomerPw);
			// 디버깅
			System.out.println("updateCustomerAction - changeCustomerPwRow = " + changeCustomerPwRow);
		} else {
			// 사용 불가능
			String msg = URLEncoder.encode("이전에 사용했던 비밀번호입니다. 다른 비밀번호를 사용해주세요", "UTF-8");
			response.sendRedirect("/shop/customer/checkInfoUpdateCustomer.jsp?msg=" + msg);
			return;
		}
	}

 

해당 코드에서 CustomerDAO의 checkCustomerPwHistory메서드를 사용해 pw히스토리에 변경할 pw가 이미 사용한 적이 있는 pw인지 확인한다.

/* 고객 pw 변경 시 이전 비밀번호에 동일한 값이 있는지 확인(true면 pw 변경 가능). */
	public static boolean checkCustomerPwHistory(String customerId, String newCustomerPw) throws Exception{
		// pw가 history테이블에 있는지 없는지 boolean값으로 설정
		boolean result = true;
		
		Connection conn = DBHelper.getConnection();
		// 변경할 pw가 history에 있는지 SELECT
		String sql = "SELECT c.id, c.name, h.pw, h.createdate"
				+ " FROM customer c INNER JOIN cpw_history h"
				+ " ON c.id = h.id"
				+ " WHERE c.id = ? AND h.pw = ?";
		PreparedStatement stmt = conn.prepareStatement(sql);
		stmt.setString(1, customerId);
		stmt.setString(2, newCustomerPw);
		ResultSet rs = stmt.executeQuery();
		// history에 있다면 사용 불가능이므로 false로 변경
		if (rs.next()) {
			result = false;
		}
		
		conn.close();
		return result;
		
	}

 

customer테이블과 cpw_history테이블을 동일 id로 조인하여 변경할 pw가 이미 사용한 적이 있는지 SELECT문으로 조회해본다.

 

존재한다면(사용불가) 다시 회원정보를 수정하기위해 id,pw를 입력하는 checkInfoUpdateCustomer.jsp로 redirect하고,

존재하지않다면(사용가능) 고객 pw history테이블에 변경할 pw를 insert시키면 완료이다.

 

 

728x90