항해99/개발일지

20220206 개발일지 #배달앱 기본 기능 구현

paran21 2022. 2. 6. 22:34

오늘은 어제 제대로 못한 order 기능을 구현하는 것이 목표였고, 테스트 에러 문제도 다른 팀원 분들의 도움을 받아서 해결하였다.

테스트 에러는 return값 id를 restaurant로 하니 해결됬다!

앞으로 테스트코드 볼 때는 리턴 값도 잘 확인해야 할 것 같다.

2번 food의 경우에는 return이 없어야 했고, 3번 order는 return 값에서 변수명을 잘못 지정해서 nullexception이 났다.

 

먼저 테이블을 다시 설계하였다.

관련 기능을 구현한 블로그를 보고 많이 참고하였다.

id의 경우 중복값 오류가 나오는 거 같아서 각각 테이블 명_id로 하였다.

 

Entity는 Food, Order, OrderFood, Restaurant이다.

모두 1:N 양방향 관계이고, N쪽이 주가 된다.

처음에 Food와 orderFood도 연결을 했었는데, 관계가 너무 복잡해지고 스프링이 아에 실행이 안되서 관계를 변경하였다.

아에 실행이 안되고 entity 관련 에러가 나왔었는데 테이블 구성 문제였는지, JPA 설정을 잘못 한 건지는 잘 모르겠다.

Order entity가 연관된 객체가 많아서, 구글링한 예제를 참고하여 이렇게 작성하였다.

바로 생성자를 쓰지 않고, 연관된 객체를 나누어서 각각 메소드로 구현하고 별도로 생성 메소드를 만드는 방식이다.

연결된 테이블이 많을 때 좋은 방법인 것 같다.

그런데 아직 테이블 관계에 따라서 양방향/단방향이 좋은지(우선 해당 객체로 조회하고 싶어서 모두 다 양방향으로 설정했다.), 각각 객체를 어느쪽에서 생성자로 넣어주어야 하는지, 설정은 어떻게 해야하는지는 더 찾아봐야 할 것 같다.

 

order를 통해서 orderfood가 생성되기 때문에 order 생성 메소드에 orderFood.setOrder(this)를 썼고,

restaurant의 경우에는 이미 먼저 생성되어 있기 때문에 restaurant.getOrderList().add(this)로 추가해준거 같긴한데 이부분도 더 살펴봐야할 것 같다.

 

@NoArgsConstructor
@Setter
@Getter
@Entity
@Table(name = "orders")
public class Order {
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    @Column(name = "order_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonIgnore
    @JoinColumn(name = "restaurant_id")
    private Restaurant orderRestaurant;

    @JsonIgnore
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderFood> foods = new ArrayList<>();

    @Column(nullable = false)
    private Long totalPrice;

    //연관관계 메소드
    public void setOrderRestaurant(Restaurant restaurant) {
        this.orderRestaurant = restaurant;
        restaurant.getOrderList().add(this);
    }

    public void addOrderFoodList(List<OrderFood> foods, Long totalPrice) {
        this.foods = foods;
        for (OrderFood orderFood : foods) {
            orderFood.setOrder(this);
        }
        this.totalPrice = totalPrice;
    }

    //생성 메소드

    public static Order addOrder(Restaurant restaurant,
                                 List<OrderFood> foods, Long totalPrice) {
        Order order = new Order();
        order.setOrderRestaurant(restaurant);
        order.addOrderFoodList(foods, totalPrice);

        return order;
    }
    
}

주문을 받을 때 restaurantId와 foodsList를 받는데, Dto에 inner static class로 List를 구현하였다.

@Getter
public class OrderDto {
    private Long restaurantId;
    private List<Foods> foods;

