본문 바로가기

ETC

13. 마이페이지-1 (장바구니, 위시 리스트, 주문목록)

마이페이지의 router - index

들어가기 전 마이페이지는 로그인을 진행 후 들어갈수 있는 페이지라서 

해당 페이지에 접속하면? 네비게이션 가드의 beforeEach를 호출하고 대기상태가 된다.

{
                path: '/my',
                component: () =>  import('@/views/mypage/My'),
                meta: {
                    auth: true, //는 경로가 로그인 할 필요가 있음을 나타낸다
                },
                children:[
                    {
                        path: 'wish',
                        name: 'WishList',
                        component: () =>  import('@/views/mypage/WishList'),
                    },
                    {
                        path: 'comment',
                        name: 'MyComment',
                        component: () =>  import('@/views/mypage/MyComment')
                    },

                    {
                        path: 'cart',
                        name: 'Cart',
                        component: () =>  import('@/views/mypage/Cart'),
                    },

                    {
                        path: 'order',
                        name: 'MyOrderComponent',
                        component: () =>  import('@/views/mypage/Order'),
                    },
                    {
                        path: 'order/:orderId',
                        name: 'orderDetail',
                        component: () =>  import('@/views/mypage/OrderDetail'),
                    },
                    {
                        path: 'infoEdit',
                        name: 'InfoEdit',
                        component: () =>  import('@/views/mypage/InfoEdit')
                    },
                ]
            },

meta : { auth : true }  : 해당 경로와 자식 경로들로 접속하려면 로그인 상태여야 한다

router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.auth)) {
        if (store.state.member.loginData.loginState) {
            next();
        } else {
            alert("로그인이 필요한 페이지입니다.")
            router.push({path:'/login'})
        }
    }else{
        next();
    }
})

Store에 있는 로그인 상태를 확인하고 만약 로그인이 되어있지 않은 상태면

로그인 메시지 창을 출력한다.

 

 


마이페이지는 크게 4가지 카테고리가 있다.

 

1. 장바구니

2. 위시리스트

3. 나의 댓글 목록

4. 회원정보 수정 (프로필 설정, 연락처 설정, 배송지 설정, 비밀번호 변경)

 

 

1. 장바구니


장바구니 사이트에 들어가면 mounted로 장바구니 정보를 가져오고

장바구니 정보에는 아래 정보들이 담겨있다.

 

 1. cart id

 2. mid (회원id)

 3. book (책의 모든 정보 : 다대 일 매핑으로 책정보를 가져온다)

 4. 책 수량

 

위 사진과 같이 책을 선택하면 결제하기, 선택삭제 버튼이 활성화 된다. 

* 선택된 책들은 리스트에 cartId로 담긴다. *

 

1-1. 여기서 결제버튼을 누르면?

 

https://dwc04112.tistory.com/173

 

12. Vuex Store ( 로그인 회원정보와 주문정보 Store )

index.js import Vue from 'vue'; import Vuex from "vuex"; import createPersistedState from 'vuex-persistedstate' import toOrderStore from "@/store/modules/toOrderStore"; import member from "@/store/..

dwc04112.tistory.com

 

위 글에 정리되어있는 주문정보 Store에 정보가 담기며 결제화면으로 넘어간다

linkOrder(){
      let cartArr = this.bookData.filter(e => this.selected.includes(e.cartId))
      cartArr = cartArr.map( e=>{
        return {
          bid: e.bid,
          bookCount: e.bookCount
        }
      })
      this.$store.dispatch('getOrderByCart',cartArr).then(()=> this.$router.push({name: 'Order'}) )
    },

(위 코드는 마이페이지의 결제로 이동 )

filter로 선택된 책의 cart id와 장바구니에 있는 책들의 cart id를 비교해서 선택된 책 book id와 책 수량을 담아준다.

그리고 스토어로 dispatch를 실행하고 주문화면으로 넘어간다

주문과 결제에 대한 글은 다음글을 참고!

 

 

1-2. 선택한 책 삭제하기 

 

책들을 선택 후 삭제버튼 누르면?

   //cart-controller cartId 책 삭제
    @DeleteMapping("/{cartArr}")
    public ApiResponse<Cart> deleteCartList(@PathVariable List<Long> cartArr){
        return cartService.deleteCartList(cartArr);
    }

삭제하기 버튼을 누르면 cart/{cartArr} 로 Spring boot에 넘어가고 

Spring 장바구니 컨트롤러에서는 위 코드와 같이 선택된 책들의 cart id list를 받는다

 

 

