Back-End/Java

[Spring] Legacy Project 페이징 구현하기

CJun 2021. 6. 13. 14:09
반응형

 

페이징(Paging)이란?

사용자가 어떠한 데이터를 필요할때
데이터 중의 일부를 보여주는 방식이다.


예를 들자면 게시판에 등록된 글이 1000개라면
하나의 페이지에서 1000개의 데이터를 출력하게 된다면..?
로딩속도도 느려지고 사용자가 필요한 데이터를 찾는 불편하기 때문에
페이징과 검색 기능을 통해 해결할 수 있다.

BoardController.java

 

package com.example.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.example.domain.BoardVO;
import com.example.domain.Criteria;
import com.example.domain.PageDTO;
import com.example.service.BoardService;

import lombok.Setter;
import lombok.extern.java.Log;

@Controller
@RequestMapping("/board/*")
@Log
public class BoardController {
	
	@Setter(onMethod_ = @Autowired)
	private BoardService boardService;
	
	
	@GetMapping("/list")
	public String list(Criteria cri, Model model) {
		
		// board 테이블에서 전체글 리스트로 가져오기
		//List<BoardVO> boardList = boardService.getBoards();
		
		List<BoardVO> boardList = boardService.getList(cri);
		
		int totalCount = boardService.getTotalCount(); // 전체글개수 가져오기
		
		PageDTO pageDTO = new PageDTO(cri, totalCount);
		
		model.addAttribute("boardList", boardList);
		model.addAttribute("pageMaker", pageDTO);
		
		return "board/boardList";
	} // list
	
}

※ Board 테이블에서 전체글을 리스트로 가져와야만 한다.

 

PageDTO.java

 

package com.example.domain;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class PageDTO {
	
	private int startPage; // 시작페이지
	private int endPage;   // 끝페이지
	private boolean prev, next;  // 이전, 다음
	
	private int total;  // 전체 글개수
	private Criteria cri; // 요청한 페이지번호, 한페이지당 글개수
	
	public PageDTO(Criteria cri, int total) {
		
		this.cri = cri;
		this.total = total;
		
		// 여기서 5는 페이지블록을 구성하는 페이지 개수
		this.endPage =  (int) Math.ceil(cri.getPageNum() / 5.0) * 5;
		
		this.startPage = this.endPage - (5-1);
		
		// 실제 끝페이지
		int realEnd = (int) Math.ceil((double)total / cri.getAmount());
		
		if (realEnd < this.endPage) {
			this.endPage = realEnd;
		}
		
		this.prev = this.startPage > 1;
		
		this.next = this.endPage < realEnd;
		
	} // 생성자
	
	
}

시작페이지, 마지막페이지, 이전, 다음을 만들고

페이지블록을 구성하는 페이지 개수를 정함

 

Criteria.java

 

package com.example.domain;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Criteria {

	private int pageNum;  // 페이지번호
	private int amount;   // 한 페이지당 글개수
	
	public Criteria() {
		this(1, 10);
	}

	public Criteria(int pageNum, int amount) {
		this.pageNum = pageNum;
		this.amount = amount;
	}
}

private int pageNum = 페이지번호
private int amount = 한 페이지당 글개수

boardList.jsp

 

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

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>

