๐Ÿ’ท ๐Ÿ”ฅ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ๐Ÿ”ฅ

gdhiยท2023๋…„ 12์›” 19์ผ
post-thumbnail

๐Ÿ’ท์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ƒํ’ˆ ๋‹ด๊ธฐ

๋งŒ๋“œ๋Š” ๊ฒƒ ์ค‘์—” ์ œ์ผ ์–ด๋ ค์šด ํŽธ


๐Ÿ“ŒCartItemDto ํด๋ž˜์Šค ์ƒ์„ฑ

package com.shop.dto;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class CartItemDto {

    // ์ œํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์„ ์ƒํ’ˆ Id ์™€ ์ˆ˜๋Ÿ‰์„ ์ „๋‹ฌ ๋ฐ›์Œ
    @NotNull(message = "์ƒํ’ˆ ์•„์ด๋””๋Š” ํ•„์ˆ˜ ์ž…๋ ฅ ๊ฐ’ ์ž…๋‹ˆ๋‹ค.")
    private Long itemId;

    @Min(value = 1, message = "์ตœ์†Œ 1๊ฐœ ์ด์ƒ ๋‹ด์•„์ฃผ์„ธ์š”.")
    private int count;

}



๐Ÿ“ŒCart ์—”ํ‹ฐํ‹ฐ ์ˆ˜์ •


...

    // ๋ฉค๋ฒ„๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์„œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ์ƒ์„ฑํ•˜๋Š” static ๋ฉ”์†Œ๋“œ 
    // static ๐Ÿ‘‰ ํ˜ผ์ž ๋†€๊ฒ ๋‹ค
    public static Cart createCart(Member member){

        // ํšŒ์› ํ•œ ๋ช…๋‹น 1๊ฐœ์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์—
        // ์ฒ˜์Œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ƒํ’ˆ์„ ๋‹ด์„ ๋•Œ๋Š” ํ•ด๋‹น ํšŒ์›์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ๋ฅผ ์ƒ์„ฑ
        Cart cart = new Cart();
        cart.setMember(member);

        return cart;

    }

}



๐Ÿ“ŒCartItem ์—”ํ‹ฐํ‹ฐ ์ˆ˜์ •

...

    // ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์„ 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;
    }

}



๐Ÿ“ŒCartRepository ์ธํ„ฐํŽ˜์ด์Šค ์ˆ˜์ •

package com.shop.repository;

import com.shop.entity.Cart;
import com.shop.entity.CartItem;
import org.springframework.data.jpa.repository.JpaRepository;


// ์ฟผ๋ฆฌ๋ฌธ ๋‚ ๋ฆฌ๋Š” JpaRepository
public interface CartRepository extends JpaRepository<Cart, Long> {

	//ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ(Cart)๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ
    Cart findByMemberId(Long memberId);
    
}



๐Ÿ“ŒCartItemRepository ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ

package com.shop.repository;

import com.shop.entity.CartItem;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CartItemRepository extends JpaRepository<CartItem, Long> {

    // ์ƒํ’ˆ์ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋“ค์–ด์žˆ๋Š”์ง€ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ
    CartItem findByCartIdAndItemId(Long cartId, Long itemId);

}



๐Ÿ“ŒCartService ํด๋ž˜์Šค ์ƒ์„ฑ

package com.shop.service;

import com.shop.dto.CartItemDto;
import com.shop.entity.Cart;
import com.shop.entity.CartItem;
import com.shop.entity.Item;
import com.shop.entity.Member;
import com.shop.repository.CartItemRepository;
import com.shop.repository.CartRepository;
import com.shop.repository.ItemRepository;
import com.shop.repository.MemberRepository;
import jakarta.persistence.EntityExistsException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
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(EntityExistsException::new);

        Member member = memberRepository.findByEmail(email);

        Cart cart = cartRepository.findByMemberId(member.getId());

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
        if (cart == null){

            cart = Cart.createCart(member);
            cartRepository.save(cart);

        }

        CartItem savedCartItem = cartItemRepository.
                findByCartIdAndItemId(cart.getId(), item.getId());

        // ํ•ด๋‹น ์ƒํ’ˆ์ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์ด๋ฏธ ์กด์žฌ ํ•˜๋ฉด ์ˆ˜๋Ÿ‰ ์ฆ๊ฐ€ ๐Ÿ‘‰ ๋ณ€๊ฒฝ ๊ฐ์ง€
        if (savedCartItem != null){

            savedCartItem.addCount(cartItemDto.getCount());

            return savedCartItem.getId();

        }
        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์•ˆ์— ํ•ด๋‹น ์ƒํ’ˆ์ด ์กด์žฌ ํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒ์„ฑ ํ›„ ์ถ”๊ฐ€
        else {

            CartItem cartItem = CartItem.createCartItem(cart, item, cartItemDto.getCount());
            cartItemRepository.save(cartItem);

            return cartItem.getId();

        }

    }

}



