Day 55. Pagination

ho_c·2022년 5월 5일
0

국비교육

목록 보기
53/71
post-thumbnail

게시글 목록 출력, 작성, 수정, 삭제 등 일반 기능들은 다 구현했다.
그러나 현 상태에서 글 목록을 출력하게 되면, 한 페이지에 모든 글들이 출력된다. 따라서 페이지 당 출력을 조절하고, 이를 네비게이션으로 이동할 수 있는 ‘pagination’을 구현해보자.


Pagination

페이지 네비게이터를 만드는 방식은 개발자가 자신의 페이지 구성에 따라 달라진다. 그래서 누군가는 front에서 다 구성되게 하는 경우도 있고, 위치나 모양도 제각각이지만 가장 기본은 back에서 만드는 것이다.

이 기능이 어려운 것은, 설정값에 따라 알고리즘이 달라진다. 하지만 기능 자체는 크게 2가지로 구분된다.

  • 페이지 간 이동
  • 페이지 당 글 출력

1) 페이지 간 이동

페이지 간 이동은 단순한 HTML을 통한 이동을 의미한다. 다르게 말하면 페이지를 클릭 할 때마다 컨트롤러로 요청을 보내, forward로 UI가 변화가 일어나게 해야하는 것이다.

따라서 알고리즘을 통해 DAO에서 우리가 출력 JSP에 뿌려줄 양식을 만들어줘야 한다.

(1) 기본 설정

int recordTotalCount = this.totalData();
		
int recordCountPerPage = 10;
		
int naviCountPerPage = 10;
		
int pageTotalCount = 0;
  • 총 데이터의 개수(recordTotalCount) : 쿼리로 받아와야 됨.
private int totalData() throws Exception{
		String sql = "select count(*) from board";
		try(Connection conn = this.getConnection();
			PreparedStatement pstat = conn.prepareStatement(sql);){
			
			ResultSet rs = pstat.executeQuery();
			
			rs.next();
			
			return rs.getInt(1);
		}
	}
  • 한 페이지의 출력할 데이터 개수(recordCountPerPage)
  • 한 페이지에서 보여줄 네비게이션의 개수 (naviCountPerPage)
  • 총 필요한 네비게이션의 수 (pageTotalCount) : recordTotalCount / recordCountPerPage
// pageTotalCount 공식  

- 총 데이터 % 출력 데이터 > 0
	총 데이터 / 출력 데이터 + 1
if(recordTotalCount % recordCountPerPage > 0) {
	pageTotalCount = recordTotalCount / recordCountPerPage +1;
    }

- 총 데이터 % 출력 데이터 = 0 
	총 데이터 / 출력 데이터
else {
	pageTotalCount = recordCountPerPage / recordCountPerPage;
    }

(2) 네비게이션 세부 설정

  • 현재 페이지 설정 : 컨트롤러에서 get 방식으로 받아온다.
int currentPage = cpage;
		
if (currentPage < 1) {
	currentPage = 1;
} else if (currentPage > pageTotalCount) {
	currentPage = pageTotalCount;
    }

- 네비게이션의 시작-끝 페이지 설정

// 네비 시작 : 현 페이지가 페이지 당 네비의 개수의 배수면, 현 페이지보다 커진다.
int startNavi = (currentPage-1)/naviCountPerPage*naviCountPerPage+1;

// 네비 끝 : 시작점은 빼준다. 
int endNavi = startNavi + naviCountPerPage -1;
		
if (startNavi < 0) { // 0보다 크면 1로 세팅
	startNavi = 1;
} else if(endNavi > pageTotalCount) { // 총 페이지 ==  마지막 페이지
	endNavi = pageTotalCount;
}

- 다음 네비게이션으로 넘기는 기능

// 스위치처럼 키고 끄는 원리
boolean preNavi = true;
boolean nextNavi = true;
		
if (startNavi == 1) {
	preNavi = false; // 시작 페이지의 이전은 없다.
} 
if (endNavi >= pageTotalCount) {
	nextNavi = false; // 마지막 페이지의 이후는 없다.
}

(3) 출력 부분 담기 : StringBuilder.append()

모든 세팅이 끝났다면, 최종적으로 JSP에서 출력될 수 있도록 바꿔줘야 한다.
곧 DAO에서 출력 양식을 만들어서 반환해주는 것이다. 이를 위해서 StringBuilder로 문자열을 만들어서 반환한다.

