관리 메뉴

새로운 시작, GuyV's lIfe sTyle.

닷넷 게시판 만들기 Part 48 - 페이징 구현 본문

ⓟrogramming/asp.net 게시판

닷넷 게시판 만들기 Part 48 - 페이징 구현

가이브 2011. 6. 21. 19:01

2011/05/13 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 31
2011/05/16 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 32
2011/05/18 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 33
2011/05/19 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 34
2011/05/23 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 35
2011/05/25 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 36
2011/05/26 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 37
2011/05/27 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 38
2011/05/30 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 39
2011/05/31 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 40
2011/06/01 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 41
2011/06/08 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 42
2011/06/09 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 43
2011/06/13 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 44
2011/06/14 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 45
2011/06/15 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 46
2011/06/17 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 47



1. 닷넷 개발환경 준비, 테스트
2. 닷넷 알아보기 [7/7]
3. asp.net 컨트롤 [10/10]
4. 데이터베이스(DB) [7/7]
5. 닷넷 게시판을 만들어보기 전에.. [4/4]
6. 게시판 만들기 [18/..]



앞서서 만든 [이전페이지], [다음페이지] 구현에 필자가 큰 실수를 했었는데, 처음에 만들 때 라이브러리에 바로 하지마시고 aspx 에서 구현한 후에 테스트를 거쳐서 완성되면 라이브러리로 옮기는 형식으로 하시길 바란다.


이번엔 오른쪽에 있는 숫자로 움직이는 페이지 링크를 만들어보도록 하자. 숫자 페이징도 결국엔 산수놀이로 만들어지는데, 조금만 생각해보고 코드로 표현하면 아마 별 무리없이 만들어질 것이다. 먼저 구현하기 위해 필요한 자료가 어떤 건지 알아야 되겠고, 어떻게 요리조리 굴려보면 될지 빈 노트에 펜으로 그려가며 생각해보자.

먼저 구현할 기능을 점검해보자.

[이전10] 1 2 3 4 5 6 7 8 9 10 [다음10]


위와같이 처음에 1페이지일 때는 1~10까지의 숫자가 나오게 된다. 만약 페이지번호가 11에서 20 범위 내에 있을 때, 예를 들어 14페이지라고 생각하면..


[이전10] 11 12 13 14 15 16 17 18 19 20 [다음10]


이렇게 될 것이다. 즉 10개 단위로 자른게 하나의 큰 블럭이라고 보면 되겠다. 이걸 너무 길면 5개로 할 수 있고, 더 길게 15개로도 할 수 있겠다.

여기에 필요한 정보는 바로 '(1)현재 페이지'이다. 현재 페이지가 어떤 블럭에 들어있는지를 알면 표시되는 범위의 시작부터 블럭수(지금은 10개)를 쭉 표시하면 된다. 그리고 현재페이지와 같은 번호는 링크를 없애고 그저 진하게(<b>태그) 해주면 다른 페이지 이동과 구분이 될 수 있겠다.

현재 14페이지인 상황에서, 게시판의 전체 페이지 수가 "15"페이지일 경우에는 링크를 잘라야 된다. 아니면 아예 14 이후부터는 없애버려서 대놓고 '더 없음!'을 알려주는 의미를 부여해도 되겠다. 그러므로 '(2)전체 페이지 수'가 필요하다.

앞서 말한 '(3)페이지 블럭크기'도 정해주면 되겠다. 위의 예제는 블럭크기가 10이다. 이 값에 따라 [이전n개],[다음n]개 그리고 가운데 페이지 이동 링크 숫자들의 나열될 갯수가 정해진다.

마지막으로 부가적으로 필요한 값들인 우측 [이전,다음]페이지 이동처럼 'page'같은 GET으로 넘겨질 페이지변수, 검색에 필요한 변수 - 우리 게시판은 두가지(변수 stype와 svalue) - 등이 있겠다. 즉 페이지 링크는 다음처럼 <a>..</a>로 표현할 수 있는 것이다.

/board_list.aspx?[페이지변수명]=[이동할페이지]&변수1=값&변수2=값&.....

'페이지 블럭'에 대해서 한번 생각해보자. 페이지 블럭이 10이고, 전체 페이지가 12이라면 전체에서 두번째 블럭까지 나올 수 있다. 1~12 숫자 페이지를 표현해야 하므로, 이것을 [1~10], [11~12] (또는 [11~20]) 이렇게 두 구간으로 자를 수 있다. 이것은 전체 페이지 수를 알면 구할 수 있는 값이다. 만약 '현재 페이지'로 구현을 한다면 현재 페이지에서 다음으로 넘어갈 수가 없다. 당연히 전체 페이지로 구해야한다.

