SI_ 쇼핑몰 예제 - 주문 전체 조회 페이지(★)

김지영·2024년 4월 11일

Sl

목록 보기
8/10

-SimpleCartList.vue

  • 주문페이지 이동 함수
// TODO: 주문페이지 이동 함수
    goOrder() {
      this.$router.push("/simple-order");
    }

-SimpleOrderList.vue

  • 주문 전체 조회 페이지(핵심:복잡)

-> 디자인

<template>
      <div>
    <!-- {/* dname start */} -->
    <div class="row mb-5 justify-content-center">
      <!-- {/* w-50 : 크기 조정, mx-auto : 중앙정렬(margin: 0 auto), justify-content-center */} -->
      <div class="col-12 w-50 input-group mb-3">
        <input
          type="text"
          class="form-control"
          placeholder="Search by Title"
        />
        <div class="input-group-append">
          <button
            class="btn btn-outline-secondary"
            type="button"
          >
            Search
          </button>
        </div>
      </div>
    </div>
    <!-- {/* dname end */} -->

    <!-- {/* paging 시작 */} -->
    <div class="mb-3">
      Items per Page:
      <select >
        <option>
        </option>
      </select>
    </div>

    <b-pagination
      v-model="page"
      :total-rows="count"
      :per-page="pageSize"
    ></b-pagination>
    <!-- {/* paging 끝 */} -->

    <div class="row">
      <div >
        <div class="row g-0 p-3">
          <div class="col-md-4 p-3 border">
            <img
             
              class="img-fluid rounded-start"
              alt="..."
              style="{ height: 15 + 'vh', width: 5 + 'vw' }"
            />
          </div>
          <div class="col-md-8">
            <div class="card-body">
              <h5 class="card-title">물품 : </h5>
              <h5 class="card-title">
                가격 :
              </h5>
              <h5 class="card-title">개수 : </h5>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- {/* 배송지 시작 */} -->
    <div class="col-12 mx-auto">
      <div class="row g-3 align-items-center mb-3">
        <div class="col-3">
          <label htmlFor="deliveryAddr" class="col-form-label">
            Delivery Address
          </label>
        </div>

        <div class="col-9">
          <input
            type="text"
            id="deliveryAddr"
            required
            class="form-control"
            placeholder="deliveryAddr"
            name="deliveryAddr"
          />
        </div>
      </div>

      <div class="row g-3 align-items-center mb-3">
        <div class="col-3">
          <label htmlFor="deliveryMsg" class="col-form-label">
            Melivery Message
          </label>
        </div>
        <div class="col-9">
          <input
            type="text"
            id="deliveryMsg"
            required
            class="form-control"
            placeholder="deliveryMsg"
            name="deliveryMsg"
          />
        </div>
      </div>
    </div>

    <!-- {/* 배송지 끝 */} {/* 버튼 시작 */} -->
    <div class="row d-flex justify-content-end">
      <!-- {/* 취소 버튼 시작 */} -->
      <button
        type="button"
        class="btn btn-danger w-25 me-3"
      >
        Cancel Order
      </button>
      <!-- {/* 취소 버튼 끝 */} {/* 결재 버튼 시작 */} -->
      <button type="button" class="btn btn-warning w-25">
        Go Approval
      </button>
      <!-- {/* 결재 버튼 끝 */} -->
    </div>
    <!-- {/* 버튼 끝 */} -->
  </div>
</template>

-> 데이터바인딩 속성 정의

<script>
export default {
      // TODO: 데이터 바인딩 속성 정의
  data() {
    return {
      simpleCart: [], // 장바구니 객체배열
      searchTitle: "", // 검색어

      // 배송 입력 속성 정의
      deliveryAmount: 3000, // 기본 : 3000, 배송비
      deliveryAddr: "", // 배송지 주소
      deleveryMsg: "", // 배송 메세지

      // 공통 페이징 속성
      page: 1, // 현재페이지번호
      count: 0, // 전체 데이터개수
      pageSize: 3, // 화면에 보여질 개수

      pageSizes: [3, 6, 9], // 화면에 보여질 개수배열
    };
  },
    
}
</script>

-> 함수정의

 //   TODO: 함수 정의
  methods: {
    // TODO: 장바구니 전체 조회 : 화면 뜰때 실행
    async retrieveSimpleCart() {
      try {
        // TODO: 공통 장바구니 전체 조회 서비스 함수 실행
        // TODO: 비동기 코딩 : async ~ await
        let response = await SimpleCartService.getAll(
          this.searchTitle,
          this.page - 1,
          this.pageSize
        );
        const { simpleCart, totalItems } = response.data;
        this.simpleCart = simpleCart;
        this.count = totalItems;
        // 로깅
        console.log(response.data); // 웹브라우저 콘솔탭에 벡엔드 데이터 표시
      } catch (e) {
        console.log(e); // 웹브라우저 콘솔탭에 에러 표시
      }
    },
    // TODO: 주문 함수 : 1) 주문 테이블 + 주문상세 테이블 insert
    // TODO:            2) 결재 페이지로 이동
    goApproval() {},
    // TODO: 주문 취소 : 장바구니 전체 페이지로 다시 이동
    cancelOrder() {},
    // TODO: 공통 페이징 함수 : select 태그
    pageSizeChange() {
      this.page = 1; // 현재페이지번호 : 1
      this.retrieveSimpleCart(); // 재조회
    },
  },
  //   TODO: 화면이 뜰때 장바구니 전체 조회
  mounted() {
    this.retrieveSimpleCart();
  },
};