StringBuilder sbr = new StringBuilder();

// 이전
if (preNavi) {
	// html을 포함한 문자열을 넘겨주고, 이를 통해 컨트롤러에서 cpage의 값을 받아
    // 다음 클릭 시 다음 페이지를 요청하도록 한다.
	sbr.append("<a href='list.board?cpage="+(startNavi-1) +"'>" + "< " + "</a>");
	}

// 반복문으로 네비게이션을 만든다.
for (int i=startNavi; i<endNavi; i++) {
	// 현재 페이지는 따로 표시되게 한다.
	if(i == currentPage) {
		sbr.append("<a href='list.board?cpage="+i+"'>" + "[ " +  i  + " ] " + "</a>");
	} else {
		sbr.append("<a href='list.board?cpage="+i+"'> " + i + " </a>");
        }
}

// 이후		
if (nextNavi) {
	sbr.append("<a href='list.board?cpage="+(endNavi+1) +"'>" + " >" + "</a>");
    }

6) list 출력

DAO → Controller → JSP

String pageNavi  = bDAO.getPageNavi(cpage);
request.setAttribute("navi", pageNavi);
request.getRequestDispatcher("/board/boardlist.jsp").forward(request, response);

7) JSP 세팅

<td colspan=5 align=center id="page">
	${navi} 
</td>

2) 페이지 당 글 출력

네비게이션 세팅이 끝났으면, 이제 네비게이션에 맞게 글이 출력되도록 설정해야 한다. 곧, 기존 설정에 출력의 능동성을 부여하는 과정이다.

실제 건드리는 부분은 글 목록에서 출력되는 글만 조절하면 된다.

(1) 기준 잡기

한 페이지에 10개의 글을 출력한다 할 때, 현재 1페이지라면 DB에서 1~10번 글이, 2페이지 일 때 11~20, 3페이지 21~30 이런 식으로 출력된다.

그리고 클라이언트로부터는 현 페이지가 우리가 연결해둔 링크를 통해 get방식으로 받아올 수 있다. 따라서 다음과 같이 공식을 잡을 수 있다.

int start = cpage*naviCountPerPage - (cpage*naviCountPerPage-1);
int end = cpage*cpage*naviCountPerPage;

(2) 쿼리문 만들기

기준을 잡았다면, 쿼리로 받아보기만 하면 된다. 이때, 몇 가지 고려해야한다.

① 순서 잡기 : row_number() over(order by seq desc)
② select에서 * 을 집어 넣으면 다른 컬럼을 못 넣는다. → board.* 로 빼줘야됨.
③ DQL의 실행 순서상 where이 select보다 몬저 온다. → 서브쿼리 사용

select * from (select row_number() over(order by seq desc) line, board.* from board) where line between start and end;

(3) 검색 결과를 저장하기

try(
	Connection con = this.getConnection();
	PreparedStatement pstat =  con.prepareStatement(sql);
	){
   pstat.setInt(1, start);
   pstat.setInt(2, end);
			
   try(
   	ResultSet rs = pstat.executeQuery();
	){
      List<BoardDTO> list = new ArrayList<BoardDTO>();
				
      while (rs.next()) {
	  int seq = rs.getInt("seq");
	  String title = rs.getString("title");
	  String article = rs.getString("content");
	  String writer = rs.getString("writer");
	  Date writerDate = rs.getDate("write_date");
	  int viewCount = rs.getInt("view_count");

	 BoardDTO dto = new BoardDTO(seq, writer, title, article, writerDate, viewCount);

	  list.add(dto);
      }
				
      return list;
   }
}

(4) JSP로 전달

(5) 출력 후 세팅

이렇게 세팅을 해두면, 페이지 정보가 없기 때문에 컨트롤러에서 글 출력 페이지를 설정해줄 수 없다. 따라서 기존에 글 출력으로 들어오는 모든 요청에 페이지 값을 세팅해줘야 한다.

< 생각해볼 점 >

  • 네비 출력 양식을 만들어주는 것은 DAO에 있는 건 아닌 것 같다.
  • 모든 기능이 한번에 일어나는 것이 아니다. 여러 기능이 모여 하나의 기능을 만든다.
  • CSS와 백엔드만 잘 구별하면 네비게이션 디자인은 쉽게 바꿀 수 있다.
profile
기록을 쌓아갑니다.

0개의 댓글