본문 바로가기
SPRING/SPRING 프로젝트

SPRING 프로젝트 - 펀딩 사이트 (4) : xml 조건 정렬과 Grid

by 스노위13 2022. 9. 2.

1. 내용 : 펀딩 사이트들의 내용을 크롤링하여 모은 뒤 화면에 띄워주었다. 

2. 과정 중 특이점 : 게시판을 만들 때 카테고리 별로 보여주는 것은 했어서 이번에는 정렬 기능을 넣어보았다. where 조건만 추가하면 되서 많이 어렵지 않았다. 페이지네이션도 이전 화면구현 때와 JSP 수업 때 했어서 동일하게 구현하였다.

3. 화면 및 코드 설명

각 사이트에서 진행되는 펀딩들을 모아서 보려면 먼저 텀블벅, 와디즈, 오마이펀딩 사이트를 크롤링해해야 한다. 파이썬을 이용해서 각 사이트에서 필요한 정보를 크롤링하고 그 결과를 오라클 DB에 저장하였다.

그리고 저장된 내용을 가지고 펀딩 리스트를 구현하였는데 화면은 아래와 같다.

1) 펀딩 화면

펀딩 이미지, 제목, 달성율과 그 퍼센트, 찜한 숫자, 카테고리, 남은 기간, 사이트 이름이 뜨게 있다.

아래에는 페이지네이션도 구현해두었다. 

2) xml

<sql id="search"> 
	<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(searchCategory)">
		AND fu_cate = #{searchCategory}
	</if>
	<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(searchSite)">
		AND fu_site = #{searchSite}
	</if>
</sql>

<sql id="array"> 
	<if test="@org.apache.commons.lang3.StringUtils@isBlank(arraryType)">
	ORDER BY dbms_random.value
	</if>
	<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(arraryType)">
	ORDER BY 	${arraryType}
	</if>
</sql>

<select id="getFundingList" parameterType="com.study.funding.vo.FundingVO"
resultType="com.study.funding.vo.FundingVO">	
   SELECT *  FROM                  (                    
	    SELECT a.*, ROWNUM as rnum FROM (   
	        SELECT
            fu_no	   			 , fu_site	    , fu_title
            , fu_cate       , fu_enter	    , fu_img
            , fu_percent	 , fu_amount	    , fu_dday
            , fu_url  	    , fu_like
	        FROM
            funding
	    WHERE 1=1
	<include refid="search"></include>		
	<include refid="array"></include>		
	 )   a                      
		 )   b                      
	WHERE rnum BETWEEN #{firstRow}  AND #{lastRow} 
</select>

그리고 <include refid="search"></include> 과 <include refid="array"></include>로 조건문이 들어가게 만들었고 rnum을 사용해서 페이지를 구분하였다

@org.apache.commons.lang3.StringUtils를 사용해서 카테고리나 정렬 부분이 isNotBlank거나 isBlank일 때 특정 조건이 sql문에 들어가도록 만들었다.

그래서 위의 사진과 같이 사용자가 원하는 카테고리와 사이트로 분류해서 보거나 원하는 조건으로 정렬할 수 있게 하였다. 이걸 하면서 xml문에서 ${  }와 #{  }이 어떤 차이가 있는지를 정확하게 알게 되었다.

* xml문에서 #{  }은 '   '이 필요할 때 사용했다. 
  예를 들어 사용자가 wadiz를 선택했을 때 AND fu_site = #{searchSite}은 오라클 sql에서 AND fu_site = 'wadiz'로 적용된다. 
  ${   }은 '  '이 필요 없을 때 사용했다. 
  사용자가 최신순을 정렬로 선택했을 때 ORDER BY ${arraryType}은 오라클 sql에서 ORDER BY fu_dday desc 로 적용된다. 

3) jsp + css (jsp 전체 코드는 아래의 더보기 클릭)

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<!DOCTYPE html>
<html>
<head>
<%@include file="/WEB-INF/inc/header.jsp" %>