앞의 구현방법으로 가상의 값으로 결과를 예상해보자.


[상황]
총페이지수 : 32개 
현재페이지 : 14페이지
한블럭크기: 10개



[결과]
1. 처음 열었을 때
(내부값 - 현재블럭위치 : 2)
[1] .. [이전10] 11 12 13 14 15 16 17 18 19 20 [다음10] .. [32]

2. [이전10] 클릭했을 때
(내부값 - 현재블럭위치 : 1)
현재페이지 페이지 : 1
[1] .. [이전10] 1 2 3 4 5 6 7 8 9 10 [다음10] .. [32]


복잡해 보일 수 있으니 (필자가 산수에 많이 약하다 ^^) 차근차근 살펴보도록 하자.

먼저 우리가 구현할 메서드의 이름은 앞에 [이전/다음]처럼 PageGen2(..)로 한다. 인수는 현재페이지번호, 총 페이지수, 현재리스트의 파일명(우리는 board_list.aspx), 기타전송값(우리는 c,style,svalue), 페이지변수이름(우리는 page), 블럭당 표시할 갯수(우리는 10개) 이 정도가 나올 수 있다. 

  public string PageGen2(int page, int totalpage, string strFileName, string strLinkString, string strLinkName, int blockcount)

메서드는 이렇게 정의하도록 하고, 처음 만들 때는 board_list.aspx 에서 작업하자. 컴파일 필요없이 바로 볼 수 있으니 좀 더 쉽다.


작업에 앞서 우리가 호출하는 방법은..

   lblPageMove2.Text = PageGen2(NOW_PAGE,
          PAGE_COUNT,
          "board_list.aspx",
          String.Format("c={0}&stype={1}&svalue={2}", CATEGORY_ID, STYPE, SVALUE),
          "page",
          4);




이렇게 줄 수 있다. 인수를 구분하는 콤마(',')를 잘 구분하자. Page_Load() 에 앞서만든 [이전/다음] 페이지 이동 Label 처럼 미리 호출해놓고 결과를 하나씩 확인하는게 좋겠다.



이렇게 선언하고, board_list.aspx 에 (일단) 메서드를 만든다.

  public string PageGen2(int page, int totalpage, string strFileName, string strLinkString, string strLinkName, int blockcount)
  {
   // 리턴해줄 문자열
   string tmp = "";

   return tmp;
  }




자, 이제 모든 준비가 다 끝이났다.

 



여러분들이 좀 더 구분하기 쉽도록 그림을 그려보았다. 위의 예제는 현재 페이지는 6페이지이고, 블럭단위를 4개로 잡았다. 현재 상태는 4개로 자른 6페이지이므로 두번째 블럭에 위치한 상태라고 볼 수 있다.

이것을 실제 구현한 결과는 다음 그림과 같다.



앞서 만든 PageGen1(..) 처럼 이 녀석도 문자열을 계속해서 붙여나갈것이다. 좌측부터 분해해보면 총 5개이다.


[1] - 1페이지 이동
[이전 4개] - 이전 블럭으로 이동
.. 5 6 7 8 .. - 현재 블럭에서 페이지 이동
[다음 4개] - 다음 블럭으로 이동
[14] - 끝페이지 이동



[1페이지 이동]을 작업하기 전에, 상수로 만들어두면 편한게 있다. 링크로 붙일 값들인데, 얘들은 앞으로 매우 빈번하게 사용할 것 같으므로 하나의 변수로 만들어주자.

 

public string PageGen2(int page, int totalpage, string strFileName, string strLinkString, string strLinkName, int blockcount)
{

string tmp = "";
string LINK_STR = strFileName + "?" + strLinkString + "&" + strLinkName + "=#PG#";

return tmp;
}



LINK_STR 이름의 문자열 상수는 필요한 값들을 인수로 받아오는 것을 잘 조합시켰다.

/board_list.aspx?strLinkString&page=#PG#

붙여보면 위처럼 나타낼 수 있다. 페이지의 값은 #PG# 로 한 이유가, 모든 링크의 페이지 번호가 다르다. 이것은 나중에 실제 페이지가 들어갈 수를 LINK_STR.Replace("바꿀문자열", "변경할문자열"); 메서드를 이용해서 쉽게 사용할 수 있기 위해서이다.