๐Ÿ“ŒCartController ํด๋ž˜์Šค ์ƒ์„ฑ

package com.shop.controller;

import com.shop.dto.CartItemDto;
import com.shop.service.CartService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.security.Principal;
import java.util.List;

@Controller
@RequiredArgsConstructor
public class CartController {

    private final CartService cartService;

    @PostMapping(value = "/cart")
    public @ResponseBody
    ResponseEntity order(@RequestBody @Valid CartItemDto cartItemDto,
                         BindingResult bindingResult, Principal principal){

        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 {

            // ์ œํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ๋„˜์–ด์˜จ CartItemDto ๊ฐ์ฒด์™€ email
            cartItemId = cartService.addCart(cartItemDto, email);

        }catch (Exception e){

            return new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);

        }

        return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);

    }

}



๐Ÿคฆโ€โ™€๏ธCartService ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ธฐ

package com.shop.service;

import com.shop.constant.ItemSellStatus;
import com.shop.dto.CartItemDto;
import com.shop.entity.CartItem;
import com.shop.entity.Item;
import com.shop.entity.Member;
import com.shop.repository.CartItemRepository;
import com.shop.repository.ItemRepository;
import com.shop.repository.MemberRepository;
import jakarta.persistence.EntityNotFoundException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
@Transactional
@TestPropertySource(locations = "classpath:application-test.properties")
class CartServiceTest {

    @Autowired
    ItemRepository itemRepository;

    @Autowired
    MemberRepository memberRepository;

    @Autowired
    CartService cartService;

    @Autowired
    CartItemRepository cartItemRepository;

    public Item saveItem(){

        Item item = new Item();
        item.setItemNm("ํ…Œ์ŠคํŠธ ์ƒํ’ˆ");
        item.setPrice(10000);
        item.setItemDetail("ํ…Œ์ŠคํŠธ ์ƒํ’ˆ ์ƒ์„ธ ์„ค๋ช…");
        item.setItemSellStatus(ItemSellStatus.SELL);
        item.setStockNumber(100);

        return itemRepository.save(item);

    }

    public Member saveMember(){

        Member member = new Member();
        member.setEmail("test@test.com");

        return memberRepository.save(member);

    }

    @Test
    @DisplayName("์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋‹ด๊ธฐ ํ…Œ์ŠคํŠธ")
    public void addCart(){

        Item item = saveItem();
        Member member = saveMember();

        CartItemDto cartItemDto = new CartItemDto();
        cartItemDto.setCount(5);
        cartItemDto.setItemId(item.getId());

        Long cartItemId = cartService.addCart(cartItemDto, member.getEmail());
        CartItem cartItem = cartItemRepository.findById(cartItemId)
                .orElseThrow(EntityNotFoundException::new);

        assertEquals(item.getId(), cartItem.getItem().getId());
        assertEquals(cartItemDto.getCount(), cartItem.getCount());

        System.out.println("item.getId() : " + item.getId());
        System.out.println("cartItem.getItem().getId() : " + cartItem.getItem().getId());

        System.out.println("--------------------------------------------------");

        System.out.println("cartItemDto.getCount() : " + cartItemDto.getCount());
        System.out.println("cartItem.getCount() : " + cartItem.getCount());

    }

}



๐Ÿ“๊ฒฐ๊ณผ



๐Ÿ“ŒItemDtl.html์— AJAX ์ถ”๊ฐ€

        function addCart(){

            // Ajax ํ†ต์‹ ํ•  ๋•Œ, csrf ํ† ํฐ ๊ฐ’์„ ์กฐํšŒํ•ด์„œ ์ง์ ‘ ๋ณด๋‚ด์•ผํ•จ
            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.stringfy(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);
                    }
                }

            });

        }



๐Ÿ“Œ๊ฒฐ๊ณผ

๐Ÿ‘‰ 10๊ฐœ ๋” ๋‹ด์•„๋ณด์ž

๐Ÿ‘‰ ์•„์ง ๋กœ์ง์„ ์งœ์ง€ ์•Š์•„์„œ 500๊ฐœ๊ฐ€ ๋‹ด๊ฒจ๋ฒ„๋ฆฐ๋‹ค

๐Ÿ‘‰ Cart DB ์—๋„ ๋‹ด๊ฒจ๋ฒ„๋ฆผ..

