[BOOK 개인프로젝트] 8. 장바구니 구현(상품 주문, 찜 목록 추가, 상품 취소)

이재민·2024년 6월 3일
0

JPA 

목록 보기
10/21
post-thumbnail

장바구니 화면에서 "상품 주문하기" 버튼을 통해 객체 넘기기

현재 장바구니 화면

DB 상태 (잘 들어가 있는 거 확인)

-1. 상품 주문하기 버튼 html에서 isbn 값을 넘겨준다.

"상품 주문하기 버튼 코드"

<form id="BasketForm1" action="/fromBasketToOrders" method="GET">
<button id="Basket1" class="btn  btn-primary btn-sm btn-fixed-width"
style="margin-right: 10px; background-color: #7013F2; border-color: #7013F2; color: white;">
상품 주문하기
</button>
<input type="hidden" id="BasketId1" name="isbn" th:value="${book.isbn}">
</form>

"/fromBasketToOrders"라는 @GetMapping 메서드를 실행 해 상품을 주문하는데 이 때 해당 책의 isbn을 넘겨준다,.

-2. action="/fromBasketToOrders" method="GET" 이 부분과 관련된 controller 메서드를 짜준다.

BasketController

    @GetMapping("/fromBasketToOrders")
    public String FromBasketToOrderBook(@RequestParam("isbn") String isbn) {
        log.info("FromBasketToOrderBook");
        try {
            orderBookService.processOrderBook(isbn);
            return "redirect:/home";
        } catch (NoSuchElementException | DuplicateOrderException | IllegalStateException e) {
            log.error(e.getMessage(), e);
            throw e;
        }
    }

OrderBookService - processOrderBook 메서드

    @Transactional
    public void processOrderBook(String isbn) {

        Book book = bookRepository.findByIsbn(isbn);
        log.info("book.isbn = {}", book.getIsbn());
        if (book == null) {
            throw new NoSuchElementException("ISBN에 해당하는 책이 존재하지 않습니다.");
        }

        OrderBook orderBook = getOrderBook(book);

        if (orderBookRepository.findByIsbn(isbn) != null) {
            throw new DuplicateOrderException("이미 주문하기 화면에 해당 상품이 존재합니다.");
        }

        try {
            saveOrderBook(orderBook);
            bookService.deleteBook(book.getIsbn());
        } catch (Exception e) {
            log.error("주문 저장을 실패하였습니다");
            throw new IllegalStateException(e.getMessage());
        }
    }

isbn으로 책을 book db(장바구니 db)에서 찾은 뒤,
책이 존재하면, orderbook에 기존 book을 매핑해주고 저장(orderBook db (주문하기 db))
책이 존재하지 않으면 예외를 던져줌

