나만의 프로젝트 배포하기 12일차

박세건·2023년 9월 25일
0

개인 프로젝트

목록 보기
12/15

장바구니에 들어있는 상품 제거

저번 시간에 장바구니 등록기능을 만들어보았고 이번에는 장바구니에 들어있는 내용을 확인할 수 있는 html을 만들어주고 장바구니에 들어있는 상품을 제거하는 API를 만들어보자

제일 먼저 장바구니에 들어있는 상품들을 보여주는 html을 설계해보자!

  • 먼저 해당 정보들을 가져와야 하기때문에 Cart와 CartItem의 정보를 갖고있는 dto들을 만들어준다.
  • CartResponseDto
package com.qkrtprjs.happyexercise.dto;

import com.qkrtprjs.happyexercise.entitiy.member.Member;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;


@NoArgsConstructor
@Getter
public class CartResponseDto {

    private Long id;

    private int price;

    private MemberResponseDto memberResponseDto;

    @Builder

    public CartResponseDto(Long id, int price, MemberResponseDto memberResponseDto) {
        this.id = id;
        this.price = price;
        this.memberResponseDto = memberResponseDto;
    }
}
  • CartItemResponseDto
package com.qkrtprjs.happyexercise.dto;

import com.qkrtprjs.happyexercise.entitiy.BaseTimeEntity;
import com.qkrtprjs.happyexercise.entitiy.cart.Cart;
import com.qkrtprjs.happyexercise.entitiy.cart.CartItem;
import com.qkrtprjs.happyexercise.entitiy.item.Item;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor
public class CartItemResponseDto {

    private Long id;

    private int count;

    private CartResponseDto cartResponseDto;

    private ItemResponseDto itemResponseDto;

    @Builder

    public CartItemResponseDto(Long id, int count, CartResponseDto cartResponseDto, ItemResponseDto itemResponseDto) {
        this.id = id;
        this.count = count;
        this.cartResponseDto = cartResponseDto;
        this.itemResponseDto = itemResponseDto;
    }
}
  • DTO로 정보를 이동시켜주는 서비스 설계
    public List<CartItemResponseDto> findByMember(SessionMember sessionMember) {
        Member member = memberRepository.findByEmail(sessionMember.getEmail()).orElseThrow(() -> new IllegalArgumentException("해당 이메일은 존재하지 않습니다!"));
        Cart cart = cartRepository.findByMember(member).orElseThrow(() -> new IllegalArgumentException("해당 member 값은 존재하지않습니다!"));
        return cartItemRepository.findByCart(cart).stream().map(cartItem -> CartItem.toDto(cartItem)).collect(Collectors.toList());

    }
    public CartResponseDto findByMember(SessionMember sessionMember) {
        Member member = memberRepository.findByEmail(sessionMember.getEmail()).orElseThrow(() -> new IllegalArgumentException("해당 이메일은 존재하지않습니다!"));
        Cart cart = cartRepository.findByMember(member).orElseThrow(() -> new IllegalArgumentException("해당 member는 존재하지않습니다!"));
        return Cart.toDto(cart);
    }
  • 해당 정보를 html로 넘겨주는 컨트롤러 설계
    @GetMapping("/cartDetail")
    private String cartDetail(Model model, @LoginMember SessionMember sessionMember) {
        List<CartItemResponseDto> cartItemResponseDtoList = cartItemService.findByMember(sessionMember);
        CartResponseDto cartResponseDto = cartService.findByMember(sessionMember);
        model.addAttribute("cartItemList", cartItemResponseDtoList);
        model.addAttribute("cart", cartResponseDto);
        return "cart/cartDetail";
    }

장바구니에 들어있는 총 금액을 알 수 있는 기능도 추가하기위해서 Entity 수정

  • cart Entity
package com.qkrtprjs.happyexercise.entitiy.cart;

import com.qkrtprjs.happyexercise.dto.CartResponseDto;
import com.qkrtprjs.happyexercise.entitiy.BaseTimeEntity;
import com.qkrtprjs.happyexercise.entitiy.member.Member;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@NoArgsConstructor
@Entity
public class Cart extends BaseTimeEntity {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;

    private int price;	//수정된 부분

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "memberId")
    private Member member;

    @Builder
    public Cart(int price,Member member) {
        this.price = price;
        this.member = member;
    }


    public static CartResponseDto toDto(Cart cart) {

        return CartResponseDto.builder()
                .id(cart.getId())
                .price(cart.getPrice())
                .memberResponseDto(Member.toDto(cart.getMember()))
                .build();
    }

    public void sumPrice(int price) {
        this.price += price;

    }
}
  • Setter를 따로 사용하는것은 선호하지 않기때문에 클래스에 함수 설계
    public void sumPrice(int price) {
        this.price += price;

    }
  • 장바구니에 저장할때에 Cart의 price가 추가되어야하기때문에 등록서비스 수정
    @Transactional
    public Long save(Item item, int count, Member member) {
    //장바구니가 존재하는지 확인
        if (!cartRepository.findByMember(member).isPresent()) {
            cartRepository.save(
                    Cart.builder()
                            .price(0)
                            .member(member)
                            .build()
            );
        }

        Cart cart = cartRepository.findByMember(member).orElseThrow(() -> new IllegalArgumentException("해당 member 값은 존재하지않습니다!"));
        cart.sumPrice(count * item.getPrice());	//추가된 부분!
        return cartItemRepository.save(CartItem.builder()
                .count(count)
                .item(item)
                .cart(cart)
                .build()).getId();
    }
  • 해당 HTML
