WEB JAVA SPRING/PROJECT
10. 장바구니 담기
sshhhh
2023. 9. 12. 17:06
1.CartItemDto
/**
* 상품 상세 페이지에서 장바구니에 담을 상품 아이디와 수량 전달받음
*/
package com.shop.dto;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
@Getter @Setter
public class CartItemDto {
@NotNull(message = "상품 아이디는 필수 입력 값 입니다.")
private Long itemId;
@Min(value = 1 ,message = "최소 1개 이상 담아주세요")
private int count;
}
2.Cart
/*
회원 한명당 1개의 장바구니를 가지므로
처음 장바구니에 상품을 담을 때는 해당 회원의 장바구니를 생성할 것
회원 엔티티를 파라미터로 받아서 장바구니 엔티티 생성
*/
public static Cart createCart (Member member){
Cart cart = new Cart();
cart.setMember(member);
return cart;
}
3.CartItem
//장바구니에 담을 상품 엔티티 생성
//장바구니에 담을 상품 엔티티 생성
public static CartItem createCartItem(Cart cart, Item item, int count){
CartItem cartItem = new CartItem();
cartItem.setCart(cart);
cartItem.setItem(item);
cartItem.setCount(count);
return cartItem;
}
//장바구니에 담을 수량 증가
public void addCount(int count){
this.count += count;
}
4.CartRepository
//현재 로그인한 회원의 Cart 엔티티 찾음
Cart findByMemberId(Long memberID);
5.CartService
/**
* 장바구니에 상품 담기
*/
@Service
@RequiredArgsConstructor
@Transactional
public class CartService {
private final ItemRepository itemRepository;
private final MemberRepository memberRepository;
private final CartRepository cartRepository;
private final CartItemRepository cartItemRepository;
public Long addCart(CartItemDto cartItemDto, String email) {
Item item = itemRepository.findById(cartItemDto.getItemId()) //장바구니에 담을 상품엔티티 조회
.orElseThrow(EntityNotFoundException::new);
Member member = memberRepository.findByEmail(email); //현재 로그인한 회원엔티티 조회
Cart cart = cartRepository.findByMemberId(member.getId()); //현재 로그인한 회원의 장바구니엔티티 조회
if (cart == null) { //상품을 처음으로 장바구니에 담을 경우 해당 회원의 장바구니 엔티티 생성
cart = Cart.createCart(member);
cartRepository.save(cart);
}
CartItem saveCartItem = //현재 상품이 장바구니에 이미 들어가있는지 조회
cartItemRepository.findByCartIdAndItemId(cart.getId(), item.getId());
if (saveCartItem != null) {//장바구니에 이미 있다면
saveCartItem.addCount(cartItemDto.getCount()); //기존 수량에 현재 장바구니에 담을 수량만큼 더함
return saveCartItem.getId();
} else {//없다면
//장바구니,상품엔티티,장바구니에 담을 수량을 이용해 CartItem 엔티티 생성
CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
cartItemRepository.save(cartItem); //장바구니에 들어갈 상품 저장
return cartItem.getId();
}
}
6.CartController
//장바구니 관련 요청 처리
@Controller
@RequiredArgsConstructor
public class CartController {
private final CartService cartService;
@PostMapping(value = "/cart")
public @ResponseBody
ResponseEntity order(@RequestBody @Valid CartItemDto cartItemDto,
BindingResult bindingResult, Principal principal){ //Principal: 시큐리티,시스템을 사용하고자하는 사용자
//CartItemDto 객체에 데이터 바인딩시 에러가 있는지 검사
if (bindingResult.hasErrors()){
StringBuilder sb = new StringBuilder();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors){
sb.append(fieldError.getDefaultMessage());
}
return new ResponseEntity<String>(sb.toString(), HttpStatus.BAD_REQUEST);
}
String email = principal.getName();//현재 로그인한 회원의 이메일 정보 저장
Long cartItemId;
//화면으로부터 넘어옴옴
try { //장바구니에 담을 상품 정보,현재 로그인한 회원의 이메일 정보이용 장바구니에 상품담는 로직
cartItemId =cartService.addCart(cartItemDto, email);
}catch (Exception e){
return new ResponseEntity<String>(e.getMessage(),HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<Long>(cartItemId, HttpStatus.OK); //결과값으로 생성된 장바구니 상품아이디와 요청이 성공했다는 http응답상태코드 반환
}
itemDtl.html
//장바구니
function addCart(){
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var url = "/cart";
var paramData = {
itemId : $("#itemId").val(),
count : $("#count").val()
};
var param = JSON.stringify(paramData);
$.ajax({
url : url,
type : "POST",
contentType : "application/json",
data : param,
beforeSend : function(xhr){
/!* 데이터를 전송하기 전에 헤더에 csrf값을 설정 *!/
xhr.setRequestHeader(header, token);
},
dataType : "json",
cache : false,
success : function(result, status){
alert("상품을 장바구니에 담았습니다.");
location.href='/';
},
error : function(jqXHR, status, error){
if(jqXHR.status == '401'){
alert('로그인 후 이용해주세요');
location.href='/members/login';
} else{
alert(jqXHR.responseText);
}
}
});
}
<div th:if="${item.itemSellStatus == T(com.shop.constant.ItemSellStatus).SELL}" class="text-right">
<button type="button" class="btn btn-light border border-primary btn-lg" onclick="addCart()">장바구니 담기</button>
<button type="button" class="btn btn-primary btn-lg" onclick="order()">주문하기</button>
</div>
CartList.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/layout1}">
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>
<!-- 사용자 스크립트 추가 -->
<th:block layout:fragment="script">
<script th:inline="javascript">
$(document).ready(function(){ //주문할 상품 체크,해제
$("input[name=cartChkBox]").change( function(){
getOrderTotalPrice();
});
});
function getOrderTotalPrice(){ //총주문 금액 구하기
var orderTotalPrice = 0;
$("input[name=cartChkBox]:checked").each(function() {
var cartItemId = $(this).val();
var price = $("#price_" + cartItemId).attr("data-price");
var count = $("#count_" + cartItemId).val();
orderTotalPrice += price*count; //가격*수량
});
$("#orderTotalPrice").html(orderTotalPrice+'원');
}
function changeCount(obj){ //수량변경시 상품금액 변경
var count = obj.value;
var cartItemId = obj.id.split('_')[1];
var price = $("#price_" + cartItemId).data("price");
var totalPrice = count*price;
$("#totalPrice_" + cartItemId).html(totalPrice+"원");
getOrderTotalPrice();
updateCartItemCount(cartItemId, count);
}
function checkAll(){ //전체 체크,해제
if($("#checkall").prop("checked")){
$("input[name=cartChkBox]").prop("checked",true);
}else{
$("input[name=cartChkBox]").prop("checked",false);
}
getOrderTotalPrice();
}
function updateCartItemCount(cartItemId, count){
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var url = "/cartItem/" + cartItemId+"?count=" + count;
$.ajax({
url : url,
type : "PATCH", //부분업데이트
beforeSend : function(xhr){
/* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
xhr.setRequestHeader(header, token);
},
dataType : "json",
cache : false,
success : function(result, status){
console.log("cartItem count update success");
},
error : function(jqXHR, status, error){
if(jqXHR.status == '401'){
alert('로그인 후 이용해주세요');
location.href='/members/login';
} else{
alert(jqXHR.responseJSON.message);
}
}
});
}
function deleteCartItem(obj){
var cartItemId = obj.dataset.id;
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var url = "/cartItem/" + cartItemId;
$.ajax({
url : url,
type : "DELETE",
beforeSend : function(xhr){
/* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
xhr.setRequestHeader(header, token);
},
dataType : "json",
cache : false,
success : function(result, status){
location.href='/cart';
},
error : function(jqXHR, status, error){
if(jqXHR.status == '401'){
alert('로그인 후 이용해주세요');
location.href='/members/login';
} else{
alert(jqXHR.responseJSON.message);
}
}
});
}
function orders(){
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
var url = "/cart/orders";
var dataList = new Array();
var paramData = new Object();
$("input[name=cartChkBox]:checked").each(function() {
var cartItemId = $(this).val();
var data = new Object();
data["cartItemId"] = cartItemId;
dataList.push(data);
});
paramData['cartOrderDtoList'] = dataList;
var param = JSON.stringify(paramData);
$.ajax({
url : url,
type : "POST",
contentType : "application/json",
data : param,
beforeSend : function(xhr){
/* 데이터를 전송하기 전에 헤더에 csrf값을 설정 */
xhr.setRequestHeader(header, token);
},
dataType : "json",
cache : false,
success : function(result, status){
alert("주문이 완료 되었습니다.");
location.href='/orders';
},
error : function(jqXHR, status, error){
if(jqXHR.status == '401'){
alert('로그인 후 이용해주세요');
location.href='/members/login';
} else{
alert(jqXHR.responseJSON.message);
}
}
});
}
</script>
</th:block>
<!-- 사용자 CSS 추가 -->
<th:block layout:fragment="css">
<style>
.content-mg{
margin-left:25%;
margin-right:25%;
margin-top:2%;
margin-bottom:100px;
}
.repImgDiv{
margin-right:15px;
margin-left:15px;
height:auto;
}
.repImg{
height:100px;
width:100px;
}
.fs18{
font-size:18px
}
.fs24{
font-size:24px
}
</style>
</th:block>
<div layout:fragment="content" class="content-mg">
<h2 class="mb-4">
장바구니 목록
</h2>
<div>
<table class="table">
<colgroup>
<col width="15%"/>
<col width="70%"/>
<col width="15%"/>
</colgroup>
<thead>
<tr class="text-center">
<td>
<input type="checkbox" id="checkall" onclick="checkAll()"> 전체선택
</td>
<td>상품정보</td>
<td>상품금액</td>
</tr>
</thead>
<tbody>
<tr th:each="cartItem : ${cartItems}">
<td class="text-center align-middle">
<input type="checkbox" name="cartChkBox" th:value="${cartItem.cartItemId}">
</td>
<td class="d-flex">
<div class="repImgDiv align-self-center">
<img th:src="${cartItem.imgUrl}" class = "rounded repImg" th:alt="${cartItem.itemNm}">
</div>
<div class="align-self-center">
<span th:text="${cartItem.itemNm}" class="fs24 font-weight-bold"></span>
<div class="fs18 font-weight-light">
<span class="input-group mt-2">
<span th:id="'price_' + ${cartItem.cartItemId}"
th:data-price="${cartItem.price}"
th:text="${cartItem.price} + '원'" class="align-self-center mr-2">
</span>
<input type="number" name="count" th:id="'count_' + ${cartItem.cartItemId}"
th:value="${cartItem.count}" min="1"
onchange="changeCount(this)" class="form-control mr-2" >
<button type="button" class="close" aria-label="Close">
<span aria-hidden="true" th:data-id="${cartItem.cartItemId}" onclick="deleteCartItem(this)">×</span>
</button>
</span>
</div>
</div>
</td>
<td class="text-center align-middle">
<span th:id="'totalPrice_' + ${cartItem.cartItemId}"
name="totalPrice" th:text="${cartItem.price * cartItem.count} + '원'">
</span>
</td>
</tr>
</tbody>
</table>
<h2 class="text-center">
총 주문 금액 : <span id="orderTotalPrice" class="text-danger">0원</span>
</h2>
<div class="text-center mt-3">
<button type="button" class="btn btn-primary btn-lg" onclick="orders()">주문하기</button>
</div>
</div>
</div>
</html>