본문 바로가기

자바/스프링부트 기초

스프링부트! 게시판 만들면서 배우기! 3-1 . 페이징!

이번 글에는 저번글에서 구현만하고 넘어갔던 페이징기법에 대해서 공부해보도록 하겠습니다.

 

우선 페이징에 필요한 변수들을 선언해놧던 Criteria부터 살펴보도록 하겠습니다.

 

package com.example.starter.pageing;

import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import lombok.Data;

@Data
public class Criteria {
	
	/** 현재 페이지 번호 */
	private int currentPageNo;

	/** 페이지당 출력할 데이터 개수 */
	private int recordsPerPage;

	/** 화면 하단에 출력할 페이지 사이즈 */
	private int pageSize;

	/** 검색 키워드 */
	private String searchKeyword;

	/** 검색 유형 */
	private String searchType;

	public Criteria() {
		this.currentPageNo = 1;
		this.recordsPerPage = 10;
		this.pageSize = 10;
	}

	public String makeQueryString(int pageNo) {

		UriComponents uriComponents = UriComponentsBuilder.newInstance()
				.queryParam("currentPageNo", pageNo)
				.queryParam("recordsPerPage", recordsPerPage)
				.queryParam("pageSize", pageSize)
				.queryParam("searchType", searchType)
				.queryParam("searchKeyword", searchKeyword)
				.build()
				.encode();

		return uriComponents.toUriString();
	}
}

1. currentPageNo : 현재 보여지고 있는 페이지의 번호를 뜻합니다.

2. recordPerPage :  한페이지당 보여질 게시물 갯수입니다. 6으로 되면 한페이지당 6개의 글을 보여줍니다.

3. pageSize : 하단에 출력될 페이지 번호 수 입니다. 

4. searchKeyword : 검색 기능 사용시 사용될 검색어 변수 입니다.

5. searchType :  검색 기능 사용시 사용될 검색 필터변수 입니다( (예) 작성자 , 내용, 제목) )

6. 생성자 초기화 :  객체 생성시 초기값들을  지정해줍니다.

7. makeQueryString : 

 

 

다음은 Dao 부분을 보겠습니다

	<select id="selectArticleList" parameterType="Article" resultType="Article">
		SELECT
			*
		FROM
			article
		ORDER BY
			aid DESC
		LIMIT
			#{paginationInfo.firstRecordIndex}, #{recordsPerPage}
	</select>

MySQL에서는 페이징을 LIMIT문을 이용하여 처리합니다.

LIMIT 10 ,20 ; 이라고하면 10번쨰 레코드부터 시작해서 10개를 가져온다 라는 의미입니다.

 

Dao에서는 시작 레코드 번호 부터 recordsPerPage 페이지당 보여줄 게시물 갯수만큼 가져와서 보여주겠다는 의미입니다.

 

 

자 다음은 Pagin 계산 클래스PaginationInfo 를 보겠습니다.

 

package com.example.starter.pageing;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
public class PaginationInfo {

	/** 페이징 계산에 필요한 파라미터들이 담긴 클래스 */
	private Criteria criteria;

	/** 전체 데이터 개수 */
	private int totalRecordCount;

	/** 전체 페이지 개수 */
	private int totalPageCount;

	/** 페이지 리스트의 첫 페이지 번호 */
	private int firstPage;

	/** 페이지 리스트의 마지막 페이지 번호 */
	private int lastPage;

	/** SQL의 조건절에 사용되는 첫 RNUM */
	private int firstRecordIndex;

	/** SQL의 조건절에 사용되는 마지막 RNUM */
	private int lastRecordIndex;

	/** 이전 페이지 존재 여부 */
	private boolean hasPreviousPage;

	/** 다음 페이지 존재 여부 */
	private boolean hasNextPage;

	public PaginationInfo(Criteria criteria) {
		if (criteria.getCurrentPageNo() < 1) {
			criteria.setCurrentPageNo(1);
		}
		if (criteria.getRecordsPerPage() < 1 || criteria.getRecordsPerPage() > 100) {
			criteria.setRecordsPerPage(10);
		}
		if (criteria.getPageSize() < 5 || criteria.getPageSize() > 20) {
			criteria.setPageSize(10);
		}

		this.criteria = criteria;
	}

	public void setTotalRecordCount(int totalRecordCount) {
		this.totalRecordCount = totalRecordCount;

		if (totalRecordCount > 0) {
			calculation();
		}
	}