<body>
    <!-- App -->
    <div id="app">

        <%-- include header.jsp --%>
		<jsp:include page="/WEB-INF/views/include/header.jsp" />

		<div class="container">
            <!-- Breadcrumbs -->
            <nav>
                <div class="nav-wrapper cyan">
                    <div class="col s12">
                        <a href="index.html" class="breadcrumb">홈</a>
                        <a href="boardList.html" class="breadcrumb">게시판 글목록</a>
                    </div>
                </div>
            </nav>
            <!-- end of Breadcrumbs -->

            
            <div class="row">
                <h4 class="center-align">게시판 글목록</h4>
                <hr style="margin-bottom: 50px;">
            </div>

            <div class="row">
                <a href="boardWrite.html" class="waves-effect waves-light btn right">
                    <i class="material-icons left">create</i>새글쓰기
                </a>
            </div>

            <div class="row">
                <!-- Table -->
                <table class="highlight responsive-table ">
                    <thead class="blue white-text">
                        <tr>
                            <th class="center-align">번호</th>
                            <th class="center-align">글제목</th>
                            <th class="center-align">글쓴이</th>
                            <th class="center-align">작성일</th>
                            <th class="center-align">조회수</th>
                        </tr>
                    </thead>
            
                    <tbody>
                    	<c:choose>
                    		<c:when test="${ pageMaker.total gt 0 }">
                    		
                    			<%-- pageScope → requestScope → sessionScope → applicationScope --%>
                    			<c:forEach var="board" items="${ boardList }">
                    				<tr onclick="location.href='/board/content'" style="cursor: pointer;">
			                            <td class="center-align">${ board.num }</td>
			                            <td>${ board.title }</td>
			                            <td class="center-align">${ board.mbrid }</td>
			                            <td class="center-align"><fmt:formatDate value="${ board.regDate }" pattern="yyyy.MM.dd" /></td>
			                            <td class="center-align">${ board.readcount }</td>
			                        </tr>
                    			</c:forEach>
                    			
                    		</c:when>
                    		<c:otherwise>
                    			<tr>
                    				<td colspan="5">게시판 글이 없습니다.</td>
                    			</tr>
                    		</c:otherwise>
                    	</c:choose>
                    </tbody>
                </table>
                <!-- end of Table -->
            </div>


            <div class="row center">
                <!-- Pagination -->
                <ul class="pagination">
                    <li class="${ pageMaker.prev ? 'waves-effect' : 'disabled' }"><a id="prev"><i class="material-icons">chevron_left</i></a></li>
                    
                    <c:forEach var="i" begin="${ pageMaker.startPage }" end="${ pageMaker.endPage }" step="1">
                    	<li class="${ pageMaker.cri.pageNum == i ? 'active' : 'waves-effect' }"><a href="/board/list?pageNum=${ i }">${ i }</a></li>
                    </c:forEach>
                    
                    <li class="${ pageMaker.next ? 'waves-effect' : 'disabled' }"><a id="next"><i class="material-icons">chevron_right</i></a></li>
                </ul>
                <!-- end of Pagination -->
            </div>


            <div class="row">
                <form action="">
                    <!-- AutoComplete -->
                    <div class="col s12 l6 offset-l3">
                        <div class="input-field">
                            <i class="material-icons prefix">find_in_page</i>
                            <input type="text" id="autocomplete-input" class="autocomplete">
                            <label for="autocomplete-input">검색</label>
                        </div>
                    </div>
                    <!-- end of AutoComplete -->
                </form>
            </div>



        </div>
        <!-- end of Container -->

        
        <!-- Footer -->
        <%-- include footer.jsp --%>
 		<jsp:include page="/WEB-INF/views/include/footer.jsp" />
        <!-- end of Footer -->

    </div>
    <!-- end of App -->
    


    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <script>
        const sideNav = document.querySelector('.sidenav');
        M.Sidenav.init(sideNav, {});

        const ac = document.querySelector('.autocomplete');
        M.Autocomplete.init(ac, {
            data: {
                '파리': null,
                '베네치아': null,
                '암스테르담': null,
                '부다페스트': null,
                '프랑크푸르트': null,
                '비엔나': null,
                '드라스덴': null,
                '프라하': null,
                '로마': null
            }
        });
    </script>
    <script>
    	// [이전] a태그 클릭이벤트
    	var prev = document.querySelector('a#prev');
    	
    	prev.addEventListener('click', function (event) {
    		event.preventDefault();
    		
    		var isPrev = ${ pageMaker.prev };
    		if (!isPrev) {
    			return;
    		}
    		location.href = '/board/list?pageNum=${ pageMaker.startPage - 1 }';
    	});
    	
    	// [다음] a태그 클릭이벤트
		var next = document.querySelector('a#next');
    	
		next.addEventListener('click', function (event) {
			event.preventDefault();
			
    		var isNext = ${ pageMaker.next };
    		if (!isNext) {
    			return;
    		}
    		location.href = '/board/list?pageNum=${ pageMaker.endPage + 1 }';
    	});
    
    </script>
</body>

</html>

 

반응형