메인화면에 있는 상품의 구매하러 가기 버튼을 클릭하면 상품명, 상품가격, 상품설명, 리뷰가 나와있는 페이지로 이동 시켜준다.
내 주소보기에 보러가기 버튼을 클릭하면 자신이 회원가입때 입력한 주소를 보여주는 Modal창을 띄워준다.
또한 자신이 회원가입때 입력한 주소로 배달을 받고 싶지 않은 고객들을 위해 우편번호 변경하기
버튼을 클릭시 주소를 변경할 수 있도록 주소 검색 창을 띄워준다.
그 후 이 배송지로 받기를 누르고 구매하기를 누르고 구매에 성공 했다면 해당 alert창을 보여준다.
DB에 들어가 select를 해보면 잘 저장되있는것을 볼 수 있다.
평소에는 리뷰를 작성하는 form이 보이지 않지만 리뷰 작성하기 버튼을 누른다면
이 처럼 리뷰를 작성하는 form을 보여준다.
이름과 email은 readonly를 줘서 사용자 임의대로 바꾸지 못한다.
쓰고 싶은 내용을 적고 작성하기 버튼을 누른다면
alert창을 띄워주며 location.reload()를 이용해 페이지를 새로고침 시켜준다.
새로고침 된 후 페이지를 다시 보면 자신이 쓴 리뷰가 페이지에 잘 보이는 것을 확인할 수 있다.
리뷰 삭제와 수정버튼은 리뷰를 쓴 작성자의 아이디와 현재 로그인중인 유저의 아이디를 비교해서 리뷰를 쓴 작성자라면 삭제버튼과 수정버튼을 보여준다.
수정 버튼을 누를 시 수정버튼은 감추고 수정 완료버튼을 보여주고 input태그의 readonly를 false로 바꿔준다.
내용을 수정하고 수정완료를 누르면 수정이된다.
삭제 버튼 클릭시 리뷰를 삭제해준다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Myshop</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<link href="/resources/css/styles.css" rel="stylesheet" />
<link href="/resources/css/product/board.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css">
<style>
.zipModal{
position: absolute;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
top:0;
left:0;
display:none;
}
.zipModal_body {
position: absolute;
top: 50%;
left: 50%;
padding: 190px;
background-color: rgb(255, 255, 255);
border-radius: 10px;
box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
transform: translateX(-50%) translateY(-50%);
z-index: 1;
}
input[type="text"]{
border-color: rgba(144, 144, 144, 0.25);
height: 3.25rem;
appearance: none;
border-radius: 4px;
border: solid 1px;
color: inherit;
outline: 0;
padding: 2px;
text-align: center;
width:15%;
text-decoration: none;
}
input{
font-family: 'SLEIGothicTTF';
font-weight: 300;
font-size: 1rem;
line-height: 2.15;
}
form > :last-child {
margin-bottom: 0;
}
.wrapper.special {
text-align: center;
}
.wrapper {
padding: 6rem 0 4rem 0;
}
.py-5 .bg-dark{
margin-top:90px;
}
.zipnum.inputt{
width:100%;
}
.reviewBTN{
float : right;
margin-right:10px;
}
.inlinereview{
display:inline;
}
</style>
</head>
<body>
<!-- nav 시작 -->
<%@include file="../user/nav.jsp" %>
<!-- nav 끝 -->
<div class="main">
<div class="container">
<div class="row margin-bottom-40">
<div class="col-md-9 col-sm-7">
<div class="product-page">
<div class="row">
<div class="col-md-6 col-sm-6">
<div class="product-main-img" style="position: relative; overflow:hidden;">
<img src="/resources/img/${filename}" class="img-responsive">
</div>
</div>
<div class="col-md-6 col-sm-6">
<h1>${product.productname}</h1>
<div class="price-availability-block clearfix">
<div class="price">
<strong>
${product.productprice}원
</strong>
</div>
</div>
<form action="/user/buyproduct">
<div id="container" class="container">
<div id="content" class="content">
<div class="subindex_wrap" role="main">
<div class="subindex_item">
<div class="subindex_onebox">
<div class="onebox_title desc">
<h2 class="subindex_title">내 주소 보기</h2>
</div>
<button type="button" class="link_right">
<span class="case">보러가기</span>
</button>>
<div class="subindex_desc">구매 하시기전에 배송지를 설정해주세요~~</div>
</div>
</div>
</div>
</div>
</div>
<input type="hidden" value="${product.productnum}">
<div class="product-page-cart">
<div class="product-quantity">
<button class="btn btn-primary buy" type="submit">구매하기</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="textarea-div">
<textarea rows="10" cols="10" readonly style="word-break:break-all;width:100%;text-align:center;">${product.productcontents}</textarea>
</div>
<!-- 리뷰 작성 -->
<button type="button" name="review" id="onReview">리뷰 작성하기</button>
<div class="product-page-content" id="review" >
<ul id="myTap" class="nav nav-tabs">
<li class="active">
<a href="#" data-togle="tab">리뷰</a>
</li>
</ul>
<div class="tab-content" style="width:100%;">
<div class="tab-pane fade in active">
<c:forEach items="${review}" var="review">
<div class="review-item clearfix">
<div class="review-item-submitted">
<strong>${review.username}</strong>
<em>${review.regdate}</em>
</div>
<div class="reivew-item-content">
<input class="inlinereview" value = "${review.reviewcontents}" readonly>
<c:if test="${loginUsername == review.username}">
<a href="${review.reviewnum}" class="reviewBTN del">삭제</a>
<a href="#" class="reviewBTN mdf" id="mdf">수정</a>
<a href="${review.reviewnum}" class="reviewBTN mdfOk" id="mdfOk" style="display:none;">수정 완료</a>
</c:if>
</div>
</div>
</c:forEach>
<form class="reviews-form" role="form" style="display:none;">
<h2>리뷰 작성</h2>
<div class="form-group">
<label for="username">
이름
<span class="require"></span>
</label>
<input type="text" class="form-control" id="username" value="${loginUsername}" readonly style="width:14%;">
</div>
<div class="form-group">
<label for="useremail">Email</label>
<input type="text" value="${loginUserid}" id="useremail" readonly>
</div>
<div class="form-group">
<label for="review">리뷰</label>
<textarea class="form-control" rows="8" id="reviewTxt" style="word-break:break-all;width:100%;text-align:center;"></textarea>
</div>
<div class="padding-top-20">
<button type="submit" class="btn btn-primary reviewBtn">작성하기</button>
</div>
</form>
</div>
</div>
</div>
<!-- Footer-->
<footer class="py-5 bg-dark">
<div class="container"><p class="m-0 text-center text-white">Copyright © Your Website 2022</p></div>
</footer>
<!-- 우편번호 Modal -->
<form action="/" method="get" class="buyForm">
</form>
<div class="zipModal">
<div class="zipModal_body">
<div class="wrapper style1 special">
<div class="inner">
<form name="buy">
<input type="hidden" value="${loginUserid}" name="useremail">
<table class = "zipnum-container">
<tr class="zipcode_area">
<th>우편번호</th>
<td>
<input readonly class="zipnum inputt" name="postnum" type="text" id="postnum" value="${postnum}"><input type="button" onclick="DaumPostcode()" value="우편번호 변경하기">
</td>
</tr>
<tr class="addr_area">
<th>주소</th>
<td><input readonly class="zipnum inputt" name="addr" type="text" id="addr" value="${addr}"></td>
</tr>
<tr>
<th>상세주소</th>
<td><input class="zipnum inputt" name="detailaddress" type="text" id="detailaddress" value="${detailaddress}"></td>
</tr>
<tr>
<th>참고항목</th>
<td><input readonly class="zipnum inputt" name="seealso" type="text" id="seealso" value="${seealso}"></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" id="zipSubmit" value="이 배송지로 받기">
<input type="submit" id="zipCancle" value="나가기">
</th>
</tr>
</table>
</form>
</div>
</div>
</div>
</div>
</body>
<script src="/resources/js/daum.js"></script>
<script src="/resources/js/board.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
<script>
let postnum = $("#postnum").val();
let addr = $("#addr").val();
let seealsos = $("#seealso").val();
let detailaddress = $("detailaddress").val();
let useremail = "${loginUserid}";
let productnum = "${product.productnum}";
let productname = "${product.productname}";
let productprice = "${product.productprice}";
let username = "${loginUsername}";
let buyForm = $(".buyForm");
//구매하기 클릭시 이벤트
$(".buy").on("click",function(e){
postnum = $("#postnum").val();
addr = $("#addr").val();
detailaddress = $("#detailaddress").val();
seealso = $("#seealso").val();
if(useremail == ""){
alert("로그인 후 진행해주세요");
return false;
}
e.preventDefault();
buyService.add(
{useremail:useremail,username:username,productnum:productnum,productname:productname,postnum:postnum
,addr:addr,detailaddress:detailaddress,seealso:seealso
},
function(result){
alert(productname+"상품 구매완료");
}
);
});
// 주소 보러가기 클릭시 미 로그인 상태라면 alert창 띄움
$(".link_right").on("click",function(e){
let useremail = "${loginUserid}";
if(useremail == ""){
alert("로그인 후 이용해주세요");
return false;
}
//로그인 되어있다면 모달창 띄우기
e.preventDefault();
$(".zipModal").show();
});
//모달창 나가기 클릭시 모달창을 닫아주면서 입력 된 값들을 초기로 돌려준다.
$("#zipCancle").on("click",function(e){
e.preventDefault();
$(".zipModal").hide();
$("[name = 'postnum']").val("${postnum}");
$("[name = 'addr']").val("${addr}");
$("[name = 'detailaddress']").val("${detailaddress}");
$("[name = 'seealso']").val("${seealso}");
});
//이 주소로 받기 클릭시 유효성검사를하고 모두 통과한다면 모달창을 닫아준다.
$("#zipSubmit").on("click",function(e){
e.preventDefault();
const zipForm = $(".zipForm");
let npostnum = $("#postnum").val();
let ndetailaddress = $("#detailaddress").val();
if(postnum ==""){
alert("우편번호를 입력해주세요");
}
else if(detailaddress == ""){
alert("상세주소를 입력해주세요");
}
else{
$(".zipModal").hide();
}
});
//리뷰 작성 버튼 클릭시 리뷰 작성 폼 보여주거나 닫기
let flaut = false;
$("#onReview").on("click",function(e){
if(flaut == true){
$(".reviews-form").hide();
$("#reviewTxt").val("");
flaut = false;
}
else{
flaut = true;
e.preventDefault();
$(".reviews-form").show();
}
})
//작성하기 버튼 클릭시
$(".reviewBtn").on("click",function(e){
e.preventDefault();
let reviewcontents = $("#reviewTxt").val();
if(useremail == ""){
alert("로그인 후 이용해주세요");
return;
}
else if(reviewcontents == null){
alert("내용을 입력해주세요");
return;
}
buyService.addreview(
{useremail:useremail, username:username, productnum:productnum, reviewcontents:reviewcontents},
function(result){
if(result > 0){
alert(result+"번 리뷰 작성 성공!");
location.reload();
}
}
);
});
//리뷰 삭제
$(".del").on("click",function(e){
e.preventDefault();
let reviewnum = $(this).attr('href');
buyService.drop(
reviewnum,
function(result){
if(result == "success"){
alert(reviewnum+"번 리뷰 삭제 성공!");
location.reload();
}
}
)
})
//리뷰 수정 버튼 눌렀을 시 수정 버튼은 숨기고 수정 완료버튼 보여주기
let mf = false;
$("#mdf").on("click",function(e){
e.preventDefault();
if(mf == true){
alert("이미 수정중인 리뷰가 있습니다");
return;
}
mf = true;
$(".inlinereview").attr("readonly",false);
$(this).hide();
$(this).next().show();
})
//수정 완료 버튼
$("#mdfOk").on("click",function(e){
e.preventDefault();
mf == false;
let reviewcontents = $(".inlinereview").val();
let reviewnum = $(this).attr('href');
buyService.modify(
{reviewcontents:reviewcontents, reviewnum:reviewnum},
function(result){
if(result=="success"){
alert("리뷰를 수정 하였습니다.");
$(".inlinereview").attr("readonly",true);
$(this).show();
$(this).prev().hide();
location.reload();
}
}
)
})
</script>
</html>
const buyService = (function(){
//상품 구매 ajax
function insert(buy,callback){
$.ajax({
type:"POST",
url:"/buy/buyProduct",
data:JSON.stringify(buy),
contentType:"application/json; charset=utf-8",
success:function(result){
if(callback){
callback(result);
}
},
error:function(status){
alert("구매 실패");
}
})
}
//리뷰 작성 ajax
function review(review, callback){
$.ajax({
type:"POST",
url:"/buy/review",
data:JSON.stringify(review),
contentType:"application/json; charset=utf-8",
success:function(result){
if(callback){
callback(result);
}
},
error:function(err){
alert("리뷰 작성 실패!");
}
})
}
//리뷰 삭제
function reviewDelete(review,callback){
$.ajax({
type:"POST",
url:"/buy/reviewDelete",
data:JSON.stringify(review),
contentType:"application/json; charset=utf-8",
success:function(result){
if(callback){
callback(result);
}
},
error:function(err){
alert("리뷰를 삭제하지 못했습니다. 다시 시도해 주세요.");
}
})
}
//리뷰 수정
function reviewModify(review,callback){
$.ajax({
type:"PUT",
url:"/buy/"+review.reviewnum,
data:JSON.stringify(review),
contentType:"application/json; charset=utf-8",
success:function(result){
if(callback){
callback(result);
}
},
error:function(err){
alert("리뷰 수정 실패. 다시 시도해주세요~");
}
})
}
return {add:insert,addreview:review, drop:reviewDelete, modify:reviewModify};
})();
productController 밑에 코드를 추가해준다.
@GetMapping("/board")
public void goboard(ProductDTO productnum, Model model) {
String filename = service.getFilename(productnum.getProductnum());
ProductDTO prod = service.getproduct(productnum.getProductnum());
List<ReviewDTO> review = service.getReview(productnum.getProductnum());
//board.jsp로 넘겨줄 데이터
model.addAttribute("filename", filename);
model.addAttribute("product", prod);
model.addAttribute("review", review);
}
package com.my.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.my.domain.BuyProductDTO;
import com.my.domain.ReviewDTO;
import com.my.service.UserService;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
@RestController
@RequestMapping("/buy/*")
@Log4j
public class BuyController {
@Setter(onMethod_ = @Autowired)
private UserService service;
//상품 구매
@PostMapping(value ="/buyProduct", consumes = "application/json")
public ResponseEntity<String> buyProduct(@RequestBody BuyProductDTO buy){
boolean check = service.buyProduct(buy);
String productname = buy.getProductname();
return check ? new ResponseEntity<String>(productname,HttpStatus.OK) : new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
//리뷰 등록
@PostMapping(value ="/review", consumes = "application/json")
public ResponseEntity<String> review(@RequestBody ReviewDTO review){
return service.review(review) ? new ResponseEntity<String>(service.getReviewnum()+"",HttpStatus.OK) : new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
//리뷰 삭제
@PostMapping(value="/reviewDelete", consumes = "application/json")
public ResponseEntity<String> reviewDelete(@RequestBody int reviewnum){
return service.reviewDelete(reviewnum) ? new ResponseEntity<String>("success",HttpStatus.OK) : new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
//리뷰 수정
@RequestMapping(method = {RequestMethod.PUT, RequestMethod.PATCH}, value="/{reviewnum}", consumes = "application/json")
public ResponseEntity<String> reviewModify(@RequestBody ReviewDTO review){
return service.reviewModify(review) ? new ResponseEntity<String>("success",HttpStatus.OK):new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}