๐Ÿ‘‰ ์žฌ๊ณ ๋Š” ๊ทธ๋Œ€๋กœ



โ“์–ด๋–ค ๊ตฌ์กฐ๋กœ ์‹คํ–‰?



๐Ÿ”ฅTodo

  • ํšŒ์›๊ฐ€์ž… ํ™”๋ฉด
  • ๋กœ๊ทธ์ธ ํ™”๋ฉด
  • ??? ๋‹˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค ๋“ฑ ์ด์˜๊ฒŒ ๊พธ๋ฉฐ๋ณด์ž









๐Ÿ“–์žฅ๋ฐ”๊ตฌ๋‹ˆ ์กฐํšŒํ•˜๊ธฐ


๐Ÿ“ŒCartDetailDto ํด๋ž˜์Šค ์ƒ์„ฑ

package com.shop.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class CartDetailDto {

    private Long cartItemId; // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ ์•„์ด๋””
    private String itemNm;   // ์ƒํ’ˆ๋ช…
    private int price;       // ๊ฐ€๊ฒฉ
    private int count;       // ์ˆ˜๋Ÿ‰
    private String imgUrl;   // ์ƒํ’ˆ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ

    // CartItem ๊ฐ์ฒด์™€ ๋น„์Šท ๐Ÿ‘‰ List์— ๋‹ด๊ธด๋‹ค
    public CartDetailDto(Long cartItemId, String itemNm, int price, int count, String imgUrl) {
        this.cartItemId = cartItemId;
        this.itemNm = itemNm;
        this.price = price;
        this.count = count;
        this.imgUrl = imgUrl;
    }
}



๐Ÿ“ŒCartItemRepository ์ธํ„ฐํŽ˜์ด์Šค ์ˆ˜์ •

package com.shop.repository;

import com.shop.dto.CartDetailDto;
import com.shop.entity.CartItem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface CartItemRepository extends JpaRepository<CartItem, Long> {

    // ์ƒํ’ˆ์ด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋“ค์–ด์žˆ๋Š”์ง€ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ
    CartItem findByCartIdAndItemId(Long cartId, Long itemId);

    // select ๋ถ€๋ถ„์— new ํ‚ค์›Œ๋“œ์™€ ํ•ด๋‹น DTO์˜ ํŒจํ‚ค์ง€, ํด๋ž˜์Šค๋ช…์„ ์ง€์ •
    // ๐Ÿ‘‰ Dto๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ฐ”๋กœ ๋„ฃ๋Š” ํ˜•์‹
    @Query("select new com.shop.dto.CartDetailDto(ci.id, i.itemNm, i.price, ci.count, im.imgUrl)"
    + "from CartItem ci, ItemImg im "
    + "join ci.item i " // CartItem๊ณผ ItemImg ์กฐ์ธ ๐Ÿ‘‰ itemImg๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ค๋ ค๊ณ 
    + "where ci.cart.id = :cartId " // ์กฐ๊ฑด1 : CartItem์˜ CartId์™€ ์™ธ๋ถ€ ๋งค๊ฐœ๋ณ€์ˆ˜ CartId๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ต
    + "and im.item.id = ci.item.id " // ์กฐ๊ฑด2 : CartItem์˜ itemId์™€ ItemImg์˜ itemId๊ฐ€ ๊ฐ™์€์ง€ ๋น„๊ต
    + "and im.repImgYn = 'Y' " // ์กฐ๊ฑด3 : ItemImg ๋Œ€ํ‘œ์ด๋ฏธ์ง€
    + "order by ci.regTime desc") // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋“ฑ๋ก์‹œ๊ฐ„ ๋‚ด๋ฆผ์ฐจ์ˆœ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ‘œ์ด๋ฏธ์ง€ ๋“ฑ๋ก
    // ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ํ•œ ๋ฒˆ์— ๋ฐ˜ํ™˜ ํ•˜๋„๋ก List<CartDetailDto> ํƒ€์ž… ์ง€์ •
    List<CartDetailDto> findCartDetailDtoList(Long cartId);

}



๐Ÿ“ŒCartService ํด๋ž˜์Šค ์ˆ˜์ •


