SPRING

[Spring] 페이징(Pagination)

라텐느 2024. 10. 20. 21:17
반응형

페이징(paging)은 데이터베이스에서 대량의 데이터를 효율적으로 표시하기 위해 아래와 같이여러 페이지로 나누는 것이다.


1. 페이징의 기본 원리

  • 총 데이터 수 (Total Record Count): 데이터베이스에서 조회할 수 있는 전체 데이터의 수
  • 페이지 크기 (Record Size): 한 페이지에 표시할 데이터(인스턴스)의 수
  • 현재 페이지 번호 (Current Page): 사용자가 현재 보고 있는 페이지의 번호
  • 전체 페이지 수 (Total Page Count): 위 사진에서 총 8페이지가 있는 것과 같다.


2. 코드에서의 페이징 구현

페이징은 Pagination 클래스와 SearchVo 클래스에서 처리된다.

 

2.1. Pagination 클래스

  • startPage: 현재 페이지 그룹의 시작 페이지 번호
  • endPage: 현재 페이지 그룹의 끝 페이지 번호
  • imitStart: 데이터베이스 쿼리에서 사용할 LIMIT 시작 위치
  • existPrevPage: 이전 페이지의 존재 여부
  • existNextPage: 다음 페이지의 존재 여부
Pagination 클래스의 생성자는 totalRecordCount와 SearchVo 객체를 받아 페이징 정보를 계산한다.



private void calculation(SearchVo params) {
    // 전체 페이지 수 계산
    totalPageCount = (int) Math.ceil((double) totalRecordCount / (double) params.getRecordSize());

    // 현재 페이지 번호가 전체 페이지 수보다 큰 경우, 현재 페이지 번호에 전체 페이지 수 저장
    if (params.getPage() > totalPageCount) {
        params.setPage(totalPageCount);
    }

    // 첫 페이지 번호 계산
    startPage = ((params.getPage() - 1) / params.getPageSize()) * params.getPageSize() + 1;

    // 끝 페이지 번호 계산
    endPage = startPage + params.getPageSize() - 1;

    // 끝 페이지가 전체 페이지 수보다 큰 경우, 끝 페이지 전체 페이지 수 저장
    if (endPage > totalPageCount) {
        endPage = totalPageCount;
    }

    // LIMIT 시작 위치 계산
    limitStart = (params.getPage() - 1) * params.getRecordSize();

    // 이전 페이지 존재 여부 확인
    existPrevPage = startPage != 1;

    // 다음 페이지 존재 여부 확인
    existNextPage = (endPage * params.getRecordSize()) < totalRecordCount;
}

 

  • 총 페이지 수 계산: 전체 데이터 수를 페이지 크기로 나누어 전체 페이지 수를 계산한다.
  • 페이지 번호 보정: 사용자가 요청한 페이지 번호가 전체 페이지 수를 초과할 경우 현재 페이지를 전체 페이지로 수정하고, 끝 페이지가 전체 페이지를 초과할 경우 끝 페이지를 전체 페이지로 정한다.
  • 페이지 범위 설정: 현재 페이지에 따라 시작 페이지 및 끝 페이지를 설정한다.
  • LIMIT 시작 위치 계산: 데이터베이스 쿼리에서 사용할 OFFSET 값을 계산한다.
(LIMIT은 가져올 데이터의 양, OFFSET은 가져올 데이터의 시작위치이다.)


2.2. SearchVo 클래스

  • page: 현재 페이지 번호
  • recordSize: 페이지당 출력할 데이터 개수
  • pageSize: 화면 하단에 출력할 페이지 사이즈
  • pagination: 페이징 정보를 담고 있는 Pagination 객체
public int getOffset() {
    return (page - 1) * recordSize;
}

현재 페이지 에서 데이터 베이스 쿼리에 사용할 OFFSET값을 계산한다. 즉 현재 페이지 번호가 3이고 페이지당 출력할 데이터 개수가 10개라면 20번째 데이터부터 3번째 페이지가 시작하는 것이다.

 

2.3. PagingRespose

