페이징 처리는 웹 개발에서 필수적인 기술이며, 요즘은 무한스크롤로 처리하는 경우도 많다. 무한스크롤 + 페이징을 접목하는 경우도 다수 본 것 같다. (...나중에 써봐야징..) 페이징을 처리하는 방법은 여러가지가 있지만, 간단한 예제를 통해서 가장 기본이 되는 방식으로 구현해 보자 !!
실제 이런식으로 설계하면 큰일 나겠지만 페이징처리가 목적이니 간단하게 설계하였다. (심지어 content도 안만듬 ㅋ)
(id, title, user .. 진짜 간단 머쓱..)
Pagination.java
public class Pagination {
/** 1. 페이지 당 보여지는 게시글의 최대 개수 **/
private int pageSize = 10;
/** 2. 페이징된 버튼의 블럭당 최대 개수 **/
private int blockSize = 10;
/** 3. 현재 페이지 **/
private int page = 1;
/** 4. 현재 블럭 **/
private int block = 1;
/** 5. 총 게시글 수 **/
private int totalListCnt;
/** 6. 총 페이지 수 **/
private int totalPageCnt;
/** 7. 총 블럭 수 **/
private int totalBlockCnt;
/** 8. 블럭 시작 페이지 **/
private int startPage = 1;
/** 9. 블럭 마지막 페이지 **/
private int endPage = 1;
/** 10. DB 접근 시작 index **/
private int startIndex = 0;
/** 11. 이전 블럭의 마지막 페이지 **/
private int prevBlock;
/** 12. 다음 블럭의 시작 페이지 **/
private int nextBlock;
// Getter
// Seteer
}
우선 페이징을 처리하는 Pagination 클래스를 생성한다. 변수 생성하고 주석도 달아 놓았지만, 내가 쓰고도 내가 이해하기 어려운 주석들이 있어서 추가하자면.. (setter, getter는 스크롤을 너무 잡아먹기에 생략..)
주석 번호
설명
2번 - int blockSize
// 페이징된 버튼의 블럭당 최대 개수 ? 위 캡쳐와 같이 페이징된 버튼들이 노출되는 최대 개수를 정해주는것. 블럭사이즈의 개수를 정해주지 않는다면 페이지가 UI상에서 끝도없이 늘어만 간다. 적절하기 개수 제한을 해주는 것이 바람직한듯?
ex) 위의 예시는 5개로 제한을 해준 것이며, 총 페이징 수가 14개일 경우, [1 2 3 4 5]---[5 6 7 8 9 10]---[11 12 13 14]
7번 - int totalBlockCnt
// 총 블럭 수 ? blockSize로 인해서 생성된 블럭의 총 개수를 의미한다.
ex) 총 페이징 수가 14개이고 blockSize가 5일 경우 [1 2 3 4 5]---[6 7 8 9 10] --- [11 12 13 14] 총 블럭 수 는 3개 된다.
10번 - int startIndex
// DB 접근 시작 index ? DB에 접근해서 게시물을 select할 때, 어디서부터 가져올 것인지에 대한 offset 역할을 해주는 부분
이어서 Pagination class에 페이칭 처리를 하는 메소드를 추가하자.
Pagination.java
public class Pagination {
...
// 위에서 정의한 변수
...
// setter
// getter
public Pagination(int totalListCnt, int page) {
// 총 게시물 수와 현재 페이지를 Controller로 부터 받아온다.
// 총 게시물 수 - totalListCnt
// 현재 페이지 - page
/** 3. 현재 페이지 **/
setPage(page);
/** 5. 총 게시글 수 **/
setTotalListCnt(totalListCnt);
/** 6. 총 페이지 수 **/
// 한 페이지의 최대 개수를 총 게시물 수 * 1.0로 나누어주고 올림 해준다.
// 총 페이지 수 를 구할 수 있다.
setTotalPageCnt((int) Math.ceil(totalListCnt * 1.0 / pageSize));
/** 7. 총 블럭 수 **/
// 한 블럭의 최대 개수를 총 페이지의 수 * 1.0로 나누어주고 올림 해준다.
// 총 블럭 수를 구할 수 있다.
setTotalBlockCnt((int) Math.ceil(totalPageCnt * 1.0 / blockSize));
/** 4. 현재 블럭 **/
// 현재 페이지 * 1.0을 블록의 최대 개수로 나누어주고 올림한다.
// 현재 블록을 구할 수 있다.
setBlock((int) Math.ceil((page * 1.0)/blockSize));
/** 8. 블럭 시작 페이지 **/
setStartPage((block - 1) * blockSize + 1);
/** 9. 블럭 마지막 페이지 **/
setEndPage(startPage + blockSize - 1);
/* === 블럭 마지막 페이지에 대한 validation ===*/
if(endPage > totalPageCnt){this.endPage = totalPageCnt;}
/** 11. 이전 블럭(클릭 시, 이전 블럭 마지막 페이지) **/
setPrevBlock((block * blockSize) - blockSize);
/* === 이전 블럭에 대한 validation === */
if(prevBlock < 1) {this.prevBlock = 1;}
/** 12. 다음 블럭(클릭 시, 다음 블럭 첫번째 페이지) **/
setNextBlock((block * blockSize) + 1);
/* === 다음 블럭에 대한 validation ===*/
if(nextBlock > totalPageCnt) {nextBlock = totalPageCnt;}
/** 10. DB 접근 시작 index **/
setStartIndex((page-1) * pageSize);
}
}
Controller 에서 전체 게시물 수(totalListCnt)와 현재 페이지(page)를 생성자에서 받고 setting을 시작한다.
주석에 달린 숫자의 의미는 위에서 정의한 변수에 해당하는 번호로 편의를 위해 달아두었다.
코드 중간에 validation이 걸려있는 코드가 있는데 처음에 깜빡하고 그냥 작업하다가 [이전] 페이지를 눌렀는데 0 페이지를 호출하는 error가 발생했다. 잊지말고 validation을 해줘야 예상하지 못한 error를 막을 수 있다.:)
validation 편안..
이 정도로 Pagination classs 설정을 마치고 Controller와 Repository 를 함께 살펴보자.
HomeController.java
@GetMapping("/")
public String home(Model model, @RequestParam(defaultValue = "1") int page) {
// 총 게시물 수
int totalListCnt = boardRepository.findAllCnt();
// 생성인자로 총 게시물 수, 현재 페이지를 전달
Pagination pagination = new Pagination(totalListCnt, page);
// DB select start index
int startIndex = pagination.getStartIndex();
// 페이지 당 보여지는 게시글의 최대 개수
int pageSize = pagination.getPageSize();
List<Board> boardList = boardRepository.findListPaging(startIndex, pageSize);
model.addAttribute("boardList", boardList);
model.addAttribute("pagination", pagination);
return "index";
}
BoardRepository.java
@Repository
public class BoardRepository {
@PersistenceContext
private EntityManager em;
public int findAllCnt() {
return ((Number) em.createQuery("select count(*) from Board")
.getSingleResult()).intValue();
}
public List<Board> findListPaging(int startIndex, int pageSize) {
return em.createQuery("select b from Board b", Board.class)
.setFirstResult(startIndex)
.setMaxResults(pageSize)
.getResultList();
}
}
진행과정
@RequestParam(dafault = "1") int page 를 통해 해당 요청 파라미터를 받는다. (default는 1)
Repository에서 총 게시물의 수를 select 해온다.
1번 과정의 현재 페이지와 2번 과정의 총 게시물 수를 Pagination를 매개변수로 생성한다.
위에 짜둔 Pagination 메서드로 인해서 쨔르르르~ 페이징에 필요한 변수 세팅이 완료 된다.