<meta charset="UTF-8">
<title>펀딩 전체 보기</title>
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath() %>/resources/css/funding/fundingList.css" />
</head>
<body>
<%@include file="/WEB-INF/inc/top.jsp" %>
<div class="container">

	<form class="fucategory" name="search" action="fundingList.wow" method="post" class="form-horizontal">
		<input type="hidden" name="curPage" value="${searchVO.curPage }"> 
		<input type="hidden" name="rowSizePerPage" value="${searchVO.rowSizePerPage }">	
		<div class="form-group">
			<div class="row">
				<div class="col-1"> <b>분류</b></div>
				<div class="col">
					<select id="id_searchCategory" name="searchCategory" class="form-control input-sm">
						<option value="">--선택하세요--</option>		
						<c:forEach items="${cateList }" var="cate" varStatus="st">
							<option value="${cate}" ${searchVO.searchCategory eq cate ? "selected='selected'" : ""}>${cate}</option>
						</c:forEach>
					</select>
				</div>
				<div class="col-1"> <b>사이트</b></div>
				<div class="col">
					<select id="id_searchSite" name="searchSite" class="form-control input-sm">
						<option value="">--선택하세요--</option>		
						<option value="tumblbug" ${searchVO.searchSite eq "tumblbug" ? "selected='selected'" : ""}>텀블벅</option>
						<option value="wadiz" ${searchVO.searchSite eq "wadiz" ? "selected='selected'" : ""}>와디즈</option>
						<option value="ohmycompany" ${searchVO.searchSite eq "ohmycompany" ? "selected='selected'" : ""}>오마이컴퍼니</option>
					</select>
				</div>	
				<div class="col-1"> <b>정렬</b></div>
				<div class="col">
					<select id="id_arrarytype" name="arraryType" class="form-control input-sm">	
						<option value="">--선택하세요--</option>		
						<option value="fu_dday desc" ${searchVO.arraryType eq "fu_dday desc" ? "selected='selected'" : ""}>최신순</option>
						<option value="fu_amount desc" ${searchVO.arraryType eq "fu_amount desc" ? "selected='selected'" : ""}>달성율 높은 순</option>
						<option value="fu_dday" ${searchVO.arraryType eq "fu_amount" ? "selected='selected'" : ""}>마감순</option>
					</select>
				</div>	
				<div class="col-2">
					<button type="submit" class="btn btn-sm btn-primary btn-lg"> 선택</button>
				</div>
			</div>					
		</div>	
	</form>
</div>
<div class="container" id="list">
	<c:forEach items="${fundingList }" var="funding" varStatus="st">
		<div class="funding">
			<a href="fundingView.wow?fuNo=${funding.fuNo }&memId=${USER_INFO.userId}"><img class="fundingimg" alt="" src="${funding.fuImg }"></a>
			<a href="fundingView.wow?fuNo=${funding.fuNo }&memId=${USER_INFO.userId}"><b>${funding.fuTitle }</b></a>			
			<div class="amount">${funding.fuAmount } 달성(${funding.fuPercent } %)</div>
			<div class="category">♥ ${funding.fuLike } <b>|</b> ${funding.fuCate }	</div>
			<div class="fuDday"><b>${funding.fuDday eq "0" ? "오늘 마감": funding.fuDday }${funding.fuDday eq "0" ? "" : "일 남음"}|</b> ${funding.fuSite } </div>
		</div>
	</c:forEach>
</div>
<!-- START : 페이지네이션  -->
<div class="container" id="paging">
	<ul class="pagination">
		<!-- 첫 페이지  -->
		<li class="page-item"><a class="page-link" href="fundingList.wow?curPage=1" data-page="1">
		<span	aria-hidden="true">&laquo;</span></a></li>
		<!-- 이전 페이지 -->
		<c:if test="${searchVO.firstPage!=1 }">
			<li class="page-item"><a class="page-link" href="fundingList.wow?curPage=${searchVO.firstPage-1 }"
				data-page="${searchVO.firstPage-1 }"><span aria-hidden="true">&lt;</span></a></li>
		</c:if>

		<!-- 페이지 넘버링  -->
		<c:forEach begin="${searchVO.firstPage }" end="${searchVO.lastPage }" var="i">
			<c:if test="${searchVO.curPage !=i }">
				<li class="page-item"><a class="page-link" href="fundingList.wow?curPage=${i }" data-page="${i }">${i }</a></li>
			</c:if>
			<c:if test="${searchVO.curPage ==i }">
				<li class="page-item active"><a class="page-link" href="#">${i }</a></li> 
			</c:if>
		</c:forEach>

		<!-- 다음  페이지  -->
		<c:if test="${searchVO.lastPage!=searchVO.totalPageCount }">
			<li class="page-item"><a class="page-link" href="fundingList.wow?curPage=${searchVO.lastPage+1 }" data-page="${searchVO.lastPage+1 }">
			<span	aria-hidden="true">&gt;</span></a></li>
		</c:if>

		<!-- 마지막 페이지 -->
		<li class="page-item"><a class="page-link" href="fundingList.wow?curPage=${searchVO.totalPageCount }" data-page="${searchVO.totalPageCount }">
		<span	aria-hidden="true">&raquo;</span></a></li>				
	</ul>