...

    @Transactional(readOnly = true)
    // ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ์กด์žฌํ•˜๋Š” ์ƒํ’ˆ ์กฐํšŒ
    public List<CartDetailDto> getCartList(String email){

        List<CartDetailDto> cartDetailDtoList = new ArrayList<>();

        // ๋กœ๊ทธ์ธํ•œ ์œ ์ € ์ •๋ณด
        Member member = memberRepository.findByEmail(email);

        // ์œ ์ €์˜ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์กฐํšŒ
        Cart cart = cartRepository.findByMemberId(member.getId());

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ์—†๋Š” ์ฑ„๋กœ cartDetailDtoList ๋ฐ˜ํ™˜
        if (cart == null){

            return cartDetailDtoList;

        }

        // ๋น„์–ด์žˆ์ง€ ์•Š์œผ๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์ƒํ’ˆ๋“ค์„ cartDetailDtoList์— ์ถ”๊ฐ€ ํ›„ ๋ฐ˜ํ™˜
        cartDetailDtoList = cartItemRepository.findCartDetailDtoList(cart.getId());

        return cartDetailDtoList;

    }

}



๐Ÿ“ŒCartController ํด๋ž˜์Šค ์ˆ˜์ •

...

    @GetMapping(value = "/cart")
    public String orderHist(Principal principal, Model model){

        List<CartDetailDto> cartDetailDtoList = cartService.getCartList(principal.getName());

        model.addAttribute("cartItems", cartDetailDtoList);

        return "/cart/cartList";

    }

}



๐Ÿ“Œ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;
            // name ์†์„ฑ ๊ฐ’์ด cartChkBox ์ด๊ณ  ์ฒดํฌ๋œ input ํƒœ๊ทธ์— ๋Œ€ํ•ด ๊ฐ๊ฐ ํ•จ์ˆ˜ ์ˆ˜ํ–‰
            $("input[name=cartChkBox]:checked").each(function() {
                var cartItemId = $(this).val();
                //id ๊ฐ€ price~ ์ธ ํƒœ๊ทธ๋ฅผ ์ง€์ •
                var price = $("#price_" + cartItemId).attr("data-price");
                //id ๊ฐ€ count~ ์ธ ํƒœ๊ทธ๋ฅผ ์ง€์ •
                var count = $("#count_" + cartItemId).val();
                orderTotalPrice += price * count;
            });

            $("#orderTotalPrice").html(orderTotalPrice+'์›');
        }

        // ์ƒํ’ˆ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ
        // ์ˆ˜๋Ÿ‰ ๋ถ€๋ถ„์˜ ์ˆ˜๋Ÿ‰์„ ๋ณ€๊ฒฝ ํ•˜๋ฉด changeCount() ์‹คํ–‰
        function changeCount(obj){
            var count = obj.value; // ํ˜„์žฌ ์ˆ˜๋Ÿ‰
            var cartItemId = obj.id.split('_')[1]; // count_ + id ์ด๋ฏ€๋กœ id๋ฅผ ์ถ”์ถœ
            // id = price{CartItemId} ์—˜๋ฆฌ๋จผํŠธ data ์—์„œ key = price ์ธ value ์ถ”์ถœ
            var price = $("#price_" + cartItemId).data("price");
            var totalPrice = count * price;
            $("#totalPrice_" + cartItemId).html(totalPrice+"์›");
            // ๋ณ€๊ฒฝ๋œ ์ˆ˜๋Ÿ‰์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ด ์ฃผ๋ฌธ ๊ธˆ์•ก์„ ์ˆ˜์ • ํ•˜๋Š” getOrderTotalPrice() ์‹คํ–‰
            getOrderTotalPrice();

            // DB ๋ณ€๊ฒฝ์„ ์œ„ํ•œ updateCartItemCount ํ•จ์ˆ˜ ํ˜ธ์ถœ
            updateCartItemCount(cartItemId, count);
        }

        // ์ „์ฒด ์„ ํƒ ๋˜๋Š” ์ „์ฒด ํ•ด์ œ
        function checkAll(){
            // checkall ํƒœ๊ทธ์˜ ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด checked ๋ผ๋ฉด cartChkBox ํƒœ๊ทธ๋ฅผ ๋ชจ๋‘ checked ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
            // .prop() : JavaScript์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ทจ๊ธ‰ (true,false)
            // .attr() ์€ HTML์˜ ์†์„ฑ์„ ์ทจ๊ธ‰
            if($("#checkall").prop("checked")){
                $("input[name=cartChkBox]").prop("checked",true);
            }
            // checked ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๋ชจ๋‘ checked ์ƒํƒœ๋ฅผ ํ•ด์ œ
            else{
                $("input[name=cartChkBox]").prop("checked",false);
            }
            // ๋งˆ์ง€๋ง‰์— ์ด ์ฃผ๋ฌธ ๊ธˆ์•ก์„ ์ˆ˜์ •ํ•˜๋Š” getOrderTotalPrice() ํ•จ์ˆ˜ ํ˜ธ์ถœ
            getOrderTotalPrice();
        }

        // ์ƒํ’ˆ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ DB ์ ์šฉ์„ ์œ„ํ•ด "/cartItem/{cartItemId}?count=value" ์š”์ฒญ
        function updateCartItemCount(cartItemId, count){
            var token = $("meta[name='_csrf']").attr("content");
            var header = $("meta[name='_csrf_header']").attr("content");

            // ์ƒํ’ˆ Id ๊ฐ’์€ PathVariable, ์ˆ˜๋Ÿ‰(count)์€ QueryString
            var url = "/cartItem/" + cartItemId+"?count=" + count;

            $.ajax({
                url      : url,
                // ์ผ ๋ถ€๋ถ„๋งŒ ์ˆ˜์ • ํ•˜๊ธฐ ์œ„ํ•ด PATCH ์š”์ฒญ
                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.responseText);
                    }

                }
            });
        }

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์‚ญ์ œ ์š”์ฒญ
        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.responseText);
                    }

                }
            });
        }
        
        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ(๋“ค) ์ฃผ๋ฌธ
        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.responseText);
                    }

                }
            });
        }
    </script>
