본문 바로가기

JSP/기본다지기

[JSP] 페이징(Paging) ① [11월28일]


(결과적으로 띄우고 싶은 화면!)

회원 리스트 밑에 페이지가 추가된 것을 볼 수 있음.



이번에 사용한 project의 모든 파일 일람표.


똑같은 내용에 프로젝트명만 L16Model2Paging으로 하면됩니다!



원래 프로젝트 L14Model2에서 새로 추가된 부분


vo > Paging.java


WebContent > paging폴더 > paging.jsp



원래 프로젝트 L14Model2에서 변경된 파일들


MemberDao.java


MemberListController.java


MemberList.jsp



우선 수업을 시작하기 전에


오라클 계정

jsp_lesson / 1234

의 member 테이블에 레코드를 충분히 넣어주어야 합니다.

(한 페이지에 10개씩 표시해서 최소 21페이지 이상 표시하기 위해서!)

[이 글에서는 편의상 member2 테이블을 새로 만들어서 구현합니다..]


Paging.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.model2.vo;
 
public class Paging {
    private int page =1//현재 페이지 (get)
    private int totalCount; //row 전체의 수 (get)
    private int beginPage;  //출력 시작
    private int endPage;    //출력 끝
    private int displayRow =10;  //한 페이지에 몇 개의 로우 (선택 set)
    private int displayPage =10;  //한 페이지에 몇 개의 페이지 (선택 set)
    boolean prev; //prev 버튼이 보일건지 안보일건지
    boolean next; //next 버튼이 보일건지 안보일건지
    
    public int getPage() {
        return page;
    }
    public void setPage(int page) {
        this.page = page;
    }
    public int getTotalCount() {
        return totalCount;
    }
    public void setTotalCount(int totalCount) {
        //setTotalCount()를 꼭 호출해야 paging이 되기 때문에
        //paging()함수를 setTotalCount()를 호출했을 때 자동으로 호출되게 한다.
        this.totalCount = totalCount;
        paging();
    }
    public int getDisplayRow() {
        return displayRow;
    }
    public void setDisplayRow(int displayRow) {
        this.displayRow = displayRow;
    }
    public int getDisplayPage() {
        return displayPage;
    }
    public void setDisplayPage(int displayPage) {
        this.displayPage = displayPage;
    }
    public int getBeginPage() {
        return beginPage;
    }
    public int getEndPage() {
        return endPage;
    }
    public boolean isPrev() {
        return prev;
    }
    public boolean isNext() {
        return next;
    }
    private void paging(){
        // prev, next, beginPage, endPage를 계산해서 만든다.
        // 2+9 = 11, 11/10 = 1, 1*10 = 10
        // 10+9 = 19, 19/10 = 1, 1*10 = 10
        // 11+9 = 20, 20/10 = 2, 2*10 = 20
        // 20+9 = 29, 29/10 = 2, 2*10 = 20
        // 111+9 = 120 120/10 = 12, 12*10 = 120
        
        // (2+9)/10 * 10 (1번 방법)
        //endPage = ((page+(displayPage-1))/displayPage)*displayPage;
        
        // 1/10 0.1(올림) 1 (2번 방법)
        endPage = ((int)Math.ceil(page/(double)displayPage))*displayPage;
        System.out.println("endPage : " + endPage);
        
        beginPage = endPage - (displayPage - 1);
        System.out.println("beginPage : " + beginPage);
        
        // 글 32개
        // 32/10 = 3.2 (올림) 4페이지
        // 2=?  2/10
        int totalPage = (int)Math.ceil(totalCount/(double)displayRow);
        
        if(totalPage<endPage){
            endPage = totalPage;
            next = false;
        }else{
            next = true;
        }
        prev = (beginPage==1)?false:true;//page가 11이상에만 나온다.
        System.out.println("endPage : " + endPage);
        System.out.println("totalPage : " + totalPage);
        
    }
}
 
cs



paging.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body{
    text-align:center;
}
#paging{
    font-size: 22pt;
}
</style>
</head>
<body>
<div id="paging">
<!-- 1~10까지 있는 페이지의 페이징 -->
<c:url var="action" value="/memList.do"/>
<c:if test="${param.prev}">
    <a href="${action}?page=${param.beginPage-1}">prev</a>