</div>
<!-- END : 페이지네이션  -->


<script type="text/javascript">
		$form=$("form[name='search']");
		$curPage=$form.find("input[name='curPage']");	

		// 페이지 링크 클릭
		$('ul.pagination li a[data-page]').click(function(e) {
			e.preventDefault(); 
			$curPage.val($(this).data('page'));
			$form.submit();	
		}); // ul.pagination li a[data-page]

		
		$form.find("button[type=submit]").click(function(e) {
			e.preventDefault();
			$curPage.val(1);
			$form.submit();
		});

		$('#id_rowSizePerPage').change(function(e) {
			$curPage.val(1);
			$form.find("input[name='rowSizePerPage']").val($(this).val());
			$form.submit();
		}); // '#id_rowSizePerPage'.change

	
</script>
</body>
</html>

① 카테고리, 사이트 별 분류

<div class="col-1"> <b>분류</b></div>
<div class="col">
    <select id="id_searchCategory" name="searchCategory" class="form-control input-sm">
        <option value="">--선택하세요--</option>		
        <c:forEach items="${cateList }" var="cate" varStatus="st">
            <option value="${cate}" ${searchVO.searchCategory eq cate ? "selected='selected'" : ""}>${cate}</option>
        </c:forEach>
    </select>
</div>

카테고리는 select를 이용해서 선택하여 분류하는데 Controller에서 List를 받아서 그걸 forEach를 사용하여 나타낸다. 

<div class="container" id="list">
	<c:forEach items="${fundingList }" var="funding" varStatus="st">
		<div class="funding">
			<a href="fundingView.wow?fuNo=${funding.fuNo }&memId=${USER_INFO.userId}"><img class="fundingimg" alt="" src="${funding.fuImg }"></a>
			<a href="fundingView.wow?fuNo=${funding.fuNo }&memId=${USER_INFO.userId}"><b>${funding.fuTitle }</b></a>			
			<div class="amount">${funding.fuAmount } 달성(${funding.fuPercent } %)</div>
			<div class="category">♥ ${funding.fuLike } <b>|</b> ${funding.fuCate }	</div>
			<div class="fuDday"><b>${funding.fuDday eq "0" ? "오늘 마감": funding.fuDday }${funding.fuDday eq "0" ? "" : "일 남음"}|</b> ${funding.fuSite } </div>
		</div>
	</c:forEach>
</div>

화면단에서는 DB의 정보를 받아서 forEach로 반복하여 표현하는데 페이지네이션을 이용해서 페이지를 구분해주었다. 각각의 펀딩들은 Grid를 이요해서 나눴는데 그에 대한 CSS 파일은 아래와 같다.

#list{
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(20%, auto));
	row-gap: 40px;
	/* row의 간격을 10px로 */
	column-gap: 20px;
	/* column의 간격을 20px로 */
}

.funding{
	display: grid;
	grid-template-columns: 1fr;
	grid-template-rows: 260px 3fr 1fr 1fr 1fr
}

Grid는 이번에 처음 사용해봤는데 표처럼 깔끔하게 정리할 수가 있어서 좋았다. 

4) Controller

@RequestMapping(value = "funding/fundingList.wow")
public String fundingList(Model model, @ModelAttribute("searchVO") FundingSerchVO serchVO) {
    List<FundingVO> fundingList = fuService.getFundingList(serchVO);
   List<String> cateList = Arrays.asList("문구", "여행·레저","반려동물",
       "예술·디자인","뷰티", "기부·후원","클래스·컨설팅","문화·출판","게임·취미","생활 용품",
       "테크·가전","스포츠·모빌리티","패션·잡화","푸드","액세서리" , "향수", "실용·취미");
    model.addAttribute("fundingList", fundingList);		
    model.addAttribute("cateList", cateList);
    return "funding/fungdingList";		
}

Controller에서는 cateList를 만들어서 모델에 담아서 보내주었다. 하드코딩 하지 않아도 되서 좋았음!

댓글