▸JSP & Servlet/기본 문법

MVC 패턴의 게시판 만들기_페이징 처리(오라클DB) [2/5]

코데방 2020. 3. 2.
728x90

로그인 페이지 만들기에 이어 이번에는 MVC 패턴을 적용한 웹 어플리케이션에서 게시판을 만들어봅니다. Spring 없이 순수 JSP와 서블릿으로 구성되며, 기존 로그인과 회원가입, 정보조회를 만들었던 웹페이지에 기능을 붙여서 구현합니다. 

 

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_리스트 화면 [1/3]

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_글쓰기 화면 [2/3]

[· JSP & Servlet/- 부트스트랩] - 부트스트랩으로 게시판 만들기_게시물 보기 화면 [3/3]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_계층형 게시판 로직 설계 [1/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_페이징 처리(오라클DB) [2/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_리스트 출력 로직 [3/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_글작성 로직 [4/5]

[· JSP & Servlet/- 기본 문법] - MVC 패턴의 게시판 만들기_게시물 보기 로직 [5/5]

 

 

전체 코드는 깃허브에 있습니다. 커밋 시점은 "add board" 입니다. 

https://github.com/codevang/hssweb

 

 

 


 

 

페이징 처리를 위해서는 두 가지 작업이 필요합니다.

 

첫 번 째는 요청온 페이지가 왔을 때 아래쪽에 페이지 번호들이 출력되는 페이지 목록의 범위를 지정해주는 것입니다. 이 부분은 알고리즘을 짜본 분들이라면 쉽게 작성할 수 있습니다.

 

두 번 째는 페이지 번호를 눌렀을 때 해당 페이지에 속하는 게시물의 목록을 뽑아내는 것입니다. 이 부분은 DB단에서 쿼리를 통해 수행되며, 원리만 알면 역시 간단히 처리할 수 있습니다.

 

 

 

 


 

 

[ 페이징 목록 처리하기 ]

 

1. 전체 게시물 갯수를 통한 전체 페이지 갯수 구하기

  • 전체 페이지 수 = (전체 게시물 수 / 한 페이지에 출력할 수) + 1(나머지가 있을 경우)

먼저 DB에 접속해서 count(*)를 셀렉트하면 전체 게시물의 갯수를 받아올 수 있습니다. 

 

 

위와 같이 숫자만 딱 하나 반환해주는데, result.getInt(1)로 숫자를 받아와 저장해줍니다. 매개변수를 컬럼명 문자열이 아닌 정수형으로 넣어주면 첫(1)번 째 컬럼의 값을 가져오겠다는 의미가 됩니다. 

 

그리고 한 페이지에 출력할 갯수로 나눠준 뒤, 나머지가 있으면 1을 추가해줍니다. 저 같은 경우는 해당 숫자들을 상수로 정의해뒀습니다. 게시물이 하나도 없을 경우도 따로 처리해줍니다.

 

	// 한 화면에 보여줄 리스트 갯수, 페이징 범위의 갯수
	public static final int pagePerList = 10;
	public static final int pagingCount = 10;
	/* 페이징 범위 구하기 */
	private int[] paging(int page) throws Exception {

		dbConnect();
		stmt = conn.createStatement();
		String query = "select count(*) from board_chat";
		result = stmt.executeQuery(query);

		// 전체 게시물 갯수로 총 페이지 수 산출 (하나도 없으면 null 리턴)
		int totalContent = 0;
		int totalPage = 0;
		while (result.next()) {
			totalContent += result.getInt(1);
		}
		if (totalContent == 0) {
			return null;
		}
		totalPage = totalContent / BoardList.pagePerList; // 최종 전체 페이지 갯수
		if (totalContent % BoardList.pagePerList > 0) {
			totalPage++;	// 나머지가 있다면 1을 더해줌
		}

 

 


 

 

2. 페이지 목록의 시작과 끝 범위 계산

  • 시작 페이지 : ((요청페이지 - 1) / 출력할 페이지 목록 수) * 출력할 페이지 목록 수 + 1
  • 끝 페이지 : 시작 페이지 + 출력할 페이지 목록 수 - 1 (마지막 범위는 따로 처리)

구하는 공식은 위와 같습니다. 시작 페이지의 경우 수학적으로 보면 '출력할 페이지 목록 수'의 나누기와 곱하기가 서로 상쇄될 것 같지만, 코딩에서 나누기 결과는 나머지가 없는 몫만 산출되므로 일반 수학과는 다른 결과가 나옵니다. 

 

끝 페이지는 시작 페이지에서 페이지 목록 수를 더한 값에 1을 빼주면 되는데, 주의할 점은 이 값이 전체 페이지의 수보다 클 경우 전체 페이지 수로 대체해야한다는 것입니다. 예를 들어 전체 페이지 수가 17인데 10개씩 나눠서 보여주겠다면 처음은 '1~10'만 보이고 그 다음은 '11~17'만 보여야 한다는 것입니다. 시작 페이지가 11이라고 그냥 9을 더해주면 '11~20' 범위가 나와 없는 페이지 번호가 출력되게 됩니다.

 

범위가 산출됐다면 2개짜리 배열에 담아서 리턴시켜줍니다. 범위만 나오면 나머지는 입맛에 맞게 구성하면 됩니다.

 

		// 페이징 범위 계산
		int startPage, endPage; // 시작과 끝 페이지
		startPage = ((page - 1) / BoardList.pagingCount) * BoardList.pagingCount
				+ 1;
		endPage = startPage + BoardList.pagingCount - 1;
		if (endPage > totalPage) {
			endPage = totalPage;
		}
		int[] startEnd = new int[2]; // 결과를 전달해줄 배열
		startEnd[0] = startPage;
		startEnd[1] = endPage;

 

 


 

 

* 페이징 목록 범위 산출 전체 코드

	/* 페이징 범위 구하기 */
	private int[] paging(int page) throws Exception {

		dbConnect();
		stmt = conn.createStatement();
		String query = "select count(*) from board_chat";
		result = stmt.executeQuery(query);

		// 전체 게시물 갯수로 총 페이지 수 산출 (하나도 없으면 null 리턴)
		int totalContent = 0;
		int totalPage = 0;
		while (result.next()) {
			totalContent += result.getInt(1);
		}
		if (totalContent == 0) {
			return null;
		}
		totalPage = totalContent / BoardList.pagePerList; // 최종 전체 페이지 갯수
		if (totalContent % BoardList.pagePerList > 0) {
			totalPage++;	// 나머지가 있다면 1을 더해줌
		}

		// 페이징 범위 계산
		int startPage, endPage; // 시작과 끝 페이지
		startPage = ((page - 1) / BoardList.pagingCount) * BoardList.pagingCount
				+ 1;
		endPage = startPage + BoardList.pagingCount - 1;
		if (endPage > totalPage) {
			endPage = totalPage;
		}
		int[] startEnd = new int[2]; // 결과를 전달해줄 배열
		startEnd[0] = startPage;
		startEnd[1] = endPage;
		
		
		// result 객체는 호출한 곳에서 재활용할 것이므로 자원해제
		try {
			result.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return startEnd;
	}

 

 

 


 

 

[ 오라클 DB에서 페이지 범위에 맞는 데이터 뽑아오기 ]

 

먼저 전체 쿼리는 아래와 같습니다.

select * 
from (select ROWNUM as rnum, A.* 
from (select * from board_chat order by bdgroup desc, bdorder) A)
where rnum >= 1 and rnum <=10;

 

쿼리가 좀 복잡한 이유는 게시물 순서의 번호를 매겨주는 rownum이란 기능의 순서 때문입니다. 정렬을 마친 후 rownum을 통해 게시물의 순서를 매겨줘야 하는데, rownum이 정렬 보다 먼저 작동해버려서 한번에 rownum과 order by를 쓰게 되면 게시물 순서가 이상하게 꼬여버립니다.

 

 


 

 

1. 데이터 정렬

 

먼저 게시물을 정렬해서 가져옵니다. 그룹넘버가 가장 첫 기준이고, 그룹넘버로 정렬된 후 그 안의 순서를 지정해준 컬럼으로 다시 정렬합니다. 그룹넘버는 작성 순서대로 쌓이기 때문에 내림차순(desc)으로 정렬해서 가장 최신글부터 가져오도록 합니다. 

 

select * from board_chat order by bdgroup desc, bdorder

 

 


 

 

2. 정렬된 데이터에 순서 붙이기 (rownum)

 

위에서 정렬시켜 임시로 생성한 테이블을 서브쿼리라고 합니다. 첫 번째 서브쿼리에서 다시 select를 해서 순서를 매겨줍니다. 순서를 매겨준 rownum은 컬럼명을 지정해줘야 하나의 컬럼으로 고정됩니다.

ROWNUM as rnum

 

또한 새로운 컬럼(rnum)을 추가하고 추가로 서브쿼리에서 select를 하기 때문에, 새로운 컬럼(rnum)은 자기 자신이 생성한 것이고 나머지는 서브쿼리에서 가져온다는 것을 구분해주기 위해 서브 쿼리에 별칭(예를 들어 A)을 지정해줍니다. 만약 새로 컬럼을 추가하지 않고 모두 가져오겠다고 한다면 굳이 별칭을 지정해주지 않아도 무방합니다.  

select ROWNUM as rnum, A.* -- 새로 생성한 컬럼(rnum)과, A에서 가져올 모든 컬럼(*)
from (select * from board_chat order by bdgroup desc, bdorder) A

 

 


 

 

3. 순서가 붙은 정렬된 데이터에서 특정 범위만 가져오기

 

위의 과정으로 데이터를 먼저 정렬한 후 순서를 붙여줬습니다. 서브쿼리로 select한 것은 일종의 임시 테이블이 생성됐다고 보면 됩니다. 이 임시 테이블에서 다시 select 해오면서 rnum의 범위를 조건문으로 지정해주면 됩니다. 여기서 조건을 줄 시작 페이지와 끝 페이지 범위를 코드에서 변수로 지정해주면 됩니다. 

select * 
from (select ROWNUM as rnum, A.* -- 새로 생성한 컬럼(rnum)과, A에서 가져올 모든 컬럼(*)
from (select * from board_chat order by bdgroup desc, bdorder) A)
where rnum >= 10 and rnum <=20; 

 

728x90

댓글

💲 추천 글