</c:if>
<c:forEach begin="${param.beginPage}" end="${param.endPage}" step="1" var="index">
    <c:choose>
        <c:when test="${param.page==index}">
            ${index}
        </c:when>
        <c:otherwise>
            <a href="${action}?page=${index}">${index}</a>
        </c:otherwise>
    </c:choose>
</c:forEach>
<c:if test="${param.next}">
    <a href="${action}?page=${param.endPage+1}">next</a>
</c:if>
</div>
</body>
</html>
cs


새로 추가된 파일들의 전체 코드입니다.


페이징에 사용되는 변수부터 살펴보겠습니다.


Paging.java

    private int page =1//현재 페이지 (get)
    private int totalCount; //row 전체의 수 (get)
    private int beginPage;  //출력 시작
    private int endPage;    //출력 끝
    private int displayRow =10;  //한 페이지에 몇 개의 로우 (선택 set)
    private int displayPage =10;  //한 페이지에 몇 개의 페이지 (선택 set)
    boolean prev; //prev 버튼이 보일건지 안보일건지
    boolean next; //next 버튼이 보일건지 안보일건지



현재 페이지를 표시해주기 위한 변수 : page

(처음에 보일 페이지는 1페이지이므로 page에 1을 대입해주었음.)


member테이블에 있는 전체 레코드 갯수를 받아올 변수 : totalCount

(여기서는 351개 입니다.)


처음 페이지와 끝 페이지를 받아올 변수 : beginPage, endPage

(위에 페이지 표시에서 beginPage는 1, endPage는 10입니다.)


한 번에 표시할 레코드의 갯수를 넣어줄 변수 : displayRow

(displayRow=10한 페이지에 10명의 회원정보를 표시하겠다.)


한 번에 표시할 페이지의 갯수를 넣어줄 변수 : displayPage

(displayPage=10 위 그림처럼 한 번에 1~10페이지, 즉 10개씩 표시하겠다.)


prev(이전) / next(다음)를 표시할지 말지 결정할 boolean 변수 : prev, next

(위 그림에서는 next만 보이고 prev는 안보임. 즉 next = true / prev = false)



 다음, Paging.java에

실제 페이징을 하기 위한 메소드 paging()을 만들어줍니다.

처음에는 계산이 조금 헷갈릴 수 있지만 차근차근 이해해 보시길 바랍니다.


Paging.java

    private void paging(){
        // prev, next, beginPage, endPage를 계산해서 만든다.
        // 2+9 = 11, 11/10 = 1, 1*10 = 10
        // 10+9 = 19, 19/10 = 1, 1*10 = 10
        // 11+9 = 20, 20/10 = 2, 2*10 = 20
        // 20+9 = 29, 29/10 = 2, 2*10 = 20
        // 111+9 = 120 120/10 = 12, 12*10 = 120
        
        // (2+9)/10 * 10 (1번 방법)
        //endPage = ((page+(displayPage-1))/displayPage)*displayPage;
        
        // 1/10 0.1(올림) 1 (2번 방법)
        endPage = ((int)Math.ceil(page/(double)displayPage))*displayPage;
        System.out.println("endPage : " + endPage);
        
        beginPage = endPage - (displayPage - 1);
        System.out.println("beginPage : " + beginPage);
        
        // 글 32개
        // 32/10 = 3.2 (올림) 4페이지
        // 2=?  2/10
        int totalPage = (int)Math.ceil(totalCount/(double)displayRow);
        
        if(totalPage<endPage){
            endPage = totalPage;
            next = false;
        }else{
            next = true;
        }
        prev = (beginPage==1)?false:true;//page가 11이상에만 나온다.
        System.out.println("endPage : " + endPage);
        System.out.println("totalPage : " + totalPage);
        
    }


위에서 소개했던 변수들을 이용해서

beginPage 그리고 endPage를 계산하는 방법을 먼저 알아보겠습니다.


우선 endPage부터..


위의 그림에서 endPage는 10이 나와야 합니다.

두 가지 방법이 있는데, 첫 번째 방법부터 살펴보겠습니다.


게시판을 한 번도 이용해보지 않으신 분은

아마 없으실 것이라고 생각합니다.

지금 내가 보고있는 페이지가 

1~10페이지이면 1~10페이지가 보여야하고,

11~20페이지이면 11~20페이지가 보여야합니다.


이를 계산하기 위한 변수는 page변수, 그리고 displayPage변수가 필요합니다.