public ApiResponse<Cart> deleteCartList(List<Long> cartArr) {
        for(long cartId : cartArr){
            Optional<Cart> cartData = cartRepository.findCartByCartId(cartId);
            Cart data = cartData.orElseThrow(() -> new RuntimeException("no data"));

            //해당 Wish id를 등록한 사용자가 맞는지 확인.
            boolean matchInfo = this.matchInfo(data.getMid());
            if(!matchInfo) {
                return new ApiResponse<>(false, "failed to delete cart id List " + cartArr);
            }
        }
        cartRepository.deleteCartsByCartIdIn(cartArr);
        return new ApiResponse<>(true,"cart List : " + cartArr +" is successfully deleted");
    }
    
     // mid 비교
    private boolean matchInfo( long targetMid){
        long loginMid = getMemberIdByEmail();
        if(loginMid!=targetMid){
            log.debug("cart Id와 사용자의 ID가 일치하지 않습니다");
            return false;
        }
        return true;
    }

Service에서는 삭제를 처리하는데

해당 장바구니의 id와 현재 로그인 중인 사용자 정보를 비교해야해서

for문으로 비교를 진행후 -> 장바구니에 담긴 모든 cart item들이 검사를 통과하면

JPA에서 제공하는 deleteCartsByCartIdIn 으로 cart id 리스트를 삭제한다 

    //리스트 삭제
    @Transactional
    @Modifying
    void deleteCartsByCartIdIn(List<Long> cartArr);

 

 

 

 

2. 위시리스트


    @Id
    @Column(name="wid")
    private long wid;

    @Column(unique = true)
    private long mid;
    private int titleNum;

    @Column(columnDefinition = "varchar(200) default '나의 보관함'")
    private String wishlistTitle;

    @Column(unique = true)
    private long bid;
    private String bookTitle;
    private String bookAuthor;
    private int bookSalePrice;
    private String bookThumb;

(위시리스트 Entity)

 

위시리스트에 들어가면

위시리스트에서는 다음 기능을 제공한다

 

1. 나의 위시리스트 목록별로 보기

2. 나의 위시리스트 목록 편집

3. 선택한 책 삭제하기

4. 선택한 책 장바구니로 보내기

 

 

1. 나의 위시리스트 목록별로 보기

 

우선 위시리스트 페이지로 넘어가면

getWishTitle 이 mouted되며 해당 로그인 정보의 위시리스트 타이틀 들을 받아온다

 getWishTitle(){
      this.$axios.get("wish/title/")
          .then(response=>{
            this.wishlistTitle = response.data
            this.selectWishTitle = response.data[0].titleNum
            this.getWishList();
          }).catch(error =>{
        console.log(error.response);
      })
    },

 

좌측에 위시리스트 타이틀 Chip들을 선택하면

    //선택된 위시리스트 목록 받아오기
    getWishList(titleNum){
      this.showSelect = false;  //책 선택영역 닫기
      this.selectWidList = []   // 책 선택 리스트 초기화
      if(titleNum == null){
        titleNum= this.wishlistTitle[0].titleNum;
      }
      this.$axios.get("wish/title/"+titleNum)
          .then(response=>{
            this.wishBooks = response.data
            for(let i =0; i<response.data.length; i++){
              this.$set(this.wishBooks[i],'select',false)
            }
          }).catch(error =>{
        console.log(error.response);
      })
    },

wish/title/{titleNum} 로 Spring에 넘어간다. 그리고 Spring에서 해당 타이틀에 있는 책들을 다시 Vue로 넘겨준다

이전 위시리스트 타이틀에서 선택된 책들이 있다면 다 초기화시켜준다.

 

 

2-2 나의 위시리스트 목록 편집

 

Edit 버튼을 누르면 뒤에 x버튼 생성

    deleteWishList(){
      this.$axios.delete("wish/title/"+this.deleteTitle)
          .then(response=>{
            console.log(response.data)
            this.getWishTitle()  //선택된 타이틀 번호로 타이틀 다시받기 (리로드)
            this.deleteDialog =false
            this.snackbarDelay("위시리스트를 삭제했습니다");
          }).catch(error =>{
            console.log(error.response);
          })
    },

위시리스트 편집을 누르면 위 사진과 같이 x버튼이 보인다.

x버튼을 누르면 -> 삭제확인 메시지가 뜨고 확인을 누르면 -> 

 

위시리스트 타이틀에 있는 모든 책 삭제 

 // WishLIst Serivce 의 Delete Title
    public ApiResponse<Wishlist> deleteWishListTitle(int titleNum) {
        List<Long> ids = wishlistRepository.findWidList(getMemberId(),titleNum);
        log.debug("Wid list : " + ids);
        if(ids.size()==0){
            return new ApiResponse<>(false,"no data");
        }else {
            wishlistRepository.deleteWishlistsByWidIn(ids);
            return new ApiResponse<>(true, "title Number : " + titleNum + " is successfully deleted");
        }
    }

해당 위시리스트 타이틀 번호로 책들의 id 리스트를 가져와서 

JPA에서 제공하는 deleteWishlistByWidIn 으로 다중 삭제

 

 

2-3, 2-4 우측 상단의 체크를 누르면?

 