</th:block>

<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">
                                <!--// id = price{CartItemId} ์—˜๋ฆฌ๋จผํŠธ์— data ์ž๋ฃŒ๊ตฌ์กฐ ์ƒ์„ฑ ํ›„ key = price ์— ๋Œ€ํ•œ value ์ง€์ •-->
                                <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)">&times;</span> <!-- &times;๋Š” X ๋ชจ์–‘์ž„ -->
                                </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-success btn-lg" onclick="orders()">์ฃผ๋ฌธ ํ•˜๊ธฐ</button>
        </div>
    </div>
</div>
</html>



๐Ÿ“Œ๊ฒฐ๊ณผ

๐Ÿ‘‰ DB์™€ ๊ฐ™์ด 511๊ฐœ๊ฐ€ ๋‹ด๊ฒจ์žˆ๋‹ค

๐Ÿ‘‰ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ์ด๋‚˜ ์ฃผ๋ฌธํ•˜๊ธฐ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋



โ“์–ด๋–ค ๊ตฌ์กฐ๋กœ ์‹คํ–‰?









๐Ÿ“–์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ˆ˜์ •ํ•˜๊ธฐ


๐Ÿ“ŒCartItem ์—”ํ‹ฐํ‹ฐ ์ˆ˜์ •

...

    // ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ์„ ํ•˜๋ฉด ๋ณ€๊ฒฝ ๊ฐ์ง€๋กœ ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๋ฉ”์†Œ๋“œ
    public void updateCount(int count){
        this.count = count;
    }

}



๐Ÿ“ŒCartService ํด๋ž˜์Šค ์ˆ˜์ •

...

    @Transactional(readOnly = true)
    public boolean validateCartItem(Long cartItemId, String email){

        Member curMember = memberRepository.findByEmail(email);

        CartItem cartItem = cartItemRepository.findById(cartItemId)
                .orElseThrow(EntityExistsException::new);

        Member savedMember = cartItem.getCart().getMember();

        // ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์™€ ํ•ด๋‹น ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ์˜ ์ €์žฅํ•œ ์œ ์ €๊ฐ€ ๊ฐ™์€์ง€ ๊ฒ€์ฆ
        if(!StringUtils.equals(curMember.getEmail(), savedMember.getEmail())){

            return false;

        }

        return true;

    }

    // ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ํ†ตํ•œ update
    public void updateCartItemCount(Long cartItemId, int count){

        CartItem cartItem = cartItemRepository.findById(cartItemId)
                .orElseThrow(EntityExistsException::new);

        cartItem.updateCount(count);

    }

}



๐Ÿ“ŒCartController ํด๋ž˜์Šค ์ˆ˜์ •

