이번 글은 게시글 리스트 페이지에 페이징 기능을 적용한 과정을 담았다.

 

페이징을 적용하기 전에는 불러온 게시글 목록이 한 번에 모두 표시되어 사용자가 많은 양의 정보를 한꺼번에 보게 되었다. 그러나 페이징 기능을 적용한 후, 한 페이지당 10개의 게시글만 보여주도록 설정함으로써, 페이지가 더 깔끔하고 가독성이 좋아졌다. 

 

 

Controll Class

//내가 쓴 글 보기

@GetMapping("/myPost")

public String myPost(HttpSession session, Model model, @RequestParam(defaultValue = "1") int page) {

 

imMyPostListService.myPostList(session, model, page);

 

return "post/myPost";

}

 

처음에 생각해야 될 것이 게시글을 불러오는 페이지로 이동 시 게시글이 바로 나타나야 함과 동시에 페이지는 1번이 체크되어 있어야한다. 즉, 다른페이지에서 게시글 리스트 페이지로 이동시에는 게시물 목록 페이지인 1번을 클릭하는 과정이 없으므로

@RequestParam(defaultValue = "1") int page

page값을 전달할 떄 값이 없다면 (defaultValue = "1") 로 1을 기본 값으로 설정을 해준다.

이후 다음 게시물 리스트로 넘어가기 위해 현재 페이지 외에 다른 페이지를 클릭 시 int page에는 클릭한 데이터의 값이 들어간다.

 

 

 

Service Class

@Service

@RequiredArgsConstructor

public class ImMyPostListService {

 

private final ImPostMapper imPostMapper;

 

public void myPostList(HttpSession session, Model model, int page) {

//로그인 된 유저의 유저코드

String userCode = (String) session.getAttribute("userCode");

//페이지당 게시글 수 설정

int postPerPage = 10;

//전체 게시글 수 가져오기

int totalPost= imPostMapper.countMyPostList(userCode);

//페이징 데이터 가져오기

ImPostPageVO pagination = new ImPostPageVO(page, totalPost, postPerPage);

//현재 페이지에 해당하는 게시글 가져오기

int offset = (page - 1) * postPerPage;

List<ImPostListDto> myPostList = imPostMapper.myPostList(userCode, offset, postPerPage);

//모델에 담아 뷰로 전달

model.addAttribute("myPostList", myPostList);

model.addAttribute("pagination", pagination);

 

}

 

}

 

int postPerPage = 10;

페이지별 나타낼 게시물의 갯수를 정해준다.

 

int totalPost= imPostMapper.countMyPostList(userCode);

mybatis mapper를 이용해 게시물의 총 갯수를 불러온다.

 

ImPostPageVO pagination = new ImPostPageVO(page, totalPost, postPerPage);

이전 1 2 3 4 5 6 7 8 9 10 다음 

위의 예시와 같은 게시물 페이징 처리를 위한 클래스로서 

page = 현재 페이지

totalPost = 총 게시글의 갯수

postPerPage = 한 페이지당 게시글 갯수

의 데이터를 넘겨

총 게시물 및 페이지당 출력되는 게시글의 갯수를 계산하여 총 페이지 및 몇개의 페이지를 나타낼지 계산해주는 클래스이다. (ex 총 게시물의 갯수는 15개이고 한 페이지당 10개를 나타낼거라면 1 2 의 페이지만 나와야한다.)

 

int offset = (page - 1) * postPerPage;

List<ImPostListDto> myPostList = imPostMapper.myPostList(userCode, offset, postPerPage);

offset을 구한 이유는 1페이지에선 게시글이 1~10이 나와야하고, 2페이지에선 게시글이 11~20이 나와야하므로

쿼리의 limit을 사용하기 위함이다.

 

int offset = (page - 1) * postPerPage;

ex) 현재 페이지가 1번이라면 (1-1)*10의 식으로 인해 결과값이 0이된다.

List<ImPostListDto> myPostList = imPostMapper.myPostList(userCode, offset, postPerPage);

