在微軟的ASP程式設計系統中,ADO物件的建立,使得從網頁存取資料庫成為一件易事,特別是ADO的Recordset物件使得控制資料的輸出顯示更為方便、自由。而在Visual InterDev6.0(以下簡稱VI6.0)中,由於Script Object Model(以下簡稱SOM)、Design-Time Control(以下簡稱DTC)以及Data Environment Object Model(以下簡稱DEOM)等物件模型的引入,讓網頁對資料庫的存取設計顯得更為方便。
因為主題方面的原因,關於資料庫的連接,下文只給出程式碼和簡要註釋,而把重點放在如何利用Recordset物件(或控制項)實現資料記錄的分頁顯示方面。根據我的理解,分頁顯示的關鍵在於ADO的Recordset物件或DTC(設計時控制項)的Recordset控制項的屬性和方法的熟練把握。
這七種分頁顯示的武器概括起來說分四類:
第一、二種我暫取名叫純ASP法,這也是國內的ASP網站上用得最多的方法,它們的差異只在實現技巧的不同。這兩種方法的實作最易理解,用到的物件概念也最少,對開發環境的要求也最低(只要記事本就行)。可以說,這兩種方法的實質還是CGI的程式設計思想,只是在程式中引入了ADO物件而已。
第四、五種暫取名叫SOM的DHTML法。這兩種方法要求在VI6.0的環境下,利用微軟提出的腳本物件模型(Script Object Model)和DHTML中Table物件的與資料庫綁定的新特性(許多書籍和文章只介紹了DHTML的CSS特性在樣式設計中的運用而忽略介紹其資料綁定特性),實作在客戶端控制翻頁。但它要求使用者的瀏覽器必須支援DHTML,如:Microsoft Internet Explorer 4.0以上的版本。
第六種暫取名叫SOM伺服器端法。要求在VI6.0的環境下開發,它利用微軟提出的腳本物件模型(Script Object Model)中的幾個DTC控制項:Recordset、PageObject、Grid等在伺服器端(客戶端)實現翻頁控制。這是一種令人興奮的、全新的程式設計方法,它把網頁看成物件(這種物件模型和傳統的DOM----document object model是有區別的:DOM只能控制客戶端,而SOM可控制伺服器端和客戶端),它真正實現了網頁的物件導向程式設計。但遺憾的是,也許是我個人能力有限,這種技術我個人認為還不是很成熟,例如,與瀏覽器的結合還不是很好,這將在後文詳細說明。
第七種暫取名叫DEOM法。它也是利用了VI6.0中建立的資料環境物件模型(Data Environment Object Model)來建立Recordset物件。這也是在網頁程式設計上比較少見的新方法,與SOM模型相比,自有它的優點,這將在後文詳述。
在後面所舉的所有例子原始碼,都可以直接拷貝使用,你甚至可以不懂其原理,只要把其中的粗斜體字部分換成對應自己的資料庫名稱或欄位名稱就可以了。
在開始詳細介紹各種分頁方法前,讓我們先建立一個資料庫:用Office97中的access自創一個Employee.mdb,其中建立一個表emp,只設三個欄位:emp ID,last name和first name。為什麼這麼簡單,是因為我們關心的是怎麼處理recordset的結果。
第一種:參數直接代入法
這種方法是用手動建立Recordset對象,利用其pagesize(每頁指定顯示記錄數),pagecount(總頁碼數)和absolutepage(當前頁碼數)屬性來控制分頁的輸出。分頁採用<href>直接帶頁碼參數的方法來控制翻頁。網頁的名稱為emp1.asp。原始碼如下:
<%//建立與employee.mdb資料庫的連線。
Set conn = Server.CreateObject(ADODB.Connection)
conn.Open driver={Microsoft Access Driver (*.mdb)};dbq=employee.mdb
//建立emp表的Recordset物件實例rs。
Set rs = Server.CreateObject(ADODB.Recordset)
rs.Open emp, conn, 3
PageSize = 10 //pagesize屬性指定了每頁要顯示的記錄條數
Page = CLng(Request(Page)) 'string型轉換為long型
If Page < 1 Then Page = 1
If Page > rs.PageCount Then Page = rs.PageCount
If Page <> 1 Then
Response.Write <A HREF=emp1.asp?Page=1>第一頁</A>
Response.Write <A HREF=emp1.asp?Page= & (Page-1) & >上一頁</A>
End If
If Page <> rs.PageCount Then
Response.Write <A HREF=emp1.asp?Page= & (Page+1) & >下一頁</A>
Response.Write <A HREF=emp1.asp?Page=&rs.PageCount & >最後一頁</A>
End If
Response.write頁碼: & Page & / & rs.PageCount & </font>
//每一頁的顯示
//顯示表頭
Response.Write <CENTER><TABLE BORDER=1>
Response.WRITE <TR><TD> & rs.Fields(emp ID).Name & </TD>
Response.WRITE <TD> & rs.Fields(last name).Name & </TD>
Response.WRITE <TD> & rs.Fields(first name).Name & </TD></TR>
//循環顯示每筆記錄
rs.AbsolutePage = Page //把頁碼賦給absolutepage屬性從而知當前頁的首條記錄號
For iPage = 1 To rs.PageSize //
Response.WRITE <TR><TD> & rs.Fields(emp ID).Value & </TD>
Response.WRITE <TD> & rs.Fields(first name).Value & </TD>
Response.WRITE <TD> & rs.Fields(last name).Value & </TD></TR>
rs.MoveNext
If rs.EOF Then Exit For
Next
Response.Write </TABLE></CENTER>%>
第二種:表單傳送參數法
此方法在建立Recordset物件時與第一種相同,只是在翻頁控制時,採用<input>和case語句配合來實現翻頁。網頁的名稱為:emp2.asp。此方法在程式設計邏輯上有個缺點:就是在按過上頁或下頁鈕後,再在瀏覽器上按下刷新按鈕時,會自動翻頁。原始碼如下:
if Pagenum = Then Pagenum = 1 //從第一頁開始顯示
//建立資料庫連線和Recordset物件實例rs。
與第一種方法相同,此處略過。
RS.Pagesize = 10 ' 設定一頁中顯示的記錄條數為10條
// 確定翻頁的動作
Select Case Request(NAV)
Case
session(Pagenum) = 1
case First ' First Record
session(Pagenum) = 1
case Prev ' Previous Record
if session(Pagenum) > 1 then
session(Pagenum) = session(Pagenum) - 1
End If
case Next ' Next Record
if session(Pagenum)< RS.PageCount then
session(Pagenum) = session(Pagenum) + 1
End if
case Last ' Last Record
session(Pagenum) = RS.PageCount
End Select
RS.Absolutepage = Clng(session(Pagenum)) //決定目前頁的第一筆記錄號
// 顯示目前頁
同第一種方法,此處略過。
// Nav 翻頁按鈕設定
<form method=GET action=emp2.asp>
<input type=submit name=NAV Value=首頁>
<input type=submit value=上頁name=NAV>
<input type=submit value=下頁name=NAV>
<input type=submit value=末頁name=NAV></form>
第三種:用Grid控制項設計分頁
在所有的方法中,這種方法最容易。你只需拖DTC中的Recordset控制項和Grid控製到asp網頁就行了。而且,你還能選擇在伺服器平台還是在客戶端平台控制翻頁。缺點就是你必須用它給定的格式顯示,而不能自己自由控製表格的顯示格式。
方法如下:
在VI6.0中建造一個工程emp.vip。再在工程中加入一個asp網頁:emp3.asp。
第一步:選取VI6.0選單條上的add data connect…,依照開發工具的導覽提示,你就可以輕鬆建立與Employee.mdb資料庫的連線。從DTC工具列中拖曳一個Recordset控制項到網頁中,並設定其屬性。具體如圖:
當你拖曳控制項到網頁中時,VI6.0會自動提示你是否使用Scripting object model,按yes。
第三步:從DTC工具列中拖曳一個Grid控制項到網頁中,然後按一下滑鼠右鍵,設定其屬性,如:選在第二步驟中建立的Recordset控制項名,選擇emp表中的字段,每頁顯示多少筆記錄以及顯示格式等。非常簡單方便,只要照著導航提示做就行了。
第四種:DHTML法一。
數據記錄顯示在一個HTML表中。它利用DHTML中表格的資料綁定特性來控制記錄的分頁顯示。缺點就是你的翻頁方法將被限制為一種特定的方式:只能上頁和下頁而不能首頁和末頁。由於是在客戶端控制翻頁,所以,這種和第五種方法是速度最快的,但遺憾的是它只能在支援DHTML的瀏覽器上使用。
在DHTML中,<TABLE>的DATASRC屬性可將表格綁定到一個資料來源,另一個屬性DATAPAGESIZE可指定一頁一次顯示的記錄數。
我們來看下面的例子:
第一步:拖曳Recordset控制項到新建的網頁emp4.htm中,設定其屬性,方法同第三種,此處略。
第二步:輸入下面的程式碼:
<TABLE ID=Table1 DATASRC=#Recordset1_RDS DATAPAGESIZE=5> //假定前面設定Recordset控制項名為Recordset1。每頁顯示5筆記錄。
<THEAD>
<TH ALIGN=left WIDTH=150>Emp ID</TH> //輸出表頭
<TH ALIGN=left WIDTH=200>Last Name</TH>
<TH ALIGN=left WIDTH=200>First Name</TH>
</THEAD>
<TR>
<TD><DIV DATAFLD=Emp ID></DIV></TD> //輸出表內容
<TD><DIV DATAFLD=Last Name></DIV></TD>
<TD><DIV DATAFLD=First Name></DIV></TD>
</TR>
</TABLE>
第三步:然後,增加一對DTCs Button按鈕控制項來做翻頁導航,一個命名為btnPrevious(上一頁),一個命名為btnNext(下一頁)。它們對應的腳本如下:
<SCRIPT LANGUAGE=VBScript>
Function btnPrevious_onclick()
Table1.previousPage()
End Function
Function btnNext_onclick()
Table1.nextPage()
End Function
</SCRIPT>
第五種:DHTML法二
這種方法是對第四種方法的完善。採用手工編寫腳本的方法,使我們能做首頁,末頁翻頁導航按鈕,並能確定每筆記錄的位置(記錄號)。由於篇幅的關係,我在下面只介紹一個具體例子,並給出簡要說明。其它關於DHTML和Recordset控制項的一些屬性和方法請讀者自行參考相關書籍。這裡要提請注意的是,Recordset控制項與第一、二種方法中介紹的ADO的Recordset物件有些不同:Recordset控制項並沒有直接給予pagesize和pagecount等屬性,需要用下面介紹的方法來計算。
第一步:拖曳Recordset控制項到新建的網頁emp5.htm中,名字為Recordset1,設定其屬性,方法同第三種,此處略。
第二步:定義三個全域變數和編寫Recordset1的ondatasetcomplete(資料設定完成時)腳本。
Dim gCurrentPageNumber //目前頁號
Dim gMaxPageNumber //最大頁數
Dim gRecordsPerPage //每頁顯示記錄數
gRecordsPerPage = 5 // 設定每頁顯示記錄數為5筆記錄。
Function Recordset1_ondatasetcomplete()
totalRecordCount = Recordset1.getCount() //總的記錄條數
gMaxPageNumber = Int(totalRecordCount / gRecordsPerPage) //取得最大頁數
If (totalRecordCount Mod gRecordsPerPage) > 0 then
gMaxPageNumber = gMaxPageNumber + 1
End If
End Function
第三步:建立翻頁導航按鈕。
Function btnFirst_onclick() ' 翻到首頁
gCurrentPageNumber = 1
DisplayData()
End Function
Function btnPrevious_onclick() ' 翻到上一頁
if gCurrentPageNumber > 1 Then
gCurrentPageNumber = gCurrentPageNumber - 1
DisplayData()
End If
End Function
Function btnNext_onclick() ' 翻到下一頁
if gCurrentPageNumber < gMaxPageNumber Then
gCurrentPageNumber = gCurrentPageNumber + 1
DisplayData()
End If
End Function
Function btnLast_onclick() '翻到末頁
gCurrentPageNumber = gMaxPageNumber
DisplayData()
End Function
第四步:寫出顯示每一頁的函數。其中使用了許多DHTML的屬性與方法,請讀者自行參考相關書籍。
Sub DisplayData()
startRecord = ((gCurrentPageNumber - 1) * gRecordsPerPage) + 1 //計算每一頁開始顯示的記錄號數(位置,第幾條)
rowCtr = 1
lblPageNumber.innerHTML = gCurrentPageNumber & / & gMaxPageNumber
For recordPtr = startRecord To (startRecord + gRecordsPerPage - 1) //循環顯示一頁的各筆記錄
If recordPtr > Recordset1.getCount() Then //顯示空表
Table1.rows(rowCtr).cells(0).innerHTML = <P> </P>
Table1.rows(rowCtr).cells(1).innerHTML = <P> </P>
Table1.rows(rowCtr).cells(2).innerHTML = <P> </P>
Table1.rows(rowCtr).cells(3).innerHTML = <P> </P>
Else //具體顯示每一頁
Recordset1.moveAbsolute(recordPtr) //移動記錄指標。
empID = Recordset1.fields.getValue(emp ID)
empLName = Recordset1.fields.getValue(first name)
empFName = Recordset1.fields.getValue(last name)
Table1.rows(rowCtr).cells(0).innerText = recordPtr ' Counter
Table1.rows(rowCtr).cells(1).innerText = empID
Table1.rows(rowCtr).cells(2).innerText = empLName
Table1.rows(rowCtr).cells(3).innerText = empFName
End If
rowCtr = rowCtr + 1
Next
End Sub
另外,我們還需要在window物件的onload事件中編寫以下腳本:
For rowCtr = 1 to gRecordsPerPage
Table1.insertRow(rowCtr) ' 插一新列
For cellCtr = 0 至 3
Table1.rows(rowCtr).insertCell()
Next
Next
第六種:伺服器端控制翻頁方法。
如果我們在伺服器端對資料進行分頁形成HTML語句後再輸出到客戶端,就不會有瀏覽器不支援DHTML的問題了。可是用伺服器端法使得我們每次翻頁時,都得讓Recordset控制項重新產生一次,因此速度一定要比用DHTML的方法慢。但如果伺服器夠快的話,這點慢客戶是察覺不到的。
下面的範例中,我將介紹一個新的DTC控制項:PageObject。這個控制項使被指定的網頁成為一個網頁對象,使用者在此網頁的伺服器腳本中組織的子程序和函數可被視為該網頁對象的方法。它提供了管理狀態資訊的一種先進的方法:網頁物件有一些屬性(變數),使用者可以定義這些屬性的生存期。因為以上這些特性,使我們在編制翻頁的腳本時變得非常方便。
但這種方法的缺點是:當你按了上頁或下頁按鈕後,再瀏覽器上的按刷新按鈕,網頁會自動翻頁。另外,如果按了瀏覽器上的回退按鈕後,再按翻頁按鈕,可能會出現一次亂翻。這都是因為網頁物件屬性(全域變數)造成的。
第一步:拖Recordset控制項到新建的網頁emp6.asp中,名字為Recordset1,設定其屬性,方法同第三種,此處略。
第二步:拖PageObject控製到網頁中,取名叫emplist。然後右鍵單擊此控制項開啟屬性頁並設定MaxPageNumber,RecordsPerPage,CurrrentPageNumber三個屬性(全域變數)。 VI6.0可用get和set方法來讀寫它們的值,具體用法請查閱相關資料。
步驟三:編寫Recordset1的ondatasetcomplete事件。
Function Recordset1_ondatasetcomplete()
recordsPerPage = 5
empList.setRecordsPerPage(recordsPerPage)//設定網頁物件每頁記錄條數屬性為5
totalRecordCount = Recordset1.getCount()//取得記錄集的總條數
mpn = Int(totalRecordCount / recordsPerPage) //計算mpn為總頁數
If (totalRecordCount Mod recordsPerPage) > 0 then
mpn = mpn + 1
End If
empList.setMaxPageNumber(mpn)
End Function
第四步:拖曳四個button控制項到網頁中,編寫翻頁控制腳本。我們主要是透過改變網頁物件的CurrentPageNumber屬性的值來實現翻頁。
Function btnFirst_onclick() ' 翻到首頁
empList.setCurrentPageNumber(1)
End Function
Function btnPrevious_onclick() ' 翻到上一頁
cpn = empList.getCurrentPageNumber()
if cpn > 1 Then
empList.setCurrentPageNumber(cpn - 1)
End If
End Function
Function btnNext_onclick() ' 翻到下一頁
cpn = empList.getCurrentPageNumber()
if cpn < empList.getMaxPageNumber() then
empList.setCurrentPageNumber(cpn + 1)
End If
End Function
Function btnLast_onclick() ' 翻到末頁
empList.setCurrentPageNumber( empList.getMaxPageNumber() )
End Function
為確保首次進入該頁時,顯示的是第一頁,我們還得撰寫該網頁物件的onEnter事件。
Function empList_onEnter()
If empList.firstEntered Then
empList.setCurrentPageNumber(1)
End If
End Function
第五步:編寫顯示每一頁的腳本。
<HR><TABLE BORDER=0><TR>//顯示表頭
<TH ALIGN=left WIDTH=35></TH>
<TH ALIGN=left WIDTH=150>Emp ID</TH>
<TH ALIGN=left WIDTH=200>Last Name</TH>
<TH ALIGN=left WIDTH=200>First Name</TH></TR>
<%
pageNumber = empList.getCurrentPageNumber()//計算翻頁所需的各種參數,同DHTML法二
recordsPerPage = empList.getRecordsPerPage()
startRecord = ((pageNumber - 1) * recordsPerPage) + 1
lastRecord = Recordset1.getCount()
For recordPtr = startRecord To (startRecord + recordsPerPage - 1)%>
<%If Recordset1.EOF = True Then%>
<TR>
<TD> </TD>
<TD> </TD>
<TD> </TD>
<TD> </TD>
</TR>
<%Else%>
<%Recordset1.moveAbsolute(recordPtr)%>
<TR>
<% If recordPtr <= lastRecord Then %>
<TD><%=recordptr%></TD>
<%Else%>
<TD> </TD>
<% End If %>
<TD><%=Recordset1.fields.getValue(emp ID)%></TD>
<TD><%=Recordset1.fields.getValue(last name)%></TD>
<TD><%=Recordset1.fields.getValue(first name)%></TD>
</TR>
<%End If%>
<%Next%>
</TABLE><HR>
第七種:Data Environment Object Model(資料環境物件模型)法
Data Environment物件模型把ADO物件模型及它的物件----Connection,Command,Recordset,Field以及Parameter物件----抽像到一個更容易的表單中。 Data Environment Object Model將指令顯露為方法。使用者可以呼叫這些方法,這些方法會執行這些命令並傳回所得到的記錄集。關於DEOM物件模型詳細資料請參考相關書籍。我們來看下面網頁emp7.asp的範例:
第一步:在VI6.0的project Explorer視窗中的工程項目上按滑鼠右鍵並從彈出式功能表選擇Add Data Connection。在根據VI給的導航提示建立一個到資料庫的連線之後,使用者就加入了一個實作從ASP應用程式存取資料庫的資料指令。同時,你將會在Project Explorer視窗中的global.asa檔案下方看到一個Data Environment物件。
第二步:右鍵點選Data Environment物件然後從彈出式選單中選擇Add Data Command選項,新增一個資料命令Command1。根據VI6.0的導覽提示,你可以在Command1 Properties彈出視窗的Genetal頁中選SQL Statement,輸入:select * from emp。按OK返回。
第三步:你建立了這個資料指令後,就已經為該Data Environment物件建立了一個方法,然後就可以從腳本中呼叫這個方法,而且該方法將會為使用者傳回一個記錄集。
thisPage.createDE() //在SOM模式下,thisPage表示目前網頁對象,createDE()方法建立了DE對象。
DE.Command1//執行DE物件的指令,後面可代參數,做有條件查詢時很有用。
Set rs=DE.rsCommand1//DE.rscommand1使得rs物件完全等同於一個ADO的Recordset物件。
第四步:因為rs為ADO對象,所以,以下的實作翻頁程式碼完全參考以上介紹的幾種方法,此處略過。
其它還有如FrontPage2000的資料庫導航中實現的方法等,因與本主題無關,此處略。
綜上所述,前面介紹的每種方法都包含了許多新的技術,由於篇幅的關係,無法深入。本文只是想透過實現翻頁這一具體的例子來介紹ASP網頁編程的多種方法;讓大家親身體驗一下VI6.0在編制網頁中的強大功能;了解並熟悉微軟在網頁編程中提出的ADO、 DHTML、DTC控制項、SOM物件模型和DEOM物件模型的使用方法;希望能為大家在編製網頁時提供更多的選擇與參考。