[spring]스프링 mybatis을 이용한 게시판 페이징 처리와 css

Map<String, Object> map = new HashMap<String, Object>();
map.put("searchType", searchType);
map.put("searchTxt", searchTxt);

int pageRow = 10;
int totalcount = boardService.boardCount(map);
log.info("totalcount : "+ totalcount);
model.addAttribute("total_count", totalcount);

int total_page = totalcount / pageRow + (totalcount % pageRow > 0 ? 1 : 0);
log.info("total_page : "+ total_page);
model.addAttribute("pages", total_page);

map.put("pageNum", pageNum);
map.put("pageRow", pageRow);

List<ResultMap> boardlist = boardService.boardList(map);

model.addAttribute("pageNum", pageNum);
model.addAttribute("list", boardlist);

 

먼저 페이징을 하기 위해선 총 게시물수와 현재페이지 번호가 필요하다.

int total_page = totalcount / pageRow + (totalcount % pageRow > 0 ? 1 : 0);

총 게시물수를 구해와서 최대 페이지 갯수를 구한다.

필자는 게시물이 10개씩 보이게 끔 설정을 해주었다.

게시물 갯수 구하기

<select id="boardCount" parameterType="map" resultType="java.lang.Integer">

    SELECT count(*) FROM 테이블명
    <where>
    0=0
    <if test="searchTxt != ''">
        <if test="searchType == 'mem_name'">
             and mem_name like #{searchTxt}
        </if>
        <if test="searchType == 'company_name'">
             and company_name like #{searchTxt}
        </if>
    </if>
    </where>

</select>

 

총 게시물수는 게시판일 경우 검색어에 따른 개수가 달라지기에 검색 쿼리를 사용해 구한다.

한 가지 주의할 점은 where 절에 and 사용을 편하게 하기 위해 0=0 혹은 1=1을 사용할 수 있는데 

이는 전체조회가 되는 관점에서는 매우 위험하다.

게시물 리스트 가져오기

ROW_NUMBER() 버전

