고객이 상품을 주문하고 주문 내역을 조회하는 페이지
온라인 쇼핑몰에서는 내가 주문한 내역을 확인할 수 있다. 주문 이력 페이지에서는 보통 주문한 상품정보와 현재 상품의 배송 단계까지 보여준다. 주문 내역을 통해 반품 혹은 교환, 취소 등을 진행할 수도 있다. 프로젝트에서는 일단 주문 취소 기능만 구현할 계획이다.
주문 이력 조회를 위해 리스트업을 해보았다.
먼저 주문 상품과 주문 정보에 관한 데이터가 있어야하는데 이 때, 주문 상품 데이터(OrderItem)를 화면에 보낼 때 사용하는 DTO 클래스와 주문 정보(OrderHist)를 담는 DTO 클래스를 따로 만들어준다. 그리고 주문 이력 조회 쿼리를 OrderRepository
에 추가하기로 했다.
구매 이력 페이지에서도 대표 이미지를 보여주어야할 필요성이 있어 ItemImgRepository
에 상품의 대표 이미지 찾는 쿼리 메소드를 추가 -> 주문 목록 조회 로직을 실제 구현 -> Controller
단에서 로직 호출하는 방식으로 진행하게 되었다.
주문 상품 정보를 담을 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;
}
다음으로는 실제 주문 정보를 담을 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);
}
}
addOrderItemDto
: orderItemDto
객체를 주문 상품 리스트에 추가하는 메소드이다. @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);
: 현재 로그인한 회원의 주문 개수가 몇 개인지 조회기존 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);
}
기존에 만들었던 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
: 주문한 상품의 대표 이미지를 조회
구매이력을 조회할 수 있도록 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";
}
💡Pagination(페이지네이션)
: 한 번에 모든 데이터를 요청하는 게 아니라 사용자가 볼 만큼만 서버에 요청하면서 서버에 부하를 줄이도록 하는 기술
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)
: 페이지 번호와 개수, 정렬 관련 정보