주문 이력 조회하기 기능 구현

jihan kong·2023년 3월 2일
0
post-thumbnail
post-custom-banner

고객이 상품을 주문하고 주문 내역을 조회하는 페이지

온라인 쇼핑몰에서는 내가 주문한 내역을 확인할 수 있다. 주문 이력 페이지에서는 보통 주문한 상품정보와 현재 상품의 배송 단계까지 보여준다. 주문 내역을 통해 반품 혹은 교환, 취소 등을 진행할 수도 있다. 프로젝트에서는 일단 주문 취소 기능만 구현할 계획이다.

주문 이력 조회를 위해 리스트업을 해보았다.

먼저 주문 상품과 주문 정보에 관한 데이터가 있어야하는데 이 때, 주문 상품 데이터(OrderItem)를 화면에 보낼 때 사용하는 DTO 클래스와 주문 정보(OrderHist)를 담는 DTO 클래스를 따로 만들어준다. 그리고 주문 이력 조회 쿼리를 OrderRepository 에 추가하기로 했다.

구매 이력 페이지에서도 대표 이미지를 보여주어야할 필요성이 있어 ItemImgRepository 에 상품의 대표 이미지 찾는 쿼리 메소드를 추가 -> 주문 목록 조회 로직을 실제 구현 -> Controller 단에서 로직 호출하는 방식으로 진행하게 되었다.


1. OrderItemDto 생성

주문 상품 정보를 담을 OrderItemDto 클래스이다.

orderItemDto.java

package com.shop.dto;

import com.shop.entity.OrderItem;
import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class OrderItemDto {

    public OrderItemDto(OrderItem orderItem, String imgUrl) {
        this.itemNm = orderItem.getItem().getItemNm();
        this.count = orderItem.getCount();
        this.orderPrice = orderItem.getOrderPrice();
        this.imgUrl = imgUrl;
    }

    private String itemNm;

    private int count;

    private int orderPrice;

    private String imgUrl;
}
  • OrderItemDto의 생성자는 orderItem 객체와 이미지 경로를 파라미터로 받는다.

2. OrderHistDto 생성

다음으로는 실제 주문 정보를 담을 OrderHistDto 클래스를 생성한다.

OrderHistDto.java

package com.shop.dto;

import com.shop.constant.OrderStatus;
import com.shop.entity.Order;
import lombok.Getter;
import lombok.Setter;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Getter
@Setter
public class OrderHistDto {

    public OrderHistDto(Order order) {
        this.orderId = order.getId();
        this.orderDate = order.getOrderDate().format(DateTimeFormatter.ofPattern("yyyy-mm-dd HH:mm"));
        this.orderStatus = order.getOrderStatus();
    }

    private Long orderId;

    private String orderDate;

    private OrderStatus orderStatus;

    private List<OrderItemDto> orderItemDtoList = new ArrayList<>();

    public void addOrderItemDto(OrderItemDto orderItemDto) {
        orderItemDtoList.add(orderItemDto);
    }
}
  • OrderHistDto 클래스의 생성자로 order 객체를 파라미터로 받는다. 주문 날짜의 경우, 화면에 "yyyy(년)-MM(월)-dd(일) HH(시):mm(분)" 형태로 전달하기 위해 포맷을 수정한다.
  • addOrderItemDto : orderItemDto 객체를 주문 상품 리스트에 추가하는 메소드이다.

3. OrderRepository 생성

@Query 어노테이션을 이용하여 주문 이력을 조회하는 쿼리를 작성하도록 했다.

OrderRepository.java

package com.shop.repository;

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

import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface OrderRepository extends JpaRepository<Order, Long> {

    @Query("select o from Order o " +
            "where o.member.email = :email " +
            "order by o.orderDate desc"
    )
    List<Order> findOrders(@Param("email") String email, Pageable pageable);

    @Query("select count(o) from Order o " +
            "where o.member.email = :email"
    )
    Long countOrder(@Param("email") String email);
}
  • List<Order> findOrders(@Param("email") String email, Pageable pageable); : 현재 로그인한 사용자의 주문 데이터를 페이징 조건에 맞춰서 조회
  • Long countOrder(@Param("email") String email); : 현재 로그인한 회원의 주문 개수가 몇 개인지 조회

4. 대표 이미지를 찾는 쿼리 메소드 추가

기존 ItemImgRepository 인터페이스에서 상품의 대표 이미지를 찾는 쿼리 메소드를 추가한다.

ItemImgRepository.java

package com.shop.repository;

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

import java.util.List;

public interface ItemImgRepository extends JpaRepository<ItemImg, Long> {

    List<ItemImg> findByItemIdOrderByIdAsc(Long itemId);

    ItemImg findByItemIdAndRepimgYn(Long itemId, String repimgYn);
}


5. 주문 이력 조회 로직 구현 (OrderService)