그리고 전체의 블록 갯수와, 현재의 블록 위치를 구한다.

 

public string PageGen2(int page, int totalpage, string strFileName, string strLinkString, string strLinkName, int blockcount)
{

string tmp = "";
string LINK_STR = strFileName + "?" + strLinkString + "&" + strLinkName + "=#PG#";

   // 총 페이지 수로 전체 블록갯수를 구함
   int TOTAL_BLOCK = totalpage / blockcount;
   if (totalpage % blockcount != 0)
    TOTAL_BLOCK++;
   // 현재의 페이지 번호로 지금 위치한 블록을 구함
   int NOW_BLOCK = page / blockcount;
   if (page % blockcount != 0)
    NOW_BLOCK++;


return tmp;
}






이 그림처럼 15페이지의 전체 블록수는 4개이다. 그리고 현재 페이지인 6페이지가 위치한 곳은 2블럭이다. 이 값을 구해놓으면 앞으로 만들 녀석들이 쉽게 구해진다.


이제 화면에 보여질 첫 페이지 이동링크를 tmp 문자열 변수에 붙여보자. 첫 페이지는 지금 페이지가 1페이지가 아니라면 무조건 나오도록 하기로 한다. 


(..)

   // 첫 페이지 이동링크
   if (page != 1)
    tmp += String.Format("<a href='{0}'>[1]</a> .. ", LINK_STR.Replace("#PG#", "1"));




좀 복잡할 수 있지만, 현재 페이지가 1페이지가 아니라면 tmp 문자열 변수에 <a>..</a>태그로 감싸진 [1]을 보여준다는 말이다. 앞서 만든 꽤 길어지는 LINK_STR 을 활용해서 쉽게 1페이지로 이동하는 링크를 만들 수 있다.



#참고#
String.Format() 메서드와 Replace() 메서드가 함께 사용되어서 헷갈릴 수 있으나, 괄호를 먼저 감싸주면 코딩하기에 매우 편하니 괄호처리부터 해주고 인수들을 하나씩 넣는 방법으로 하자.

tmp += String.Format("<a href='{0}'>[1]</a> .. ", LINK_STR.Replace("#PG#", "1"));


이것은 다음처럼...

tmp += String.Format("", );

tmp += String.Format("<a href='{0}'>[1]</a> .. ", );

tmp += String.Format("<a href='{0}'>[1]</a> .. ", LINK.Replace("", ""));

tmp += String.Format("<a href='{0}'>[1]</a> .. ", LINK.Replace("#PG#", "1"));

이렇게 완성시킬 수 있다. 사용할 메서드의 인수를 먼저 잡아주고 내용을 넣어주면 편하다. 그리고 과감히 엔터를 쳐서 문법에 맞추고 알아보기 쉽게 하는 방법도 괜찮다


이제 두번째 [이전o개] 를 붙여보자. 이 조건은 아까 구했던 "현재 블록위치"로 구분할 수 있다.




(..)

   // 첫 블럭은 [이전n]이 없음 링크도 없음
   if (NOW_BLOCK == 1)
    tmp += String.Format("[이전 {0}개] .. ", blockcount);
   // 두번째 블럭은 [이전n]에 링크
   // 공식: 현재 블럭에서 앞으로 두칸 앞 블럭수에서 블럭단위를 곱해주고 +1 을 해주면 이전블럭의 첫 페이지가 구해짐
   else
    tmp += String.Format("<a href='{0}'>[이전 {1}개]</a> .. ",
      LINK_STR.Replace("#PG#", ((NOW_BLOCK-2)*blockcount+1).ToString()  ),
      blockcount);
 


(계속해서 tmp 문자열에 붙이고 있음을 생각하시기 바란다)

이렇듯 현재 블럭이 1이라면 이동할 필요가 없으므로 링크없이 보여주고, 1이 아니라면 이전 블럭으로 위치를 이동할 수 있으므로, 이전 블럭이 시작되는 페이지를 구해준다.





즉, 현재처럼 6페이지에 있다면 지금은 두번째 블럭이므로 이전 블럭인 '1'로 이동가능하다. 그리고 실제 이동할 페이지는 이전 블럭의 첫 페이지인 '1'페이지이다. 이것은 14페이지라고 해도 이전블럭인 '9'로 이동가능해야 하므로, 산수놀이가 필요하다.