	private void calculation() {

		/* 전체 페이지 수 (현재 페이지 번호가 전체 페이지 수보다 크면 현재 페이지 번호에 전체 페이지 수를 저장) */
		totalPageCount = ((totalRecordCount - 1) / criteria.getRecordsPerPage()) + 1;
		if (criteria.getCurrentPageNo() > totalPageCount) {
			criteria.setCurrentPageNo(totalPageCount);
		}

		/* 페이지 리스트의 첫 페이지 번호 */
		firstPage = ((criteria.getCurrentPageNo() - 1) / criteria.getPageSize()) * criteria.getPageSize() + 1;

		/* 페이지 리스트의 마지막 페이지 번호 (마지막 페이지가 전체 페이지 수보다 크면 마지막 페이지에 전체 페이지 수를 저장) */
		lastPage = firstPage + criteria.getPageSize() - 1;
		if (lastPage > totalPageCount) {
			lastPage = totalPageCount;
		}

		/* SQL의 조건절에 사용되는 첫 RNUM */
		firstRecordIndex = (criteria.getCurrentPageNo() - 1) * criteria.getRecordsPerPage();

		/* SQL의 조건절에 사용되는 마지막 RNUM */
		lastRecordIndex = criteria.getCurrentPageNo() * criteria.getRecordsPerPage();

		/* 이전 페이지 존재 여부 */
		hasPreviousPage = firstPage != 1;

		/* 다음 페이지 존재 여부 */
		hasNextPage = (lastPage * criteria.getRecordsPerPage()) < totalRecordCount;
	}

}

1.criteria  : 페이징 계산에 필요한 변수들을 저장해놓은 criteria입니다

2. totalRecordCount : 총 게시물 갯수입니다. dao에 getTotalCount()를 이용해서 가져올 수 있습니다.

3. totalPageCount : 게시물에 따라 생기는 페이지 갯수입니다.

4. firstPage :  페이지에 따른 첫 게시물의 번호입니다.

5. lastPage : 페이지에 따른 마지막 게시물의 번호입니다.

6. firstRecordIndex : limit절에 사용할 첫번째 인자입니다.

7. lastRecordIndex : Oracle 등 Limit절이 없는 db 에서 필요한 변수입니다. Mysql에서는 사용안해도됩니다.

7. hasPreviousPage : 이전 페이지 존재 여부를 저장할 변수입니다.

8. hasNextPage : 다음 페이지 존재 여부를 저장할 변수 입니다.

 

PaginationInfo(Critera criteria)

- 만약 현재페이지가 0보다 작으면 현재페이지를 1로 저장해줍니다.

- 한 페이지당 보여질 게시물의 갯수가 1보다 작거나 100보다 크면  10으로 다시 세팅해줍니다.

- 페이지 갯수가 5개 아래거나 20개 이상이면 10개로 맞춰줍니다.

 

calculation 메소드

 

-totalPageCount = (전체 데이터 갯수 - 1)/페이지당 출력할 데이터 수 )+1입니다.

만약 30개 데이터가있고 페이지당 10개를 출력한다면

(30-1)/10 +1 = 2.9+1 = 3.9로 3이됩니다.

 

-firstPage = (현재페이지 번호 -1)/ 페이지의 갯수)* 페이지의 갯수 +1입니다.

현재 페이지가 13페이지이고 페이지의 갯수를 10개씩 한다고하면

(13-1)/10*10+1  -> (1.2=1)*10+1 =11이됩니다. 

 

-lastPage  = ( 첫 페이지 번호 + 페이지 갯수) -1입니다. 

현재 페이지가 13페이지고 페이지의 갯수를 10개씩이라고하면

firstPage를 구하면 11이되고 11+10-1 = 20이됩니다.

 

이렇게 페이징에 필요한 변수와 계산법을 알아봤구요

이제 CommonDto를 만들고 상속시키고 사용하는지 알아보겠습니다

Controller는 본 목적이 뷰에 데이터를 전달하는 목적입니다.

때문에 Critria, PaginationInfo 등을 그대로 쓰면 컨트롤러 단에서  불필요한 코드가 생깁니다.

이를 MVC패턴에 맞게 바꾸기위함입니다.

// 사용 중인 전체 게시글 수를 구한다.
int boardTotalCount = boardService.getBoardTotalCount(criteria);

// PaginationInfo 클래스의 객체를 생성하여 전체 게시글 수를 저장한다.
PaginationInfo paginationInfo = new PaginationInfo(criteria);
paginationInfo.setTotalRecordCount(boardTotalCount);

// 계산된 페이징 정보를 뷰로 전달한다.
model.addAttribute("paginationInfo", paginationInfo);

출처-https://congsong.tistory.com/26