[Spring][쇼핑몰 프로젝트] 19. 상품 목록 기능 구현

YB·2023년 2월 23일
0

쇼핑몰

목록 보기
30/40

목표

상품 목록 페이지에 구현되어야 할 '페이징화', '검색'등을 적용할 것입니다. '작가 목록' 기능 구현과 동일한 기능이기 때문에 간략하게 진행할 것입니다.

검색 기능의 경우 '책 제목'을 통한 검색 기능만 구현하겠습니다. 다른 여러 옵션을 통한 구현은 차후 일반 사용자의 검색에서 구현할 것입니다.

1. Mapper 메서드

Mapper작업을 하기전 페이징 기능 구현이 제대로 되는지 확인하기 위해, 아무 의미 없는 행들을 추가해줍니다. 아래의 재귀 복사를 통하여 행들을 추가해주었습니다.

insert into test_book(bookName, authorId, publeYear, publisher, cateCode, bookPrice, bookStock, bookDiscount,bookIntro, bookContents)
(select bookName, authorId, publeYear, publisher, cateCode, bookPrice, bookStock, bookDiscount,bookIntro, bookContents from test_book);

상품 목록 페이지에서 기본적으로 필요로한 쿼리문과 이를 호출하는 Mapper메서드를 먼저 작업합니다.

1) AdminMapper.java

AdminMapper.java인터페이스에 아래 두개의 메서드를 추가합니다. 'goodsGetList()'메서드는 각각 상품 목록 페이지에 출력될 페이징화 된 상품 데이터입니다.

	/* 상품 리스트 */
	public List<BookVO> goodsGetList(Criteria cri);
	
	/* 상품 총 개수 */
	public int goodsGetTotal(Criteria cri);

2) AdminMapper.xml

'상품 목록(상품 관리)' 페이지에 출력시킬 열들의 정보는 'bookId', 'bookName', 'authorName', 'cateName', 'bookPrice', 'bookStock'입니다. 문제는 'bookName', 'cateName' 열의 정보는 "test_book"테이블에 있지 않습니다.