...

    @PatchMapping(value = "/cartItem/{cartItemId}")
    // ์œ„์— ์กด์žฌํ•˜๋Š” updateCartItemCount() ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ์ „์†ก ๋˜๋Š” PATCH(์ˆ˜์ •) ์š”์ฒญ์— ๋Œ€ํ•œ Controller
    public @ResponseBody ResponseEntity updateCartItem(@PathVariable("cartItemId") Long cartItemId,
                                                       int count, Principal principal){

        System.out.println(cartItemId);

        // ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์™€ ํ•ด๋‹น ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ์˜ ์ €์žฅํ•œ ์œ ์ €๊ฐ€ ๊ฐ™์€์ง€ ๊ฒ€์ฆ
        if (count <= 0){

            return new ResponseEntity<String>("์ตœ์†Œ 1๊ฐœ ์ด์ƒ ๋‹ด์•„์ฃผ์„ธ์š”.", HttpStatus.BAD_REQUEST);

        }
        // ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์œ ์ €์™€ ํ•ด๋‹น ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ์˜ ์ €์žฅํ•œ ์œ ์ €๊ฐ€ ๊ฐ™์€์ง€ ๊ฒ€์ฆ
        else if (!cartService.validateCartItem(cartItemId, principal.getName())){

            return new ResponseEntity<String>("์ˆ˜์ • ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.", HttpStatus.FORBIDDEN);

        }

        // ๋ฐ”๊พผ count ๊ทธ๋Œ€๋กœ ์˜ฌ๋ฆผ
        cartService.updateCartItemCount(cartItemId, count);

        return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);

    }

}



๐Ÿ“ŒcartList.html ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ AJAX

        // ์ƒํ’ˆ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ DB ์ ์šฉ์„ ์œ„ํ•ด "/cartItem/{cartItemId}?count=value" ์š”์ฒญ
        function updateCartItemCount(cartItemId, count){
            var token = $("meta[name='_csrf']").attr("content");
            var header = $("meta[name='_csrf_header']").attr("content");

            // ์ƒํ’ˆ Id ๊ฐ’์€ PathVariable, ์ˆ˜๋Ÿ‰(count)์€ QueryString
            var url = "/cartItem/" + cartItemId+"?count=" + count;

            $.ajax({
                url      : url,
                // ์ผ ๋ถ€๋ถ„๋งŒ ์ˆ˜์ • ํ•˜๊ธฐ ์œ„ํ•ด PATCH ์š”์ฒญ
                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.responseText);
                    }

                }
            });
        }



๐Ÿ“Œ๊ฒฐ๊ณผ

๐Ÿ‘‰ 100๊ฐœ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์—”ํ„ฐ

๐Ÿ‘‰ ์ž๋™์œผ๋กœ DB์— ๋ฐ˜์˜ ๋๋‹ค.

๐Ÿ‘‰ 1๊ฐœ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€์ง€ ์•Š์œผ๋ฉฐ 0์„ ๊ฐ•์ œ๋กœ ์ž…๋ ฅ์‹œ ์—๋Ÿฌ๋ฉ”์„ธ์ง€๊ฐ€ ์ž˜ ์ถœ๋ ฅ ๋œ๋‹ค

๐Ÿ‘‰ DB์—๋Š” 1๊ฐœ๋กœ ์ €์žฅ์ด ๋œ๋‹ค



๐Ÿ“Œ์–ด๋–ค ๊ตฌ์กฐ๋กœ ์‹คํ–‰?









๐Ÿ“–์žฅ๋ฐ”๊ตฌ๋‹ˆ ์‚ญ์ œํ•˜๊ธฐ


๐Ÿ“ŒCartService ํด๋ž˜์Šค ์ˆ˜์ •

...

    // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ ๋ฒˆํ˜ธ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์„œ ์‚ญ์ œ
    public void deleteCartItem(Long cartItemId){

        CartItem cartItem = cartItemRepository.findById(cartItemId)
                .orElseThrow(EntityExistsException::new);
        cartItemRepository.delete(cartItem);

    }

}



๐Ÿ“ŒCartController ํด๋ž˜์Šค ์ˆ˜์ •

...

    // ์‚ญ์ œ ์š”์ฒญ์ด๋ฏ€๋กœ DeleteMapping ์–ด๋…ธํ…Œ์ด์…˜ ์ง€์ •
    @DeleteMapping(value = "/cartItem/{cartItemId}")
    public @ResponseBody ResponseEntity deleteCartItem(@PathVariable("cartItemId") Long cartItemId,
                                                       Principal principal){

        // ์ƒํ’ˆ ์‚ญ์ œ ์š”์ฒญ์„ ํ•˜๋Š” ์œ ์ €์™€ ํ•ด๋‹น ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ์˜ ์œ ์ €๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆ
        if (!cartService.validateCartItem(cartItemId, principal.getName())){

            return new ResponseEntity<String>("์‚ญ์ œ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.", HttpStatus.FORBIDDEN);

        }

        cartService.deleteCartItem(cartItemId);

        return new ResponseEntity<Long>(cartItemId, HttpStatus.OK);

    }

}



๐Ÿ“ŒcartList.html ์‚ญ์ œ AJAX

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์‚ญ์ œ ์š”์ฒญ
        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.responseText);
                    }

                }
            });
        }



๐Ÿ“Œ๊ฒฐ๊ณผ

