본문 바로가기
모각코

[모각코 6회차] 주문관리 API

by moonstal 2022. 8. 11.

목표: 주문 API 만들기 실습

ERD

Entity

  • Order Entity는 아이디, 주문시간, 주문상태, 메모, 회원, 주문아이템을 필드로 갖으며 작성자와 생성시간을 제공하는 BaseEntity를 상속 받음

  • Order 엔티티에서 setMember와 addOrderItem 연관관계 편의 메서드를 제공

  • 오더와 멤버는 다대일 관계

  • 오더와 오더아이템은 일대다 관계

    @Entity
    @Table(name = "orders")
    @Getter
    @Setter
    public class Order extends BaseEntity {
      @Id
      @Column(name = "id")
      private String uuid;
    
      @Column(name = "order_datetime", columnDefinition = "TIMESTAMP")
      private LocalDateTime orderDatetime;
    
      @Enumerated(EnumType.STRING)
      private OrderStatus orderStatus;
    
      @Lob
      private String memo;
    
      @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
      @JoinColumn(name = "member_id", referencedColumnName = "id")
      private Member member;
    
      @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
      private List<OrderItem> orderItems = new ArrayList<>();
    
      public void setMember(Member member) {
          if(Objects.nonNull(this.member)) {
              this.member.getOrders().remove(this);
          }
    
          this.member = member;
          member.getOrders().add(this);
      }
    
      public void addOrderItem(OrderItem orderItem) {
          orderItem.setOrder(this);
      }
    }

Dto

dto 객체 만들어 통신

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderDto {
    private String uuid;
    private LocalDateTime orderDatetime;
    private OrderStatus orderStatus;
    private String memo;

    private MemberDto memberDto;
    private List<OrderItemDto> orderItemDtos;
}

Converter

Converter를 통해 엔티티를 DTO로, DTO를 엔티티로 변환

@Component
public class OrderConverter {

    public Order convertOrder(OrderDto orderDto) {
        Order order = new Order();
        order.setUuid(orderDto.getUuid());
        order.setMemo(orderDto.getMemo());
        order.setOrderStatus(orderDto.getOrderStatus());
        order.setOrderDatetime(LocalDateTime.now());
        order.setCratedAt(LocalDateTime.now());
        order.setCreatedBy(orderDto.getMemberDto().getName());

        order.setMember(this.convertMember(orderDto.getMemberDto()));
        this.convertOrderItems(orderDto).forEach(order::addOrderItem);

        return order;
    }

    public OrderDto convertOrderDto (Order order) {
        return OrderDto.builder()
                .uuid(order.getUuid())
                .memo(order.getMemo())
                .orderStatus(order.getOrderStatus())
                .orderDatetime(order.getOrderDatetime())
                .memberDto(this.convertMemberDto(order.getMember()))
                .orderItemDtos(order.getOrderItems().stream()
                        .map(this::convertOrderItemDto)
                        .collect(Collectors.toList())
                )
                .build();
    }
}

주문 저장

entity를 트랜잭션 밖으로 보내는 것 좋지 않음, dto 객체 만들어 통신

@Transactional 
    public String save(OrderDto dto) {
        //1. dto -> entity 변환(준영속)
        Order order = orderConverter.convertOrder(dto);
        //2. orderRepository.save(entity)-> 영속화
        Order entity = orderRepository.save(order);
        //3. 결과 반환
        return entity.getUuid();
    }

주문 조회

@Transactional
    public OrderDto findOne(String uuid) throws NotFoundException {
        //1. 조회를 위한 키값 인자로 받기
        //2. orderRepository.findById(uuid)-> 조회(영속화된 엔티티)
        return orderRepository.findById(uuid)
                .map(orderConverter::convertOrderDto)//3. entity -> dto
                .orElseThrow(() -> new NotFoundException("주문을 찾을 수 없습니다."));
    }

@Transactional
    public Page<OrderDto> findAll(Pageable pageable) {
        return orderRepository.findAll(pageable)
                .map(orderConverter::convertOrderDto);
    }

API 전송 객체

컨트롤러에서 API 전송 객체에 담아서 결과 반환

@Getter
@Setter
@NoArgsConstructor
public class ApiResponse<T> {
    private int statusCode;
    private T data;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
    private LocalDateTime serverDatetime;

    public ApiResponse(int statusCode, T data) {
        this.statusCode = statusCode;
        this.data = data;
        this.serverDatetime = LocalDateTime.now();
    }

    public static <T> ApiResponse<T> ok(T data) {
        return new ApiResponse<>(200, data);
    }

    public static <T> ApiResponse<T> fail(int statusCode, T errData) {
        return new ApiResponse<>(statusCode, errData);
    }
}

Controller

컨트롤러에서 호출

@PostMapping("/orders")
    public ApiResponse<String> save(@RequestBody OrderDto orderDto) {
        return ApiResponse.ok(orderService.save(orderDto));
    }

@프로그래머스 미니 데브코스 & CNU SW Academy 강의 내용 정리