    @Getter
    public static class Foods {
        private Long id;
        private Long quantity;
    }
}

그리고 controller에서는 service로 보내주는 역할만 하고 필요한 모든 메소드는 service에 구현하였다.

그리고 return값은 다른 팀원 분 아이디어를 활용해서 responseDto를 하나 만들었다.

public OrderResponseDto addOrder(OrderDto orderDto) {

    //주문 식당 찾기
    Restaurant restaurant = restaurantRepository.findById(orderDto.getRestaurantId())
            .orElseThrow(() -> new NullPointerException("해당 음식점이 존재하지 않습니다."));

    //주문 음식 List 생성
    List<OrderFood> orderFoodList = new ArrayList<>();
    for (int i = 0; i < orderDto.getFoods().size(); i++) {
        OrderDto.Foods foods = orderDto.getFoods().get(i);
        Food food = foodRepository.findById(foods.getId())
                .orElseThrow(() -> new NullPointerException("해당 음식이 존재하지 않습니다."));
        OrderFood orderFood = new OrderFood(
                food.getName(), foods.getQuantity(), food.getPrice());
        orderFoodList.add(orderFood);
    }
    //주문 음식 List 저장
    orderFoodRepository.saveAll(orderFoodList);

    //음식금액총합(sumPrice), 최종결제금액(totalPrice) 계산
    Long sumPrice = 0L;
    for (OrderFood orderfood : orderFoodList) {
        sumPrice += orderfood.getPrice();
    }
    //주문최소가격 유효성검사
    if (sumPrice < restaurant.getMinOrderPrice()) {
        throw new IllegalArgumentException("주문 금액이 최소 주문 가격을 넘지 않습니다.");
    }
    Long deliveryFee = restaurant.getDeliveryFee();
    Long totalPrice = sumPrice + deliveryFee;

    //주문 저장
    Order order = Order.addOrder(restaurant, orderFoodList, totalPrice);
    orderRepository.save(order);

    OrderResponseDto orderResponseDto = new OrderResponseDto(
            order.getOrderRestaurant().getName(),
            order.getFoods(), deliveryFee, totalPrice);

    return orderResponseDto;

}

주문 내역을 조회하는 부분은 responseDto를 활용해서 다음처럼 담긴다.

이 return값을 별도의 주문서 entity를 만들어서 주문시 저장을 하고 조회할때 바로 불러오는게 나은지,

아니면 불필요한 entity는 생성하지 않고 Dto에 필요한 값을 넣어서 보내주는게 나은지 잘 모르겠다.

public List<OrderResponseDto> getOrderList() {
    List<Order> orderList = orderRepository.findAll();
    List<OrderResponseDto> orderResponseDtoList = new ArrayList<>();
    for (Order order : orderList) {
        OrderResponseDto orderResponseDto = new OrderResponseDto(
                order.getOrderRestaurant().getName(),
                order.getFoods(),
                order.getOrderRestaurant().getDeliveryFee(),
                order.getTotalPrice());
        orderResponseDtoList.add(orderResponseDto);
    }
    return orderResponseDtoList;
}

food를 List로 입력하는 경우는 생각하지 못해서 이 부분을 수정하고,

유효성 검사에서 입력한 List 내에서 음식명이 중복되는 경우를 처음에 생각하지 못해서 테스트 코드를 통과하는데 조금 시간이 걸렸다.

 

월요일에는 우선 심화 5주차를 다 듣고, JPA공부하면서 + 추가 기능 구현해야겠다.

프로젝트 들어가기 전에 git도 조금 더 봐야할 것 같다.

 

생각보다는 시간이 걸렸지만 기본과제는 빨리 마무리를 한 것 같고 좋았고, JPA는 security보다는 더 관심사여서 그런지 재미있어서 책을 사던지 다른 강의 자료를 찾아보던지 빨리 더 공부하고 싶다.

 

'항해99 > 개발일지' 카테고리의 다른 글

20220208 개발일지  (0) 2022.02.08
20220207 개발일지 #기능일부 추가  (0) 2022.02.07
20220204 개발일지  (2) 2022.02.06
20220203 개발일지 #개인과제 정리  (0) 2022.02.03
20220202 개발일지  (0) 2022.02.03