몇가지 예를 들어 설명해보겠습니다.

잘 이해가 되지 않으시면 직접 적어가면서 따라와 보시기 바랍니다.


현재 내가 보고있는 페이지가 2페이지라면

endPage는 10이 나와야 합니다.


또, 내가 보고 있는 페이지가 10페이지라면

endPage는 10이 나와야하고,


11페이지를 보고있다면 endPage는 20이 나와야 합니다.



displayPage 변수는 10으로 이미 정해져 있고,

변하는 수는 자신이 보고있는 page변수 뿐입니다.


여기에서 page를 displayPage로 나눈 몫을 살펴 봅시다.


page/displayPage = endPage

1/10 = 0

2/10 = 0

3/10 = 0

4/10 = 0

5/10 = 0

6/10 = 0

7/10 = 0

8/10 = 0

9/10 = 0

10/10 = 1


여기에는 약간의 문제가 있습니다.

다른 페이지를 볼때는 정상적으로 0이 계산되는데

10페이지를 보고있을 때는 1이 계산되어, 같은 결과가 나오지 않는 것입니다.


여기서는 간단히 page에서 1을 빼주면 전부 0이 나오도록 만들 수 있습니다.


그런데.. 우리가 얻고 싶은 값은 0이 아니라 10입니다.


endPage = page/displayPage 에서

page가 1~10일 때, 항상 10이 나오도록 하기 위해서는


page/displayPage가 0이 아닌 1이 나오도록 해주고

거기에 10을 곱해주면 되겠군요..


분자 page = [1~10]

분모 displayPage = [10]


몫이 항상 1이 나오려면

분자가 10이상 19이하여야 하므로

page에 displayPage(여기에선 10)를 더해서 1을 빼주면

1~10페이지를 볼때 항상 10~19가 나옵니다.


그러면 몫이 항상 1이 나오게 되고 거기에 10을 곱하면

1~10페이지를 볼때 endPage가 항상 10이 나오게 되겠죠?


(page + displayPage - 1) / displayPage = endPage

1 + (10 - 1) / 10 = 1

2 + (10 - 1) / 10 = 1

3 + (10 - 1) / 10 = 1

...

10 + (10 - 1) / 10 = 1


여기에 10, 즉, displayPage를 곱해주면 

언제나 10이 나오게 됩니다.


결론은


