본문 바로가기
Programming

페이징 처리 UI&Application Logic

by Mizix 2010. 3. 8.
반응형
페이징 처리 UI&Application Logic

  

    UI 페이징은 왜 필요할까?

    게시판의 글은 1개 부터 수천 혹은 수만개 일수 있다. 게시글이 몇 개에 그치는 경우는 굳이 페이징 처리라는 개념을 생각

    할 필요가 없다. 하지만 게시글 수가 증가가 예상되거나 혹은 게시글 수가 엄청 많은 경우 하나의 페이지에 모든 것을

    표현하기에는 불가능하겠다. 그럼으로 게시판 하단에 페이지 나누어서 페이지간의 이동을 원활하게 해줄 수 있는 페이지

    링크를 만들기 위해 필요하다고 하겠다.

 

    TonkJsp 카페 전체 게시글에 대해서 보면 아래 그림과 같이 나올 것이다.

 

    

 

    네이버는 보통 게시글을 10개 페이지로 나누어서 보여줍니다. 11개 페이지는 다음으로 링크가 걸려 있는 거죠 .

    만일 11페이지를 보고 있다면 "이전" 이라는 글자가 나오고 10페이지로 링크가 걸려 있을 것입니다.

 

    현재 페이지는 굵게 표시가 되고 나머지는 링크가 걸려 있습니다. "다음"은 11페이지를 가르키면서 링크가 걸려 있는 것이

    되겠네요.

    즉, 게시글이 더 있지만 한 페이지에 다 표시하기에는 무지 불편할 것입니다. 페이지가 나누어져 있지 않다면 마우스 커서

    로 해당 게시물을 찾거나 커서를 움직여서 해당 게시물을 봐야 하지 않을까 싶네요. 허허 ^^

 

    DB 단의 페이징 쿼리가 시스템의 성능면을 강조한 것이라면 UI 단의 페이징 처리는 사용자의 편리성을 더 강조한 것이라

    할 수 있을 것입니다.     

 

    JSP 스크립트 단에서 처리

 

        예를 들어 DB에 데이터가 총 26개가 아래 그림과 같이 들어 있다고 가정합니다.(오라클 기준)

 

       

       

        그리고 한 페이지에 3개의 게시물이 출력되도록 하고 네비게이션 부분은 3 페이지씩 나오도록 설계를 하겠습니다.

       

        

 

        [방법 - 1]

 

        pagenum : 페이지 번호 (1페이지, 2페이지, ....)

        pagesize : 페이지 사이즈(한 페이지에 몇개의 게시글을 출력할 것인지 나타내는 변수) 

        total  :  전체 게시글 수는 26개 위의 데이터를 기준으로 ^^

 

        int pagenum = 1;

        int pagesize = 3;

        int pageGroup = 3; 

 

        total =  26 (위의 데이터를 기준으로 ^^)

      

        ① 페이지 네비게이션을 위한 전체 페이지 수

            int totalPage = (total-1)/pagesize + 1; 혹은 int totalPage= total/pagesize + (total%pagesize == 0?0:1);

 

            [예 1 페이지인 경우 - 결과는 나머지 페이지] 

 

           

        

        ② 이전 페이지 존재 여부

            

             이전에 보여줄 3개의 페이지가 있는지 계산은

             int prev3 = (int)Math.floor((pagenum-1)/pageGroup(3.0))*pageGroup;

 

             [1,2,3 페이지의 경우는 모두 0개의 이전 페이지가 존재]

 

             

 

             [4,5,6 페이지의 경우는 모두 3개의 이전 페이지가 존재]

 

            

             

             [7,8,9 페이지의 경우는 모두 6개의 이전 페이지가 존재]

              

             계산 생략 ...

          

             실제로 사용하는 경우예는

 

             if(prev3>0){

                  <a href="listTest.jsp?pagenum=<%=prev3%>" style="text-decoration: none">이전</a>

             }

 

             Math : double floor() 메소드

             입력된 매개변수보다 같거나 적은 수들 중에서 가장 작은 정수를 리턴하는 메소드           

 

        ③ 다음 페이지 존재 여부

 

            이후에 보여줄 3 개의 페이지가 존재하는 경우는

            int next3 = prev3+(pageGroup+1);

           

            [1,2,3 페이지의 경우는 모두 4페이지라는 다음 페이지가 존재]

            [4,5,6 페이지의 경우는 모두 7페이지라는 다음 페이지가 존재]

            [7,8,9 페이지의 경우는 모두 10페이지라는 다음 페이지가 존재]

            [10,11,12 페이지의 경우는 모두 13페이지라는 다음 페이지가 존재]

            [13,14,15 페이지의 경우는 모두 16페이지라는 다음 페이지가 존재]

            [16,17,18 페이지의 경우는 모두 19페이지라는 다음 페이지가 존재]

            [19,20,21 페이지의 경우는 모두 22페이지라는 다음 페이지가 존재]

            [22,23,24 페이지의 경우는 모두 25페이지라는 다음 페이지가 존재]

            [25,26 페이지의 경우는 모두 27페이지라는 다음 페이지가 존재할까?]

            

            위의 데이터를 보면 27페이지는 존재하지 않는다. 무작정 prev3+(pagesize+1)를 더하는 것이 아니라 

            어느 시점이 되면 없다는 것을 표시하는 로직을 구현해야 한다. 그 시점이라는 것은 위에서 구한 

            totalPage를 넘어서는 안되는 것이다. totalPage 크다는 것은 로직상 맞지 않음으로 표현할 수 없다. 오류^^

 

            실제로 사용하는 경우에는

           

            if(next3<=totalPage){

                 <a href="listTest.jsp?pagenum=<%=next3%>" style="text-decoration: none">다음</a>

            }

 

        ④ 페이지 링크 수

            페이지 네비게이션 부분은 반복문을 써야 하는 로직으로 어떻게 보면 복잡해 보이지만 또 어떻게 보면

            별로 복잡한 것도 없다.

 

           - 반복문의 초기값은

             매 페이지마다 시작되는 값은 다 틀리다. 즉, 값을 고정해서 사용할 수 없다는 결론을 같게 된다. 

             int i=prev3+1;     // 시작값으로 적당하겠네요 ,,, 생각하는 관점에 따라 틀림 ...

 

           - 반복문의 조건은

             총 페이지 수를 넘어선 되지 않고 다음 페이지 값보다는 무조건 작아야 한다.

              i<next3 && i<=totalPage

 

          - 반복될 내용의 조건은

            현재 페이지가 링크 페이지를 구별 짓기 위해 간단 조건문을 하나 넣어 둔다.

            if(i==pagenum){

                 [<b><font color="red"><%=i%></font></b>]

            }else{

                 [<a href="listTest.jsp?pagenum=<%=i%>" style="text-decoration: none"><%=i%></a>]

            }          

 

            실제로 사용하는 경우예

 

           for(int i=1+prev3 ; i<next3 && i<=totalPage ; i++){
                 if(i==pagenum){
                      [<b><font color="red"><%=i%></font></b>]
                 }else{
                      [<a href="listTest.jsp?pagenum=<%=i%>" style="text-decoration: none"><%=i%></a>]
                 }
            }

         

        ⑤ 첫 페이지, 마지막 페이지

             첫 페이지를 나타내는 Top는 1 페이지를 링크만 걸면 되어서 굳이 설명할 것도 없네요 ^^

             예) <a href="listTest.jsp?=pagenum=1" style="text-decoration: none">Top</a>

             마지막 페이지는 총 페이지를 구한 값이 되겠다. 즉 Bottom 값은 총 페이지 값과 동일하다. ^^

             예) <a href="listTest.jsp?pagenum=<%=totalPage%>" style="text-decoration: none">Bottom</a>           

 

        ---------------------------------------------------------------------------------------------------

 

        [방법 - 2]

 

        [방법 -1] 과는 별반 차이는 없지만 생각하는 관점을 다른 식으로 하여 접근하도록 하겠습니다.

        

        pagenum : 페이지 번호 (1페이지, 2페이지, ....)

        pagesize : 페이지 사이즈(한 페이지에 몇개의 게시글을 출력할 것인지 나타내는 변수) 

        total  :  전체 게시글 수는 26개 위의 데이터를 기준으로 ^^

 

        int pagenum = 1; //  현재 페이지를 나타냄... 기본 1페이지 부터 시작을 해서, 별 다른 기준은 없음

        int pagesize = 3;

        int pageGroup = 3;

        total =  26 (위의 데이터를 기준으로 ^^)

 

        ① 페이지 네비게이션을 위한 전체 페이지 수

            [방법-1]과 동일함.

        ② 출력될 시작 페이지와 끝 페이지 별도로 계산

            [시작 페이지 계산]

            int startPage = ((pagenum-1)/pageGroup)*pageGroup+1;

            혹은 int startPage=(int)(pagenum/pageGroup)*pageGroup+1

           

            예) 1,2,3 페이지인 경우는 1 시작페이지다.  

 

               

 

            예) 4,5,6 페이지인 경우는 4 시작페이지다.

 

            

 

            예) 7,8,9 페이지인 경우는 7 시작페이지다.

     

             계산 생략 ...

                                      

           [끝 페이지 계산]

           int endPage = (((startPage -1)+pageGroup)/pageGroup)*pageGroup;

           혹은 int endPage=startPage+pageGroup-1;

          

           예) 시작 페이지가 1 인 경우 끝 페이지는 3

           

           

 

           예)  시작 페이지가 4인 경우 끝 페이지는 6

 

           

 

           예) 시작 페이지가 7인 경우 끝 페이지는 9

 

           계산 생략 ...          

 

        ③ 이전

            "이전" 버튼이라는 것이 나오기 위해서는 현재 페이지가 한 페이지에 출력되는 링크의 수보다 클 경우에

             나오게 된다. (말이 좀 복잡해 보이지만 그렇지도 않는 거 같다.) 

 

             [방법 -1]과는 틀리게 생각할 문제인데, [방법-1]은 "이전" 페이지 계산에서 1를 더하지 않았다.

             즉, "이전" 페이지가 0보다 크다면 무조건 이전 페이지가 존재한다는 것으로 계산한 것이다. 

 

             하지만 [방법-2]의 경우는 좀 틀리다.  pagesize가 현재 페이지 보다 크다면 무조건 "이전" 페이지가

             존재하는 것으로 계산한 것이다. 결국 [방법-1]과 [방법-2]의 결론은 같다. 생각하는 관점이 틀린 것 뿐이다.  

            

             실제로 사용하는 경우는

           

             if(pagenum>pageGroup){

                    <a href="listTest.jsp?pagenum=<%=startPage-1%>" style="text-decoration: none">이전</a>

             }

  

        ④ 다음

            "다음" 버튼이 나오기 위한 방법은 [방법-1]과 비슷하다.

            "다음" 버튼이 나오기 위해서는 전체 페이지 수 보다는 작게 로직을 짜면 되겠다.

 

            실제로 사용하는 경우에는

 

            if(totalPage>endPage){

                   <a href="listTest.jsp?pagenum=<%=endpage+1%>" style="text-decoration: none">다음</a>

            }

              

        ⑤ 페이지 링크 수

            현재 페이지가 위치한 그룹 내의 페이지를 모두 구하는 로직을 구현해야 한다. 시작 페이지와 끝 페이지를 

            이미 구하였음으로 시작과 끝사이의 값 사이를 반복하면 된다. 

 

            실제로 사용하는 경우에는 

             

             for(int i=startpage; i<=endpage; i++){
                    if(i==pagenum){
                        [<b><font color="red"><%=i%></font></b>]          
                   }else{
                       [<a href="listTest1.jsp?pagenum=<%=i%>" style="text-decoration: none"><%=i%></a>]
                  }
             } 

        

    JAVA 어플리케이션을 이용하는 방법(빈즈 사용)

 

         JSP 스크립트 단에서 처리하는 것과는 별반 차이는 없다. 빈즈 처리 임으로 별도의 유틸리티 메소드를 만드는 과정이

         필요하다.

 

         메소드는 2개로 분리해서 작성하도록 한다.

 

         ① 게시물의 총 페이지 구하기

 

          [인자 값]

          - 총 게시물 수 : total

          - 페이지 사이즈 : pagesize

 

          [리턴 값]

          - 총 페이지수 : page_cnt 

 

          [로직]

          int page_cnt = (int)(total/pagesize);

    

          if(page_cnt == 0)

               page_cnt = 1;

         else if(page_cnt >0 && (total%pagesize) > 0 )

               page_cnt = page_cnt+1;

         else if(page_cnt >0 && (total%pagesize) == 0 )

               page_cnt = page_cnt+1;

 

         return page_cnt;

 

         위의 식을 한 줄로 쓰려면  int page_cnt = total/pagesize + (total%pagesize == 0?0:1);

 

         실제로 사용하는 경우

           

         public static int totalpage(int total , int pagesize){

                   int page_cnt = (int)(total/pagesize);

    

                   if(page_cnt == 0)

                        page_cnt = 1;

                  else if(page_cnt >0 && (total%pagesize) > 0 )

                        page_cnt = page_cnt+1;

                  else if(page_cnt >0 && (total%pagesize) == 0 )

                        page_cnt = page_cnt+1;

 

                  return page_cnt;

         }

  

         ② 페이지 링크 메소드

 

         [인자 값]

         list 게시물 페이지를 나타내는 페이지명 : list_url

         파라미터로 값을 넘기는 경우 파라미터 값들 : queryString

         총 게시물 수 : total

         페이지 사이즈 :  pagesize

         현재 페이지 : pagenum        

         링크 페이지 그룹 : pageGroup

 

         [리턴 값]

         "이전" + 페이지 링크 + "이후" 를 받아 전달하기 위한 문자열 값  : pBuf

 

         [로직]

         StringBuffer pBuf = new StringBuffer("\r\n");

 

         if(queryString == null || queryString.equals("")) queryString = "";

 

         /*

             실제로 사용하는 경우에는 페이지 번호와 문자열 값이 붙어서 하나의 스트링 값으로 넘기는 경우가 많다. 

             그도 그럴께 하나 하나 파라미터 값을 메소드에 넘기는 것은 무지하게 비효율적이다. 파라미터가 100개라고 가정하면

             끝도 없을 것이다. 따라서 이런 경우 페이지 번호와 문자열 값을 분리해서 작업을 해야 한다.

 

             문자열 값은 보통 게시물 검색에 주로 사용됨으로 띠어 놓고 생각하기 어려운 문제이다. 꼭 로직을 이해하고

             본인의 개발 스타일에 맞추기 바란다.

 

             페이지 번호를 맨 뒤에 파라미터 값으로 붙여서 사용하는 경우로 예를 들어서 설명하겠다.

             req_pg = 1, 2, 3, .........

         */

        

         int idx = queryString.indexof("&req_pg");

 

         /* indexof("문자열 인자값") 해당 문자열 값이 없으면 -1를 반환한다.  */

 

         if(idx>-1) {

              queryString = queryString.subString(0,idx);

         }

 

         int totalpage = totalpage(int total , int pagesize);  //  위에서 작성한 총 페이지를 구하는 메소드 사용

 

        /* 시작 페이지 */

        

       int startPage = ((pagenum%pageGroup)>0)

                            ?((int)(pagenum/pageGroup)*pageGroup+1)

                            :(((int)(pagenum/pageGroup)-1)*pageGroup+1);

       int endPage = startPage+pageGroup-1;

 

       /* "이전" 버튼

            1. pagenum>pageGroup 보다 큰 경우에도 이전페이지는 존재한다.  

            2. 아니면 이전 버튼 값을 미리 구하는 경우

                int prev3 = (int)Math.floor((pagenum-1)/pageGroup(3.0))*pageGroup;

                prev3>0 보다 큰 경우에도 이전 페이지는 존재한다.

       */ 

 

       if(startPage !=1){

            pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + (startPage-1) + "'> ◀◀ </a> /");

       }

    

       /* 페이지 링크 반복 문 */

 

      for(int i = startPage ; i<endPage && i<=totalPage; i++){

           if(i == pagenum){

                 pBuf.append("<Font size=2 color=red> " + i + " </Font>/");

           }else{

                 pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + i + "'><Font size=2> ");

                 pBuf.append(i + " </Font></a>/"); 

           }

      }

 

       /*  "이후" 버튼 */

      

      if(totalPage>endPage){

           pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + (endPage+1) + "'> ▶▶ </a> /");

      }

 

      /*  리턴 값  */

    

     return pBuf.toString();

 

     실제로 사용하는 경우에는

 

     public static String pageNavigation(String list_url,String queryString,int total,int pagesize,int pagenum,int pageGroup){

           StringBuffer pBuf = new StringBuffer("\r\n");

           if(queryString == null || queryString.equals("")) queryString = "";

 

           int idx = queryString.indexof("&req_pg");

 

           if(idx>-1) {

              queryString = queryString.subString(0,idx);

           }

 

           int totalpage = totalpage(int total , int pagesize);  //  위에서 작성한 총 페이지를 구하는 메소드 사용       

        

           int startPage =  ((pagenum%pageGroup)>0)

                                 ?((int)(pagenum/pageGroup)*pageGroup+1)

                                 :(((int)(pagenum/pageGroup)-1)*pageGroup+1);

           int endPage = startPage+pageGroup-1;

 

           if(startPage !=1){

                pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + (startPage-1) + "'> ◀◀ </a> /");

           }

   

           for(int i = startPage ; i<endPage && i<=totalPage; i++){

                 if(i == pagenum){

                       pBuf.append("<Font size=2 color=red> " + i + " </Font>/");

                 }else{

                      pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + i + "'><Font size=2> ");

                      pBuf.append(i + " </Font></a>/"); 

                }

           }

       

           if(totalPage>endPage){

                  pBuf.append("<a href='" + list_url + "?" + queryString + "&req_pg=" + (endPage+1) + "'> ▶▶ </a> /");

           }

    

           return pBuf.toString();

     }

 

   ⑶ JavaScript 를 이용하는 방법

 

   페이징 처리 UI 단을 자바 스크립트로 구현한 경우도 있다. 하지만 별로 추천하고 싶지는 않다.  왠지 자바스크립트는

   엔진에 대한 완벽성을 보장 받기 힘이든다. IE와 FireFox, 넷스케이프 모두 지원하도록 크로스 브라우저 코딩하기가 여간

   힘이 드는게 아니게 때문이다. 소스의 노출 역시 막기 힘이들고 이것은 결국엔 보안에 취약함을 나타내게 된다

반응형

'Programming' 카테고리의 다른 글

Boxing 과 Unboxing  (0) 2010.04.30
C# 기초.  (0) 2010.04.30
HTML과 XHTML의 차이  (0) 2010.02.14
[PHP Tip] PHP 함수를 Javascript 에서 사용하기  (0) 2010.02.12