기존에 만들었던 OrderService 클래스에 주문 이력 조회 로직을 구현한다.

package com.shop.service;

import com.shop.dto.OrderDto;
import com.shop.dto.OrderHistDto;
import com.shop.dto.OrderItemDto;
import com.shop.entity.*;
import com.shop.repository.ItemImgRepository;
import com.shop.repository.ItemRepository;
import com.shop.repository.MemberRepository;
import com.shop.repository.OrderRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Service
@Transactional
@RequiredArgsConstructor
public class OrderService {

    private final ItemRepository itemRepository;
    private final MemberRepository memberRepository;
    private final OrderRepository orderRepository;
    private final ItemImgRepository itemImgRepository;

	// 기존 import 생략

    @Transactional(readOnly = true)
    public Page<OrderHistDto> getOrderList(String email, Pageable pageable) {

        List<Order> orders = orderRepository.findOrders(email, pageable);
        Long totalCount = orderRepository.countOrder(email);

        List<OrderHistDto> orderHistDtos = new ArrayList<>();

        for (Order order : orders) {
            OrderHistDto orderHistDto = new OrderHistDto(order);
            List<OrderItem> orderItems = order.getOrderItems();
            for (OrderItem orderItem : orderItems) {
                ItemImg itemImg = itemImgRepository.findByItemIdAndRepimgYn
                        (orderItem.getItem().getId(), "Y");
                OrderItemDto orderItemDto =
                        new OrderItemDto(orderItem, itemImg.getImgUrl());
                orderHistDto.addOrderItemDto(orderItemDto);
            }

            orderHistDtos.add(orderHistDto);
        }

        return new PageImpl<OrderHistDto>(orderHistDtos, pageable, totalCount);
    }
}
  • List<Order> orders = orderRepository.findOrders(email, pageable);
    : 유저의 아이디와 페이징 조건을 이용하여 주문 목록을 조회

  • Long totalCount = orderRepository.countOrder(email); : 유저의 주문 총 개수

  • for문으로 주문 리스트를 순회하면서 구매 이력 페이지에 전달할 DTO를 생성.

  • ItemImg itemImg = itemImgRepository.findByItemIdAndRepimgYn : 주문한 상품의 대표 이미지를 조회


6. 로직 호출 - OrderController

구매이력을 조회할 수 있도록 OrderController 에 지금까지 구현한 로직을 호출하는 메소드를 만든다.

OrderController.java

package com.shop.controller;

// ..기존 import 생략

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.shop.dto.OrderHistDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.ui.Model;
import java.util.Optional;

@Controller
@RequiredArgsConstructor
public class OrderController {

	// 코드 생략

    @GetMapping(value = {"/orders", "/orders/{page}"})
    public String orderHist(@PathVariable("page") Optional<Integer> page, Principal principal, Model model){

        Pageable pageable = PageRequest.of(page.isPresent() ? page.get() : 0, 4);
        Page<OrderHistDto> ordersHistDtoList = orderService.getOrderList(principal.getName(), pageable);

        model.addAttribute("orders", ordersHistDtoList);
        model.addAttribute("page", pageable.getPageNumber());
        model.addAttribute("maxPage", 5);

        return "order/orderHist";
    }
  • 한 번에 가지고 올 주문의 개수는 4개로 설정
  • 현재 로그인한 회원은 이메일과 페이징 객체를 파라미터로 전달하여 화면에 전달한 주문 목록 데이터를 리턴 값으로 받게 된다.

배운 것✍️

💡Pagination(페이지네이션)
: 한 번에 모든 데이터를 요청하는 게 아니라 사용자가 볼 만큼만 서버에 요청하면서 서버에 부하를 줄이도록 하는 기술

  • Pageable 을 이용한 Pagination 처리
    • JPA에서는 페이지처리, 페이지의 크기, 정렬방식 설정 등을 Pageable 이라는 객체를 통해 수행한다.
    • Controller 에서 Pageable 객체를 파라미터로 설정하고 요청이 들어오면 Pageable 객체를 자동으로 만들어준다.
    • 적용 방법은 Repository 로 Pageable을 넘겨주고 쿼리문을 작성해주면 된다.
  • PageRequest 생성자에서는 page, size, Sort 라는 정보를 이용해서 객체를 생성한다.
    • of(int page, int size) : 0부터 시작하는 페이지 번호와 개수(size), 정렬이 지정되지 않음
    • of(int page, int size, Sort.Direction direction, String …props) : 0부터 시작하는 페이지 번호와 개수, 정렬의 방향과 정렬 기준 필드들
    • of(int page, int size, Sort sort) : 페이지 번호와 개수, 정렬 관련 정보

(출처 : https://rachel1208.tistory.com/8)

profile
학습하며 도전하는 것을 즐기는 개발자
post-custom-banner

0개의 댓글