๐Ÿ‘‰ X ๋ฅผ ๋ˆ„๋ฅด๋ฉด ์‚ญ์ œ๊ฐ€ ๋œ๋‹ค.



โ“์–ด๋–ค ๊ตฌ์กฐ๋กœ ์‹คํ–‰?









๐Ÿ“–์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฃผ๋ฌธํ•˜๊ธฐ


๐Ÿ“ŒCartOrderDto ํด๋ž˜์Šค ์ƒ์„ฑ

package com.shop.dto;

import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
// ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€์—์„œ ์ฃผ๋ฌธํ•  ์ƒํ’ˆ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ Dto
public class CartOrderDto {

    private Long cartItemId;

    // List์— ์ž๊ธฐ ์ž์‹ ์„ ๋‹ด๋Š”๋‹ค.
    private List<CartOrderDto> cartOrderDtoList;

}



๐Ÿ“ŒOrderService ํด๋ž˜์Šค ์ˆ˜์ •

...

    // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€์—์„œ ์ „๋‹ฌ ๋ฐ›์€ ๊ตฌ๋งค ์ƒํ’ˆ์œผ๋กœ ์ฃผ๋ฌธ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ
    public Long orders(List<OrderDto> orderDtoList, String email){

        // ๋กœ๊ทธ์ธํ•œ ์œ ์ € ์กฐํšŒ
        Member member = memberRepository.findByEmail(email);

        List<OrderItem> orderItemList = new ArrayList<>();

        // orderDto ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ itme ๊ฐ์ฒด์™€ count ๊ฐ’์„ ์–ป์–ด OrderItem ๊ฐ์ฒด ์ƒ์„ฑ
        for (OrderDto orderDto : orderDtoList){

            Item item = itemRepository.findById(orderDto.getItemId())
                    .orElseThrow(EntityNotFoundException::new);
            OrderItem orderItem = OrderItem.createOrderItem(item, orderDto.getCount());

            orderItemList.add(orderItem);

        }

        // Order Entity ํด๋ž˜์Šค์— ์กด์žฌํ•˜๋Š” createOrder ๋ฉ”์†Œ๋“œ๋กœ Order ์ƒ์„ฑ ๋ฐ ์ €์žฅ
        Order order = Order.createOrder(member, orderItemList);
        orderRepository.save(order);

        return order.getId();

    }

}



๐Ÿ“ŒCartService ํด๋ž˜์Šค ์ˆ˜์ •

...
    private final OrderService orderService;
...

    public Long orderCartItem(List<CartOrderDto> cartOrderDtoList, String email){

        List<OrderDto> orderDtoList = new ArrayList<>();

        // CartOrderDto ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด cartItem ๊ฐ์ฒด ์กฐํšŒ
        // cartItem ๊ฐ์ฒด์—์„œ itemId ์™€ count ๊ฐ’์„ ์ด์šฉํ•ด orderDto ๊ฐ์ฒด ์ƒ์„ฑ
        for (CartOrderDto cartOrderDto : cartOrderDtoList){

            CartItem cartItem = cartItemRepository.findById(cartOrderDto.getCartItemId())
                    .orElseThrow(EntityExistsException::new);
            OrderDto orderDto = new OrderDto();
            orderDto.setItemId(cartItem.getItem().getId());
            orderDto.setCount(cartItem.getCount());
            orderDtoList.add(orderDto);

        }

        Long orderId = orderService.orders(orderDtoList, email);

        // ์ฃผ๋ฌธํ•œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ์„ ์ œ๊ฑฐ
        for (CartOrderDto cartOrderDto : cartOrderDtoList){

            CartItem cartItem = cartItemRepository.findById(cartOrderDto.getCartItemId())
                    .orElseThrow(EntityExistsException::new);
            cartItemRepository.delete(cartItem);

        }

        return orderId;

    }

}



๐Ÿ“ŒCartController ํด๋ž˜์Šค ์ˆ˜์ •

...

    @PostMapping(value = "/cart/orders")
    public @ResponseBody ResponseEntity orderCartItem(@RequestBody CartOrderDto cartOrderDto,
                                                      Principal principal){

        System.out.println(cartOrderDto.getCartItemId());

        List<CartOrderDto> cartOrderDtoList = cartOrderDto.getCartOrderDtoList();

        if(cartOrderDtoList == null || cartOrderDtoList.size() == 0){

            return new ResponseEntity<String>("์ฃผ๋ฌธํ•  ์ƒํ’ˆ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.", HttpStatus.FORBIDDEN);

        }

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ฃผ๋ฌธ ์ƒํ’ˆ ํ•˜๋‚˜์”ฉ ๊ฒ€์ฆ
        for (CartOrderDto cartOrder : cartOrderDtoList){

            if (!cartService.validateCartItem(cartOrder.getCartItemId(), principal.getName())){

                return new ResponseEntity<String>("์ฃผ๋ฌธ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.", HttpStatus.FORBIDDEN);

            }

        }

        Long orderId = cartService.orderCartItem(cartOrderDtoList, principal.getName());

        return new ResponseEntity<Long>(orderId, HttpStatus.OK);
    }

}