그러면 mapper로 전달하여 쿼리문 마지막에 limit 0(offset),10(postPerPage / 여기는 위에서 10개로 지정해줬다.)을 입력되게 하여 데이터를 불러온다면

index값 0부터 10개의 데이터를 받는다

 

만약 다음 게시글을 보기위해  3 페이지를 눌렀다고 가정하면,

(3-1) * 10 의 식으로 인해 20이 된다.

그러면 limit 20, 10 으로 인해 index 20번부터 10개의 데이터가 출력되는 것이다.

 

그럼 여기까지는 게시글 리스트 페이지에서 다음 게시글을보기 위해 페이지를 눌렀을 떄 그 페이지 맞게 10개의 게시글이 리스트업 되는거까지는 확인이 됏다. 그러면 이제 다음 게시글을 보기 위한 페이징 설정이 어떻게 되는지 알아보겠다.

 

 

 

Page VO Class

@Getter

public class ImPostPageVO {

private int currentPage; // 현재 페이지

private int totalPages; // 전체 페이지 수

private int startPage; // 페이지 네비게이션의 시작 페이지

private int endPage; // 페이지 네비게이션의 끝 페이지

 

public ImPostPageVO(int currentPage, int totalPost, int postPerPage) {

this.currentPage = currentPage;

 

// 전체 페이지 수 계산

this.totalPages = (int) Math.ceil((double) totalPost / postPerPage);

 

// 페이지 네비게이션 계산 (한 블록에 10페이지 표시)

int pageBlock = 10;

this.startPage = ((currentPage - 1) / pageBlock) * pageBlock + 1;

this.endPage = Math.min(this.startPage + pageBlock - 1, this.totalPages);

}

}

 

// 전체 페이지 수 계산

this.totalPages = (int) Math.ceil((double) totalPost / postPerPage);

총 게시글 갯수에 따른 페이지 갯수를 구해준다

ex) 총 게시글 갯수가 25개면서 한 페이지당 10개씩 나타낸다는 조건이라면, 3이 나와야한다.

이 때, int로 정의를 해버리면 결과값이 2가 나와 최대 페이지는 2로 설정된다. 그러면 페이지당 10개씩 나타내기로 한다면 마지막 5개의 게시글은 볼 수가 없다. 그래서 double로 정의한 후 Math.ceil의 올림을 이용해 소수점이 있을 경우엔 올림을하여 나머지 게시글도 보일 수 있는 마지막 페이지를 만들어 안보이는 게시글이 없도록 만들어줘야 한다.

 

// 페이지 네비게이션 계산 (한 블록에 10페이지 표시)

int pageBlock = 10;

this.startPage = ((currentPage - 1) / pageBlock) * pageBlock + 1;

this.endPage = Math.min(this.startPage + pageBlock - 1, this.totalPages);

int pageBlock = 10;

한 블록에 보여줄 페이지의 갯수

ex) 1 2 3 4 5 6 7 8 9 10

      11 12 13 14 15 16 17 18 19 20

 

this.startPage = ((currentPage - 1) / pageBlock) * pageBlock + 1;

이건 현재 머무르고 있는 페이지의 제일 왼쪽에 위치한 첫번째 페이지를 나타내는 것인데(ex 1 2 3 4 5 6 7 8 9 10 중 1을 구하기 위함),

페이지 1에 위치하고 있다는 가정을 하면

((1-1)/10)*10+1 의 결과값인 1이 첫번째 페이지인 것이고 (ex 1 2 3 4 5 6 7 8 9 10),

 

페이지 6에 위치하면 위와 같이

((6-1)/10)*10+1 의 결과값인 1이 첫번째 페이지인 것이고 (ex 1 2 3 4 5 6 7 8 9 10),

 

만약 페이지가 10 이상인 15에 위치하고있다고 가정을 하면

((15-1)/10)*10+1 의 결과값인 11이 첫번째 페이지가 되는 것이다(ex 11 12 13 14 15 16 17 18 19 20).

 

