SPRING/Homme Shop

[스프링] 쇼핑몰 - 상품목록과 페이징

간펴니 2021. 12. 9. 17:15
728x90

관리자가 등록한 상품을 사용자가

 

회원가입 - 로그인 - 상품목록 - 상품내용 - 장바구니 - 주문 의 로직으로 주문을 완료하면

 

관리자가 다시 주문관리에서 배송 및 취소 등 주문관리를 통해 상품을 판매하고 쇼핑몰을 운영할 수 있도록 구현했다.

 

이번엔 그 중, 상품목록과 페이징 그리고 비동기 검색에 관한 포스팅을 작성하려고 한다.

 

 

상품들은 다수의 카테고리를 가지고 있기 때문에, 카테고리별로 페이징이 되어야하며,

 

신상품순, 높은가격순, 낮은가격순으로 정렬을 할 수 있도록 구현했다.

 

 

검색은 상품목록 페이지에서 하는 것이 아닌,

 

상단바에 넣어서 사이트 어느곳이던 검색을 할 수 있도록 했고,

 

비동기로 처리해서 페이지 새로고침없이,

 

따로 버튼을 누르지 않고 키워드 입력만으로 검색이 되도록 만들었다.

 

다수의 카테고리

 


 

검색창


 

KNIT 입력


 

 


페이징에 필요한 파라미터를 받을 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)

 

페이징에 대하여

그간 웹개발을 공부하면서 , 다수의 프로젝트들을 만들었었는데 항상 빠지지않고 사용했던게 바로 페이징인 것 같다. 이젠 많이 어렵지 않다고 느낄 정도로 많이 사용해서 익숙해졌지만 정리한

kimfk567.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> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=coat&sort=">COAT</a> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=jacket&sort=">JACKET</a> &nbsp;&nbsp;&nbsp;
             <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> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=knit&sort=">KNIT</a> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=halftee&sort=">1/2 TEE</a> &nbsp;&nbsp;&nbsp;
             <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> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=denim&sort=">DENIM</a> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=halfpants&sort=">1/2PANTS</a> &nbsp;&nbsp;&nbsp;
             <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> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=boots&sort=">BOOTS</a> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=walker&sort=">WALKER</a> &nbsp;&nbsp;&nbsp;
             <a href="/main/itemView?page=1&perPageNum=8&catemain=item&catesub=derby&sort=">DERBY</a> &nbsp;&nbsp;&nbsp;
             <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 입니다 -->

다음 포스팅은 상품에 대한 비동기 검색 부분을 작성하려고 한다.

728x90