๐Ÿ“Œ๐Ÿ”ฅcartList.html ์ฃผ๋ฌธ AJAX๐Ÿ”ฅ

        // ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ƒํ’ˆ(๋“ค) ์ฃผ๋ฌธ
        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.responseText);
                    }

                }
            });
        }
    </script>
</th:block>



๐Ÿ“Œ๊ฒฐ๊ณผ

๐Ÿ‘‰ ํ•œ๊บผ๋ฒˆ์— ์ฃผ๋ฌธ ๋จ (์ฃผ๋ฌธ์„œ)

๐Ÿ‘‰ ์ฃผ๋ฌธ๋œ ์ƒํ’ˆ๋“ค

๐Ÿ‘‰ ์žฅ๋ฐ”๊ตฌ๋‹ˆ์—์„œ ์‚ฌ๋ผ์ง

๐Ÿ‘‰ ํ•˜๋‚˜๋งŒ ์ฃผ๋ฌธ



โ“์–ด๋–ค ๊ตฌ์กฐ๋กœ ์‹คํ–‰?

cartList.html ๐Ÿ‘‰ CartContoller ๐Ÿ‘‰ CartService ๐Ÿ‘‰ OrderService ๐Ÿ‘‰ CartService ๐Ÿ‘‰ CartController ๐Ÿ‘‰ carList.html
๋ณต์žกํ•˜๋‹ค..

๊ณ„์ธต์„ ์ด๋™ํ•  ๋•Œ๋Š” Dto ๊ฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธฐ๊ณ , ํ•ด๋‹น ๊ณ„์ธต์—์„œ Dto ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ Entity ๊ฐ์ฒด๋ฅผ ์กฐํšŒ, ํ•ด๋‹น Entity ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž์‹ ์˜ ๋กœ์ง์„ ์ˆ˜ํ–‰

Controller

  1. CartOrderDto ์—์„œ CartOrderList ๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค cartService.orderCartItem() ๋ฉ”์†Œ๋“œ ์ˆ˜ํ–‰

CartService

  1. cartOrderDto ์— ์กด์žฌํ•˜๋Š” cartItemId ๋ฅผ ์ด์šฉํ•˜์—ฌ CartItem ๊ฐ์ฒด ์กฐํšŒ
  2. cartItem ์— ์กด์žฌํ•˜๋Š” ItemId ์™€ count ๊ฐ’์„ ์–ป์€ ๋’ค์— ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ OrderDto ๊ฐ์ฒด ์ƒ์„ฑ
  3. OrderDtoList ๋ฅผ orderService.orders() ๋ฉ”์†Œ๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ ํ˜ธ์ถœ

OrderService

  1. OrderDto ์— ์กด์žฌํ•˜๋Š” ItemId ์™€ count ๊ฐ’์„ ์–ป์€ ๋’ค์— ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ OrderItem ๊ฐ์ฒด ์ƒ์„ฑ
  2. Order.createOrder() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœํ•˜์—ฌ Order ๊ฐ์ฒด ์ƒ์„ฑํ›„ save. ์ด ๋•Œ, ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” member, orderItemList



๐Ÿ”ฅTodo

์žฌ๊ณ ๋ณด๋‹ค ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๋Š” ์ˆ˜๋Ÿ‰์ด ๋งŽ์„ ๊ฒฝ์šฐ ๊ทธ๋Œ€๋กœ DB์— ๋‹ด๊ธฐ๋Š” ํ˜„์ƒ ์ˆ˜์ •


  • ์ฃผ๋ฌธ ์ทจ์†Œํ•˜๊ณ  ๋‹ค์‹œ ๋‹ด๊ธฐ
  • ์ฃผ๋ฌธ ์ทจ์†Œํ•˜๋ฉด ํŒ๋งค์ž๊ฐ€ ์ทจ์†Œ ํ™•์ธํ•˜๊ธฐ
  • ๊ฒฐ์ œ ์ •๋ณด?

0๊ฐœ์˜ ๋Œ“๊ธ€