-> 주문함수
1) 주문 테이블 + 주문상세 테이블 insert
2) 결재 페이지로 이동

◈ js 날짜 객체
// 날짜 포맷 : yyyy-mm-dd hh:mi:ss 형태
// 년도 : now.getFullYear()
// 월 : now.getMonth()
// 일 : now.getDate()
// 시 : now.getHours()
// 분 : now.getMinutes()
// 초 : now.getSeconds()

① 주문날짜 : 현재날짜

let now = new Date(); // js 날짜 객체
      let formatNow = `${now.getFullYear()}-${now.getMonth()}-${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;

② 장바구니의 상품별 금액 = 단가(unitPrice) * 개수(cartCount)

  • 모든 상품별 총금액

  • 모든 상품별 총금액
    -배열변수에 사용하는 함수 : map, foreach, filter 등 + reduce

★ reduce => 매개변수의 값을 계속 누적시켜 합또는 차를 구할수 있는 함수

-누적합 알고리즘 : 누적변수 = 누적변수 + 배열값

★ 사용법 : reduce((누적변수, 배열값) => 누적변수 + 배열값);

let totalPrice = this.simpleCart
                    .map((data)=> data.unitPrice * data.cartCount) // 상품별 금액 배열
                    // 사용법 : reduce((누적변수, 배열값) => 누적변수 + 배열값);
                    .reduce((acc, cur) => acc + cur);              // 총금액

    },

③ 주문상세 객체 정의 => 배열이 되어야함

--------> 정리하기


--> 백엔드

  1. 주문 엔티티 만들기
    -SimpleOrder.java
@Entity
@Table(name = "TB_SIMPLE_ORDER")
@SequenceGenerator(
        name = "SQ_SIMPLE_ORDER_GENERATOR"
        , sequenceName = "SQ_SIMPLE_ORDER"
        , initialValue = 1
        , allocationSize = 1
)
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
// soft delete
@Where(clause = "DELETE_YN = 'N'")
@SQLDelete(sql = "UPDATE TB_SIMPLE_ORDER SET DELETE_YN = 'Y', DELETE_TIME=TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') WHERE SONO = ?")
public class SimpleOrder extends BaseTimeEntity2 {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE
            , generator = "SQ_SIMPLE_ORDER_GENERATOR"
    )
    private Integer sono;        // 주문번호, 기본키, 시퀀스

    private String  orderDate;   // 주문일자
    private String  orderStatus; // 주문상태(50001: 주문완료, 50002: 결재완료,  50011: 결재취소)
    private Integer  productAmount; // 총 상품금액
    private Integer  deliveryAmount; // 배송비
    private Integer  orderAmount;    // 주문금액 = 총 상품금액 + 배송비
    private String  deliveryAddr;   // 배송지 주소
    private String  deliveryMsg;   // 배송지 메모
}
  1. 주문 상세 엔티티 만들기
    -SimpleOrderDetail
    -자식테이블
@Entity
@Table(name = "TB_SIMPLE_ORDER_DETAIL")
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
// 복합키 사용클래스 정의
@IdClass(SonoSpnoPk.class)
public class SimpleOrderDetail {
    @Id
    private Integer sono;         // 주문번호(PK:복합키), FK
    @Id
    private Integer spno;         // 상품번호(pk2:복합키), fk

    private Integer productCount; // 상품수량
}
  1. 복합키(기본키 2개) 정의 클래스

복합키 정의 : 컬럼 2개이상을 묶어서 기본키로 사용하는 것
기본키는 유일성을 보장해야하므로 복합키 또한 유일성을 보장해야함
예) 주문상세 : 주문번호 + 상품번호 => 유일성 보장
샤프(2) => 2개 컬럼 합치면 유일성 보장됨(복합키)
1 연필(3)
2 샤프(2)
2 지우개(4)
~> DB 사용법 : primary key(컬럼명, 컬럼명2)

2) 자바에서 복합키 사용법 :
2-1) 복합키로 사용할 클래스의 속성(필드)들에 @Id 붙임
2-2) 그 속성명(필드)으로 복합키 정의 클래스를 만듬
2-3) 복합키를 사용하는 클래스 위에 @IdClass(복합키 정의 클래스.class) 추가

=> 사용법 : @IdClass(복합키클래스.class)
public class 클래스명{
@Id
private 자료형 복합키속성1;
@Id
private 자료형 복합키속성2;
}

=> 복합키 클래스 정의 사용법 : 롬북 6개 어노테이션 사용
public class 복합키클래스 implements Serializable {
private 자료형 복합키속성1;
private 자료형 복합키속성2;
}

  1. 주문 레포지토리
    -SimpleOrderRepository
@Repository
public interface SimpleOrderRepository extends JpaRepository<SimpleOrder, Integer> {
}
  1. 주문상세 레포지토리
    -SimpleOrderDetailRepository
@Repository
public interface SimpleOrderDetailRepository extends JpaRepository<SimpleOrderDetail, SonoSpnoPk> {
}
  1. 프론트에서 전달한 객체를 담을 클래스 (DTO)
    --> 프론트에서 보낸 속성들과 동일하게!
    -SimpleOrderDto
@Setter
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SimpleOrderDto {
    private Integer sono; // 기본키, 시퀀스
    private List<SimpleOrderDetail> simpleOrderDetailList; // 주문상세 객체배열
    private String orderDate;                              // 주문날짜
    private Integer orderStatus;        // 주문상태(50001: 주문완료, 50002: 결재완료, 50011:결재취소)
    private Integer productAmount;      // 상품 총금액
    private Integer deliveryAmount;      // 배달비(3000 : 하드코딩)
    private Integer orderAmount;          // 주문금액 = 총금액 + 배달비
    private String deliveryAddr;          // 배달 주소
    private String deliveryMsg;           // 배달 메세지
}
  1. 주문 서비스

1) DTO -> Entity 변환
▶ 사용법 : modelMapper.map(DTO클래스, 엔티티명.class);

@Service
public class SimpleOrderService {

    @Autowired
    SimpleOrderRepository simpleOrderRepository; // DI
    @Autowired
    SimpleOrderDetailRepository simpleOrderDetailRepository; // DI

    //    DTO 변환 패키지
    ModelMapper modelMapper = new ModelMapper();

    //    TODO: 저장함수 : 주문 테이블 insert + 주문상세(배열) insert(반복문)
//      => 주문 객체 DTO 정의 : (주문상세 객체배열(List), 주문상태 등)
    @Transactional
    public SimpleOrder insert(SimpleOrderDto simpleOrderDto) {
//        1) insert 할때는 DTO -> Entity 변환해서 insert
//        => DTO -> Entity : 1) 직접 변환로직 코딩 : 숙련자에게 추천
//                           2) 자동 변환 패키지 : 초보자 추천
//                             (ModelMapper 패키지 => 단점 : 성능저하)
//        TODO: 1) DTO -> Entity 변환
//          사용법 : modelMapper.map(DTO클래스, 엔티티명.class);
        SimpleOrder simpleOrder
                = modelMapper.map(simpleOrderDto, SimpleOrder.class);

//        TODO: 2) 부모테이블 저장 (부모저장 -> 자식저장)
        SimpleOrder simpleOrder2
                = simpleOrderRepository.save(simpleOrder); // 부모 테이블 저장

//        TODO: 3) 자식테이블도 저장 : 주문상세 테이블 (반복문)
//          DB 트랜잭션(transaction, 거래) :
//              1) CUD 작업에 대해 여러개가 있을경우 중간에 에러가 발생하면 모두 롤백함
//              2) 위의 있는 기능을 사용하려면 : @Transactional 함수위에 붙임
        for (int i = 0; i < simpleOrderDto.getSimpleOrderDetailList().size(); i++) {
//            자식테이블(SimpleOrderDetail) insert : 기본키(부모쪽 insert 할때 시퀀스로 생성되어 있음)
//            생성된 주문번호 -> 주문상세객체에 저장
            SimpleOrderDetail tmpSimpleOrderDetail = simpleOrderDto.getSimpleOrderDetailList().get(i);
            tmpSimpleOrderDetail.setSono(simpleOrder2.getSono());
//            DB 저장
            simpleOrderDetailRepository.save(tmpSimpleOrderDetail);
        }
        return simpleOrder2;  // 저장된 주문 객체
    }
}
  1. 주문 컨트롤러
@Slf4j
@RestController
@RequestMapping("/api/shop")
public class SimpleOrderController {

    @Autowired
    SimpleOrderService simpleOrderService; // DI

    //    TODO: 저장 함수
    @PostMapping("/simple-order")
//    저장(insert) -> post 방식 -> @PostMapping
    public ResponseEntity<Object> create(
            @RequestBody SimpleOrderDto simpleOrderDto
    ) {
        try {
//            저장 서비스 실행
            SimpleOrder simpleOrder = simpleOrderService.insert(simpleOrderDto);

            return new ResponseEntity<>(simpleOrder, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

profile
그냥 졍이라구하자

0개의 댓글