20221021_fri
실습내용
- 메뉴나오기
- 주문내역조회
- 매출관리
메뉴나오기
- base_layout.html
- admin_layout.html
- (추가) myInfo_layout.html
: 기존의 레이아웃을 사용할것인가, admin레이아웃처럼 새로운 레이아웃을 만들것인가 두가지방법이있다.
순서
- 1) 새로운 레이아웃 파일을 생성 버전.
- top.html에서 장바구니였던 버튼을 my Info(내정보관리)버튼으로 바꾼다.
: 로그인인증한 회원만 들어가기때문에myInfo_layout.html
레이아웃을 새로 만들어 메뉴 사이드바를 만든다.- 새로만든 myInfo_layout파일에서 fragment를 수정해야한다.
- 그리고 사이드메뉴 myinfo_side.html 도 다시만든 후, 변경해야한다.
- 2) 기존의 레이아웃 수정하는 버전
- myInfo_layout.html파일을 따로 만들지 않고 기존에 있던 side.html과 cart_list.html파일만 수정해도 가능하다.
2 2022-10-10 22:10:10 에 총 3건의 주문으로 30,000원을 구매했습니다.
1 2022-10-10 22:10:10 에 총 3건의 주문으로 30,000원을 구매했습니다.
<!-- 아코디언 제목줄 구매내역 조회 + 전체줄 구매내역 조회 같이 -->
<!-- 뽑아야하는 데이터 : 2022-10-10 22:10:10 에 총 3건의 주문으로 30,000원을 구매했습니다. -->
<select id="selecteBuy" resultMap="buyMapper.buy"><!-- 기존에 있던 cart매퍼를 사용한다. -->
SELECT BUY_CODE
, TO_CHAR(BUY_DATE, 'YYYY-MM-DD HH24:MI:SS') BUY_DATE
, TOTAL_PRICE
, (SELECT COUNT(BUY_DETAIL_CODE)
FROM SHOP_BUY_DETAIL
WHERE BUY_CODE = B.BUY_CODE ) as BUY_CNT <!-- buy테이블이랑 buyDetail테이블 buycode와 같으면! -->
FROM SHOP_BUY B
where MEMBER_ID = #{memberId}
order by BUY_CODE DESC
</select>
- 구매내역 전체 목록조회 쿼리 결과
: 구매날짜시간에 따라서 시간이 동일하게 구매가 된 것은 같은 상품코드이며, 시간이 다르게 표시된 것은 다르게 구매가 된 것이다.
: 이걸로 구매목록을 테이블 데이터 뿌려줄 때, 잘 생각하고 결과를 뿌려줘야한다!!!
: 그래서 구매날짜시간이 동일한 코드는 buyVO 3개를 가진 하나의 buyList로 가져온다. 구매날짜시간이 다른 것은 buyVO 한개로 상품정보와 상세정보를 가져온것과 같다.
- 쿼리문 작성 후, 쿼리 실행결과데이터를 자바로 가져오려면
resultMap 을 사용하면 된다!!!- 1번 구매로 상품을 다수 여러개를 할 수 있다.
shop_buy : shop_buy_detail -> 1:N 관계니까 collection 사용해야한다.
주문(구매) 2번한다고 했을 때, BuyVO로 총 2개(1번,2번)의 데이터를 들고온다.
: 구매목록조회 테이블 작성시,
1번.BuyVO-> a상품 3개 -> 이상품의 상세정보는 buyDetailList안에 있다.
2번.BuyVO-> a상품 1개,b상품 2개 c상품 1개...
: 이후 null값이 아닌 확인된 값이 있다면 이를 buy_list.html파일에 바로 데이터를 뿌려서 확인한다.
BuyVO
(buyCode=BUY_007,
memberId=null,
buyDate=2022-10-20 16:54:09,
totalPrice=32000,
buyCnt=2,
cateName=소설,
itemName=이국에서,
itemPrice=16000,
attachedName=1bb400e3-67d1-4d9d-b6ee-0c714ac9fa61.jpg, buyPrice=16000,
cartCodeList=null,
itemVO=ItemVO
(itemCode=null,
itemName=아주 오랜만에 행복하다는 느낌,
itemPrice=16000,
itemComment=null,
regDate=null, itemStock=0, cateCode=null, itemStatus=null, cateName=null, cateStatus=null, memberId=null,
imgList=[ImgVO(imgCode=null, originName=null, attachedName=a783e530-31dd-4e66-a438-3f7dced6fbfd.jpg, isMain=null, itemCode=null)],
categoryVO=CategoryVO(cateCode=null, cateName=기타, cateStatus=null)),
imgVO=null, memberVO=null,
cartVO=CartVO(cartCode=null, itemCode=null, memberId=null, cartAmount=0, regDate=null, totalPrice=32000, cateName=기타, itemName=아주 오랜만에 행복하다는 느낌, itemPrice=16000, attachedName=a783e530-31dd-4e66-a438-3f7dced6fbfd.jpg,
itemVO=ItemVO(itemCode=null, itemName=아주 오랜만에 행복하다는 느낌, itemPrice=16000, itemComment=null, regDate=null, itemStock=0, cateCode=null, itemStatus=null, cateName=null, cateStatus=null, memberId=null,
imgList=[ImgVO(imgCode=null, originName=null, attachedName=a783e530-31dd-4e66-a438-3f7dced6fbfd.jpg, isMain=null, itemCode=null)],
categoryVO=CategoryVO(cateCode=null, cateName=기타, cateStatus=null)),
imgVO=null,
memberVO=null,
cartCodeList=null),
buyDetailList=[BuyDetailVO(buyDetailCode=null, itemCode=null, buyCode=BUY_007, buyAmount=1, buyCnt=2, cateName=소설, itemName=이국에서, itemPrice=16000, buyPrice=16000, attachedName=1bb400e3-67d1-4d9d-b6ee-0c714ac9fa61.jpg), BuyDetailVO(buyDetailCode=null, itemCode=null, buyCode=BUY_007, buyAmount=1, buyCnt=2, cateName=기타, itemName=아주 오랜만에 행복하다는 느낌, itemPrice=16000, buyPrice=16000, attachedName=a783e530-31dd-4e66-a438-3f7dced6fbfd.jpg)],
itemCode=null, buyDetailVO=null)
package Kh.study.shop.buy.vo;
import java.util.List;
import Kh.study.shop.cart.vo.CartVO;
import Kh.study.shop.item.vo.ImgVO;
import Kh.study.shop.item.vo.ItemVO;
import Kh.study.shop.member.vo.MemberVO;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class BuyVO {
private String buyCode;
private String memberId;
private String buyDate;
private int totalPrice;
// mapper 같이 추가
// 구매내역조회하기위해 추가함.
private int buyCnt;
private String cateName;
private String itemName;
private int itemPrice;
private String attachedName;
//임의 별칭부여한 구매한 총가격
private int buyPrice;
private List<String> cartCodeList;
private ItemVO itemVO;
private ImgVO imgVO;
private MemberVO memberVO;
private CartVO cartVO;
// 한 번 구매하면 여러개의 상품디테일정보가 여러개 들어가있으므로
// 리스트로 변수선언하고 리절트맵에 컬렉션으로 추가하기 1:N 관계
private List<BuyDetailVO> buyDetailList; // 주의!! 리절트맵의 프로퍼티와 이름이 같아야한다.
private String itemCode;//??없어도 될듯
private BuyDetailVO buyDetailVO;
}
package Kh.study.shop.buy.vo;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class BuyDetailVO {
private String buyDetailCode;
private String itemCode;
private String buyCode;
private int buyAmount;
// mapper에서 구매목록조회시
//리절트맵 추가한것 변수선언하기
private int buyCnt;
private String cateName;
private String itemName;
private int itemPrice;
private int buyPrice;
private String attachedName;
}
package Kh.study.shop.buy.service;
import java.util.List;
import Kh.study.shop.buy.vo.BuyVO;
import Kh.study.shop.cart.vo.CartVO;
import Kh.study.shop.item.vo.ItemVO;
public interface BuyService {
//구매할 목록조회
List<CartVO> selecteBuyingList(CartVO cartVO);
// 다음 buycode조회
String selectNextBuyCode();
//구매등록
void insertBuy(BuyVO buyVO,CartVO cartVO);
//구매를 위한 장바구니 정보 조회
List<CartVO> getCartInfoForBuy(CartVO cartVO);
//단일 구매 조회
ItemVO DirectSelectBuyingInfo(String itemCode);
// 구매내역 조회_요약줄
List<BuyVO> selecteBuy(String memberId);
// 구매내역 목록조회_ 내용줄
List<BuyVO> selecteBuyList(String memberId);
}
package Kh.study.shop.buy.service;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import Kh.study.shop.buy.vo.BuyVO;
import Kh.study.shop.cart.vo.CartVO;
import Kh.study.shop.item.vo.ItemVO;
@Service("buyService")
public class BuyServiceImpl implements BuyService{
@Autowired
private SqlSessionTemplate sqlSession;
//구매등록(+ 구매상세정보,장바구니삭제 같이 트랜잭션 처리해야한다)
@Transactional(rollbackFor = Exception.class)//어떤 오류든 간에 뭐든지 롤백하겠다.
@Override
public void insertBuy(BuyVO buyVO,CartVO cartVO) {
sqlSession.insert("buyMapper.insertBuy",buyVO);
sqlSession.insert("buyMapper.insertBuyDetail",buyVO);
// 단일구매시 장바구니상품에 담지않기때문에 장바구니 삭제할 필요가 없다. 그래서 단일구매시 컨트롤러에서 cartVO 매개변수대신 null을 던진다.
//아래는 단일구매가 아닌 장바구니 상세페이지에서 선택구매를 할 때를 말한다.
//왜? 장바구니에 등록이 된 후, 선택구매를 하기때문에 구매 후에는 장바구니에 등록되었던 것을 삭제해야하기때문이다.
if(cartVO != null) {
sqlSession.delete("cartMapper.deleteCarts",cartVO);
}
}
@Override
public String selectNextBuyCode() {
return sqlSession.selectOne("buyMapper.selectNextBuyCode");
}
//구매할 장바구니목록조회
@Override
public List<CartVO> selecteBuyingList(CartVO cartVO) {
return sqlSession.selectList("buyMapper.selecteBuyingList",cartVO);
}
//구매위한 장바구니정보조회
@Override
public List<CartVO> getCartInfoForBuy(CartVO cartVO) {
return sqlSession.selectList("buyMapper.getCartInfoForBuy",cartVO);
}
//단일 구매 조회
@Override
public ItemVO DirectSelectBuyingInfo(String itemCode) {
return sqlSession.selectOne("buyMapper.DirectSelectBuyingInfo",itemCode);
}
// 구매내역조회_전체줄
@Override
public List<BuyVO> selecteBuyList(String memberId) {
return sqlSession.selectList("buyMapper.selecteBuyList",memberId);
}
// 구매내역조회 요약줄
@Override
public List<BuyVO> selecteBuy(String memberId) {
return sqlSession.selectList("buyMapper.selecteBuy",memberId);
}
}
// 구매내역조회(전체 + 요약 모두 한꺼번에)
@GetMapping("/buyList")
public String buyList(Model model,Authentication authentication,CartVO cartVO, ItemVO itemVO,BuyVO buyVO) {
User user = (User)authentication.getPrincipal();
// 구매내역조회_요약 쿼리문
model.addAttribute("buys",buyService.selecteBuy(user.getUsername()));
//리스트를 만들면 반복문으로 하나씩 빼서
// buyVO하나씩의 값들을 잘 들고왔는지 확인해보자!!!!
for(BuyVO e : buyService.selecteBuy(user.getUsername()) ) {
System.out.println("XOXOXOXOOXOXOXOXOXOXOXOOXOXOXOXO"+e);
}
// 요약과 전체 따로 쿼리문 만들었다면 아래 코드 작성
//(전체)구매내역조회 쿼리문
//model.addAttribute("buyList", buyService.selecteBuyList(user.getUsername()));
return "content/buy/buy_list";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultra.net.nz/thymeleaf/layout"
layout:decorate="layout/myInfo_layout"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<div layout:fragment="content">
<div class="row mb-3">
<div class="col">
<!-- 제목줄 -->
<div class="row">
<div class="col">
<h2>✔ 상품 구매 내역 </h2>
</div>
</div>
<!-- 중간줄 -->
<div class="row mt-3 " style="font-size: 15px; color: #3C4048;">
<span style="font-style: italic;"> ※ [ <span sec:authentication="name"></span> ] 님이 결제하신 상품구매내역입니다.</span>
</div>
<!-- 내용줄- 아코디언사용-->
<div class="row mt-1 mb-5">
<div class="col-12">
<!-- 아코디언 펼쳐지기 전 구매요약 내용 -->
<div class="accordion" id="accordionPanelsStayOpenExample">
<div class="accordion-item">
<th:block th:each="buyInfo : ${buys}">
<h2 class="accordion-header" id="panelsStayOpen-headingOne">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" th:data-bs-target="|#panelsStayOpen-collapseOne${buyInfoStat.count}|" aria-expanded="true" aria-controls="panelsStayOpen-collapseOne">
<!-- 스판태그는 너비가 먹지않는다!!! div(블록태그)는 조절가능하지만 스판태그(인라인)태그는 조절이 불가능하다.
그래서 display속성값으로 인라인블록으로 변경해야 너비 조정이 가능해진다. -->
<span style="font-weight: bold; width: 20%; padding-left: 10px;">No.[[${#lists.size(buys) - buyInfoStat.index}]] </span>
<span> <span style="font-size: 1.1rem;">[[${buyInfo.buyDate}]] </span> <!-- rem : 원ㄹ 글자크기의 배수를 의미함 -->
에 총
<span style="font-size: 1.1rem;">[[${buyInfo.buyCnt}]]</span>
건의 주문으로
<span style="font-size: 1.1rem;">[[${#numbers.formatCurrency(buyInfo.totalPrice)}]]</span>
원을 결제했습니다.
</span>
</button>
</h2>
<div th:id="|panelsStayOpen-collapseOne${buyInfoStat.count}|" class="accordion-collapse collapse " aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<!-- <strong>강조하는 줄 영역</strong> -->
<!-- 아코디언 클릭시 펼쳐지는 구매 상세 내용줄 -->
<table class="table table-sm">
<thead>
<tr>
<td>No.</td>
<td colspan="2" style="text-align: center;">상품정보</td>
<td>단가 가격</td>
<td>수량</td>
<td>총가격</td>
</tr>
</thead>
<!-- 구매목록에서 buy_001의 buy_001_01,02...를 조회하는 것 -->
<tbody >
<tr th:each="buyList,status : ${buyInfo.buyDetailList}">
<td>[[${status.index}+1]] </td>
<td ><img width="100px;" height="140px;" th:src="|@{/images/}${buyList.attachedName}|"> </td>
<td>
[<span style="color: #749F82;" th:text=" ${buyList.cateName}"></span>]
<span th:text=" ${buyList.itemName}" ></span> </td>
<td>[[${buyList.itemPrice}]]</td>
<td>[[${buyList.buyAmount}]]</td>
<td>[[${buyList.buyPrice}]]</td>
</tr>
</tbody>
</table>
</div>
</div>
</th:block>
</div>
</div>
</div>
</div>
<!-- 뒤로가기 버튼 줄 -->
<div class="row mt-3">
<div class="col">
<div align="center">
<button class="btn btn-light" type="button" th:onclick="@{/item/list}">뒤로가기</button>
</div>
</div>
</div>
</div>
</div>
</div>
</html>
- 구매내역조회 페이지 첫화면
: 부트스트랩의 아코디언(accordion) 디자인을 가져와서 수정하여 사용
: 첫화면부터 모두 열리지않게 show삭제, 반복문마다의 버튼의 id값과 내용줄 div의 id값을 각각 다르게 설정(i,인덱스값부여하기)하면 하나를 클릭시 모두가 열리지않고 1:1로 열리도록 만들고, 첫 화면에서부터 파란색이 뜨지않고 하얀배경으로 시작하도록 collapse라는 속서을 버튼의 class값에 넣어준다.
- 상품코드별로 조회된 목록을 한 줄씩 클릭하면, 목록List안에 있는 buyDetailList 데이터를 하나씩 뽑아서 확인 할 수 있다.