@RequestMapping("List")
public   ModelAndView   list(int nowpage, BoardVo  boardVo) {
	// 메뉴 목록
	List<MenuVo>  menuList =  menuMapper.getMenuList();
	
	
	//------------------------------------
	// 게시물 목록 조회 (페이징해서)
	//   해당하는 자료수가 1 보다 작으면
	//   응답 데이터에 비어있는 리스트와 null 을 담아 리턴 
	// count : boardVo 안의 menu_id 에 해당하는 총자료수		
	int  count  = boardPagingMapper.count( boardVo );
	System.out.println( count );   // totalRecordCount

    PagingResponse<BoardVo> response = null;
    if( count < 1 ) {   // 현재 Menu_id 조회한 자료가 없다면
    	response = new PagingResponse<>(
    		Collections.emptyList(), null);
    	// Collections.emptyList() : 자료는 없는 빈 리스트를 채운다
    }
  • boardPagingMapper.count(boardVo)를 호출하여 특정 메뉴 ID에 해당하는 게시물의 총 개수를 조회한다.
    
    // 페이징을 위한 초기설정
    SearchVo  searchVo = new SearchVo();
    searchVo.setPage(nowpage);   // 현재 페이지 정보
    searchVo.setRecordSize(10);  // 페이지당 10개
    searchVo.setPageSize(10);    // paging.jsp 에 출력할 페이지번호수

    // Pagination 설정
    Pagination  pagination = new Pagination(count, searchVo);
    searchVo.setPagination(pagination);
  • Pagination 객체를 생성하여 총 게시물 수와 SearchVo 객체를 사용하여 페이징 정보를 계산 후, searchVo에 이 pagination 객체를 설정한다.
    String   menu_id     =  boardVo.getMenu_id();
  //  String   menu_id     =  "MENU02";
    
    // 추가된 조회 옵션들
    String   title       =  boardVo.getTitle();
  //  String   title       =  "Spring3";
    String   writer      =  boardVo.getWriter();
    String   content     =  boardVo.getContent();
 // 추가된 조회 옵션들 끌
    
    int      offset      =  searchVo.getOffset();
    int      recordSize  =  searchVo.getRecordSize();
    
    List<BoardVo> list = boardPagingMapper.getBoardPagingList(
    	menu_id, title, writer, content, offset, recordSize );
    response = new PagingResponse<>(list, pagination);
    
    System.out.println(response);
  	    				
	ModelAndView  mv  =  new  ModelAndView();
	mv.addObject("menuList", menuList);
	
	mv.addObject("menu_id",   menu_id );
	mv.addObject("nowpage",   nowpage );
	
	mv.addObject("searchVo",  searchVo );
	
	mv.addObject("response", response );
	
	mv.setViewName("boardpaging/list");
	return        mv;
}
  • 조회된 게시물 목록과 페이징 정보를 담아 PagingResponse 객체를 생성해 변수 response에 담는다.

 

@Getter
@ToString
public class PagingResponse<T> {
	// 현재 페이지에 보여줄 db 자료 : 10 줄 짜리 record - select 결과
	private   List<T>      list = new ArrayList<>();  
	
	// 아래의 paging.jsp 에서 사용할 변수들
	private   Pagination   pagination;

	public PagingResponse(List<T> list, Pagination pagination) {
		this.list.addAll( list );
		this.pagination = pagination;
	} 
	
	
	
}

조회된 게시물 목록과 페이징 정보를 PagingResponse에 담아 클라이언트에게 전달한다.

3. MyBatis 페이징

 

SELECT
    IDX, MENU_ID, TITLE, WRITER, TO_CHAR(REGDATE, 'YYYY-MM-DD') REGDATE, HIT
FROM
    BOARD
WHERE
    MENU_ID = #{arg0} AND
    TITLE = #{arg1} AND
    WRITER = #{arg2} AND
    CONTENT = #{arg3}
ORDER BY
    IDX DESC
OFFSET #{arg4} ROWS FETCH NEXT #{arg5} ROWS ONLY

 

OFFSET: 가져올 데이터의 시작 위치이다. 여기서 #{arg4}는 limitStart로, 현재 페이지에 맞는 시작 위치를 계산하여 전달합니다.
FETCH NEXT: 지정한 수만큼의 행을 반환한다. 여기서 #{arg5}는 페이지당 데이터 수(recordSize)를 전달한다.


4. pagin.jsp

<c:if test="${ startnum gt 1 }">
    <td>
        <a href="/BoardPaging/List?menu_id=${menu_id}&nowpage=1">⏮</a>
    </td>
    <td>  
        <a href="/BoardPaging/List?menu_id=${menu_id}&nowpage=${startnum-1}">◀</a>
    </td>
</c:if>
<c:forEach var="pagenum" begin="${startnum}" end="${endnum}" step="1">
    <td>
        <c:if test="${ pagenum ne 0 }">
            <a href="/BoardPaging/List?menu_id=${menu_id}&nowpage=${pagenum}">
                ${ pagenum }
            </a>
        </c:if> 
    </td>
</c:forEach>
<c:if test="${ endnum ne totalpagecount }"> 
    <td>
        <a href="/BoardPaging/List?menu_id=${menu_id}&nowpage=${endnum+1}">▶</a>
    </td>
    <td>
        <a href="/BoardPaging/List?menu_id=${menu_id}&nowpage=${totalpagecount}">⏭</a>
    </td>
</c:if>

 

📍jstl (부)등호 문법
== : eq
!= : ne
< : lt
> : gt
<= : le
>= : ge

 

 

반응형