본문 바로가기
⚙️Backend/Spring

[Spring] Paging + PageMaker 알고리즘

by Bㅐ추 2020. 6. 22.
728x90
반응형

 

나중에 유용하게 쓸 일이 있을 것 같아서 따로 정리한다.

해당 게시글의 뼈대(?)는 https://blog.naver.com/jydev/220797272899블로그를 이다. 정말.. 이해하기 쉽게 설명해주셧고 JSP코드로 이루어져 있지만 이해만 했다면 java코드 및 서블릿로 변환하기 쉬울 것이다.


1. Paging

Paging이란 게시판을 page단위로 나누는 행위를 의미한다. 모든 알고리즘은 직접 구현해보는 것이 가장 좋다.  특히, 페이징의 경우는 어느 게시판에서도 적용되는 알고리즘이기 때문에 남의 코드를 가져다 쓰면 매번 페이징을 할 때 마다 남의 코드를 가져다 써야 한다. 처음에는 남의 코드를 참고해서 작성하되, 그 코드를 자신의 것으로 만들어야 한다. 

 

페이징 기능이 적용되지 않는다면 만약 게시판 DB에 100개의 게시글이 있다면 100개의 게시글이 모두 보여진다.ㅋㅋ 만약 1000개 10000개가 된다면....ㅎ.. ㅋㅋㅋㅋㅋ

 

2. Paging  객체 구상

Paging을 구현하기 전 지켜야 할 규칙을 구상해보자. 먼저 페이징이 어떤 식으로 처리되는지 이해해보자. 

페이징 객체에 필요할 변수들은 무엇이 있을 지 생각해보자.

일단 현재 페이지가 몇 페이지인지 알려주는 변수가 필요할 것이다.

그리고 그 페이지에 맞춰서 board table에 게시글들을 가져와야 하므로, 페이지에 출력 될 게시글의 시작 행과 끝 행을 저장할 변수가 필요하다.

그리고 해당 페이지가 총 몇 페이지 인지 알 수 있는 변수가 필요하며, 총 몇페이지 인지 알기 위해서는 총 게시글의 개수도 알아야 한다. 마지막으로 한 페이지에 출력 될 게시글의 개수도 알아야 한다.

 

정리하자면,

  1. 현재 페이지가 몇 페이지 인지 알려주는 변수 ==> int page
  2. 페이지에 출력 될 게시글의 시작 행과 끝행을 저장할 변수 ==> int startRow, int endRow
  3. 해당 페이지의 총 개수 ==> int totalPage
  4. 총 게시글의 개수 ==> int totalArticle
  5. 한 페이지에 출력될 게시글의 개수 ==> int pageSize
public class Paging {
	private int page; // 페이지 번호 : 현재 몇 페이지 인지 << [1] [2] [3] [4] [5] >> 이런 식의 페이지 번호를 나타내는 것.
	private int totalPage; // 페이지 갯수 :  << [1] [2] [3] [4] [5] >> 총 5개의 페이지
	private int pageSize = 9; // 한 페이지 게시글 개수 : 한 페이지에 출력 될 개시글 개수
	private int totalArticle; //전체 게시글 개수
	private int startRow; // 한 페이지에 게시글 시작 행
	private int endRow; // 한 페이지에 게시글 끝 행
	// -----> 한 페이지 내에 출력되는 게시글의 개수가 10개라면, startRow + endRow 합쳐서 한 페이지 당 총 10개 보여주기. (startRow(1) + endRow(10))
	
	public Paging() {
		super();
		// TODO Auto-generated constructor stub
	}
		
	
	// 페이지 번호 설정
	public void setPage(int page) {
		// 페이지 번호가 없을 때 1로 맞춰줌
		if (page <= 0) {
			this.page = 1;
			return;
		}
		this.page = page;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}


	// 전체 게시글 갯수
	public void setTotalArticle(int totalArticle) {
		this.totalArticle = totalArticle;
	}
	
	// 페이지 갯수
	public void setTotalPage(int totalArticle) {
		this.totalPage = this.totalArticle/this.pageSize + (this.totalArticle%this.pageSize==0?0:1);
		
		// 유효성 검사
		if(this.page <=0 || this.page > totalPage){
			this.page = 1;
		}
	}
	
	// 게시글 시작 행 설정
	public void setStartRow() {
		this.startRow = (this.page - 1) * this.pageSize + 1;
	}
	
	// 게시글 끝 행 설정
	public void setEndRow() {
		this.endRow = page * pageSize;
		if(endRow > this.totalArticle) endRow = this.totalArticle;	
	}
    // 생략....
	
	}

3. Paging객체가 동작하는 순서

* 시작하기 전, 한 페이지에 출력될 게시글의 개수를 변경하고 싶으면 setter를 이용하여 pageSize 변경.

 

1 ) page가 바뀔 때 마다 setPage

	// 페이지 번호 설정
	public void setPage(int page) {
		// 페이지 번호가 없을 때 1로 맞춰줌
		if (page <= 0) {
			this.page = 1;
			return;
		}
		this.page = page;
	}

 

