외국어 직독직해하듯 코드 독해하기

 

목표

1. 게시판 List에서 기본 페이지네이션 구현하기 [1]
2. 원래 있던 페이지 번호로 돌아가기 [2]
      - 게시글 상세에서 [목록]버튼 눌렀을 때
      - 게시글 수정 후 [목록]버튼 눌렀을 때
      - 게시글 삭제 후

 

 

 

 

게시판 List에서 페이지네이션 활성화시키기

 

Criteria.java -- 페이지네이션 출력 기본 설정 관리
public class Criteria {

  private int page; // 현재 페이지 번호
  private int postsPerPage; // 한 페이지 당 게시글 수
  
  //Criteria 디폴트 생성자
  public Criteria() { 
    this.page = 1; // 현재 페이지를 1페이지로 설정
    this.postsPerPage = 10; // 한 페이지 당 게시글 수 10개로 설정
  }
  
  
  //getter and setter
  
  public int getPage() {
    return page;
  }
  
  public void setPage(int page) {
    if(page <= 0) { // 현재 페이지 번호가 음수라면,
      this.page = 1; // 페이지 번호 1로 설정
    }
    else
      this.page = page;
  }
  
  public int getPostsPerPage() {
    return postsPerPage;
  }
  
  public void setPostsPerPage(int postsPerPage) {   
    if(postsPerPage <=0 || postsPerPage > 100) { // 페이지 당 게시글 수가 0개 이하거나 100개를 초과할 때
      this.postsPerPage = 10;  // 페이지 당 게시글 수를 10개로 설정.
    }
    else
      this.postsPerPage = postsPerPage;
  }
  
  
  @Override
  //Criteria 정보 콘솔 출력 메서드
  public String toString() {
    return "Criteria [page=" + page + ", postsPerPage=" + postsPerPage + "]";
  }
  
  //쿼리문에서 limit에 사용되는 인덱스를 계산하는 getter
  public int getPageStart() {
    return (this.page -1) * postsPerPage;
  }
}

 마지막 getter -- getPageStart()는 아래 BoardMapper.xml에서 활용되니 거기서 설명.

 

PageMaker.java -- 페이지네이션 출력 상세 설정 관리
import lombok.Data;

@Data
public class PageMaker {
  private int totalCount; // 총 게시글 수
  private int startPage; // 시작 번호
  private int endPage; // 끝 번호
  private boolean prev; // 이전 버튼 유무
  private boolean next; // 다음 버튼 유무
  private int displayPageNum; // 페이지네이션 한 세트에 보여질 페이지번호 갯수
  private Criteria criteria; // 페이지네이션 기본 설정 정보
  
  //endPage, startPage, prev, next 값을 계산하는 메서드
  public void calcData() {
    
    endPage = (int) (Math.ceil(criteria.getPage()/(double) displayPageNum)*displayPageNum);
    //endPage = (int)(Math.ceil(3/(double)10) * 10)
    startPage = (endPage - displayPageNum)+1;
    
    //총 게시글 개수를 이용하여 제일 마지막 페이지 번호를 계산
    int theLastPage = (int)(Math.ceil(totalCount/(double)criteria.getPostsPerPage()));
    
    if(endPage > theLastPage) {
      endPage = theLastPage;
    }
    
    //현재 페이지가 1페이지면 이전(prev)버튼이 없어야 함
    prev = startPage == 1 ? false : true;
    //현재 페이지에 마지막 게시글이 포함되어 있으면 다음(next)버튼이 없어야 함
    next = endPage * criteria.getPostsPerPage() >= totalCount ? false:true;
  }

}
EX ) 현재 페이지가 13페이지이고, 페이지네이션 한 세트에 보여지는 페이지 번호 수가 10일 때 
          ==> startPage = 11 , endPage = 20 이어야 함.
  • endPage의 계산 : (int) (Math.ceil(criteria.getPage()/(double) displayPageNum)*displayPageNum);
    Math.ceil() : 소수점 올림. (현재 실수와 같거나 큰 정수를 반환)
    endPage = (13/10.0)*10 => 1.3*10 => 2*20 => 20
  • startPage의 계산 : (endPage - displayPageNum)+1;
    startPage = (20 - 10)+1 => 11
결과 : prev   11 12 13 14 15 16 17 18 19 20   next

 

 

EX) 총 게시글 수가 223개이고, 한 페이지 당 게시글 수가 10개일 때
  • 페이지네이션의 맨~~~마지막 페이지 계산 : (int)(Math.ceil(totalCount/(double)criteria.getPostsPerPage()));
    theLastPage = (223/10.0) => 6.2 => 23
결과 : prev   21 22 23

 

 

 

 

 