따라서 같이 출력 되도록해주기 위해선 '서브쿼리' 또는 '조인'을 사용해야 합니다.

	<!-- 상품 리스트 -->
	<select id="goodsGetList" resultType="com.test.model.BookVO">
		select bookId, bookName, b.authorName, c.cateName, bookStock, a.regDate
		from test_book a
		left outer join test_author b on a.authorId = b.authorId
		left outer join test_bcate c on a.cateCode = c.cateCode
		<if test="keyword != null">
			where (bookName like concat ('%', #{keyword}, '%'))
		</if>
		order by bookId desc
		limit #{skip}, #{amount}
	</select>

	<!-- 상품 총 갯수 -->
	<select id="goodsGetTotal" resultType="int">
		select count(*) from test_book
		<if test="keyword != null">
			where bookName like concat ('%', #{keyword}, '%')
		</if>
	</select>

2. Service

AdminController.java에서 위에서 작성한 메서드를 실행할 수 있도록 연결해주는 Service단계의 메서드를 작성합니다.

AdminService.java인터페이스에 아래의 메서드를 추가해줍니다.

	/* 상품 리스트 */
	public List<BookVO> goodsGetList(Criteria cri);
	
	/* 상품 총 개수 */
	public int goodsGetTotal(Criteria cri);

AdminServiceImpl.java클래스에 인터페이스에서 작성한 메서드를 오버라이드 구현부를 작성해줍니다.

	/* 상품 리스트 */
	@Override
	public List<BookVO> goodsGetList(Criteria cri) {
		
		log.info("goodsGetList()...........");
		
		return adminMapper.goodsGetList(cri);
		
	}

	/* 상품 총 개수 */
	@Override
	public int goodsGetTotal(Criteria cri) {
		
		log.info("goodsGetTotal()...........");
		
		return adminMapper.goodsGetTotal(cri);
		
	}

3. Controller

기존의 '상품 관리(상품 목록)' 페이지 이동 URL("/goodsManage")매핑 메서드 Criteria.model파라미터를 추가해줍니다.

  • 구현부에는 '상품 목록 데이터', '페이지 인터페이스 데이터'를 뷰(View)에 전송하는 아래의 코드를 추가합니다.

	/* 상품 목록 페이지 접속 */
	@RequestMapping(value="goodsManage", method=RequestMethod.GET)
	public void goodsManageGET(Criteria cri, Model model) throws Exception {
		
		logger.info("상품 목록 페이지 접속");
		
		/* 상품 리스트 데이터 */
		List list = adminService.goodsGetList(cri);
		
		if(!list.isEmpty()) {
			model.addAttribute("list", list);
		} else {
			model.addAttribute("listCheck", "empty");
			return;
		}
		
		/* 페이지 인터페이스 데이터 */
		model.addAttribute("pageMaker", new PageDTO(cri, adminService.goodsGetTotal(cri)));
		
	}

4. View 처리

JSTL태그라이브러리 코드를 추가하고 'admin_content_subject'아래에 코드를 추가하였습니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>  
                    <div class="goods_table_wrap">
                    	<!-- 상품 리스트 O -->
	                    <c:if test="${listcheck != 'empty'}">
	                    	<table class="goods_table">
	                    		<thead>
	                    			<tr>
										<td class="th_column_1">상품 번호</td>
	                    				<td class="th_column_2">상품 이름</td>
	                    				<td class="th_column_3">작가 이름</td>
	                    				<td class="th_column_4">카테고리</td>
	                    				<td class="th_column_5">재고</td>
	                    				<td class="th_column_6">등록날짜</td>
	                    			</tr>
	                    		</thead>	
	                    		<c:forEach items="${list}" var="list">
	                    		<tr>
	                    			<td><c:out value="${list.bookId}"></c:out></td>
	                    			<td><c:out value="${list.bookName}"></c:out></td>
	                    			<td><c:out value="${list.authorName}"></c:out></td>
	                    			<td><c:out value="${list.cateName}"></c:out></td>
	                    			<td><c:out value="${list.bookStock}"></c:out></td>
	                    			<td><fmt:formatDate value="${list.regDate}" pattern="yyyy-MM-dd"/></td>
	                    		</tr>
	                    		</c:forEach>
	                    	</table>
	                    </c:if>
	                    <!-- 상품 리스트 X -->
                		<c:if test="${listCheck == 'empty'}">
                			<div class="table_empty">
                				등록된 작가가 없습니다.
                			</div>
                		</c:if> 
                	</div>
                	
                	<!-- 검색 영역 -->
                	<div class="search_wrap">
                		<form id="searchForm" action="/admin/goodsManage" method="get">
                			<div class="search_input">
                    			<input type="text" name="keyword" value='<c:out value="${pageMaker.cri.keyword}"></c:out>'>
                    			<input type="hidden" name="pageNum" value='<c:out value="${pageMaker.cri.pageNum }"></c:out>'>
                    			<input type="hidden" name="amount" value='${pageMaker.cri.amount}'>
                    			<input type="hidden" name="type" value="G">
                    			<button class='btn search_btn'>검 색</button>                				
                			</div>
                		</form>
                	</div>
                	
                	<!-- 페이지 이름 인터페이스 영역 -->
                	<div class="pageMaker_wrap">
                		<ul class="pageMaker">
                			
                			<!-- 이전 버튼 -->
                			<c:if test="${pageMaker.prev }">
                				<li class="pageMaker_btn prev">
                					<a href="${pageMaker.pageStart -1}">이전</a>
                				</li>
                			</c:if>
                			
                			<!-- 페이지 번호 -->
                			<c:forEach begin="${pageMaker.pageStart }" end="${pageMaker.pageEnd }" var="num">
                				<li class="pageMaker_btn ${pageMaker.cri.pageNum == num ? 'active':''}">
                					<a href="${num}">${num}</a>
                				</li>	
                			</c:forEach>
                		
	                    	<!-- 다음 버튼 -->
	                    	<c:if test="${pageMaker.next}">
	                    		<li class="pageMaker_btn next">
	                    			<a href="${pageMaker.pageEnd + 1 }">다음</a>
	                    		</li>
	                    	</c:if>
	                    </ul>
                	</div>
                	
                	<form id="moveForm" action="/admin/goodsManage" method="get" >
 						<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
						<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
						<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
                	</form>

추가한 태그들에 css설정을 추가해주기 위해서 'goodsManage.css'에 아래의 코드를 추가해주었습니다.

/* 상품 목록 영역 */
.goods_table_wrap{
	padding: 20px 35px
}
.goods_table{
	width: 100%;
    border: 1px solid #d3d8e1;
    text-align: center;
    border-collapse: collapse;
}
.goods_table td{
	padding: 10px 5px;
	border : 1px solid #e9ebf0;
}
.goods_table thead{
	background-color: #f8f9fd;	
	font-weight: 600;
}
.goods_table a{
	color:#1088ed;
	font-weight: 500;
}
.th_column_1{
	width:120px;
}
.th_column_3{
	width:110px;
}
.th_column_4{
	width:140px;
}
.th_column_5{
	width:140px;
}
.th_column_6{
	
}
	
.table_empty{
	height: 50px;
    text-align: center;
    margin: 200px 0 215px 0px;
    font-size: 25px;
}

/* 검색 영역 */
.search_wrap{
	margin-top:15px;
}
.search_input{
    position: relative;
    text-align:center;	
}
.search_input input[name='keyword']{
	padding: 4px 10px;
    font-size: 15px;
    height: 20px;
    line-height: 20px;
}
.search_btn{
	height: 32px;
    width: 80px;
    font-weight: 600;
    font-size: 18px;
    line-height: 20px;
    position: absolute;
    margin-left: 15px;
    background-color: #c3daf7;
}


/* 페이지 버튼 인터페이스 */
.pageMaker_wrap{
	text-align: center;
    margin-top: 30px;
    margin-bottom: 40px;
}
.pageMaker{
    list-style: none;
    display: inline-block;
}	
.pageMaker_btn {
    float: left;
    width: 40px;
    height: 40px;
    line-height: 40px;
    margin-left: 20px;
}
.active{
	border : 2px solid black;
	font-weight:400;
}
.next, .prev {
    border: 1px solid #ccc;
    padding: 0 10px;
}
.pageMaker_btn a:link {color: black;}
.pageMaker_btn a:visited {color: black;}
.pageMaker_btn a:active {color: black;}
.pageMaker_btn a:hover {color: black;}
.next a, .prev a {
    color: #ccc;
}

페이지 이동 인터페이스 동작하도록 만들기 위해서 <script>태그에 아래의 js코드를 추가해줍니다.

let searchForm = $('#searchForm');
let moveForm = $('#moveForm');

/* 작가 검색 버튼 동작 */
$("#searchForm button").on("click", function(e){
	
	e.preventDefault();
	
	/* 검색 키워드 유효성 검사 */
	if(!searchForm.find("input[name='keyword']").val()){
		alert("키워드를 입력하십시오");
		return false;
	}
	
	searchForm.find("input[name='pageNum']").val("1");
	
	searchForm.submit();
	
});


/* 페이지 이동 버튼 */
$(".pageMaker_btn a").on("click", function(e){
	
	e.preventDefault();
	
	moveForm.find("input[name='pageNum']").val($(this).attr("href"));
	
	moveForm.submit();
	
});

5. 테스트


profile
개인이 공부한걸 작성하는 블로그입니다..

0개의 댓글