<select id="boardList" parameterType="map" resultType="ResultMap">

    SELECT *
    FROM
    (
        SELECT ROW_NUMBER() OVER(ORDER BY reg_date desc) AS rownum
            ,* FROM 테이블명 lc
    <where>
    0=0

    <if test="searchTxt != ''">
        <if test="searchType == 'mem_name'">
             and mem_name like #{searchTxt}
        </if>
        <if test="searchType == 'company_name'">
             and company_name like #{searchTxt}
        </if>
    </if>
    </where>
    ) A
    WHERE rownum BETWEEN ((#{pageNum})*#{pageRow})+1 AND ((#{pageNum}+1)*#{pageRow})

</select>

OFFSET FETCH 버전

<select id="boardOftsetList" parameterType="map" resultType="ResultMap">
    SELECT t1.* 
    FROM 테이블명 AS t1 WITH(NOLOCK)  
    INNER JOIN ( 
        SELECT id 
        FROM 테이블명 WITH(NOLOCK)
        <where>
        0=0
        <if test="searchTxt != ''">
            <if test="searchType == 'mem_name'">
                 and mem_name like #{searchTxt}
            </if>
            <if test="searchType == 'company_name'">
                 and company_name like #{searchTxt}
            </if>
        </if>
        </where>
        ORDER BY reg_date  DESC
        OFFSET (#{pageNum}) * #{pageRow} ROWS
        FETCH NEXT (#{pageRow})  ROWS ONLY 
    ) AS t2
    ON t1.id = t2.id ORDER BY reg_date  DESC 

</select>

 

보통 mssql의 경우 row_number() 이나  offset fetch를 통해 페이징 쿼리를 만든다.

offset fetch는 2012 버전부터 사용가능하며 빠르고 간편한 편이지만 특정구문 등을 사용할 수 없다.

row_number()는 모든 게시물에 번호를 달아주기 때문에 특정 범위의 검색을 할수 있지만 부하를 일으킬 수 있고 속도가 느린 편이다.

페이징 만들기

<div class="row">
	<div class="col-lg-12 txt_center">
		<ul class="pagination">
	     	<fmt:parseNumber var="screenPageNum" integerOnly="true" type="number" value="${pageNum/5}" />
			<fmt:parseNumber var="startScreenPageNum" integerOnly="true" type="number" value="${screenPageNum == 0 ? 1 : (screenPageNum * 5) + 1}" />
			<fmt:parseNumber var="endScreenNum" integerOnly="true" type="number" value="${(screenPageNum + 1) * 5 <= pages ? (screenPageNum + 1) * 5 : pages}" />
			<c:choose>
				<c:when test="${screenPageNum gt 0}">
					<li class="" id="p_previous_btn"><a href="#go_prevPage">&laquo;</a></li>
				</c:when>
				<c:otherwise>
					<li class="disabled" id="p_previous_btn"><a href="javascript:void(0);">&laquo;</a></li>
				</c:otherwise>
			</c:choose>
			<c:forEach var="i" begin="${startScreenPageNum}" end="${endScreenNum}">
				<li class="<c:if test="${i-1 eq pageNum}">active</c:if>"><a href="#go_Page" data-index="${i-1}">${i}</a>
				<li>
			</c:forEach>
			<c:choose>
				<c:when test="${(screenPageNum+1)*5 ge totalPageNum}">
					<li class="disabled" id="p_next_btn"><a href="javascript:void(0);">&raquo;</a></li>
				</c:when>
				<c:otherwise>
					<li class="" id="p_next_btn"><a href="#go_nextPage">&raquo;</a></li>
				</c:otherwise>
			</c:choose>
		</ul>
	</div>
</div>

<script type="text/javascript">
$(function(){
    $("a[href='#go_prevPage']").click(function(e) {
        e.preventDefault();
        var iPageNum = $("input[name='pageNum']").val();
        var screenPageNum = parseInt(iPageNum / 5);
        var ppn = (screenPageNum * 5) - 5;
        $("input[name='pageNum']").val(ppn);
        search(ppn);
    });

    $("a[href='#go_Page']").click(function(e) {
        e.preventDefault();
        var index = $(this).data("index");
        $("input[name='pageNum']").val(index);
        search(index);
    });

    $("a[href='#go_nextPage']").click(function(e) {
        e.preventDefault();
        var iPageNum = $("input[name='pageNum']").val();
        var screenPageNum = parseInt(iPageNum / 5);
        var npn = (screenPageNum + 1) * 5;
        $("input[name='pageNum']").val(npn);
        search(npn);
    });
});
</script>

 

총 페이지 개수와 현재페이지로 시작 페이지와 끝 페이지를 구한다.

첫 페이지와 마지막 페이지는 클릭이 안되게 하고 현재 페이지는 볼드를 넣어주어 다른 페이지번호와 다르게 표시한다.

 

페이지를 누르면 해당페이지로 이동이 되며 다음페이지나 이전페이지를 누를 경우 페이지묶음이 5개 단위로 변경되게 된다.

페이징 CSS

<style>
.pagination {
  display: inline-block;
  padding-left: 0;
  margin: 20px 0;
  border-radius: 4px;
}
.pagination > li {
  display: inline;
}
.pagination > li > a,
.pagination > li > span {
  position: relative;
  float: left;
  padding: 6px 12px;
  margin-left: -1px;
  line-height: 1.42857143;
  color: #428bca;
  text-decoration: none;
  background-color: #fff;
  border: 1px solid #ddd;
}
.pagination > li:first-child > a,
.pagination > li:first-child > span {
  margin-left: 0;
  border-top-left-radius: 4px;
  border-bottom-left-radius: 4px;
}
.pagination > li:nth-last-child(1) > a,
.pagination > li:nth-last-child(1) > span {
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}
.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
  color: #2a6496;
  background-color: #eee;
  border-color: #ddd;
}
.pagination > .active > a,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
  z-index: 1;
  color: #fff;
  cursor: default;
  background-color: #428bca;
  border-color: #428bca;
}
.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
  color: #999;
  cursor: not-allowed;
  background-color: #fff;
  border-color: #ddd;
}
.pagination-lg > li > a,
.pagination-lg > li > span {
  padding: 10px 16px;
  font-size: 18px;
}
.pagination-lg > li:first-child > a,
.pagination-lg > li:first-child > span {
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}
.pagination-lg > li:nth-last-child(1) > a,
.pagination-lg > li:nth-last-child(1) > span {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}
.pagination-sm > li > a,
.pagination-sm > li > span {
  padding: 5px 10px;
  font-size: 12px;
}
.pagination-sm > li:first-child > a,
.pagination-sm > li:first-child > span {
  border-top-left-radius: 3px;
  border-bottom-left-radius: 3px;
}
.pagination-sm > li:nth-last-child(1) > a,
.pagination-sm > li:nth-last-child(1) > span {
  border-top-right-radius: 3px;
  border-bottom-right-radius: 3px;
}
</style>

페이징 소스는 include로 만들어 넣어줬다.

리스트에서 총 페이지와 현재페이지수만 구하고 게시판 하단에 페이징 include 파일만 넣어주면 여러 게시판에서 활용도 있게 사용할 수 있다.