BoardController.java -- 게시글 리스트 출력 컨트롤러
  @GetMapping("/noticeBoard/noticeList")
  public ModelAndView noticeBoardListGet(ModelAndView mv, Criteria cri) { // 매개변수 Criteria cri 를 추가.
    
    cri.setPostsPerPage(5); // 한 페이지당 보여질 게시글 개수 설정
    PageMaker pm = new PageMaker(); // PageMaker 객체 생성
    pm.setCriteria(cri); // cri 정보를 pm의 Criteria에 담기.
    pm.setDisplayPageNum(2); // 페이지네이션 한 세트에 보여지는 페이지 번호의 개수를 설정
    
    int totalCount = boardService.getTotalCount(cri); // 게시글 총 개수 구하기
    pm.setTotalCount(totalCount); // pm의 TotalCount에 위에서 구한 게시글 총 개수 설정하기
    pm.calcData(); // endPage, startPage, prev/next 버튼 노출 여부 설정하는 메서드 실행

    ArrayList<PostVO> list = boardService.getBoardList(cri);
    mv.addObject("list", list);
  
    mv.addObject("pm", pm); // pm정보를 "pm"에 담아 jsp에 전달
    mv.setViewName("/template/board/noticeBoard/noticeList");
    return mv;
  }

 

  • noticeBoardListGet -- Controller의 매개변수에 Criteria cri 를 추가
  • 한 페이지당 게시글 5개씩, 페이지네이션 한 세트당 2개 페이지가 설정되도록 작성 됨.
  • addObject로 pm객체 정보를 전달.

 

 

BoardService.java

 

ArrayList<PostVO> getBoardList(Criteria cri); // 매개변수 Criteria cri 추가
int getTotalCount(Criteria cri);
  • getBoardList - Service에 Criteria cri 추가.
  • getTotalCount - Service 생성.

 

 

BoardServiceImp.java
  @Override
  public ArrayList<PostVO> getBoardList(Criteria cri) {  // 매개변수 Criteria cri 추가
    return boardDao.getBoardList(cri); // cri 추가
  }

  @Override
  public int getTotalCount(Criteria cri) {
    return boardDao.getTotalCount(cri);
  }
  • getBoardList - ServiceImp에 Criteria cri 추가.
  • getTotalCount - ServiceImp 생성.

 

 

BoardDAO.java
  ArrayList<PostVO> getBoardList(@Param("cri") Criteria cri); // 매개변수 Criteria cri 추가
  int getTotalCount(@Param("cri") Criteria cri);
  • getBoardList - DAO에 Criteria cri 추가.
  • getTotalCount - DAO 생성.

 

 

BoardMapper.xml -- 게시판의 게시글을 불러오는 쿼리문 수정
<select id="getBoardList" resultType="com.ysy.bakingdom.vo.PostVO">
  select * from post where post_state = '1' order by post_num desc
    <!-- 불러올 게시글 개수 설정  -->
    limit #{cri.pageStart}, #{cri.postsPerPage}
</select>
  • limit #{cri.pageStart}, #{cri.postsPerPage} : 전체 데이터 값에서 "pageStart+1부터 postsPerPage까지" 불러옴
    cri.pageStart : Critera.java 에 있는 인덱스 계산 getter의 리턴 값 => return (this.page -1) * postsPerPage;    
EX) 만약 한 페이지당 게시글 수가 3개 라고 가정하면,



BoardMapper.xml -- 전체 게시글 수를 구하는 쿼리문 작성
<select id="getTotalCount" resultType="int">
  select count(*) from post where post_state = '1'
</select>

 

 

 

<nav aria-label="Page navigation example">
  <ul class="pagination d-flex justify-content-center">
  
    <!-- 이전 버튼 눌렀을 때 -->
    <c:if test="${pm.prev}">
      <li class="page-item">
        <a class="page-link" href="<%=request.getContextPath()%>/noticeBoard/noticeList?page=${pm.startPage-1}" aria-label="Previous">
          <span aria-hidden="true">&laquo;</span> <!-- &laquo; = "<<" -->
        </a>
      </li>
    </c:if>
    
    <!-- 페이지 번호를 눌렀을 때 -->
    <c:forEach begin="${pm.startPage}" end="${pm.endPage}" var="index">
      <li class="page-item <c:if test="${pm.criteria.page == index}">active</c:if>">
        <a class="page-link" href="<%=request.getContextPath()%>/noticeBoard/noticeList?page=${index}">${index}</a></li>
    </c:forEach>

    <!-- 다음 버튼 눌렀을 때 -->
    <c:if test="${pm.next}">
      <li class="page-item">
        <a class="page-link" href="<%=request.getContextPath()%>/noticeBoard/noticeList?page=${pm.endPage+1}" aria-label="Next">
          <span aria-hidden="true">&raquo;</span> <!-- &raquo; = ">>" -->
        </a>
      </li>
    </c:if>
    
  </ul>
</nav>
  • <c:if test="${ [pm.prev | pm.next] }"> </c:if>
    - [pm.prev | pm.next] 가 ture이면 [ 이전 | 다음 ] 버튼 활성화.
  • <c:forEach begin="${pm.startPage}" end="${pm.endPage}" var="index">
    - begin(시작페이지) 부터 end(끝페이지)까지 (PageMaker.java 참고) 를 반복문으로 변수 "index"에 담고, 쭉 출력(나열)한다. 
  • 현재 페이지 번호와 index가 같은 페이지네이션 번호는 active(파란 색 표시)를 활성화 시킨다.

 

 

작업완료 결과
http://localhost:8080/noticeBoard/noticeList
페이지네이션 한 세트에 2개의 페이지가 설정되고, 한 페이지 당 게시글 5개씩 보여짐.

 

 

 

 

여기까지가 기본 페이지네이션 구현이다.

다음 포스트는..

 

2. 원래 있던 페이지 번호로 돌아가기
      - 게시글 상세에서 [목록]버튼 눌렀을 때
      - 게시글 수정 후 [목록]버튼 눌렀을 때
      - 게시글 삭제 후

 

를 작성해보겠다. (힘들당..)