endPage = (((page + (displayPage -1)) / displayPage) * displayPage


가 되는 것이죠.


두 번째 방법은

밑에서 사용해볼 Math 클래스의 ceil()메소드를 

사용해서 '올림'을 하는 방법입니다.


1/10 = 0.1 (올림 = 1)

2/10 = 0.2 (올림 = 1)

3/10 = 0.3 (올림 = 1)

4/10 = 0.4 (올림 = 1)

5/10 = 0.5 (올림 = 1)

6/10 = 0.6 (올림 = 1)

7/10 = 0.7 (올림 = 1)

8/10 = 0.8 (올림 = 1)

9/10 = 0.9 (올림 = 1)

10/10 = 1 (올림 = 1)


여기에 displayPage만 곱해주면 

항상 10이 나오게 됩니다.


endPage = Math.ceil(page/displayPage) * displayPage


여기까지 이해하셨다면 뒤는 쉽습니다!


beginPage를 구해보죠


beginPage는 위에서 어렵게 어렵게 구한

endPage와 displayPage를 이용해서 구해보겠습니다.


다시 그림을 소환하면..

beginPage는 endPage가 10이 나올때는 항상 1이 나와야 하죠?


그럼 간단하게

beginPage = endPage - 9


라고 하면 해결이군요..

그런데 이 구문은 이번 예제에서는 통하지만

10페이지 씩이 아니라 20페이지씩 표시하고 싶을때는

써먹을수가 없습니다..


따라서 조금 개선해서

beginPage = endPage - (displayPage - 1)


라고해주면 표시하고 싶은 페이지가

몇 페이지건 원하는 시작페이지와 끝페이지를 

구해낼 수 있게 되었습니다.



이번에는

totalPage

를 구해보겠습니다.


totalPage는 게시판에 총 몇개의 페이지가 필요한지를

넣어놓을 변수입니다.


그러기위 해서는 레코드의 총 갯수(totalCount)가 몇개인지

알아야합니다.


예를 들어 우리 예제에서

totalCount가 341개라고 한다면,


10개씩 표시되는 페이지 34개와

1개만 표시되는 페이지 1개


총 페이지는 35페이지가 되어야하죠.


즉,

totalPage(총 페이지)는

totalCount(341개)를 10으로 나눈

34.1을 '올림'해 준 값인 35가 된다.


라는 이야기입니다.


여기서 '올림'을 해주기 위해서는

자바에서 기본적으로 제공하는

Math객체의 ceil 메소드를 이용해야 합니다.

(ceil은 '천정'이라는 뜻으로 '올림'을 나타냅니다.)


Math.ceil()함수를 사용해서 totalPage를 계산해보면


totalPage = Math.ceil(totalCount/10)


이 됩니다.


앞서 beginPage를 계산했을 때와 마찬가지로,

우리 예제처럼 한 페이지에 10개씩 표시할 경우에는


그냥 저렇게 써도 아무 문제가 없겠지만,

20개 30개씩 표시한다면 위 식은 사용할 수가 없습니다.


그럼 이렇게 바꿔보겠습니다.


totalPage = Math.ceil(totalCount/displayRow)


이제 displayRow에 한 페이지에 몇개씩 표시할지만

넣어주면 어떤 상황에서든 totalPage를 계산할 수 있게 되었습니다.



이제

next와 prev입니다.


next와 prev는


표시를 할 것이냐 = true

표시하지 않을 것이냐 = false


두 가지 경우만 존재합니다.



우선 next와 prev의 개념은 다들 아실 것이라 생각하지만

한번 더 짚고 넘어가겠습니다.


현재 보고있는 페이지가 1~10일 때, next를 누르면 11페이지로

11~20일 때, next를 누르면 21페이지로 갑니다.


반대로 prev는

11~20페이지를 보고있을때 누르면 1페이지로,

21~30페이지를 보고있을때 누르면 11페이지로 갑니다.



그러면 next가 표시되는 경우의 수를 살펴보겠습니다.


예를 들어 총 341개의 레코드가 존재해서

35페이지까지 표시되어야 할 경우


1~10페이지를 볼 때 -> 표시됨(true)

11~20페이지를 볼 때 -> 표시됨(true)

21~ 30페이지를 볼 때 -> 표시됨(true)

31~35페이지를 볼 때 -> 표시되지 않음(false)


여기에서의 totalPage는 35

endPage는 10, 20, 30, 40입니다.


위와 똑같은 상황을 두가지 변수로 표시해보면


totalPage(35) > endPage(10) -> true

totalPage(35) > endPage(20) -> true

totalPage(35) > endPage(30) -> true

totalPage(35) > endPage(40) -> false


즉,

        if(totalPage<endPage){
            endPage = totalPage;
            next = false;
        }else{
            next = true;
        }


이렇게 하면 next를 표시할지 안할지 결정할 수 있습니다.



prev는 간단합니다.


현재 보는 페이지가 1~10페이지가 아니면

무조건 표시됩니다.


이번 예제에서는 beginPage를 이용해서 작성하였습니다.


지겨운 그림을 또 소환하면..

beginPage가 1이 아니면 무조건 표시이므로!


if(beginPage==1){prev = false}

else{prev = true}


가 됩니다.

삼항 연산자로 표시하면

위에 적은 우리 예제에 있는 코드가 됩니다.


이제 paging() 메소드의 작성이 모두 완료되었습니다.


그러면 이 paging()메소드를 어디에서 호출할 것이냐?


위에서 생성해준 getter / setter 중에서


totalCount의 setter인 

setTotalCount() 메소드는 페이징을 하기 위해서는

반드시 호출되어야 하는 메소드이기 때문에

이 메소드 안에서 paging() 메소드를 호출해줍니다.



paging.java에 대한 설명은

이것으로 마치고 이후의 포스팅에서

위에서 만든 변수들을 가지고 어떻게

paging을 구현하는지 살펴보도록 하겠습니다.



'JSP > 기본다지기' 카테고리의 다른 글

[JSP] 페이징(Paging) ③ [11월28일]  (1) 2016.11.29
[JSP] 페이징(Paging) ② [11월28일]  (2) 2016.11.29
JSP 8일차 필기 (EL 태그)  (0) 2016.10.28
JSP 7일차 필기 (Bean)  (0) 2016.10.26
JSP 7일차 필기 (Cookie)  (0) 2016.10.26