체크를 누르고 책을 선택하면 -> 하단에 장바구니에 담을건지 삭제할건지 버튼이 활성화 된다

(책을 선택안하면 둘 다 비활성화 상태(회색) )

 

 

2-3 장바구니에 등록을 누르면? 

( Spring Boot - Cart Controller)

    //장바구니 담기 - list (wishList id 받음)
    @GetMapping("/fromWish/{widArr}")
    public ApiResponse<List<Long>> addToCart(@PathVariable List<Long> widArr){
        return cartService.addListToCart(widArr);
    }

Springboot 장바구니 컨트롤러로 위시리스트 목록들이 전송되고

 

( Spring Boot - Cart Service)

 //장바구니 담기 - list
    public ApiResponse<List<Long>> addListToCart(List<Long> widArr) {
        Long mid = getMemberIdByEmail();
        //장바구니에 성공적으로 등록한 id목록
        ArrayList<Long> successfulBid = new ArrayList<>();
        //장바구니에 등록 실패한 id목록
        ArrayList<Long> failedBid = new ArrayList<>();

        for(long wid : widArr){
        	//해당 wishlist id의 책 id를 가져와서
            long bid = wishlistRepository.getBidByWid(wid); 
            // 로그인된 회원 정보와 위에서 가져온 book id로 검색된 정보가 있는지 확인
            int matchBid = cartRepository.selectByMidAndBid(mid, bid);
            
            //있다면? > 이미 등록되어 있으므로 pass
            if(matchBid>0){
                successfulBid.add(bid);
            }else{
                 //없으면 새 cart id 생성 후 등록
                long newCartIdValue = this.getNewCartIdValue(cartRepository);
                int result = cartRepository.addToCart(newCartIdValue, mid, bid, 1);
                if (result < 1) {
                    failedBid.add(bid);
                }else {
                    successfulBid.add(bid);
                }
            }
        }
        boolean result = failedBid.size() == 0;
        return new ApiResponse<List<Long>>(result,
                "장바구니에 추가된 Bid : " + successfulBid+ " ,장바구니 추가에 실패한 Bid : "+ failedBid, successfulBid);
    }

위 주석의 내용으로 코드가 진행 후

추가된 아이디와 실패한 아이디 목록이 리턴된다.

 

 

2-4 삭제를 누르면? 

( Spring Boot - Wishlist Service )

 //DELETE Wid Array List
    public ApiResponse<Wishlist> deleteWishList(List<Long> widArr) {

        for (long wid : widArr) {
            //해당 Wish id 와 일치하는 책이 있는지 확인. 없으면 Exception
            Optional<Wishlist> wishData = wishlistRepository.findWishlistByWid(wid);
            Wishlist data = wishData.orElseThrow(() -> new RuntimeException("no data"));

            //해당 Wish id를 등록한 사용자가 맞는지 확인.
            boolean matchInfo = this.matchInfo(wishlistRepository, data.getMid());
            if(!matchInfo) {
                return new ApiResponse<>(false, "failed to delete board id List " + widArr);
            }
        }

        wishlistRepository.deleteWishlistsByWidIn(widArr);
        return new ApiResponse<>(true,"wid List : " + widArr +" is successfully deleted");

    }

컨트롤러에서 선택된 아이디 리스트를 받아 삭제를 진행한다

Wish id리스트와 일치하는 책이 있는지 없는지? 해당 위시리스트 사용자가 맞는지?

확인해야해서 for문으로 삭제를 진행하였다.

 

 

 

3. 주문 목록


주문목록은 총 3개의 테이블을 사용한다

자세한 엔티티&테이블 내용은 아래 결제와 취소 글을 확인!

 

1. order - 주문정보를 저장하는 테이블이다

 

2. orderItem - 주문정보에 들어가는 책들이 저장되는 테이블이다

 

3. payments - 결제 내역이 저장되는 테이블이다.

 

 

주문목록에선 주문 내역과 환불기능을 사용할수 있다.

왼쪽 Nav에서는 결제완료된 정보와 취소된 정보를 한 눈에 확인이 가능하고

열람하고자 하는 주문정보를 클릭하면 주문 상세보기 페이지로 이동한다.

결제 완료된 정보와 결제취소된 정보를 볼 수 있다

 

주문 상세보기 페이지에서는 결제정보를 확인할수 있고 결제취소가 가능하다.

환불을 진행하면 아래 Spring boot의 결제 환불 컨트롤러로 데이터가 전송되고

결제환불을 위해 Spring boot에서 아임포트모듈과 통신한다.

자세한 내용은 아래 결제취소(환불) 참고!

 

15. 결제와 환불 (아임포트 모듈 사용)

들어가기 전에 12. Vuex Store ( 로그인 회원정보와 주문정보 Store ) index.js import Vue from 'vue'; import Vuex from "vuex"; import createPersistedState from 'vuex-persistedstate' import toOrderStore..

dwc04112.tistory.com