<!DOCTYPE html>
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/default_layout}">

<div layout:fragment="content">

    <div class="container mt-3">
        <h2>내 장바구니 보기</h2>

        <br>
        <table class="table">
            <thead>
            <tr>
                <th>상품명</th>
                <th>개당 가격</th>
                <th>개수</th>
                <th>가격</th>
            </tr>
            </thead>
            <tbody>
            <th:block th:each="cartItem:${cartItemList}">
                <tr>
                    <td th:text="${cartItem.itemResponseDto.name}"></td>
                    <td th:text="${cartItem.itemResponseDto.price}"></td>
                    <td th:text="${cartItem.count}"></td>
                    <td th:text="${cartItem.itemResponseDto.price*cartItem.count}"></td>
                </tr>
            </th:block>
            </tbody>
        </table>
        <br>
        <div class="mb-3">
            <label for="orderPrice">총 주문 금액:</label>
            <input type="text" class="form-control" id="orderPrice" th:value="${cart.price}" name="orderPrice" readonly>
        </div>
    </div>
</div>
</html>

정상적으로 데이터를 불러오는 것을 확인했기때문에 장바구니에서 상품을 삭제하는 기능을 추가해보자!
과정

  • 버튼 추가
  • 버튼에 id 값을 전달할 수 있는 속성 추가
  • id값을 js파일로 들고와서 ajax통신에 전달
  • 해당 컨트롤러로 id 값을 받아주고 서비스로 전달
  • 서비스에서 id값을 통한 CartItem 삭제 및 Cart의 총 가격 수정
  • 버튼 추가
  • 버튼에 id 값을 전달할 수 있는 속성 추가
        <table class="table">
            <thead>
            <tr>
                <th>상품명</th>
                <th>개당 가격</th>
                <th>개수</th>
                <th>가격</th>
                <th></th>
            </tr>
            </thead>
            <tbody>
            <th:block th:each="cartItem:${cartItemList}">

                <tr>
                    <td th:text="${cartItem.itemResponseDto.name}"></td>
                    <td th:text="${cartItem.itemResponseDto.price}"></td>
                    <td th:text="${cartItem.count}"></td>
                    <td th:text="${cartItem.itemResponseDto.price*cartItem.count}"></td>
                    <td><button th:cartItemId="${cartItem.id}" type="button" class="btn btn-danger" name="cartItemDelete-btn">삭제</button></td>
                </tr>
            </th:block>
            </tbody>
        </table>
  • id값을 js파일로 들고와서 ajax통신에 전달
  $("[name=cartItemDelete-btn]").on('click',function (){
            let id = this.getAttribute("cartItemId");
            if (confirm("해당 상품을 장바구니에서 삭제하시겠습니까?")) {
                _this.deleteCartItem(id);
            }else{
                alert("취소되었습니다!");
            }
        });
    deleteCartItem: function (id) {

        $.ajax({
            url: '/api/cartItem/'+id ,
            method: 'DELETE',
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
        }).done(function () {
            alert("상품이 장바구니에서 삭제되었습니다!");
            location.href = '/cartDetail';
        }).fail(function (error) {
            alert(JSON.stringify(error));
        });
    },
  • 해당 컨트롤러로 이동후에 주소값으로 id 값을 받아주고 서비스로 전달

    @DeleteMapping("/api/cartItem/{id}")
    private Long delete(@PathVariable Long id) {
        cartItemService.delete(id);
        return id;
    }
  • 서비스에서 id값을 통한 CartItem 삭제 및 Cart의 총 가격 수정
    @Transactional
    public void delete(Long id) {
        CartItem cartItem = cartItemRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 id는 존재하지않습니다!"));
        //장바구니 가격 수정
        Cart cart = cartItem.getCart();
        cart.deleteItem(cartItem);
        cartItemRepository.delete(cartItem);
    }
    public void deleteItem(CartItem cartItem) {
        this.price -= cartItem.getItem().getPrice()*cartItem.getCount();
    }

장바구니에 가격을 추가하고 수정하는 부분에 있어서 가격이라는 민감한 부분에 대해서 해당 함수들은 더해주거나 빼주는 너무 1차원적인 단순한 로직으로 구현되어있다는게 불안하지만 더 공부하면서 이런 금액적인 부분에서는 다른 플랫폼들이나 다른 개발자분들은 어떻게 처리하는지 공부하자.

그럼 다음에 이어서 장바구니에 들어있는 상품들을 한번에 주문하는 기능을 추가해보자

profile
멋있는 사람 - 일단 하자

0개의 댓글