관리자가 등록한 상품을 사용자가
회원가입 - 로그인 - 상품목록 - 상품내용 - 장바구니 - 주문 의 로직으로 주문을 완료하면
관리자가 다시 주문관리에서 배송 및 취소 등 주문관리를 통해 상품을 판매하고 쇼핑몰을 운영할 수 있도록 구현했다.
이번엔 그 중, 상품목록과 페이징 그리고 비동기 검색에 관한 포스팅을 작성하려고 한다.
상품들은 다수의 카테고리를 가지고 있기 때문에, 카테고리별로 페이징이 되어야하며,
신상품순, 높은가격순, 낮은가격순으로 정렬을 할 수 있도록 구현했다.
검색은 상품목록 페이지에서 하는 것이 아닌,
상단바에 넣어서 사이트 어느곳이던 검색을 할 수 있도록 했고,
비동기로 처리해서 페이지 새로고침없이,
따로 버튼을 누르지 않고 키워드 입력만으로 검색이 되도록 만들었다.
페이징에 필요한 파라미터를 받을 VO
public class ItemCriteria
{
private int page;
private int perPageNum;
private int rowStart;
private int rowEnd;
private String catemain;
private String catesub;
private String sort;
/* */ public String getSort() {
/* 16 */ return this.sort;
/* */ }
/* */
/* */ public void setSort(String sort) {
/* 20 */ this.sort = sort;
/* */ }
/* */
/* */ public String getCatemain() {
/* 24 */ return this.catemain;
/* */ }
/* */
/* */ public void setCatemain(String catemain) {
/* 28 */ this.catemain = catemain;
/* */ }
/* */
/* */ public String getCatesub() {
/* 32 */ return this.catesub;
/* */ }
/* */
/* */ public void setCatesub(String catesub) {
/* 36 */ this.catesub = catesub;
/* */ }
/* */
/* */ public ItemCriteria() {
/* 40 */ this.page = 1;
/* 41 */ this.perPageNum = 8;
/* */ }
/* */
/* */ public void setPage(int page) {
/* 45 */ if (page <= 0) {
/* 46 */ this.page = 1;
/* */ return;
/* */ }
/* 49 */ this.page = page;
/* */ }
/* */
/* */ public void setPerPageNum(int perPageNum) {
/* 53 */ if (perPageNum <= 0 || perPageNum > 100) {
/* 54 */ this.perPageNum = 10;
/* */ return;
/* */ }
/* 57 */ this.perPageNum = perPageNum;
/* */ }
/* */
/* */ public int getPage() {
/* 61 */ return this.page;
/* */ }
/* */
/* */ public int getPageStart() {
/* 65 */ return (this.page - 1) * this.perPageNum;
/* */ }
/* */
/* */ public int getPerPageNum() {
/* 69 */ return this.perPageNum;
/* */ }
/* */
/* */ public int getRowStart() {
/* 73 */ this.rowStart = ((this.page - 1) * this.perPageNum) + 1;
/* 74 */ return this.rowStart;
/* */ }
/* */
/* */ public int getRowEnd() {
/* 78 */ this.rowEnd = this.rowStart + this.perPageNum - 1;
/* 79 */ return this.rowEnd;
/* */ }
/* */
/* */
/* */ public String toString() {
/* 84 */ return "Criteria [page=" + this.page + ", perPageNum=" + this.perPageNum + ", rowStart="
+ this.rowStart + ", rowEnd=" + this.rowEnd +
/* 85 */ "]";
/* */ }
/* */ }
}
페이징에 필요한 파라미터를 받아서 페이징버튼을 만들 클래스
package kr.co.vo;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
public class ItemPageMaker {
private int totalCount;
private int startPage;
private int endPage;
private boolean prev;
private boolean next;
private int displayPageNum = 10;
private ItemCriteria cri;
public void setCri(ItemCriteria cri) {
this.cri = cri;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
calcData();
}
public int getTotalCount() {
return totalCount;
}
public int getStartPage() {
return startPage;
}
public int getEndPage() {
return endPage;
}
public boolean isPrev() {
return prev;
}
public boolean isNext() {
return next;
}
public int getDisplayPageNum() {
return displayPageNum;
}
public ItemCriteria getCri() {
return cri;
}
private void calcData() {
endPage = (int) (Math.ceil(cri.getPage() / (double)displayPageNum) * displayPageNum);
startPage = (endPage - displayPageNum) + 1;
int tempEndPage = (int) (Math.ceil(totalCount / (double)cri.getPerPageNum()));
if (endPage > tempEndPage) {
endPage = tempEndPage;
}
prev = startPage == 1 ? false : true;
next = endPage * cri.getPerPageNum() >= totalCount ? false : true;
}
public String makeQuery(int page) {
UriComponents uriComponents =
UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", cri.getPerPageNum())
.queryParam("catemain", cri.getCatemain())
.queryParam("catesub", cri.getCatesub())
.queryParam("sort", cri.getSort())
.build();
return uriComponents.toUriString();
}
public String makeOrderQuery(int page) {
UriComponents uriComponents =
UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", cri.getPerPageNum())
.queryParam("delivstate", cri.getCatemain())
.build();
return uriComponents.toUriString();
}
}
UriComponents를 이용해 쿼리를 만들어준다.
uriComponents의 사용법을 전에 정리한 적이 있다..
UriComponents과 URLEncoding :: 간편 웹프로그래밍 (tistory.com)
Mapper
<select id="itemList" resultType="kr.co.vo.ItemVO"
parameterType="kr.co.vo.ItemCriteria">
SELECT ITEM_NO , ITEM_NAME , ITEM_PRICE , ITEM_SIZE, ITEM_COLOR,
ITEM_DISC, ITEM_CONTENT
, ITEM_IMGMAIN, ITEM_IMGSUB, ITEM_DATE,
ITEM_STAR, ITEM_CATEMAIN,
ITEM_CATESUB
FROM (
SELECT ITEM_NO , ITEM_NAME
, ITEM_PRICE , ITEM_SIZE, ITEM_COLOR, ITEM_DISC,
ITEM_CONTENT
,
ITEM_IMGMAIN, ITEM_IMGSUB,ITEM_DATE, ITEM_STAR, ITEM_CATEMAIN,
ITEM_CATESUB,
ROW_NUMBER() OVER(
<include refid="sort" />
) AS RNUM
FROM ITEM
WHERE ITEM_CATEMAIN =
<include refid="catemain" />
AND
ITEM_CATESUB =
<include refid="catesub" />
)
WHERE RNUM BETWEEN #{rowStart} AND #{rowEnd}
<include refid="sort" />
</select>
<!-- 페이징에 필요한 글의 총 개수 -->
<select id="itemCount" resultType="int" parameterType="kr.co.vo.ItemCriteria">
SELECT COUNT(*) FROM (select * from ITEM where
ITEM_CATEMAIN =
<include refid="catemain"/>
AND
ITEM_CATESUB =
<include refid="catesub"/>
) WHERE
<![CDATA[
ITEM_NO > 0
]]>
</select>
<!-- 정렬 -->
<sql id="sort">
<if test="sort == '' ">
ORDER BY ITEM_NO DESC
</if>
<if test="sort == 'no' ">
ORDER BY ITEM_NO DESC
</if>
<if test="sort == 'pricedesc' ">
ORDER BY ITEM_PRICE DESC
</if>
<if test="sort == 'priceasc' ">
ORDER BY ITEM_PRICE ASC
</if>
</sql>
<!-- 메인카테고리 -->
<sql id="catemain">
<if test="catemain == ''">
'item'
</if>
<if test="catemain == 'item'">
'item'
</if>
<if test="catemain == 'main'">
'main'
</if>
<if test="catemain == 'popular'">
'popular'
</if>
</sql>
<!-- 서브카테고리 -->
<sql id="catesub">
<if test="catesub == 'outer' ">
'jumper' OR ITEM_CATESUB = 'coat' OR ITEM_CATESUB =
'jacket' OR ITEM_CATESUB
= 'padding'
</if>
<if test="catesub == 'top' ">
'long' OR ITEM_CATESUB = 'knit' OR ITEM_CATESUB =
'halftee' OR ITEM_CATESUB
= 'shirts' OR ITEM_CATESUB = 'blank'
</if>
<if test="catesub == 'bottom' ">
'pants' OR ITEM_CATESUB = 'denim' OR ITEM_CATESUB =
'halfpants' OR
ITEM_CATESUB = 'jogger' OR ITEM_CATESUB = 'sult'
</if>
<if test="catesub == 'shoes' ">
'sneakers' OR ITEM_CATESUB = 'boots' OR ITEM_CATESUB =
'walker'
OR ITEM_CATESUB = 'derby' OR ITEM_CATESUB = 'sandal'
</if>
<if test="catesub == 'jumper'">
'jumper'
</if>
<if test="catesub == 'coat'">
'coat'
</if>
<if test="catesub == 'jacket'">
'jacket'
</if>
<if test="catesub == 'padding'">
'padding'
</if>
<if test="catesub == 'long'">
'long'
</if>
<if test="catesub == 'knit'">
'knit'
</if>
<if test="catesub == 'halftee'">
'halftee'
</if>
<if test="catesub == 'shirts'">
'shirts'
</if>
<if test="catesub == 'blank'">
'blank'
</if>
<if test="catesub == 'pants'">
'pants'
</if>
<if test="catesub == 'denim'">
'denim'
</if>
<if test="catesub == 'halfpants'">
'halfpants'
</if>
<if test="catesub == 'jogger'">
'jogger'
</if>
<if test="catesub == 'sult'">
'sult'
</if>
<if test="catesub == 'sneakers'">
'sneakers'
</if>
<if test="catesub == 'boots'">
'boots'
</if>
<if test="catesub == 'walker'">
'walker'
</if>
<if test="catesub == 'derby'">
'derby'
</if>
<if test="catesub == 'sandal'">
'sandal'
</if>
</sql>
그간 웹개발을 공부하면서 , 다수의 프로젝트들을 만들었었는데
항상 빠지지않고 사용했던게 바로 페이징인 것 같다.
이젠 많이 어렵지 않다고 느낄 정도로 많이 사용해서 익숙해졌지만 정리한 적이 없어 한번 정리해보려고 한다.
적다보니 너무 길어져서 따로 글을 작성했다.
페이징에 대하여 :: 간편 웹프로그래밍 (tistory.com)
Controller
@RequestMapping(value = {"/itemView"}, method = {RequestMethod.GET})
public String itemView(Model model, @ModelAttribute("cri") ItemCriteria cri) throws Exception {
logger.info("itemView" + cri.getPage());
model.addAttribute("itemList", this.mainService.itemList(cri));
ItemPageMaker pageMaker = new ItemPageMaker();
pageMaker.setCri(cri);
pageMaker.setTotalCount(this.mainService.itemCount(cri));
model.addAttribute("pageMaker", pageMaker);
return "/main/itemView";
}
특별할 것은 없다.
페이징에 필요한 매개변수를 @ModelAttribute로 받고, 던지고,
mapper에 넣어주고, 페이징을 계산하여 출력해준다.
View
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- header 입니다 -->
<%@include file="../include/header.jsp"%>
<!-- header 입니다 -->
<div class="main">
<section class="module bg-dark-60 shop-page-header" data-background="assets/images/shop/product-page-bg.jpg">
<div class="container">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<h2 class="module-title font-alt">Shop Products</h2>
<div class="module-subtitle font-serif">A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart.</div>
</div>
</div>
</div>
</section>
<section class="module-small">
<div class="container">
<div class="col-sm-12 mb-sm-20" style="text-align:center; font-size:20px;">
<c:if test="${cri.catesub=='outer' or cri.catesub=='jamper' or cri.catesub=='coat'or cri.catesub=='jacket'or cri.catesub=='padding'}">
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=jamper&sort=">JAMPER</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=coat&sort=">COAT</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=jacket&sort=">JACKET</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=padding&sort=">PADDING</a>
</c:if>
<c:if test="${cri.catesub=='top' or cri.catesub=='long' or cri.catesub=='knit' or cri.catesub=='halftee'or cri.catesub=='shirts'or cri.catesub=='blank'}">
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=long&sort=">LONG</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=knit&sort=">KNIT</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=halftee&sort=">1/2 TEE</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=shirts&sort=">SHIRTS</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=blank&sort=">BLANK</a>
</c:if>
<c:if test="${cri.catesub=='bottom' or cri.catesub=='denim' or cri.catesub=='halfpants' or cri.catesub=='jogger'or cri.catesub=='sult'}">
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=bottom&sort=">BOTTOM</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=denim&sort=">DENIM</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=halfpants&sort=">1/2PANTS</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=jogger'or&sort=">Jogger</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=sult&sort=">sult</a>
</c:if>
<c:if test="${cri.catesub=='shoes' or cri.catesub=='sneakers' or cri.catesub=='boots' or cri.catesub=='walker' or cri.catesub=='derby' or cri.catesub=='sandal'}">
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=sneakers&sort=">SNEAKERS</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=boots&sort=">BOOTS</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=walker&sort=">WALKER</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=derby&sort=">DERBY</a>
<a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=sandal&sort=">SANDAL</a>
</c:if>
</div>
</div>
</section>
<hr class="divider-w">
<section class="module-small">
<div class="container">
<div class="row multi-columns-row">
<form>
<c:forEach items="${itemList}" var="itemList">
<div class="col-sm-6 col-md-3 col-lg-3 mt-60 mb-40">
<div class="shop-item">
<a href="/main/itemContent?item_no=${itemList.item_no}&page=${cri.page}&perPageNum=${cri.perPageNum}&catemain=${cri.catemain}&catesub=${cri.catesub}&sort=${cri.sort}">
<div class="shop-item-image"><img width="10%" src="/img/${itemList.item_imgmain}" alt="Accessories Pack"/>
<div class="shop-item-detail"><img src="/img/${itemList.item_imgsub}" alt="Accessories Pack"/></div>
</div>
<h4 class="shop-item-title font-alt">${itemList.item_name}</h4>
₩ <fmt:formatNumber pattern="###,###,###" value="${itemList.item_price}"/>
</a>
</div>
</div>
</c:forEach>
</form>
</div>
<div class="row">
<div class="col-sm-12" style="text-align:center;">
<div class="pagination font-alt">
<c:if test="${pageMaker.prev}">
<a href="/main/itemView${pageMaker.makeQuery(pageMaker.startPage - 1)}"><i class="fa fa-angle-left"></i></a>
</c:if>
<c:forEach begin="${pageMaker.startPage}" end="${pageMaker.endPage}" var="idx">
<a class="active" href="/main/itemView${pageMaker.makeQuery(idx)}">${idx}</a>
</c:forEach>
<c:if test="${pageMaker.next && pageMaker.endPage > 0}">
<a href="/main/itemView${pageMaker.makeQuery(pageMaker.endPage + 1)}"><i class="fa fa-angle-right"></i></a>
</c:if>
</div>
</div>
</div>
</div>
</section>
<!-- footer 입니다 -->
<%@include file="../include/footer.jsp"%>
<!-- footer 입니다 -->
다음 포스팅은 상품에 대한 비동기 검색 부분을 작성하려고 한다.
'SPRING > Homme Shop' 카테고리의 다른 글
[스프링] 쇼핑몰 - 비동기 검색 (0) | 2021.12.09 |
---|---|
[스프링] 쇼핑몰 - 주문관리 (0) | 2021.12.09 |
[스프링] 쇼핑몰 - 주문목록 (0) | 2021.12.09 |
[스프링] 쇼핑몰 - 상품 주문 [ 2 ] (0) | 2021.12.09 |
[스프링] 쇼핑몰 - 상품 주문 [ 1 ] (0) | 2021.12.08 |