((NOW_BLOCK-2)*blockcount+1)
[풀이] (2 - 2) * 4 + 1 = 1


필자의 산수방법인 이와 같다. 산수실력이 더 뛰어난 여러분들도 나름대로의 방법을 생각해서 값들을 조합해보자. 별별 산수가 다 나올 수 있다. 가상으로, 현재의 페이지가 12일 때도 적용되는지 계산을 해보자. 원하는 값이 구해지면 된다.

이제 중간에 숫자로 연속되게 나오며 이동할 수 있는 부분을 붙여보자.



(..)

    for (int i=1; i <= blockcount; i++)
    {
     int START_NUMBER = (NOW_BLOCK-1)*blockcount;
     // 숫자가 현재페이지와 같으면 그냥 링크없이 빨간색 진하게 표시
      if (START_NUMBER + i == page)
      {
       tmp += String.Format(" <font color='red'><b>{0}</b></font> ", page);
      }
      // 다르면 링크가능
      else
      {
       tmp += String.Format(" <a href='{0}'>{1}</a> ",
            LINK_STR.Replace("#PG#", (START_NUMBER+i).ToString()),
            ((NOW_BLOCK-1)*blockcount + i ));
      }
     // 숫자가 계속 돌다가 전체페이지에 다다르면 현재의 for()를 빠져나옴
     if (START_NUMBER + i == totalpage)
      break;
    }






그림처럼 지금 상황으로는 [5 6 7 8] 이 나와야되고, [5 6 7 8] 이렇게 현재페이지는 빨간색으로 링크를 걸어줄 필요가 없는 결과를 내는 것이다. 즉, 현재의 블럭위치에서 첫 번호. 그러니까 블럭단위 4로 잘라주면 나오는 처음의 값(녹색 동그라미처럼 ) 1/5/9/13/.. 이 총 페이지에 대해 나오게 되는데, 이 현재의 블럭의 시작 값을 구해주고 블럭 갯수만큼 for(..)로 루프를 돌려버리면 된다. 소스와 잘 비교해보자.

이제 다음 블럭과 마지막 페이지는 앞서 한 1페이지이동, [이전n] 이동과 거의 동일한 방법이다.




(..)


   // 다음 블럭은 현재의 블럭과 총 블럭이 같지 않을 때 표시
   if (NOW_BLOCK == TOTAL_BLOCK)
    tmp += String.Format(" .. [다음 {0}개] ", blockcount);
   else
    tmp += String.Format(" .. <a href='{0}'>[다음 {1}개]</a> ",
      LINK_STR.Replace("#PG#", ((NOW_BLOCK*blockcount)+1).ToString()  ),
      blockcount);
   // 마지막 페이지 이동링크
   if (page != 1)
    tmp += String.Format(" .. <a href='{0}'>[{1}]</a>",
           LINK_STR.Replace("#PG#", totalpage.ToString()),
           totalpage);

   // 만든 페이징 리턴
   return tmp;
  }





필자 입장에서도 설명하기가 참 곤란한 부분이긴 한데, 뭐든지 결국 구현하는 방법을 좀 고민해보고 손으로 직접 그려가며 고심해보면 만들어지는 녀석이다. 단지 코딩이 좀 안된다거나 하는 문제가 있겠지만 말이다.

직접 테스트를 해보고, 문제가 발생하거나 오류가 발생하면 수정도 하자. 일부러 전체 소스를 미리 제공하지 않고 마지막에 드리는 이유는 일단 삽질을 해보시라는 의미이다. ^^

잘 작동한다면 이를 Board.cs 라이브러리에 넣고 컴파일 한 후, 적용하자. 
다시 말씀드리지만, 필자는 이미 이 글을 작성하면서 결과물을 완성 후 정리를 한다. (다음 강의물을 미리 해놓지는 않지만) 그러므로 여러분들은 중간중간에 잘 작동하지 않는 것이 당연하다.

(여담이지만 필자가 글 하나를 작성하는 시간은 최소 1.5시간에서 길게는 3시간을 넘긴다.)



board_list.aspx

Board.cs




이제 게시판 리스트도 슬슬 마무리되어가는 느낌이 든다. 물론 더 많은 기능을 넣을 수 있다. 그 기능이 어떤 것이든 여러 값을 어떻게 asp.net 문법과 함께 잘 가지고 놀 수 있는지의 방법일 뿐이다.


그럼 다음시간에..









반응형
Comments