2008. 9. 8. 14:54

JSP/Servlet 기본

@servlet-->was에서 실행되는 자바클래스를 만드는 규칙.
was(web application server)


-JavaEE 기술명세에 따라 작성된 서버
--톰켓(web:servlet/Jsp)
--weblogic(web+ 분산기능(EJB)):Bea's
--websphere:IBM's
--JEUS:Tmax's
--sun Java System AS9:sun's

 

@ Servlet 기술
- JavaEE 구현서버에서 실행되는 자바 클래스 만들기.

 interface (규칙): caller 와 callee사이의 규칙
 -callee(규칙을 준수하는 자바 클래스)가 갖춰야할 기능을 선언하고 있다.
 -caller가 이 기능을 사용(call)할 수있다.


caller (WAS) - servlet container : 생성과 사용 소멸 관리.
 servlet의 생성과 사용 소멸관리.(life-cycle)
Servlet Interface?
 -Caller 인 "Servlet Container"와 callee인 "Web Application " 사이의 호출 규칙


Servlet Container?
 Servlet Web Application의 life-cycle을 관리하는 서버
Servlet Application ?
 -Servlet Container에 의해 실행가능하도록 servlet규칙에따라 작성된 웹 애플리케이션


Servlet 규칙의 기능 명세?
-init() : Servlet Container가 서블릿을 생성 시킨후 초기화를 수행하기 위해 호츨..
-service() : Servlet Container가 클라이언트의 요청에 대해 작업을 수행하기 위해 호출.
-destory() : Servlet Container가 서블릿을 메모리에서 제거하기 전에 마무리작업을 위해 호출.
-getServletConfig()
-getServletInfo()

 

@ callback method(function)? 
-만든 메소드를 Application 이 호출하지 않고, Container 나 Server, OS 에서 호출하는 경우.


@ Web Servlet App. 서버에 배치하는 방법(deploy)..?
-JavaEE 구현(기술명세에 따라 만든)서버에 웹 에플리케이션을 배치.
 즉 "톰켓서버에 배치했다" 등의 표현.

@Web Application 배치 방법?
 -디렉토리 또는 묶음파일(*.war)로 서버의 특정 디렉토리에 올린다.


 - 디렉토리 구조.
StudyWeb.war
 /WEB_INF/web.xml       <--- 배치 설명 파일(Deployment Descriptor File:DD File)
  /classes <--- 컴파일된 클래스 파일
  /lib  <--- 컴파일 된 클래스 파일들을 .jar 파일들.
 /...   <--- 기타


@ Servlet 생성후 배치설명 파일에 등록?
-web.xml 파일에 Servlet에 대한 정보를 등록
-서블릿 정의 방법:
 <servlet>
         <servlet-name>HelloWorld</servlet-name>                  <-- servlet명
         <servlet-class>study.servlets.Hello</servlet-class>      <-- servlet 클래스 명
    </servlet>
-서블릿 서비스 이름(클라이언트에서 사용할 이름) 등록 방법:
 <servlet-mapping>
         <servlet-name>HelloWorld</servlet-name>           <-- 위에서 정의한 서블릿명
         <url-pattern>/Hi</url-pattern>                           <-- client에서 사용할 별명(url)
  </servlet-mapping>
@ Fully Qualified Name?(QName)
-패키지명을 포함한 클래스명


@ Context name?
- 웹 application 이름.
- 즉 클라이언트에서 접근할때 사용할 웹 application 이름


@public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        //web browser에 출력할 내용을 작성...개발자가..
    }
- 서블릿은 오직한번만 호출된다. 서비스메소드 안에 수행할 작업을 작성

 

@ Servlet 작성절차?
1) Servlet 인터페이스 구현 클래스 작성
2) web.xml 파일에 Servlet 클래스 정보 등록
3) 서버에 deploy (setup, install의 의미)


@ Servlet? Servlet App.
- 클라이언트에게 특정 서비스를 제공하기 위해 만들어진 Server-Side Application.
- javaEE 기술명세에 따라서 만든 서버에 의해 실행되는 프로그램.
- 서비스당 하나의 서블릿 하나를 만들어야한다.

 

@ GenericServlet??
--실제 service() 메소드에 구현에 관심..
--service() 메소드를 제외한 나머지 메소드를 미리 구현했음.
--개발자를 위한 도우미 클래스.
--javax.servlet.Servlet 인터페이스를 구현했음. 오직 하나의 메소드만을 구현하지 않았음..(service)

--추상클래스.

 

@ServletRequest??
- caller ? Servlet Application.
- callee ? Servlet Container
-Client 의 요청정보를 다루는 규칙(기능들)

 

@ServletResponse??
- caller ? Servlet Application.
- callee ? Servlet Container
-Client 로의 응답과 관련된 규칙

 

@service() 메소드에 넘어오는 파라미터(값)?
-ServletContainer가 값을 넘긴다.
-파라미터는?? ServletRequest와 ServletResponse 규칙에 따라 작성된 객체


@ Servlet의 출력에서 한글이 깨진다면 ??
- Servlet에서 출력할때 기본적으로 Unicode --> ISO-8859-1 로 변환 시키기 때문.
- ISO-8859-1(ISO-Latin-1): 영어및 유럽문자에 대한 코드(신호)정의. 한글에 대한 정의는 없다.
- 해결 : 출력스트림 객체를 얻기 전에 어떤 Character Set으로 변환할 지를 설정해야한다.
- res.setContextType("text/html;charset=UTF_8");

 

@ HTTP protocol??(www.w3.org)
-Web Server 와 Web Browser사이의 통신(요청/응답) 프로토콜.


@ HTTPRequest?
 - Web Browser에서 Web Server로 요청하는 형식

request-line
header-line*
CRLF
(message body)