2 ) 전체 게시글 개수

	// 전체 게시글 갯수
	public void setTotalArticle(int totalArticle) {
		this.totalArticle = totalArticle;
	}

먼저 게시글이 총 몇 개인지 가져와서 설정을 해준다. 해당 쿼리는 다음과 같다.

SELECT COUNT(*) FROM BOARD_TB

 

게시글 총 개수를 받아왔으니, 그 개수를 이용하여 페이지의개수를 구할 수 있다.

 

3) 페이지 개수 구하기

	// 페이지 갯수
	public void setTotalPage(int totalArticle) {
		this.totalPage = this.totalArticle/this.pageSize + (this.totalArticle%this.pageSize==0?0:1);
		
		// 유효성 검사
		if(this.page <=0 || this.page > totalPage){
			this.page = 1;
		}
	}

 

만약, 현재 총 게시글이 32개가 존재하고 한 페이지 당  5개의 게시글이 보여진다면 총 몇 개의 페이지가 있을까?
일단 확실한 건 한 페이지에는 5개의 페이지가 출력된다.
그렇다면 32개의 게시글은 몇 페이지 일까?
확실한건, 32/5 = 6 , 6페이지가 필요하다.
하지만, 남은 2개의 게시글도 출력해주어야 하므로 남은 2개의 게시글을 출력하기 위한 한 개의 페이지가 더 필요하다.
이걸 식으로 나타내어 보면,
32/5 + 1  = 7
총 7페이지가 필요하다.

다시, 그렇다면 30개의 게시글은 총 몇페이지 일까?
30/5 = 6페이지가 필요하다. 남은 페이지가 없으므로 그대로 6페이지만 있으면 된다.

30/5 + (30%5) = 7

식을 정리해보면,
this.totalPage  =  this.totalArticle / this.pageSize  +  (this.totalArticle % this.pageSize == 0 ? 0:1);

4) 게시글 시작 행과 끝 행 설정하기

	// 게시글 시작 행 설정
	public void setStartRow() {
		this.startRow = (this.page - 1) * this.pageSize + 1;
	}
	
	// 게시글 끝 행 설정
	public void setEndRow() {
		this.endRow = page * pageSize;
		if(endRow > this.totalArticle) endRow = this.totalArticle;	
	}

 

SELECT PAGING.TITLE,PAGING.WIRTE_DATE,...
FROM (SELECT ROWNUM RN, TEMP.*
	FROM (SELECT * FROM BOARD WHERE BOARDNO DESC) TEMP
	) PAGING
WHERE PAGING.RN BETWEEN #{startRow} AND #{endRow}

4. PageMaker  구상하기

이제 아래 페이지 블록을 구현하기 전 필요한 변수들을 구상해보자.

일단 몇 개의 페이지 블럭을 보여줄 것인지 알아야 한다. 그리고 페이지 블럭에 출력 될 시작 페이지와 마지막페이지를 알 수 있어야한다. 그리고 이전,다음 버튼이 있는지 없는지를 알아야 할 것이다. 해당 pageMaker는 Paging에 의존한다.

 

정리하자면,

  1. 페이지 블럭의 개수 ==> int displayBlockNum
  2. 출력 될 시작 페이지 ==> int startPage
  3. 출력 될 마지막 페이지 ==> int endPage
  4. 이전 , 다음 버튼 여부 ==> boolean prev , boolean next
  5. 페이징 객체 ==> Paging paging
public class PageMaker {
	private final static int displayBlockNum = 5; // 페이지 블럭 개수 << [<] [1] [2] [3] [4] [5] [>] >> 일 때, 5 
	private int startPage = 1; // 페이지 블럭에 출력 될 시작 페이지
	private int endPage; // 페이지 블럭에 출력 될 마지막 페이지
	private boolean prev; //이전
	private boolean next; //다음
	private Paging paging;
	
	public void setPaging(Paging paging) {
		this.paging = paging;
		calcData();
	}
	
	private void calcData() {
		
		this.startPage = ( paging.getPage()/this.displayBlockNum-(paging.getPage()%this.displayBlockNum!=0?0:1))*this.displayBlockNum+1;
		this.endPage = this.startPage + this.displayBlockNum - 1;
					
		if(this.endPage>paging.getTotalPage()) {this.endPage=paging.getTotalPage();}
		
		// 이전 버튼 생성 여부 = 시작 페이지 번호 == 1 ? false : true (시작페이지가 1이 아니면 생김)
		prev = startPage == 1 ? false : true;
		// 다음 버튼 생성 여부 = 끝 페이지 번호 * 한 페이지당 보여줄 게시글의 갯수 < 총 게시글의 수 ? true: false
		next = endPage * paging.getPageSize() < paging.getTotalArticle() ? true : false;
	}
    
//... 생략

}

여기서 block이란 1~5 page가 속해있는 그룹을 의미한다. 6~10 page는 1~5 page와 다른 그룹이 되는 것이다. 그 block의 첫번째 page번호를 startPage, 마지막 page번호를 endPage이라는 변수에 담는 것이다.

https://blog.naver.com/jydev/220797272899

728x90
반응형