두 가지 짚고 넘어갈 점
1. html에서 isbn을 넘겨줄 때(th:value="${book.isbn}) controller에서는 "@RequestParam"으로 받아준다.
2. isbn으로 넘어가는 값은 em.find를 통해 조회하지 못한다!

처음에는 em.find(isbn, Book.class) 이런식으로 조회하려고 했지만, em.find 자체가 pk기준으로 조회하는 것이기 때문에 이렇게
아예 코드를 짜줘야 함 pk로 값을 조회하는거 아니면.

이제 장바구니에서 상품 주문하기 버튼 클릭시 홈 화면으로 들어가면서 DB에 들어가게 될 것이다.

DB 연동 확인

-3. 홈 화면에서 상품 주문으로 바로 들어가기 위한 메서드 생성

    @GetMapping("home/mypage/orderBooks")
    public String OrderBookPage(Model model) {

        log.info("주문하기 화면으로 이동합니다.");
        List<OrderBook> orderBooks = orderBookRepository.orderBookList();
        log.info("orderBooks={}", orderBooks);

        int totalOrderAmount = orderBookService.calculateTotalOrderAmount(orderBooks);

        if (orderBooks != null && !orderBooks.isEmpty()) {
            model.addAttribute("orderBooks", orderBooks);
            model.addAttribute("totalOrderAmount", totalOrderAmount);
            return "home/mypage/orders";
        } else {
            throw new OrderBooknotFoundException("장바구니에 상품이 존재하지 않습니다.");
        }
    }

orderBookRepository.orderBookList();

    public List<OrderBook> orderBookList() {
        return em.createQuery("select ob from OrderBook ob", OrderBook.class).getResultList();
    }

orderBookList를 통해 orderBookRepository db에 있는 값들을 List형식으로 가져와서 model에 orderBooks 이름으로 넘긴 뒤,
html에서

           <tr>
                <th>ISBN</th>
                <th>이미지</th>
                <th>제목</th>
                <th>저자/출판사</th>
                <th>출판일</th>
                <th>discount</th>
                <th>기타</th>
            </tr>
            </thead>

            <!-- 수정 후 코드 -->
            <tr th:each="orderbook:${orderBooks}">
                <td>[[${orderbook.isbn}]]</td>
                <td><img th:src="${orderbook.image}" th:alt="${orderbook.name}" width="100"></td>
                <td><a th:href="${orderbook.link}">[[${orderbook.name}]]</a></td>
                <td>[[${orderbook.author}]]/[[${orderbook.publisher}]]</td>
                <td>[[${orderbook.pubdate}]]</td>
                <td>[[${orderbook.stockQuantity}]]</td>

이런식으로 가져와서 타임리프를 사용하기만 하면

상품 주문 화면에 상품 등록되는 거 확인하면 끝!

찜 목록 추가

basket.html

<form id="BasketForm2" action="/FromBasketToWishlist" method="GET">
<button id="Basket2" class="btn  btn-primary btn-sm btn-fixed-width"
style="margin-right: 10px; background-color: #F26B6B; border-color: #F26B6B; color: white;">
 찜 목록에 추가하기
</button>
 <input type="hidden" id="BasketId2" name="isbn" th:value="${book.isbn}">
</form>

BasketController

    @GetMapping("/FromBasketToWishlist")
    //isbn와 찜 목록 버튼을 통해 값 보내주기
    public String FromBasketToWishlist(@RequestParam("isbn") String isbn) {
        try {
            log.info("wishlistFromISBN");

            wishlistService.addFromBasketToWishlist(isbn);

            //성공적으로 저장 되었음 -> 홈 화면으로 리다이렉션
            return "redirect:/home";

        } catch (Exception e) {
            // Wishlist 저장 실패 또는 다른 예외 발생 시 처리
            log.error("해당 상품이 이미 찜 목록에 존재합니다 : {}", e.getMessage());
            throw new IllegalStateException("해당 상품이 이미 찜 목록에 존재합니다.");
        }
    }

WishlistService - addFromBasketToWishlist

    @Transactional
    public void addFromBasketToWishlist(String isbn) {
        Book book = bookRepository.findByIsbn(isbn);
        log.info("book = {}", book);

        //책이 존재하지 않을 경우 예외 처리
        if (book == null) {
            log.error("해당 책이 존재하지 않습니다.");
            throw new EntityNotFoundException("해당 책이 존재하지 않습니다");
        }

        //찜 목록에 해당 책이 이미 존재하는지 확인
        Wishlist wishlistByIsbn = wishlistRepository.findByIsbn(book.getIsbn());
        if (wishlistByIsbn != null) {
            log.error("해당 책이 이미 찜 목록에 존재합니다.");
            throw new DuplicateIsbnException("이미 찜 목록에 해당 상품이 존재합니다.");
        }

        Wishlist wishlistBook = convertToEntityWishlistBook(book);
        log.info("wishlistBook = {}", wishlistBook);

        wishlistRepository.save(wishlistBook);
    }

해당 책이 존재하면 wishlist 형태의 book(wishlistBook)으로 변환 후 wishlist db에 값 저장
예외 시, 예외 던져준 (던져준 예외는 GlobalExceptionHandler로 잡아줌)

찜 목록에 잘 추가되었으면 성공!

장바구니 상품 삭제

현 장바구니 상황

삭제된 거를 보기 위해 먼저 2개를 DB에 넣어놓았음

삭제 로직 구현

1) 먼저 html에서 상품 취소하기 버튼 클릭시 isbn을 파라미터로 넘겨줘야 함

<form id="BasketForm3" action="/delete_book" method="GET">
<button id="Basket3" class="btn  btn-primary btn-sm btn-fixed-width" style="margin-right: 10px; background-color: #3F88C5; border-color: #3F88C5; color: white;">상품 취소하기</button>
<input type="hidden" id="BasketId3" name="isbn" th:value="${book.isbn}">
</form>

2) 그리고 controller에서 action과 method 값을 통해 구현

@GetMapping("/delete_book")
public String delete_book(@RequestParam("isbn") String isbn) {

   bookService.deleteBook(isbn);
   return "redirect:/home";
   
    }

서비스 계층에서 비즈니스 로직을 처리하기 때문에 controller에서는 @RequestParam으로 받은 isbn을 서비스 계층으로 넘겨서 처리하도록 함

3) bookService

    public void deleteBook(String isbn) {
        log.info("deleteBook - isbn = {}", isbn);

        Book book = bookRepository.findByIsbn(isbn);
        log.info("book.isbn = {}", book.getIsbn());

            //책이 존재하면
            if (book != null) {
                bookRepository.deleteByIsbn(book.getIsbn());
                log.info("Book with ISBN {} deleted successfully", isbn);
            } else {
                log.error("상품이 존재하지 않습니다. isbn = {}", isbn);
                throw new EntityNotFoundException("상품이 존재하지 않습니다. isbn = {}" + isbn);
            }
    }

넘겨온 isbn으로 책을 찾고
책이 존재할 때 bookRepository.deleteByIsbn 메서드를 통해 지우고,
책이 없다면 예외를 터트린다.

4) bookRepository

public interface BookRepository extends JpaRepository<Book, Long> {
    Book findByIsbn(String isbn);
    void deleteByIsbn(String isbn);
}

db에서 값을 지워줘야 하니까 Service 계층에서 Repository 계층으로 이동해 삭제 처리 해준다.

이제 버튼을 누르면

삭제 후

db에도 값이 지워지는 거 확인!

profile
복학생의 개발 일기

0개의 댓글

관련 채용 정보