예)
Accept: */*
Accept-Language: ko
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)

@ HTTPResponse?
- 웹서버가 웹브라우저에게 응답하는 형식

Status-line
header-line*
CRLF
(message body)

예)
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Content-Type: text/html;charset=UTF-8
Content-Length: 106
Date: Mon, 19 Mar 2007 13:42:28 GMT
Server: Sun Java System Application Server Platform Edition 9.0_01
Connection: close

<html>
<head><title>?븞?뀞?븯?꽭?슂</title></head>
<body>
<h1>?씤?궗</h1>
Hello!!!
</body>
</html>


@HEAD 요청방식??
- 서버에 요청자원의 HEAD정보만 요구함.
*프록시 서버를 개발할 경우 head를 사용한다.( 날짜를 가져오고 비교함 )

'My work space > JSP/Servlet' 카테고리의 다른 글

request.getAttribute  (0) 2008.09.08
jsp/Servlet 기본2  (0) 2008.09.08
게시판만들기-검색하기(펌)  (0) 2008.09.08
게시판만들기-페이지나누기(펌)ASP  (0) 2008.09.08
게시판 만들기 - 수정, 삭제하기(펌)  (0) 2008.09.08
2008. 9. 8. 14:53

게시판만들기-검색하기(펌)

게시판 만들기 - 검색하기(펌)




정말 지루하게 오래 지속되어 온 강좌도.. 이제 마지막 '검색하기' 부분만 남겨놓고 있습니다.
작년 가을에 시작된 강좌가 봄에 끝났으니.. 정말 게으르다는 말을 들어도 할 말이 없네요. -_-a
아는 것도 없으면서 덜컥~ 맡아버린 강좌였는데.. 어찌어찌 하다보니 여기까지 오고 말았군요.
개인적으로 아쉬움이 많이 남는 강좌였지만 나름대로 보람도 컸던 것 같습니다.
자.. 이제 칠판에 마지막으로 한마디만 쓰겠습니다.

"프랑스 만세..." (http://www.kyowoni.com/kid/kidroom/story/fine_09_01.asp)

오늘의 강좌는 '검색하기 ' 부분이 되겠습니다.
아마도 여러분들께서는.. 게시판에서 '검색' 하는 부분을 많이 접하셨을텐데요.
오늘은 그중에서도 가장 기본적인 검색 방법을 알아보도록 하겠습니다.

오늘 작성할 '검색하기' 페이지가 어떻게 작동하는지 강좌에 들어가기 전에 잠시 말씀드리면요...
검색하고픈 분류(이름, 제목, 내용)를 선택한 후, 검색할 단어를 입력합니다. 그리고 '검색' 버튼을 누르면
검색 조건에 일치하는 게시들만 추려서 '목록보기' 페이지의 형식으로 보여지게 할 것입니다.

'검색' 을 하기 위한 가장 핵심 사항은.. '기존 쿼리문에 조건문을 어떻게 주느냐 ' 는 것입니다.
사실.. 기존의 '목록보기' 쿼리문은 아무런 조건 없이 board 라는 테이블에 있는 모든 게시들을 전부~ 가져오는
것이었습니다. 단지 그 정보들을 순차적으로 정렬(ORDER BY) 했을 뿐이지요.

우리는 이미 지난 '리스트 보기(list)' 페이지 강좌에서 '조건문' 의 역할을 접해본 적이 있습니다.
기억이 안나신다면.. 잠시 다녀오시는 것도 나쁘지 않을 것 같습니다...만, 버뜨 그러나~~
여러분이나 저나, 피차.. 한곳에 몰두했을 때 다른 쪽으로 집중이 분산되는 것을 무척 싫어하는 사람들이
아니겠습니까? 더더군다나 그것이 클릭을 몇번씩이나 해야 하는 귀찮은 일이라면 더더욱 말이지요.. ^^
(사담입니다만.. 저희 사장님께서는 '프로그래머들은 적당히 게을러야 한다' 고 항상 말씀하십니다.
 그래야만 자신이 귀찮기 싫어서 더 좋은 UI(User Interface)를 생각해 낼 수 있다는 의미지요)

해서.. 오랜만에 Query Analyzer 를 가지고 몇가지 테스트를 해보도록 하겠습니다. (두둥~)
자.. 간만에 나오는 Query Analyzer. 순간 움찔하셨던 분들을 위해서 어떻게 실행하는지 말씀드리면요.

'시작 -> 프로그램 -> Microsoft SQL Server -> Query Analyzer' 를 실행하시면 됩니다.

그러면 로그인 하는 화면이 나오는데요. (화면 이미지까지 다시 올리지는 않아도 되겠지요?)
계정(Login name)과 비밀번호(password)는 여러분들 각자의 환경에 맞는 값들을 입력해 주시기 바랍니다.
(혹시 아직도 'sa' 와 '공백 비밀번호'를 쓰고 계시다면.. 이 참에 비밀번호라도 바꿔주는 것이 좋겠지요. ^^)

자.. 간만에 보는 반가운 Query Analyzer 화면이 떴습니다.
이제 우리는 검색에 관련된 테스트를 해보려고 합니다.
처음이니까.. 아주 간단하게 '김덕영' 이라는 사람이 쓴 게시만을 검색해 보도록 하겠습니다.
그렇다면 쿼리문을 어떻게 작성하면 될까요? 다음과 같이 작성하시면 되겠습니다.

Select * from board Where strName = '김덕영'

<그림 1>



페이지 나누기를 위해서 게시를 많이 입력했더니 상당히 많은 결과가 나오게 되었네요. ^^a
'훗.. 이정도야 이젠 유치하지' 싶으시지요? 자.. 그렇다면 이 상태에서 조금 더 진보된 검색을 알아보겠습니다.
글 쓴 사람중에.. '덕영'이가 있다는 것을 알고 있는데, 그 사람이 김덕영인지 이덕영인지.. 도무지 모르겠다
싶으면 어떻게 할까요?

Select * from board Where strName = '덕영'

혹시 이 방법을 생각하셨습니까? 아쉽게도.. 이렇게 하면 한개의 게시도 검색할 수가 없습니다.
이 조건문은 게시를 쓴 사람의 이름이 정확하게 '덕영' 인 경우 에만 해당하기 때문이지요.
그렇다면 어떻게 하면 좋을까요?

이런 경우에는 'like' 를 사용합니다.
이것은 '%' 문자와 함께 쓰이며, 조건에 해당하는 문자가 있는 경우를 모두 검색 합니다.
'%' 문자가 '%덕영' 처럼 앞에 있는 경우에는 문자열의 앞은 신경쓰지 않고, 마지막이 '덕영' 으로 끝나는 모든 게시를 검색하고, '덕영%' 의 경우에는 '덕영' 이라는 문자로 시작하는 게시를 모두 검색 합니다.

그렇다면 '%' 문자를 앞뒤로 모두 넣는 경우에는 어떻게 될까요? '%덕영%' 처럼 말이지요.
네.. 짐작하신 대로 문자열 전체를 통틀어서 '덕영' 이라는 문자가 존재하는 모든 게시를 가져오게 됩니다.
말만 자꾸하면 머리 아프시지요? 자.. 다음 쿼리문을 한번 실행해 보시지요.

Select * from board Where strName like '%영%'

<그림 2>



자 어떻습니까? 보신 것처럼 이름에 '영' 자가 들어간 사람은 '영'자의 위치와 상관없이 모두 검색이 된 것을
보실 수가 있습니다.

게시판에서 사용자들이 검색을 함에 있어서, 게시판 개발자로서 알아두어야 할 사항은...
대부분의 사용자들은 결코 '완전한' 단어로 검색하려 하지 않는다는 것 입니다.
예를 들어서,  글 제목이 ' 너무너무 감동적인 글입니다. 꼭 읽어봐 주세요' 라는 글이 있는데 이 글을 검색하고자
한다면.. 아마도 '감동' 과 같은 짧은 단어로 검색하려 할 것입니다. 이것마저 길다고 생각하시는 분들은 '꼭'
이라고 입력한 후 검색하기도 하지요. (제가 후자의 경우에 들어갑니다. ^^)
그렇기 때문에 검색에 있어서 like 검색은 선택이 아니라 필수사항이 되는 것입니다.

자. 그럼 우리가 쿼리문에서 like 검색을 하기 위해서는 꼭 필요한 두가지를 받아와야 하겠습니다.
그 하나는 '검색 조건' 이고, 또 하나는 '검색어 ' 가 되겠습니다. 다시 쓰면 다음과 같습니다.

Select * from board Where + 검색 조건 + like + 검색어

만약 '제목'(검색조건) 중에서 '강추'(검색어) 라는 단어가 들어간 게시를 검색하려면 어떻게 할까요?
네. 오른쪽과 같이 하면 되겠습니다. (Select * from board Where strSubject like '%강추%')
그렇다면 '내용' 중에서 '입니다' 라는 단어가 들어간 게시를 찾고싶다면?
이번에도 오른쪽과 같이 하시면 됩니다. (Select * from board Where strContent like '%입니다%')

자.. 우리는 위와 같은 결과를 보면서 이 검색의 규칙을 파악할 수가 있겠습니다.
'검색 조건' 과 '검색어' 만 넘겨주면 아주 간단하게 검색을 할 수 있다는 사실이 바로 그것이지요.
아주 간단하기에.. 우리는 '검색하기'를 위한 새로운 페이지를 만들지 않고, 기존의 list 페이지에서
'검색하기' 기능이 추가된 '업그레이드된 list.asp' 페이지를 만들어보고자 합니다.

사실.. 새로운 '검색 결과' 페이지를 만들까.. 고민을 했습니다.
하지만 저희 형 책인 <taeyo's ASP> 에서 검색 결과를 새로운 페이지로 만드는 부분을 이미 다루었고,
제가 준비한 강좌가 그 책의 내용과 상당부분 겹치게 되는 까닭에 다른 방법을 택하기로 결심했습니다.
(많은 분들께서 taeyo's ASP 책의 게시판 만들기 부분과 병행하면서 공부하신다는 메일을 주시더군요.)

그래서 우리는.. 새롭게 검색 결과를 보여주는 페이지를 만들지 않을 생각입니다.
기존의 list.asp 페이지에 검색 기능을 더한, 조금은 업그레이드된 list.asp 페이지를 만들도록 하겠습니다.

자.. 그러면 이제 바뀐 소스를 살펴볼 시간입니다.
'list.asp' 페이지를 살포시~ 열어주시고요. 빨갛게 표시된 부분을 중심으로 수정해 주시기 바랍니다.

<list.asp>

01
02
03
04
05
06
07
08
09
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

<%
    Option Explicit
 
    Dim objDBConn
    Dim objRs

    Dim strSQL
   
Dim intNowPage, intTotalCount, intTotalPage, intBlockPage, intPageSize
    Dim intTemp, intLoop
    Dim strSearchWord, strSearchString, strSearchSQL
    Dim blnSearch


    intNowPage = Request.QueryString("page")
    strSearchWord = Request.QueryString("search_word")
    strSearchString = Request.QueryString("search_string")
    blnSearch = false

    intPageSize = 10
    intBlockPage = 10

    If Len(intNowPage) = 0 Then
        intNowPage = 1
    End If

    If Len(strSearchString) <> 0 Then
        blnSearch = true
        strSearchSQL = " Where " & strSearchWord
        strSearchSQL = strSearchSQL & " like '%" & strSearchString & "%'"
    End If

 
    strSQL = "Select Count(*)"
    strSQL = strSQL & ",CEILING(CAST(Count(*) AS FLOAT)/" & intPageSize & ")"
    strSQL = strSQL & " from board"
    If blnSearch Then
        strSQL = strSQL & strSearchSQL
    End If
 
    Set objDBConn = Server.CreateObject("ADODB.Connection")
    Set objRs = Server.CreateObject("ADODB.RecordSet")
 
    objDBConn.Open "test", "sa", ""
 
    objRs.Open strSQL, objDBConn
    intTotalCount = objRs(0)
    intTotalPage = objRs(1)
    objRs.Close

    strSQL = "Select Top " & intNowPage * intPageSize & " intSeq"     ' 번호
    strSQL = strSQL & ",strName"                                                   ' 이름
    strSQL = strSQL & ",strEmail"                                                   ' 메일주소
    strSQL = strSQL & ",strSubject"                                                ' 제목
    strSQL = strSQL & ",intCount"                                                   ' 조회수
    strSQL = strSQL & ",dtmReg_Date"                                           ' 등록일
    strSQL = strSQL & " FROM board"
    If blnSearch Then
        strSQL = strSQL & strSearchSQL
   
End If
    strSQL = strSQL & " ORDER BY intSeq desc"

    objRs.Open strSQL, objDBConn
%>
<html>
<head>
<title>목록보기</title>
</head>
<body>
<div align="center">
<h2>목록보기</h2>
<table width="600">
<form name= "searchForm" method= "get">
  <tr>
    <% If intTotalCount > 0 Then %>
    <td>전체게시 <%=intTotalCount%> 개 &nbsp;&nbsp;&nbsp;&nbsp;
            현재페이지 : <%=intNowPage%> / <%=intTotalPage%>
    </td>
    <% End If %>
    <td align="right">
        <select name="search_word">
            <option value="strName">이름</option>
            <option value="strSubject">제목</option>
            <option value="strContent">내용</option>
        </select>
        <input type="text" name="search_string" size="15">
        <input type="submit" value="검색">
    </td>

  </tr>
</form>
</table>
<table border width="600">
  <tr align="center">
     <td>번호</td>
     <td>제목</td>
     <td>작성자</td>
     <td>등록일</td>
     <td>조회</td>
  </tr>
  <% If objRs.BOF or objRs.EOF Then %>
  <tr align="center">
    <td colspan="5">등록된 게시가 없습니다</td>
  </tr>
<%
         Else
              objRs.Move (intNowPage - 1) * intPageSize
              Do Until objRs.EOF
%>
  <tr align="center">
    <td><%=objRs(0)%></td>
    <td>
       <a href="content.asp?seq=<%=objRs(0)%>&_
       &page=<%=intNowPage%>"<%=intNowPage%>"><%=objRs(3)%></a>
    </td>
    <td>
       <a href="mailto:<%=objRs(2)%>"><%=objRs(1)%></a>
    </td>
    <td><%=left(objRs(5), 10)%></td>
    <td><%=objRs(4)%></td>
  </tr>
<%
                  objRs.MoveNext
              Loop
        End If
 
        objRs.Close
        Set objRs = nothing
        objDBConn.Close
        Set objDBConn = nothing
%>
</table>
<table width="600">
  <tr>
    <td align="center">
    <%
            intTemp = Int((intNowPage - 1) / intBlockPage) * intBlockPage + 1

            If intTemp = 1 Then
                Response.Write "[이전 " & intBlockPage & "개]"
            Else
                Response.Write"<a href=list.asp?page=" & intTemp - intBlockPage & _
                "&search_word=" & strSearchWord & _
                "&search_string=" & strSearchString & _

                ">[이전 " & intBlockPage & "개]</a>"
            End If

            intLoop = 1

            Do Until intLoop > intBlockPage Or intTemp > intTotalPage
                If intTemp = CInt(intNowPage) Then
                    Response.Write "<font size= 3><b>" & intTemp &"</b></font>&nbsp;"
                Else
                    Response.Write"<a href=list.asp?page=" & intTemp & _
                    "&search_word=" & strSearchWord & _
                    "&search_string=" & strSearchString & _

                    ">" & intTemp & "</a>&nbsp;"
                End If
                intTemp = intTemp + 1
                intLoop = intLoop + 1
            Loop

            If intTemp > intTotalPage Then
                Response.Write "[다음 " &intBlockPage&"개]"
            Else
                Response.Write"<a href=list.asp?page=" & intTemp & _
                "&search_word=" & strSearchWord & _
                "&search_string=" & strSearchString & _

                ">[다음 " & intBlockPage & "개]</a>"
            End If
    %>
    </td>
  </tr>
</table>
<% If blnSearch Then %>
<a href="list.asp">목록으로&nbsp;
<% End If %>

<a href="regist/regist.asp">글쓰기</a>
</div>
</body>
</html>

자.. 그럼 위의 소스를 천천히 분석해 보도록 하겠습니다.
우선 10, 11번 줄에서 검색에 관련된 변수들을 선언하였습니다.
strSearchWord검색 조건, strSearchString검색어를 의미하고, strSearchSQL 은 검색에 관련된
조건문을 추가할 때 붙을 SQL 문 이 들어갈 변수가 되겠습니다.
blnSearch 는 현재 이 페이지가 검색이 실행되었는지(true) 아닌지(false) 를 나타내는 변수가 되겠습니다.

그리고 14~16번 줄까지는 각각의 변수들에 해당하는 값을 받아오거나 지정하는 부분이 되겠습니다.
14, 15번 줄은 '검색 조건' 과 '검색어' 를 get 방식으로 받아오는 부분이 되고요.
기본적으로 리스트 페이지는 검색 하지 않은 상태라고 가정하고 blnSearch 값을 false 로 주었습니다.

그리고.. 24번 줄에서 '검색어' 에 해당하는 strSearchString 이라는 변수의 길이(Len)가 0이 아닌 경우
25~27번 줄의 내용을 실행하게 됩니다. 검색어(strSearchString) 의 길이가 0이 아니라는 의미 는 검색을
위해 검색어를 입력받았다는 의미가 되는 것
이기 때문이지요.

'무슨 소리야? 왜 검색어를 입력받았다는 의미가 되는데?' 라고 의문을 가지는 분들이 계실것 같아서
잠시 이 부분에 대한 부연 설명을 드리고 넘어가겠습니다.

우리는 잠시 후 아래부분(76~84번줄)에서  검색을 위한 select 컨트롤과 text 하나를 추가할 것입니다.
그 곳에서 '검색할 분류' 를 선택하고 '검색하려는 단어' 를 입력한 후에 '검색' 버튼을 누르게 되면
그 값들이 다시 자기 자신의 페이지(list.asp)로 전송이 되도록 할 것입니다.

그렇게 넘겨진 값들이 14, 15번 줄에서 각각의 해당하는 변수로 들어가게 되는데요.
list.asp 페이지가 처음 보여지거나 또는 다른 페이지로 이동하는 작업만을 수행했다면 14, 15번의
변수에는 아무런 값들도 들어가게 되지 않을 것입니다. (아무런 값을 받지 못했으니까요)
하지만 '검색어' 를 입력하고 '검색' 버튼을 눌렀을 경우에는 위의 변수에 그에 해당하는 값들이
들어가게 될 것입니다. 여기에서는 검색어에 해당하는 변수 strSearchString 에 값이 있는지 없는지를
검사하여 검색한 상태인지 검색하지 않은 상태인지를 판별한다는 의미가 되겠습니다.

검색어가 있는 경우의 처리는.. 우선 검색실행 여부를 나타내는 변수인 blnSearchtrue 로 변경하고요.
26~27번 줄에서는 조건문을 담을 쿼리문인 strSearchSQL 를 작성 하게 됩니다.
이해를 돕기 위해 26~27번 줄을 한줄로 나타내면 다음과 같게 될 것입니다.

strSearchSQL = " Where " & 검색조건 & " like '%" & 검색어 & "%'"   (띄어 쓰기에 유의하세요)

만약 검색조건이 이름(strName) 이고, 검색어가 '꽤싸뚜' 였다면 위의 쿼리문은 다음과 같이 될 것입니다.

strSearchSQL = " Where strName like '%꽤싸뚜%'"

자.. 그럼 여기서 초수퍼울트라에로틱스릴러판타스틱깜짝돌발퀴즈(-_-;)를 드리도록 하겠습니다.
지금 작성한 이 '조건절 쿼리문' (strSearchSQL) 은 list.asp 페이지에서 언제나,항상,꼭 사용해야 하는 것일까요?
"네에~!!!" 라고 망설임 없이 대답하신 분이라면.. OX 퀴즈에 상당히 약한 분이십니다.
강좌에 조금 더 집중해 주시기 바라고요.. 아쉽지만 다음 기회에 다시 도전을 해주시기 바랍니다.

이 '조건절 쿼리문' 은 항상 실행되는 것이 아니라 '검색이 실행되는 경우에만 ' 실행되어야 할 것입니다.
즉, blnSearch = true 인 경우에만 실행된다는 의미지요.

그래서.. 33~35번 줄과 54~56번 줄에서는 기존의 쿼리문에다가 조건절 쿼리문을 추가하였습니다.
항상? 아닙니다. '검색이 실행되었을 때에만' 이 조건절 쿼리문을 추가하는 것이지요.
그런데.. 54~56번 줄에 들어가는 '조건절 쿼리문' 의 경우 위치를 주의하셔야 합니다. '조건' 을 타나태는
Where 절의 경우 ORDER BY 절보다는 앞서 나와야 하기에 쿼리문 중간에 끼워넣은 것입니다.

그리고 넘어가서.. 69번 줄에서는 값을 전달하기 위해 <form> 을 지정하는 것을 보실 수가 있습니다.
form 의 이름은 검색(search)을 위한 폼이기에 searchForm 이라고 지어보았습니다.
그리고 방식(method)은 get 방식을 선택했습니다. 그런데.. 웬지, 무언가가 허전하지 않습니까?
네에~. 그렇습니다. 값을 전달받는 페이지를 지정하는 action 이 빠져있지요.
action을 생략하면 값들은 자기 자신의 페이지로 넘겨지게 됩니다 .
그러므로 우리는 그렇게 받아온 값들을 14, 15번 줄에서 적절하게 처리하는 것이지요.

76~84번 줄까지는 '검색 분류' 를 위한 select 컨트롤과 '검색어' 를 위한 text 컨트롤을 만드는 부분이
되겠습니다. 이 중에서 option value 에 주의해 주셔야 하는데요. 여기서.. value 값board 테이블의
컬럼 이름과 동일
하다는 것을 눈치채셨는지요? 눈치채셨다면 눈썰미가 대단한 분이십니다. ^^
이렇게 value 값과 테이블 컬럼 이름이 같게 되면 '조건절 쿼리문' 에서 그대로 사용할 수 있습니다.
그렇기에 대부분의 검색에서 option value 값을 검색하고자 하는 table 컬럼명으로 많이 사용하지요.

어쨌든.. 검색을 위해 select 컨트롤과 text 컨트롤, 그리고 submit 버튼을 하나 만든 것 외에는 이부분에서
별다른 것이 없어 보입니다. 이해하기 어렵지 않은 부분이리라 생각합니다.

그렇게 주욱~ 진행하다가 '페이지 나누기' 부분에서 반복되어 붙어 있는 어떤 부분을 보실 수가 있습니다.
138~139, 150~151, 162~163번 줄에 나와있는 아래 내용이 바로 그것입니다...

"&search_word=" & strSearchWord & _
"&search_string=" & strSearchString & _
 

'search 라는 단어가 자꾸 들어가는 것으로 미루어 보아 아무래도 검색에 관련된 값들이겠군..' 싶으시지요?
빙고~입니다. 이 부분은 검색을 위해서 받아온 '검색분류' 와 '검색어' 값들을 페이지가 이동될 때 Get 방식으로
넘겨주는 부분이 되겠습니다.
그렇다면... 도대체 왜 이 값들을 페이지가 이동될 때마다 추가해서 넣어주는 것일까요?
그 이유는.. '검색 후의 페이지 나누기 ' 가 필요할 수 있기 때문입니다.

예를 들어 보겠습니다.
여러분들께서 만든 '태지 보드' 게시판의 인기가 아주 높아서.. 게시가 상당히 많은데요.
그 게시판은 페이지 크기(intPageSize)가 10 이고, 그 게시들 중 '꽤싸뚜' 님이 작성한 글은
모두 29개가 있다고 가정해 보겠습니다.
'검색 조건' 을 '이름' 으로, '검색어' 를 '꽤싸뚜' 로 입력한 후 '검색' 버튼을 누르면 어떻게 되겠습니까?
아마도 검색 결과가 29개가 나올 것이고, 검색한 결과는 모두 3페이지가 나올 것입니다.

그렇다면 검색이 된 상태에서 다음 페이지로 이동하면 어떻게 될까요?
우리는 검색된 두번째 페이지로 이동하기를 원하고 있습니다. 하지만 저 위의 두줄이 없다면..
두번째 페이지는 '검색 결과의 두번째 페이지' 가 아닌 '전체 목록의 두번째 페이지 ' 로 이동하게 됩니다.

으음... 이것은 예측하지 못한 사태입니다. 우리는 이런 결과를 원한 것이 아닌데 말이지요.
왜 이런 현상이 발생하는고 하니.. 페이지가 이동되면서 '검색 조건' 과 '검색어' 를 담는 변수(14,15줄)에
아무런 정보를 전달해 주지 못했기 때문입니다.

이 문제를 해결하는 방법은 생각보다 간단합니다.
'검색조건(strSearchWord)' 과 '검색어(strSearchString)' 에 담겨져 있는 값을 페이지가 이동할 때마다
Get 방식으로 넘겨주기만 하면 되는 것입니다. 그 변수에 값이 들어가 있건 없건 상관없이 말이지요.
(값이 없다면 24번 줄의 조건을 만족시키지 못해 26~27번 줄의 조건절 쿼리문(strSearchSQL) 이 만들어지지
 않을 테고, 값이 있다면 조건절 쿼리문이 작성되어서 검색된 결과의 다음 페이지가 보여지게 될 것입니다.)

그래서 위의 두줄이 필요했던 것입니다. 검색에 관련된 값들을 Get 방식으로 넘기기 위해서 말이지요.

기억력이 좋은 분이시라면 제가 지난 시간에 137~140 번줄까지를 '한줄로 입력하세요' 라고 말씀드렸던
기억이 나실 것입니다. 하지만 이 부분에서 에러를 만나시는 분들이 생각보다 많고, 또 그다지 보기도
좋지 않아서.. 오늘의 강좌에서는 한줄로 쓰지 않아도 되는 방법을 사용하였습니다.
(아마도 이미 다들 알고 계시는 내용인데 뒷북을 치는 것인지도 모르겠네요. 두우웅~~~~~~)

행을 바꾸지만 시스템에 한줄로 인식시키는 방법은 '연결기호(&) + 언더스코어(_) ' 가 되겠습니다.
즉.. 아래의 두 문장은 같다는 의미가 되는 것이지요. (물론 보여지는 결과 역시 똑같습니다.)

Response.Write "How do you do~ " & _
"(너 두유를 어떻게 할거니~)"

Response.Write "How do you do~ (너 두유를 어떻게 할거니~)"

혹시 모르셨다면 유용하게 사용하시기를 바랍니다. ^^
(너 두유를어떻게할거니~개그는 최광년(mobil313) 구독자님께서 보내주셨습니다. 감사합니다)

페이지 나누기 부분을 지나 170~172번 줄에서는 (기본)목록으로 돌리는 링크를 만들어 놓았습니다.
이 부분은 검색이 이루어졌을 때에만 보이게끔 되어 있는데요. 그 이유는 검색이 이루어진 페이지에서
다시 원래의 목록보기 페이지로 돌아갈 수 있게 해주기 위함 입니다. 친절하지 않습니까?

자.. 이렇게 해서 검색부분까지 모두 알아보았습니다.
어떻습니까? 리스트 페이지 안에서 검색까지 모두 마치게 되니까 꽤 편리하다는 생각이 들지 않으십니까?
오늘 강좌의 서두에서 잠시 말씀드렸지만, 저희 형님께서 taeyo's ASP 책에서 검색 페이지를 따로 만드는
방식을 선택했기 때문에, 저는 list.asp 페이지에 통합시키는 방법을 선택했습니다.
어느 방법이 더 좋다, 또는 어느 방법이 더 빠르다~ 는 비교를 하려는 의도는 아니고요.
단지 꼭 하나의 방법이 아니라.. 이런 방법도 있고, 저런 방법도 있다는 말씀을 드리고 싶었던 것입니다.

사실 제가 지금까지 초보 분들을 위해서 '게시판 만들기' 강좌를 진행해 왔지만..
그것이 '게시판은 무조건 이렇게 만들어야 한다' 는 의도는 아니었음을 꼭 말씀드리고 싶습니다.
제가 진행한 '게시판 만들기' 강좌는 일반적, 보편적인 기준에서 이미 널리 알려진 게시판의 형식을
따다가 여러분들께 말씀드린 것 뿐이지요.
지금껏 강좌를 보던 여러분의 머릿속에 불현듯 '저런 부분은 저렇게 하는 것보다 이렇게 하는게 낫지 않을까?'
하는 생각이 들 수도 있습니다. 그렇다면 그 생각이 사라지기 전에 직접 실행하시고, 또 도전하십시오.
잘 모르겠거든 알때까지 관련 서적을 찾아보십시오. 책을 찾아도 모르겠다면, 알만한 사람 하나 붙잡고
의문이 풀릴때까지~ 물어보십시오. ^^

이 강좌를 읽고 계신 여러분들은(저를 포함해서) 아직 '초보운전' 의 딱지를 못떼신 분이라고 생각합니다.
그렇다면 우리는 우리가 잘 모르는 새로운 내용들을 받아들이는 것을 두려워해서는 안될 것입니다.
아쉬운 현실이지만, 지금 현재의 우리보다 ASP 를 잘하는 고수들은 서울에서 김서방 찾기만큼 쉬운 일이
되어 버렸습니다. 그리고 그분들은 C# 이네, 닷넷이네.. 하면서 끝없이 달려나가고 있습니다.

재미로 게시판을 하나 만들어보기 위해... 이 강좌를 참고하신 분들께는 해당사항이 없는 말이겠지만,
본격적으로 웹 프로그래밍을 업으로 삼으시려는 분이라면, 이제 가속을 붙일 시간이 되었습니다.
달려나가는 고수분들보다 더 앞서나가기 위해서는... 그 분들보다 더 열심히 달리는 수밖에 없지 않겠습니까?
(오오... 멋진 말이지 않습니까? 형님한테 들은 말입니다. -_-a)

그동안 지루하고 부족한 강좌에 관심 가져주시고, 질책 및 격려해주신 많은 분들께..
이 자리를 빌어서 감사의 말씀을 드리고 싶습니다. 한분 한분 인사드리지 못한 것을 죄송하게 생각합니다.
모두모두 항상 건강하시고, 늘 행복하시기를 기도드립니다.
특히 강좌 전체를 통틀어 많은 도움을 주신 꽤싸뚜(cassatt)님과 꼬마앙마(comadevil)님께 특히~
감사하다는 말씀을 전해드리고 싶습니다.
이상으로 '초보자도 할 수 있다 - 게시판 만들기' 강좌를 마치도록 하겠습니다. 감사합니다.


P.S (추신, 덧붙임..)

저번 강좌에서 약속드린대로.. 이 게시판이 초보용을 지나 제법 쓸만한 게시판이 되기 위해
'번외편' 을 조금씩 올리도록 하겠습니다. (이게 무슨 장편 무협 소설두 아니구... 흠흠)
'번외편' 에서는 여러가지 에러 체크나 몇가지 기능의 추가 등이 있을 예정입니다.

출처http://blog.naver.com/yj5881/20007187382

2008. 9. 8. 14:52

게시판만들기-페이지나누기(펌)ASP

게시판 만들기 - 페이지 나누기 (펌) ASP 

제가 가장 좋아하는 가수는 지금은 해체한 그룹 전람회의 리드 보컬 김동률입니다.
생일 선물로 김동률 3집 CD를 선물받았는데.. 거기에는 hidden track 하나(28번 트랙)가 숨어있었습니다.
옛 전람회의 멤버였던 서동욱과 듀엣으로 부른 그곡의 제목은 '떠나보내다' 라고 하더군요.
앨범 속지에도 그 곡에 대한 언급은 없었고, 앨범 목록에도 물론 그 곡이 실려있지 않았습니다.
아마도.. CD 를 산 사람이 아니라면 그 곡의 존재를 모를 거라는 생각이 들었습니다.
그래서 그 곡이 더욱 정겹게 느껴지는 것인지도 모르겠습니다.

그럼 오늘의 강좌를 시작하겠습니다. 오늘 우리가 진행할 내용은 '페이지 나누기 ' 부분이 되겠습니다.
지난 시간에 제가 '페이지 나누기' 부분이 게시판 만들기의 '백미' 라고 말씀드렸는데요.
그 이유가 오늘 밝혀지게 될 것 같습니다..
그럼 심호흡을 한번 크게 하시고 (흐~읍~!!!) 시작하도록 하겠습니다.

'페이지 나누기라... 왜 페이지를 나누어야 하는건데?' 라는 의문을 가지는 분들이 계실지도 모르겠군요.
그런 의문을 가진 분들을 위해.. 왜 페이지 나누기가 필요한지 잠시 말씀드리겠습니다.
사실.. 테스트를 위해서 한, 두개 게시를 올리는 경우에는 페이지를 굳이 나눌 필요가 없습니다.
하지만 여러분들께서 만든 게시판의 인기가 높아지면서 게시가 열개, 백개, 천개... 수만개에 이르게 된다면
(상상만 해도 기분 좋은 이야기지요? ^^) 이야기가 슬슬 달라지기 시작합니다.

지금까지 우리가 만든 게시판의 구조라면.. 목록보기 페이지인 'list.asp' 에 모든 목록이 다~ 나오게 됩니다.
게시가 백개건 천개건.. 전혀 상관하지 않는다는 말이지요.
만약.. 현재 맨 위에는 10000번 게시가 올라와 있는데 맨 처음 쓴 게시(1번 게시)를 보고 싶으면 어떻게 할까요?
'어.. 걱정없어. 나 휠 마우스야.' 라고 생각하십니까? 정 뜻이 그러하시다면 열심히 휠을 돌리시지여. -_-a
이런 경우에는 페이지를 방문한 사람들의 편의를 위해서 페이지를 나누어 주는 것 이 좋습니다.
그 편이 보기에도 편하고, 또한 게시판의 효율성(속도)에 있어서도 훨씬 유리하기 때문입니다.

그렇다면.. 이제 본격적으로 페이지 나누기를 알아보도록 하겠습니다.
오늘의 강좌에서는 새로운 페이지를 작성하지는 않습니다. 대신 기존의 페이지를 조금 수정할 예정입니다.
그렇다면.. 우선 목록을 보여주는 'list.asp' 페이지를 열어주시기를 바랍니다.
기존의 소스는 다음과 같습니다.

<list.asp>

01
02
03
04
05
06
07
08
09
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

<%
    Option Explicit
 
    Dim objDBConn
    Dim objRs
 
    Dim strSQL
 
    strSQL = "Select intSeq"                                          ' objRs(0) - 번호
    strSQL = strSQL & ",strName"                                  ' objRs(1) - 이름
    strSQL = strSQL & ",strEmail"                                   ' objRs(2) - 메일주소
    strSQL = strSQL & ",strSubject"                                ' objRs(3) - 제목
    strSQL = strSQL & ",intCount"                                  ' objRs(4) - 조회수
    strSQL = strSQL & ",dtmReg_Date"                           ' objRs(5) - 등록일
    strSQL = strSQL & " FROM board"
    strSQL = strSQL & " ORDER BY intSeq desc"
 
    Set objDBConn = Server.CreateObject("ADODB.Connection")
    Set objRs = Server.CreateObject("ADODB.RecordSet")
 
    objDBConn.Open "test", "sa", ""
 
    objRs.Open strSQL, objDBConn
%>
<html>
<head>
<title>목록보기</title>
</head>
<body>
<div align="center">
<h2>목록보기</h2>
<table border width="600">
   <tr align="center">
     <td>번호</td>
     <td>제목</td>
     <td>작성자</td>
     <td>등록일</td>
     <td>조회</td>
  </tr>
  <% If objRs.BOF or objRs.EOF Then %>
  <tr align="center">
    <td colspan="5">등록된 게시가 없습니다</td>
  </tr>
<%
         Else
              Do Until objRs.EOF
%>
  <tr align="center">
   <td><%=objRs(0)%></td>
    <td>
       <a href="content.asp?seq=<%=objRs(0)%>"><%=objRs(3)%></a>
    </td>
    <td>
       <a href="mailto:<%=objRs(2)%>"><%=objRs(1)%></a>
    </td>
    <td><%=left(objRs(5), 10)%></td>
    <td><%=objRs(4)%></td>
  </tr>
<%
                  objRs.MoveNext
              Loop
        End If
 
        objRs.Close
        Set objRs = nothing
        objDBConn.Close
       Set objDBConn = nothing
%>
</table>
<a href="regist/regist.asp">글쓰기</a>
</div>
</body>
</html>

간만에 보니 반가운 소스군요..
자 그러면.. 이 소스를 수정해 보도록 하겠습니다. 수정한 부분은 빨간색으로 표시하도록 하지요.


페이지 나누기가 적용된 list.asp 소스

01
02
03
04
05
06
07
08
09
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
134
135

<%
    Option Explicit
 
    Dim objDBConn
    Dim objRs

    Dim strSQL
    Dim intNowPage, intTotalCount, intTotalPage, intBlockPage, intPageSize
    Dim intTemp, intLoop

    intNowPage = Request.QueryString("page")    
    intPageSize = 10
    intBlockPage = 10

    If Len(intNowPage) = 0 Then
        intNowPage = 1
    End If
 
    strSQL = "Select Count(*)"
    strSQL = strSQL & ",CEILING(CAST(Count(*) AS FLOAT)/" & intPageSize & ")"
    strSQL = strSQL & " from board"
 
    Set objDBConn = Server.CreateObject("ADODB.Connection")
    Set objRs = Server.CreateObject("ADODB.RecordSet")
 
    objDBConn.Open "test", "sa", ""
 
    objRs.Open strSQL, objDBConn
    intTotalCount = objRs(0)
    intTotalPage = objRs(1)
    objRs.Close


    strSQL = "Select Top " & intNowPage * intPageSize & " intSeq"     ' 번호
    strSQL = strSQL & ",strName"                                                   ' 이름
    strSQL = strSQL & ",strEmail"                                                   ' 메일주소
    strSQL = strSQL & ",strSubject"                                                ' 제목
    strSQL = strSQL & ",intCount"                                                   ' 조회수
    strSQL = strSQL & ",dtmReg_Date"                                           ' 등록일
    strSQL = strSQL & " FROM board"
    strSQL = strSQL & " ORDER BY intSeq desc"

    objRs.Open strSQL, objDBConn
%>
<html>
<head>
<title>목록보기</title>
</head>
<body>
<div align="center">
<h2>목록보기</h2>
<% If intTotalCount > 0 Then %>
<table width="600">
  <tr>
    <td>전체게시 <%=intTotalCount%> 개 &nbsp;&nbsp;&nbsp;&nbsp;
            현재페이지 : <%=intNowPage%> / <%=intTotalPage%>
    </td>
  </tr>
</table>
<%  End If  %>

<table border width="600">
  <tr align="center">
     <td>번호</td>
     <td>제목</td>
     <td>작성자</td>
     <td>등록일</td>
     <td>조회</td>
  </tr>
  <% If objRs.BOF or objRs.EOF Then %>
  <tr align="center">
    <td colspan="5">등록된 게시가 없습니다</td>
  </tr>
<%
         Else
              objRs.Move (intNowPage - 1) * intPageSize
              Do Until objRs.EOF
%>
  <tr align="center">
    <td><%=objRs(0)%></td>
    <td>
       <a href="content.asp?seq=<%=objRs(0)%>"><%=objRs(3)%></a>
    </td>
    <td>
       <a href="mailto:<%=objRs(2)%>"><%=objRs(1)%></a>
    </td>
    <td><%=left(objRs(5), 10)%></td>
    <td><%=objRs(4)%></td>
  </tr>
<%
                  objRs.MoveNext
              Loop
        End If
 
        objRs.Close
        Set objRs = nothing
        objDBConn.Close
        Set objDBConn = nothing
%>
</table>
<table width="600">
  <tr>
    <td align="center">
    <%
            intTemp = Int((intNowPage - 1) / intBlockPage) * intBlockPage + 1

            If intTemp = 1 Then
                Response.Write "[이전 " & intBlockPage & "개]"
            Else
                Response.Write"<a href=list.asp?page=" & intTemp - intBlockPage & ">[이전 "
                & intBlockPage & "개]</a>"
            End If

            intLoop = 1

            Do Until intLoop > intBlockPage Or intTemp > intTotalPage
                If intTemp = CInt(intNowPage) Then
                    Response.Write "<font size= 3><b>" & intTemp &"</b></font>&nbsp;"
                Else
                    Response.Write"<a href=list.asp?page=" & intTemp & ">" & intTemp &
                    "</a>&nbsp;"
                End If
                intTemp = intTemp + 1
                intLoop = intLoop + 1
            Loop

            If intTemp > intTotalPage Then
                Response.Write "[다음 " &intBlockPage&"개]"
            Else
                Response.Write"<a href=list.asp?page=" & intTemp & ">[다음 "
                & intBlockPage & "개]</a>"
            End If
    %>
    </td>
  </tr>
</table>
<a href="regist/regist.asp">글쓰기</a>
</div>
</body>
</html>

빨간색이 남발되어서 부담스러우십니까? 너무 부담가지지 않으셔도 됩니다.
그러면.. 이제부터 페이지 나누기가 적용된 list.asp 페이지를 살펴 보도록 하겠습니다.
수정된 부분을 중점적으로 설명하도록 하지요.

먼저 8번, 9번째 줄은 페이지 나누기를 위한 변수를 선언했습니다.
intNowPage 는 지금 현재 페이지 가 몇번째 페이지인지를 나타내는 변수이고요.
intTotalCount전체 게시물의 갯수 를, intTotalPage 는 총 페이지 수를 의미합니다.
intBlockPage페이지를 몇개씩 구분할 것 인지 - 이전 O개, 다음 O개 할때 사용하지요 - 를 나타내는 변수고,
intPageSize 는 한 페이지에 몇개의 게시까지 보이게 할지 를 결정하는 변수가 되겠습니다.

9번째 줄에 있는 intTemp 와 intLoop 는 임시로 사용되는 정수형 변수인데요.
굳이 간략하게 설명을 드리자면, Do ~ Loop 문을 돌때마다 증가되는 변수가 되겠습니다.

이것으로 변수 선언을 마치고, 11번 줄에서는..
현재의 페이지가 몇 페이지인지를 intNowPage 변수에 받아오는 부분이 되겠습니다.
여기서 한가지 의문이 드실지도 모르겠네요. 우리는 이 페이지가 몇 페이지인지 값을 넘겨준 기억이 없으니까요.
하지만 이 부분은 잠시 후에 설명이 될 것이므로 여기서는 그냥 넘어가도록 하겠습니다.
Request.QueryString 으로 넘긴것을 보아 url 의 뒤에 값을 넘기는 방식인 get 방식을 사용했음을...
이제 여러분들께서는 웃으면서 크게 고개를 끄덕거리시리라 믿어 의심치 않겠습니다. ^^

12, 13 번 줄에서는 페이지의 크기에 해당하는 변수인 intPageSize10 으로 설정했으며,
마찬가지로 페이지를 몇개씩 구분할 것인지를 나타내는 변수인 intBlockPage10 으로 설정했습니다.
이 부분은 여러분들께서 내키시는대로 바꾸셔도 괜찮습니다. (한번씩 바꾸어보시는 것도 재미있을 겁니다.)

15번~17번 줄은, 아까 11번 줄에서 실행했던 intNowPage 라는 변수에 값이 없다면 ..
(즉, 현재 페이지가 몇 페이지인지 알 수가 없다면) 현재 페이지를 1로 지정 하는 부분이 되겠습니다.
다시 말해 현재 페이지가 몇페이지인지 모르는 경우에는 가장 첫번째 페이지를 보여주라는 의미가 됩니다.
그런데.. 15번 줄에서 Len() 이라는 함수가 사알짝~ 등장을 하지요?
이 함수는 괄호 안에 있는 문자열의 길이(글자의 갯수)를 반환 합니다. 예를 들면 다음과 같습니다.

strTest = "안녕하세여"
intLength = Len(strTest)

이렇게 하면 intLength 라는 변수에는 어떤 값이 들어가 있을까요? 네에.. 5가 들어있을 것입니다.
그렇다면.. 다음 문장의 경우는 어떨까요?

strTest = "안녕 하세여"
intLength = Len(strTest)

'안녕' 과 '하세여' 사이에 공백이 하나 들어갔네요. 이 경우에는 intLength 에 어떤 값이 들어갈까요..?
Len() 함수는 공백도 하나의 문자로 인식 을 하므로 정답은 6이 되겠습니다.
상당히 이해하기 쉬운 함수였지요? 쓰임새가 많은 함수이므로 자알~ 기억해 주시기를 바랍니다.

19~21번 줄에는 SQL 문이 등장을 합니다. 그런데 지금까지 보았던 Select 문과는 약간 느낌이 다르네요.
19번 줄에 등장하는 Count(*)해당하는 게시물의 갯수 를 나타냅니다.
만약 board 테이블에 게시가 모두 10개가 있는데 'Select Count(*) from board' 라고 하면 10이라는 숫자가
반환된다는 의미지요. (Where + 조건문이 포함된다면, 그 조건문에 해당하는 게시의 갯수가 반환되겠지요?)

20번 줄은 총 페이지의 수 를 나타내는 부분이 되겠습니다. 그런데 이부분은 알아내기가 조금 까다롭습니다.
20번 줄은 "CEILING(CAST(Count(*) AS FLOAT) / " & intPageSize & ")" 인데.. 이 문장은 무엇을 의미할까요?
웬지 상당히 복잡하게 보이는데요.. 한번 차근차근히 알아보도록 하겠습니다.

우선 첫째로, 앞에 나온 CEILING() 함수 를 알아보도록 하겠습니다.
CEILING 함수는 괄호 안에 들어 있는 지정한 숫자 식보다 크거나 같은 최소 정수를 반환 합니다
예를 들어 CEILING(12.34) 이라고 하면 13이라는 숫자를 반환합니다.
CEILING(12.0001) 이라면 어떨까요? 이런 경우에도 13이라는 숫자를 반환합니다.
하지만.. CEILING(12) 라고 하는 경우에는 12라는 숫자를 반환하게 되지요.

두번째로, CEILING() 함수의 괄호 안에 있는 함수인 CAST(Count(*) AS FLOAT) 에 대해서 알아보겠습니다.
우선 CAST 함수는 다음과 같은 형식을 가집니다.

CAST(내용 AS 변환하려는 형식)

이 함수는 '내용' 에 해당하는 문장을 '변환하려는 형식' 에 맞게 변환하라 는 의미를 가집니다.
이번에도 예를 들면 다음과 같습니다.

CAST(12.34 AS INT) - 이 경우 12.34라는 실수가 12라는 정수형(INT형)으로 변환됩니다.
CAST(12.99 AS INT) - 이 경우에도 12.99라는 실수가 12라는 정수형(INT형)으로 변환됩니다.
CAST(12 AS FLOAT) - 이 경우 12 라는 정수가 12.0 이라는 실수형(FLOAT형)으로 변환됩니다.

20번 줄에서 사용된 함수에 대한 설명은 다 된것 같네요. 그런데 우리는 아까 intPageSize의 값을 10으로
설정했었습니다. 기억나시죠? 그러므로 20번 줄 SQL 문의 내용은 다음과 같이 다시 쓸 수가 있겠습니다.

CEILING(CAST(Count(*) AS FLOAT) / 10)

그러면 이 내용을 해석해 보도록 하겠습니다.
우선 게시물의 총 갯수(Count(*))를 FLOAT(실수) 형으로 변환 시킨 후, 페이지의 크기인 10으로 나누어 줍니다.
그렇게 나온 결과를 CEILING 함수를 통해서 정수형으로 다시 변환을 시켜줍니다.
이런 과정을 통해서 나온 값이 바로 총 페이지의 수가 되겠습니다.

'왜 이래야 하는거지? 총 페이지 수를 구한다매? 그렇다면 변환인지 뭔지 생략하고 그냥 게시물 갯수 나누기 페이지 크기, 즉 Count(*) / 10  하면 되는거 아닌가?' 라는 생각이 드실지도 모르겠네요.
좋은 생각입니다. 하지만 그랬을 경우 자그마한 문제가 발생하게 됩니다.
만약 한 페이지에 10개의 게시가 보여지게끔 페이지를 나누었을 경우, 게시가 10개 있다면 총페이지의
숫자는 어떻게 될까요? 예. 1페이지가 됩니다. 한페이지에 정확하게 들어가지요.
하지만 게시가 하나 추가가 되어 11개의 게시가 되면 한개의 게시는 다음 페이지로 넘어가야 하고
때문에 페이지의 갯수는 한 페이지가 늘어난 2페이지가 되어야 합니다.

정리하면.. 10개까지의 게시가 있을 경우에는 1페이지가 되지만, 11개에서 19개까지의 게시가 있을
경우에는 2페이지가 되어야 한다는 것입니다. 그래서 CEILING() 이라는 함수가 필요했던 것입니다.
총게시물 수에서 페이지 크기로 나눈 값에서 나머지가 있다면(즉, 게시가 10개가 아닌 11개, 12개...
등일 때 Count(*) / 10 의 값은 1.1, 1.2 처럼 나머지가 생기게 된다는 뜻입니다)
페이지가 하나 더 생겨야 하므로 CEILING() 함수로 그것을 계산한 것이지요.

그리고, CEILING() 함수 안에서 CAST() 함수로 총 게시물의 갯수인 Count(*) 를 실수형으로 변환한 것은
Count(*) 의 값은 정수형이고, 나누는 값인 10 또한 정수형이기 때문입니다. MS-SQL 에서는 정수를 정수로 나누면 정수를 반환 합니다. (예를 들면 12/10 = 1 이고, 19/10 = 1이라는 의미입니다.)
그렇기 때문에 Count(*) 를 실수형으로 바꾸었습니다. (12.0/10 = 1.2 이고, 19.0/10 = 1.9 가 됩니다)

나름대로는 쉽게 말씀드리려고 했는데, 상당히 복잡해진 것 같네요. ^^

이렇게 작성된 19~21번 줄까지의 SQL 문을 28번 줄에서 실행하게 됩니다.
(물론 23, 24번 줄에서 Connection 개체, RecordSet 개체의 인스턴스를 생성한 것과,
26번 줄에서 Connection 개체의 인스턴스인 objDBConn 을 Open 시킨 부분은 말씀 안드려도 되겠지요?)

29번 줄에서는 게시물의 총 갯수인 Count(*) 값을 intTotalCount 라는 변수에 대입하였고,
30번 줄에서는 총 페이지 수인 CEILING(CAST(Count(*) AS FLOAT) / 10) 값을 intTotalPage 에 넣었습니다.
그리고.. 31번 줄에서 objRs 를 닫은(close) 것을 놓치지 말아주세요. 이렇게 닫은 후에는 42번 줄에서 새롭게
다른 정보를 담아서 재사용할 수가 있습니다. 만약 31번 줄이 없다면 42번 줄에서 에러가 나게 됩니다.

그리고 33번 줄에서 테이블에 있는 정보를 가져오는 SQL문이 약간 수정된 것을 볼 수가 있습니다.
다른 부분은 지난번 list.asp 페이지에서 사용한 SQL 문과 같은데요. 단 한가지, Top 이라는 문장이 들어갔네요.
Top 이라는 단어에서 대충 감을 잡으실 수 있나요? 이 Top 이라는 단어는 숫자와 함께 쓰여서
'정렬된 순서대로 숫자 만큼의 게시만 가져오라 ' 는 뜻이 됩니다. 예를 들어 보겠습니다.

Select Top 5 intSeq, strName, strEmail from Board ORDER BY intSeq desc

위와 같은 구문을 Query Analyzer 에서 실행한다면 가장 최근에 등록된 게시부터 5개까지만을 가져오게 됩니다.
만약 3개밖에 없을때 위의 구문을 실행하면 3개의 게시를 모두 가져오게 되겠지요. 어렵지 않으시지요?

42번 줄에서는 다시 작성된 strSQL 문을 실행하여 objRs에 모든 정보를 저장하였습니다.
이때 만약 objRs 에 정보가 하나도 없다면, 즉 게시판에 내용이 하나도 없다면 69~71번 줄의 내용이 실행됩니다.
(이 경우 간단하게 '등록된 게시가 없습니다' 라는 내용만이 보여지게 될 것입니다.)

하지만 게시가 있다면.. 73번 줄 이하의 내용이 실행될 것입니다. 가장 먼저 등장하는 74번 줄에서는
Move 라는 RecordSet 개체의 메소드가 나오게 되는데요. 이 메소드는 말 그대로 '이동시키는' 메소드입니다.
무엇을 어디로 이동시키냐고요? 현재의 커서를 그 위치에서 Move 다음에 지정된 숫자만큼 이동 시킵니다.

이것을 그림으로 나타내면 다음과 같습니다.

<그림 1>



위의 <그림 1> 에서는 총 30개의 게시가 들어있다고 가정한 화면이 있습니다.
조금 복잡해 보이시나요? 그럼 천천히 다음 설명을 읽어주시기 바랍니다.

우선 가장 처음, 페이지가 지정되지 않은 경우라고 가정하고 이야기를 진행해 보도록 하겠습니다.
페이지가 지정되지 않았을 경우에는 15~17번째 줄에 의해 자동적으로 1 페이지 가 됩니다.
그러므로 33번 줄에서, SQL 문 안에 있는 Top 다음의 숫자는 '페이지(1) * 페이지의 크기(10)' 이므로
strSQL = "Select Top 10 intSeq... (후략)" 이 될 것입니다. 따라서 이 strSQL 문에 의해서는 30개의 게시
모두를 가져 오는 것이 아닌 위에서 10개의 게시 을 가져오게 됩니다. 여기까지는 이해 가시지요?

또, 74번 줄에서는 '(현재 페이지(1) - 1) * 페이지 크기(10)' 일 것이므로, objRs.Move 0 이 될 것입니다.
Move 0 이라는 것은 무엇을 의미할까요? 네에~ 그렇습니다. 이동이 없다는 의미 가 되지요.
정보를 가져온 레코드셋의 커서(Cursor)는 기본적으로 가장 첫번째 레코드(게시)에 위치 합니다.
그러므로 위의 그림에서는 가장 첫번째 게시(30번 게시)에 커서가 맞추어져 있을 테지요.

그러면 정리해 볼까요? 1 페이지인 경우(또는 페이지 값이 없는 경우)에는..
커서(Cursor)는 가장 첫 게시인 30번 게시에 맞추어져 있으며, SQL 문은 게시를 상위 10개만 가져옵니다.
따라서 1 페이지에서는 가장 최근의 게시(30번 게시)부터 10개의 게시(21번 게시)까지 보여지게 되는 것이지요.

어떻습니까? 이해가 가시는지요.. 아직 무언가 부족하시다고요? 그럼 2페이지도 한번 알아보도록 하지요.
33번 줄의 SQL 문 안의 Top 다음의 숫자는 페이지(2) * 페이지 크기(10) 이므로 20이 될 것입니다.
Top 20, 즉 가장 처음 게시에서부터 20개의 게시(11번 게시까지)를 가져오라는 의미가 되는 거지요.
그 다음 74번 줄에서, 커서를 이동(Move)시킬 곳은 (2-1) * 10 이므로 10이 될 것입니다.
objRs.Move 10, 즉 위에서 10칸을 이동하므로 20번 게시가 있는 곳으로 커서를 이동시키라는 뜻이 됩니다.
따라서 2 페이지에서는 20번 게시에서부터 11번 게시까지의 10개의 내용이 보여지게 될 것입니다.

'Top 20 이니까 20개가 보여져야 하는 것이 아닌가요?' 라고 의문을 가지실 수 있을텐데요.
위에서 20개를 가져온 것은 맞습니다만, objRs.Move 10 에 의해 커서를 가장 위의 게시(30번 게시)에서
10칸 아래(20번 게시)로 이동시킨 까닭에 20번 게시부터 11번 게시까지 10개의 게시가 보여지는 것입니다.

어떻습니까.. 지금까지 페이지를 나누는 방법에 대해서 잠시 알아보았습니다.
이해가 잘 안가실 수도 있겠습니다만, 이 부분이 핵심이므로 꼭 이해하시고 넘어가기를 바랍니다.

은근슬쩍 넘어갈 뻔 했던 51번 줄부터 59번 줄까지의 내용은, 이 게시판에 등록된 게시물의 총 수
(intTotalCount)와 현재의 페이지(intNowPage), 그리고 아까 어렵게 계산했던 총 페이지 (intTotalPage)를
보여주는 부분이 되겠습니다.
그런데.. 51번 줄의 If 문은 무슨 의미로 쓰인 것일까요?
아까 19번 줄 SQL 문에서 사용된 레코드의 총 수를 구하는 Count(*) 라는 함수를 보셨는데요.
등록된 레코드가 한개도 없다면 Count(*) 함수는 0 이라는 숫자 값을 반환합니다.
즉, 51번의 If intTotalCount > 0 Then 이라는 구문의 의미는 '게시가 한개이상 있다면' 이라는 의미가 됩니다.
만약 게시가 한개도 없다면 52~58 번 줄의 내용은 보이지 않게 되지요.

그리고.. 중복되는 부분은 생략하고요. 99번째 줄로 넘어가도록 하겠습니다.
99번 줄부터 131번 줄까지는 페이지를 쉽게 이동할 수 있도록 각 페이지별로 나열하는 부분이 되겠습니다.

자.. 무언가 복잡해 보이는 부분이 또 등장을 했군요.
빨간 글자가 잔뜩 보이니까 괜시리 복잡할 것 같지 않습니까? 겁먹지 마시고 천천히 살펴보도록 하지요. ^^

우선.. 99번 줄부터 131번 줄이 적용된 결과 페이지를 먼저 보고 말씀을 드리도록 하겠습니다.
적용된 결과 페이지는 다음과 같을 것입니다. (위의 게시판 내용부분은 생략했습니다)
아까 게시가 30개 있다고 가정했으므로 페이지는 총 3 페이지가 되어 있을 것입니다.

[이전 10개] 1 2 3 [다음 10개]

앞뒤에 있는 [이전 10개], [다음 10개] 는 여러분이 13번 줄에서 intBlockPage 라는 변수에 주었던 값이 됩니다.
(만약 intBlockPage 를 5로 주었다면 [이전 5개], [다음 5개] 가 될 것입니다.)

그리고 게시물의 페이지 수가 10 보다 큰 경우(다시 말해 페이지 수가 intBlockPage 보다 큰 경우 )에는
상황에 따라 [이전 10개] 나 [다음 10개] 란에 링크가 걸려있어야 할 것입니다.
예를 들어 현재의 페이지가 23페이지인 경우에는 [이전 10개] 와 [다음 10개] 란에 모두 링크가 걸려 있어야
하며, [이전 10개] 의 링크를 클릭했을 경우에는 11페이지로, [다음 10개] 의 링크를 클릭했을 경우에는
31페이지로 이동을 해야 할 것입니다.
그렇다면.. 더이상 [이전 10개] 가 필요없을 것 같은 1~10 페이지라면 어떨까요?
네에~. [이전 10개] 라는 부분은 필요가 없기 때문에 그에 따른 적절한 처리를 해주면 됩니다.
(보이지 않게 하거나, 링크가 걸리지 않게 해주면 될 것입니다. 우리는 후자의 방법을 택하도록 하겠습니다.)

자.. 그럼 본격적으로 99 ~ 131번 줄의 소스를 살펴보도록 하겠습니다.
우선 103번 줄에 intTemp = Int((intNowPage - 1) / intBlockPage) * intBlockPage + 1 라는 줄이 나옵니다.
여기의 intTemp 라는 변수는, 위에서 잠시 언급한 [이전 10개] 와 [다음 10개] 의 링크를 클릭했을 경우
보여지는 첫번째 페이지 (1페이지, 11페이지, 21페이지, 31페이지...)를 계산하기 위한 임시적인 변수입니다.
(이것은 intBlockPage 의 값이 10인 경우를 말씀드리는 것이고, 만약 intBlockPage 의 값을 5로 지정했을 경우
 intTemp 의 값은 1, 6, 11, 16... 이 될 것입니다. 지켜보면 아시겠지만 이 변수는 상당히 유용하게 쓰지요.)

105~109번 줄까지의 내용을 살펴보겠습니다. (106번 줄은 한줄로 작성하셔야 합니다.)
105~106번 줄은 만약 intTemp 의 값이 1인 경우에는 현재 페이지가 intBlockPage 보다 작기 때문에 링크가 걸리지 않은 [이전 10개] 를 보여준다는 의미가 되겠고요.
105~106번 줄은 만약 intTemp 의 값이 1이 아닌 경우 에는 현재 페이지가 intBlockPage 보다 크기 때문에
링크가 걸린 상태의 [이전 10개] 를 보여준다는 의미가 되겠습니다.
무슨 말인지 잘 모르시겠다고요...? 그렇다면 예를 들어보겠습니다.

지금 현재의 페이지가 9페이지라고 가정을 해보지요. 그렇다면 103번 줄에 의해 intTemp 에 입력되는 값은
Int ((9 - 1) / 10) * 10 + 1 = 1 이 됩니다. (0.8 을 Int 형으로 바꾸면 0이 되기 때문입니다.)
intTemp 값이 1이므로 105~106번 줄에 의해 [이전 10개] 부분에는 링크가 걸리지 않게 됩니다.
이것은 당연한 결과입니다. 지금 현재 9페이지라면 '이전 10개의 페이지' 는 있을 수 없기 때문입니다.

그렇다면 만약 10페이지를 넘긴 13 페이지라면 어떨까요?
이때의 intTemp 값은 Int((13 - 1) / 10) * 10 + 1 = 11 이 됩니다.
그러므로 이번에는 105~106번 줄이 아닌 107~108번 줄에 의해
<a href=list.asp?page=1>[이전 10개]</a> 와 같이 링크가 걸린 모습이 보여지게 됩니다.
이것 또한 올바른 결과입니다. 13페이지라면 '이전 10개의 페이지' 가 분명히 존재하기 때문입니다.
또한 링크가 걸려진 [이전 10개] 부분을 클릭하면 페이지는 1페이지로 이동하게 될 것입니다.

또 다른 예를 하나만 더 들어보겠습니다.
현재의 페이지가 27페이지라고 가정할 때, intTemp 의 값은 21이 될 것입니다.
그러므로<a href=list.asp?page=11>[이전 10개]</a> 와 같은 링크가 걸려지게 될 것입니다.
이 부분을 클릭하게 되면 페이지는 11페이지로 이동을 하게 될테고요.

조금 장황하게 설명이 되었는데요. 어쨌든 [이전 10개] 부분은 이와 같이 작동을 하게 됩니다.
잠시 후에 다루어 볼 [다음 10개] 부분도 지금 살펴본 [이전 10개] 부분과 같은 구성이기 때문에,
지금 이 부분을 잘 이해하셨다면 그다지 어려울 부분이 없을 것 같습니다.

111번 줄부터 121번 줄까지는 직접 이동시킬 페이지를 순서대로 보여주는 부분 이 되겠습니다.
우선 111번 줄에서는 intLoop 라는 변수의 값에 1을 주었고요. (이 변수는 순환문(Do~Loop 문)에서 사용합니다)
113~121번 줄에서는 'intLoop 값이 intBlockPage(여기서는 10)보다 커질 때까지' 또는 ' intTemp 값이 총
페이지보다 커질 때까지
' 순환문을 실행하게 됩니다.

114번 줄부터 115번 줄까지의 내용은 순환문을 통해 나타나는 페이지 중에서 지금 현재의 페이지와 일치하는
페이지에는 링크를 걸지 않는 대신, 현재의 페이지라는 것을 강조하기 위해서 글자 크기를 3으로 늘리고
bold 체를 적용하라는 의미가 되겠습니다.

그런데 114번 줄에서 CInt() 함수가 등장을 하는 것을 보실 수가 있습니다.
이 함수는 '괄호 안에 있는 숫자 값을 정수형으로 변환시키라' 는 의미를 가지고 있습니다.
우리가 Request.QueryString 으로 받아온 값인 intNowPage 는 숫자입니다만, asp 는 이값이 숫자임에도 불구하고 이것을 정수형이 아닌 Variant 형으로 인식합니다. 때문에 일부러 이러한 과정을 거쳐서
정수형으로 변환시켜 준 후, intTemp 값과 비교를 하는 것을 볼 수가 있지요.
 
116번 줄부터 117번 줄까지는 현재 페이지가 아닌 경우, 해당하는 페이지로 이동하는 링크를 걸어주는 내용이
되는 것이고요. 이 내용은 그다지 어렵게 느껴지지 않으리라 생각합니다.

119번 줄과 120번 줄은 순환문을 계속하기 위해서 intTemp 와 intLoop 라는 변수를 각각 1씩 증가시켜
주는 내용이 되겠습니다.

이렇게 순환문을 모두 마친 후 123~127번 줄은 [다음 10개] 에 대한 내용이 되겠습니다.
주의 깊게 살펴보시면 이 부분 역시 [이전 10개] 와 같은 형식을 가진다는 것을 눈치채실 수 있을 것입니다.

그럼 123~124번 줄의 내용을 살펴보도록 할까요?
Do~Loop 순환문을 빠져나온 intTemp 의 값이 총 페이지 수(intTotalPage) 보다 크다면,
(즉 순환문에서 이미 마지막 페이지 까지 보여지게 되었다면 119번 줄을 통해 intTemp 값은 총 페이지 수인
intTotalPage 보다도 1이 커진 값 이 될 것입니다. 이 경우를 말하는 것이지요)
더 이상의 페이지는 없다는 의미가 되므로 [다음 10개] 에는 링크가 걸리지 않을 것입니다.
하지만 그렇지 않다는 것은 아직 남은 페이지가 더 있다는 것을 의미하므로(125~126번 줄)
[다음 10개] 부분에는 링크가 걸리게 되며, 이 링크는 Do~Loop 순환문을 통해 나열된 마지막 페이지보다
1이 더 큰(119번줄을 통한 intTemp) 값을 가진 페이지로 이동시켜 줄 것입니다.

이것으로 페이지 나누기에 관련된 이야기가 끝났습니다.
아마도 오늘의 강좌가 지금까지 제가 지금껏 올렸던 강좌중에서 가장 까다롭고 난해하지 않았나.. 싶은데요.
나름대로는 쉽게 설명하고자 했습니다만, 많이 부족했던 것 같습니다.
잘 이해가 가지 않으시더라도, 반복해서 살펴보시고 또 적용해 보시다 보면 이해가 가리라 생각합니다.

자.. 그럼 이것으로 '페이지 나누기' 에 대한 강좌를 모두 마치....기 전에 말이지요. (놀라셨나요? ^^)
페이지를 나누기가 끝났다면, 조금 귀찮으시더라도 더 효율적인 게시판이 되기 위해 약간의 수정 을 더
해주는 것이 좋습니다.

페이지 나누기를 적용시킨 까닭에.. 사실 지금 우리의 게시판에는 조그마한 문제가 발생했습니다.
내용을 보고 난 후, 또는 글을 수정하고 난 후에 우리가 보고있던 페이지가 아닌 첫페이지로 돌아와 버리는
문제
가 바로 그것인데요.. 알기 쉽게 말씀드리면 다음과 같습니다.

만약 3페이지에 있는 게시의 내용을 보고, '목록으로' 를 클릭해서 리스트로 돌아오면 어떻게 될까요?
우리가 원하는 것은 다시 3페이지로 돌아오기를 바랄 것입니다만, 현실은 그렇지가 못합니다.
1페이지로 이동하기 때문이지요. 왜냐하면 목록보기 페이지로 넘어올 때 3페이지로 넘어오라는 어떠한
정보도 넘겨주지 않았기 때문입니다. 페이지에 대한 정보가 없으면 현재 페이지는 15~17 줄에 의해
1페이지가 된다는 것은 오늘의 강좌에서 이미 몇차례 말씀을 드린 기억이 있습니다.

그렇다면 이 문제를 어떻게 해결하면 될까요?
가장 보편적인 방법은 Url 의 뒤에 붙여서 값을 넘기는 Get 방식으로 현재의 페이지를 전달하는 방식 입니다.
위의 수정된 list.asp 소스 중에서 80번 줄에 다음과 같은 부분이 있습니다.

<a href="content.asp?seq=<%=objRs(0)%>"><%=objRs(3)%></a>

여기서는 게시물의 번호인 seq 값만 넘겨주고 있는 것을 보게 되는데요.
이때 현재 페이지의 값인 intNowPage 를 추가해서 넘겨주면 됩니다. 다음처럼 말이지요.

<a href="content.asp?seq=<%=objRs(0)%>&page=<%=intNowPage%>"><%=objRs(3)%></a>

어떻습니까? 상당히 간단하지 않습니까?
그렇다면 이 값을 전달받는 content.asp 페이지에서도 무언가 수정이 있어야 할 것 같지 않나요?
빙고~ 입니다. content.asp 페이지에서는 방금 넘겨준 intNowPage 값을 받아서, 목록으로 돌아가려 할때
그 값을 전달해주기만 하면 되겠습니다. 어떻습니까.. 대충 감이 잡히지 않으시나요?
그러므로 content.asp 페이지에서 추가되어야 할 부분은 다음과 같습니다.

Dim intNowPage                                                                           ' 몇페이지였는지를 저장하는 변수
intNowPage = Request.QueryString("page")                                    ' 넘겨준 페이지 값을 받아서 저장
---중략----
<a href="list.asp?page=<%=intNowPage%>">목록으로</a>           ' 목록으로 이동시킬때 값을 전달

아마 이정도만 말씀드려도 여러분들께서는 적당한 위치에 추가 및 수정하실 수 있으시리라 생각합니다.
여기까지 강좌를 잘~ 따라오신 여러분들이라면 말이지요. ^^

이 부분은 비단 content.asp 페이지에만 적용되는 것은 아닙니다. 수정하기 페이지인 edit.asp -> edit_ok.asp
페이지에서도 마찬가지 방법으로 intNowPage 값을 전달해서, 수정이 완료될 때 수정이 이루어지기 전의
목록 페이지로 이동시킬 수가 있을 것입니다.
이 부분의 응용은 여러분들께서 충분히 하실 수 있으리라는 생각에.. 여러분들의 몫으로 남겨 두겠습니다.

제가 지난 강좌에서 오늘 '페이지 나누기' 부분이 게시판 만들기의 백미라는 말씀을 잠시 드렸는데요.
오늘의 강좌를 지금껏 따라오시면서 같이 해보신 분들께서는 이제 제 말에 조금 공감을 하시리라 생각합니다.
조금 힘들고 이해하기 어렵더라도, 천천히 그리고 꾸준히 이해하려 노력하시다 보면 어느덧 한걸음 더 나아간
자신의 모습을 발견하실 수 있을 것입니다.

복잡하게 진행된 오늘의 강좌를 여기서 줄이기로 하겠습니다. 고생 많이 하셨습니다.
다음 시간은 예정된 강좌의 마지막 부분인 '검색하기' 페이지를 작성해 보도록 하겠습니다.
검색하기 부분은 오늘의 페이지 나누기 보다는 훨씬 쉬울것 같다는.. 개인적인 생각을 해봅니다. ^^
그럼 다음 강좌까지 건강하시고, 감기 조심하세요~...


P.S (추신, 덧붙임..)

한가지 부탁의 말씀을 드려야 될 것 같습니다.
제 강좌가 초보용 강좌라서.. 제게 스스로 '왕초보'라고 생각하시는 분들의 많은 질문 메일이 오는데요.
질문을 하실 때, '제대로 입력을 했는데 에러가 나요. 왜 그럴까요?' 또는 '도대체 모르겠어요. 왜 안되는 걸까요?'
와 같은 추상적인 질문을 해주시는 분들이 의외로 많이 계십니다.
물론 질문 자체를 어떻게 해야 할지 몰라서 답답한 마음에 이렇게 물어오신다는 점을 충분히 이해를 합니다만,
이런 질문을 받게 되면 저 역시 질문하시는 분께서 어떤 문제로 고민을 하고 계신지 알 수가 없어서
상세한 답변을 드리기가 매우 어렵습니다. 그런 경우에는 정말 난감하지요.

그래서.. 에러가 났을 경우에 그 에러화면을 그림 파일로 저장해서 보내주시거나, 또는 에러 메시지와 작성하신
소스를 함께 보내주시면 제가 답변 드리는데 많은 도움이 될 것 같습니다.
그리고 정말 급한 질문이시라면 제게 메일을 주시는 것보다는, 이 사이트(taeyo's ASP)의 Q & A 게시판에
올리시는 것이 더 빠른 답변을 받으실 수 있으리라고 생각합니다.



출처http://blog.naver.com/yj5881/20007187365