위 과정을 거쳐 첫번째 페이지를 구하고,

 

this.endPage = Math.min(this.startPage + pageBlock - 1, this.totalPages);

첫번째 페이지를 구하는 것처럼 마지막 페이지도 구해야되는데, 위에 한 블록당 10개의 페이지가 나타나도록 했으니

현재 페이지의 위치가 1~10이라면 시작페이지값이 구해지니,

시작페이지 + 한 블록당 페이지갯수 -1 로 마지막 페이지를 구한다.

(만약 현재 위치하는 페이지가 1~10일 경우, 시작페이지는 1이되니, 1+10-1의 결과값인 10이 마지막 페이지가 되는것이다.)

 

근데 여기서 중요한점이

만약 게시글 불러온 갯수의 값이 100 단위로 딱 맞아떨어지지 않을 경우 페이지 마지막 블록의 마지막 페이지 값은

시작페이지 + 한 블록당 페이지 갯수 -1 의 값이 아닐 것이다.

ex) 게시글이 총 120개가 있다고 가정한다면

      첫번째 페이질 블록 : 1 2 3 4 5 6 7 8 9 10

      두번째 페이질 블록 : 11 12 

 

그러면 마지막 페이지를 구하는 것은 this.startPage + pageBlock - 1 의 결과값과 앞서 구한 totalPages값 중 Math.min을 이용하여 작은 값을 마지막 endPage로 설정해야한다. 

 

 

 

JSP

<!-- 페이지 번호 -->

<c:choose>

<c:when test="${not empty myPostList}">

<div class="pagination">

<c:if test="${pagination.currentPage > 1}">

<a href="?page=${pagination.currentPage - 1}">이전</a>

</c:if>

 

<c:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="pageNum">

<c:choose>

<c:when test="${pageNum == pagination.currentPage}">

<span class="current">${pageNum}</span>

</c:when>

<c:otherwise>

<a href="?page=${pageNum}">${pageNum}</a>

</c:otherwise>

</c:choose>

</c:forEach>

 

<c:if test="${pagination.currentPage < pagination.totalPages}">

<a href="?page=${pagination.currentPage + 1}">다음</a>

</c:if>

</div>

</c:when>

</c:choose>

 

<c:when test="${not empty myPostList}">

만약 게시물 데이터가 존재한다면,

 

<c:if test="${pagination.currentPage > 1}">

<a href="?page=${pagination.currentPage - 1}">이전</a>

</c:if>

현재 페이지가 1 초과의 값이라면 이전버튼이 생기고, 이전버튼을 누르면 현재페이지-1 의 값으로 이동

 

 

<c:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="pageNum">

<c:choose>

<c:when test="${pageNum == pagination.currentPage}">

<span class="current">${pageNum}</span>

</c:when>

<c:otherwise>

<a href="?page=${pageNum}">${pageNum}</a>

</c:otherwise>

</c:choose>

</c:forEach>

 

<c:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="pageNum">

시작페이지와 끝페이지를 포함한 사이에 존재하는 모든 값을 나타내준다.

<c:when test="${pageNum == pagination.currentPage}">

<span class="current">${pageNum}</span>

이 중 현재 페이지와 같은 숫자에는 class="current" 를 적용하여 css로 현재 페이지임을 표시하는 방법

 

<c:otherwise>

<a href="?page=${pageNum}">${pageNum}</a>

</c:otherwise>

만약 다른 페이지를 클릭 시 그 페이지로 이동

 

<c:if test="${pagination.currentPage < pagination.totalPages}">

<a href="?page=${pagination.currentPage + 1}">다음</a>

</c:if>

그리고 현재 페이지가 제일 마지막 페이지보다 작다면 다음 버튼이 생기도록한다.

다음 버튼 클릭시 현재 페이지+1 로 이동

 

 

 

결과

 

 

사용자가 페이지를 누를때마다 이 글에서 정리된 과정이 계속해서 이루어져 원하는 페이지 및 그 페이지에 맞는 게시글이 보여진다.

 

 

+ Recent posts