top
Loading...
創建服務器端的ASP搜索組件(二)
  ShowSearchFrame 方法
ShowSearchFrame是唯一一個聲明為Public 的主方法。它不接收自變量,動態生成搜索-輸入域、導航條和標題列表。這是通過調用4個支持性Private 方法實現的。

在ShowSearchFrame 方法中要聲明多個變量,是為了引用我們的支持性Private 方法時進行傳遞。在應用它們的Private 方法的上下文中進行解釋。

調用的第一個Private 方法是 SearchInputField 函數。這個函數返回一個字符串,在我們這個例子中,字符串由HTML標記和文本填充,以產生一個文本輸入區和搜索按鈕。

我們將這個HTML代碼存儲在字符串變量strHTML中:
Public Function ShowSearchFrame() As String
"''''' Local variables
Dim strHTML As String
"===== Search input field
strHTML = SearchInputField
End Function

SearchInputField 函數 SearchInputField 函數不接收自變量。但是它動態地設置一個由頁面訪問者決定的變量。它還設置源文件名和畫面名,與在SearchFrameSet.htm 文件中使用的FRAME 標記名相匹配,這是與決定我們站點的畫面特征的SearchFrameSet.htm 相同的文件。

首先看看將要返回的HTML代碼:
< FORM NAME="SearchForm" METHOD="GET" ACTION="SearchPage.asp" TARGET="SearchFrame" >
< INPUT TYPE="TEXT" NAME="Src" MAXLENGTH="50" SIZE=15 VALUE="" >
< INPUT TYPE=SUBMIT VALUE="Search" >
< /FORM >
表單的NAME標記設置為 SearchForm。ACTION標記設置為SearchPage.asp, 這是mstrSearchFrameURL變量的默認值。
任何從這個表單的輸入域中輸入的文本都將傳送到源文件(SearchPage.asp )。我們的情況是,這個源文件自引用完全相同的asp 文件,其中容納著包含SearchInputField 方法的組件。實質上,這個表單調用了它自己,這是設置默認的結構。

在瀏覽器中,這個HTML代碼生成下面的文本輸入控件:

現在當訪問者在輸入域中鍵入文本并且點擊Search 按鈕時,文本就會被附在SearchPage.asp URL結尾處。這是因為FORM標記內的METHOD被設置為GET,而不是POST。

POST當然是這兩種方法中較好的一個,因為它在HTTP 頭文件中隱藏了輸入的文本并且允許更長的值。但是我們的例子中,是一個短的文本值,? T 也能允許通過將一個查詢字符串附在任何URL的結尾來調用方法。它還有一個好處就是允許瀏覽器緩存查詢結果,因為在進行GET 時,緩存在完整的URL上工作。這樣就可以快速訪問每個搜索頁面,并且在后來離線瀏覽。

當訪問者輸入"component" 作為他們的文本輸入時,我們的表單發送下面的URL和查詢字符串:
SearchPage.asp?Src=component
你還可以從任何站點將這一聲明作為一個連接包含在一個HREF標記內--SearchPage.asp 文件不需FORM標記就能工作。
以下是完整的SearchInputField 函數,它生成以上的HTML 代碼和瀏覽器輸入控制:
Private Function SearchInputField() As String
Dim strHTML As String
"'''' Search input form start
strHTML = strHTML & "< FORM NAME=""SearchForm"" METHOD=""GET"" ACTION=""" _
& mstrSearchFrameURL & """ TARGET=""" & mstrSearchFrameName & """ >"
"'''' Search input field
strHTML = strHTML & "< INPUT TYPE=""TEXT"" NAME=""Src"" MAXLENGTH=""50""" _
& "SIZE=15 VALUE=""" & mobjRequest.QueryString("Src") & """ >"
"'''' Search input button
strHTML = strHTML & "< INPUT TYPE=SUBMIT VALUE=""Search"" >"
"'''' Search input form end
strHTML = strHTML & "< /FORM >"
SearchInputField = strHTML
End Function
請注意我們是如何在HTML代碼的連接片段內連接屬性程序變量來使用它們的。還要注意HTML標記內要求的單引號(") 是如何被雙引號("") 引用的,這樣就可以避免VB把它作為一個字符串常量的開頭或結尾而產生錯誤。
還有一個需要注意的是,在INPUT標記內被設置為VALUE的變量。它從查詢字符串mobjRequest.QueryString("Src") 中得到它的值,聰明的讀者會認出它就是標記本身的名字:
VALUE=""" & mobjRequest.QueryString("Src")
這個自引用查詢字符串將在它的文本域內顯示發送時在域中鍵入的任何文本。由于在文本輸入域中鍵入"component" 將把?Src=component附在URL的結尾,INPUT 標記的值將在輸入文本框中顯示Src的值。

假設在文本輸入域內鍵入的是"component" ,則發送的URL是?/P >
SearchPage.asp?Src=component
而下面的VB代碼< INPUT TYPE=""TEXT"" NAME=""Src"" VALUE=""" & _
mobjRequest.QueryString("Src") & """ >
將生成
< INPUT TYPE="TEXT" NAME="Src" VALUE="component" >
而且將顯示:

現在用戶可以輸入一個查詢字符串,并將其發送到我們的組件看看查詢字符串完成一次搜索。

回到ShowSearchFrame 方法第二部分
回到我們的ShowSearchFrame 方法,它是在SearchInputField 方法中被調用的,我們將返回的HTML代碼存儲在strHTML變量中。但是在我們將它發送給瀏覽器之前,必須要確定訪問者是否已經輸入了一個搜索查詢文本讓我們在搜索數據庫過程中使用。
這是通過校驗Src 查詢字符串變量是否為空實現的。如果為空,就通知訪問者現在他們可以輸入查詢字符串了。當訪問者進入一個搜索站點,連接到一個沒有Src 查詢字符串的網頁時通常就會看到這樣的提示。
ShowSearchFrame 調用 SearchInputField 方法并將HTML輸入控制代碼存儲到strHTML 變量后,我們要查看一下這是不是一個新用戶或查詢請求:
"===== Search input field
strHTML = SearchInputField
If mobjRequest.QueryString("Src") = "" Then
"''''' No query was entered
strHTML = strHTML & "Enter a query"
Else
"[Search code here]
End If

如果沒有名為Src的查詢字符串,連接來自我們的組件以外,我們可以將一個介紹性的信息附在strHTML 代碼上(從這個組件發送一個空查詢也會產生同樣效果):
strHTML = strHTML & "Enter a query"
現在我們的第一個HTML代碼已經完整了,我們將它發送給 IIS在訪問者的瀏覽器上顯示:
Else
"[Search code here]
End If
"''''' Send html code to IIS for delivery to visitors browse r
mobjResponse.Write (strHTML )
產生下面的顯示:


訪問者輸入了要組件搜索的文本以后,以上的條件If 語句就會發現VBmobjRequest.QueryString("Src") 變量不為空,分支控制邏輯就會流向選擇的Else 部分。然后連接到數據庫并在數據庫中搜索匹配的Title 和 Text 域。
因為我們要搜索一個Access Memo 型域,或者說是SQL 服務器文本型域,我們不在SQL聲明內使用LIKE 語句。相反,我們通過以下的SQL字符串返回一個記錄集:
SELECT Title, Text, URL FROM SearchTable
可以用一個帳號群ID、一個典型范圍或者在過濾表中有相關內容的任何類別來限制初始查詢。
由于SQL聲明恢復每個記錄,我們就很快地搜索Title和 Text 域尋找與我們的訪問者所提交的文本查詢字符串相匹配的內容。這個字符串的搜索用VB InStr聲明來實現。如果找到了匹配,并且我們在導航分界線的范圍之內,就將標題和URL放置在動態字符串數列里。

查看導航分界線限制實質上是從記錄的子集中選擇一個標題和UR列表L。然后,用戶就可以用"next"來訪問標題的下一個列表或用"back" 來訪問已經看過的列表中的前一個。實際上就是在向瀏覽器進行顯示時,限制從數據庫搜索返回的文本數量。

現在我們的數據庫中充滿了從SQL聲明中提取出來的記錄(如果你在SQL 聲明中使用了WHERE 過濾器的話就可能是一個有限數量的記錄)。然后用InStr 聲明在每一個返回記錄中搜索一個匹配。這就在SQL聲明返回的數據庫記錄中創建了一個虛擬子集。如果這個子集比我們將要顯示的大的話,就不將它存儲在VB變量中。相反我們選擇我們子集的另一個子集在web 頁面上顯示。我們將數據庫域的變量分配限制在最后的子集中,從而節省系統資源并提高運行速度。


為了收集與搜索查詢相匹配的web 站點標題和URL,需要創建兩個字符串數列。一個保存標題,另一個保存URL。因為我們不知道字符串數列最終將保存多少條目,所以將它們設置為動態數列,每次增加一個新條目時調整它的大小。我們還在不止一個方法中需要這些數列。我們在初始的包裝方法ShowSearchFrame 中創建它們,而不是將它們設置為全局變量。然后就將其作為自變量向每個需要的方法傳遞。我們還需要創建另外兩個整形變量,與字符串變量一起傳遞。

Public Function ShowSearchFrame() As String
"''''' Local variables
Dim strHTML As String
Dim astrTitleArray() As String
Dim astrURLarray() As String
Dim intRecordsDisplayed As Integer
Dim intRecordsMatched As Integer
聲明了兩個動態字符串變量和兩個整形變量之后,就可以將它們傳遞給第二個方法。GetRecords 函數用數據庫中的標題和URL的值來填充字符串數列。用數列中條目的個數設置intRecordsDisplayed 變量。intRecordsMatched 變量中保存與訪問者查詢字符串相匹配的記錄數。我們使mintRecordsSearched 成為一個屬性程序,可從ASP主機文件中讀取。盡管我們不在這個組件中使用它,用戶可能想知道共搜索到多少條記錄。

這是ShowSearchFrame 方法中的方法調用。記住,GetRecords函數是有條件地被調用的,當有來自用戶的搜索查詢,并且在SearchInputField方法之后:
If mobjRequest.QueryString("Src") = "" Then
"''''' No query was entered
strHTML = strHTML & "Enter a query"
Else
"[Search code here]
mintRecordsSearched = GetRecords(astrTitleArray(),astrURLarray(), _
intRecordsDisplayed, intRecordsMatched)
End If

GetRecords 函數
現在我認為對聲明和傳遞方法變量的特殊方法的細節已經介紹得夠多了。對于GetRecords方法的解釋將主要是此方法的一般功能方面。
如果你使用的是VB5的話,就需要安裝Service Pack 3 以獲得對ADO 的引用來使這些代碼工作。
首先要注意在聲明之后,代碼有一個錯誤控制聲明。
Private Function GetRecords(astrTitleArray() As String, astrURLarray() As _
String, intRecordsDisplayed As Integer, intRecordsMatched As _
Integer) As Integer
"''''' LOCAL VARIABLES
Dim intCount As Integer
Dim intRecordsSearched As Integer
Dim strHTML As String
Dim strSearchHold As String
Dim strTitleHold As String
Dim strTextHold As String
Dim strURLhold As String
Dim recSearch As New ADODB.Recordset
Dim objCmd As New ADODB.Command
Dim objConn As New ADODB.Connection
Dim strSQL As String
On Error GoTo ErrorCode
如果在使用數據庫時發生了錯誤,控制就在函數結尾處傳遞一個ErrorCode 標志。
下面的6個聲明用Data Source Name(數據源名)打開到數據庫的連接、啟動一個處理、設置SQL字符串、將SQL 字符串分配給ADO命令對象、告訴命令對象等待一個SQL字符串、設置到命令對象的連接。
在這里我使用的處理是為了示范,而且因為它在轉入命令之前用二進制存儲代碼,這樣可以提高數據庫處理的速度:
"''''' Open the connection with a data source name
objConn.Open "SearchExampleDSN"
"''''' Begin the transaction (only for speed in this case)
objConn.BeginTrans
"''''' Store the SQL command in a string
strSQL = "SELECT Title, Text, URL FROM SearchTable"
"''''' Set the Command object to the SQL string
objCmd.CommandText = strSQL
"''''' indicate that the command is a SQL string (for speed)
objCmd.CommandType = adCmdText
"''''' Set the Connection object to the Command object
Set objCmd.ActiveConnection = objConn
一旦我們用命令對象得到了所需要的打開記錄集的連接,我們就設置:
"'''''Open Recordset with the above Command settings
recSearch.Open objCmd
在繼續進行搜索之前,需要驗證我們確實向搜索返回了一些記錄。如果沒有返回記錄,記錄集就既是在開頭也是在結尾:
If recSearch.EOF And recSearch.BOF Then
"''''No records were returned by the SQL
GetRecords = 0
但是,如果SQL聲明返回了一些記錄,就需要設置一些變量確保記錄集處在開頭:
Else
"''''Initialize Procedural Variables
intRecordsMatched = 0
intRecordsDisplayed = 0
intRecordsSearched = 0
mintSearchStart = CInt(mobjRequest.QueryString("Start"))
If mintSearchStart = 0 Then mintSearchStart = 1
recSearch.MoveFirst
隨著不同的整數計數器的增加,我們在記錄集中循環,并將數據庫中的標題、文本、URL數據存儲在本地字符串變量中:
"''''Loop through the recordset
Do While Not recSearch.EOF
"Increment the total number of records to be searched
intRecordsSearched = intRecordsSearched + 1
"''''' Store the database field data in temparary strings
strTitleHold = recSearch.Fields("Title")
strTextHold = recSearch.Fields("Text")
strURLhold = recSearch.Fields("URL")
連接文本和標題字符串后,從頭至尾搜索字符串,首先將字符串變成大寫字母,然后把我們的查詢字符串片段也變成大寫字母進行搜索:
"''''Concatenate the Title and URL into a String to Search
strSearchHold = strTitleHold & strTextHold
"''''' Determine if the database record meets the visitors query
If InStr(UCase(strSearchHold), _
UCase(mobjRequest.QueryString("Src"))) Then
"''''Increment the number of records that match the visitor"s query
intRecordsMatched = intRecordsMatched + 1
如果我們的記錄數據包含了查詢字符串,就必須要確定它是否在導航列表界限范圍內。這是一點技巧,
"Determine if records are within Start/Stop display range
If intRecordsMatched >= mintSearchStart And _
intRecordsDisplayed < mintMaxSearchReturn Then
這個聲明使用了mintSearchStart 變量,導航條把它作為一個查詢字符串來獲取,然后查看一下列表頁是否達到了它的最大容量,而這個最大容量是由mintMaxSearchReturn變量決定的。如果通過了測試,就將控制傳遞給動態數列聲明。
每次傳遞動態數列保存內容之后,調整其大小。
"''''Increment number of records to display
intRecordsDisplayed = intRecordsDisplayed + 1
"''''Store Title in title array
ReDim Preserve astrTitleArray(intRecordsDisplayed)
astrTitleArray(intRecordsDisplayed) = strTitleHold
"''''Store URL in URL array
Redim Preserve astrURLArray(intRecordsDisplayed)
astrURLArray(intRecordsDisplayed) = strURLHold
End If
End If

下面我們移到下一個記錄,重新開始:
"''''Move to next record
recSearch.MoveNext
Loop
End If
因為這兩個字符串數列是由引用傳遞的(VB的默認狀態),在這個方法中所做的任何修改都會被保存。在結束之前,我們提交處理,關閉數據庫連接,進行一些整理工作:
"------ Commit & Close
objConn.CommitTrans
objConn.Close
Set research = Nothing
Set objConn = Nothing
Set objCmd = Nothing

最后要增加一個錯誤句柄,設置回到方法開頭的方法:
Exit Function
ErrorCode:
objConn.RollbackTrans
strHTML = "Error in Accessing Database File< BR >< BR >"
strHTML = strHTML & "Search::GetRecords< BR >"
strHTML = strHTML & Err.Description & "< BR >"
strHTML = strHTML & strSQL
"''''' Write the error message to the web page
mobjResponse.Write (strHTML)
"''''' Send back a negative one to indicate that there was an error
GetRecords = -1
End Function

在這里我們將數據庫代碼開始時的處理反轉過來,向瀏覽器寫一個HTML錯誤信息,然后返回一個-1,作為一個錯誤代碼通知調用的方法有錯誤發生。

回到ShowSearchFrame 方法第三部分
回到我們的調用方法,查看一下如果返回了-1,然后退出函數,如果是這種情況,-1就表明一個
數據庫錯誤。不然的話,就轉到其它方法。

Else
"[Search code here]
intRecordsSearched = GetRecords(strTitleArray(), strURLarray(), _
intRecordsDisplayed, intRecordsMatched)
"''''Exit of a database error occurred
If mintRecordsSearched = -1 Then Exit Function
End If
現在確定至少返回了一個記錄之后,就可以創建導航條了:
"''''Exit of a database error occurred
If intRecordsSearched = -1 Then Exit Function
"===== NARVIGATION BAR
If Not intRecordsDisplayed = 0 Then
strHTML = strHTML & NavigationBar(intRecordsMatched, _
intRecordsDisplayed) & "< BR >< BR >"
End If
End If
這里我們調用了NavigationBar方法,該方法有兩個自變量,保存與搜索查詢字符串相匹配的記錄數和標題、URL數列中的條目數。NavigationBar 方法返回一個字符串,其中是在瀏覽器上顯示導航條的HTML代碼。

NavigationBar 方法
用這個方法生成組成導航條的三個獨立部分。



NavigationBar 方法有三個部分,每個用來生成上圖的一部分。它接收匹配的記錄數加上顯示的記錄數作為自變量:
Private Function NavigationBar(intRecordsMatched As Integer, _
intRecordsDisplayed As Integer)
Dim strHTML As String
back按鈕用來回到條目中的上一個列表。它發送一個查詢字符串(Start) ,其中存儲著上一個列表的第一條:
"''''Navigation Back
If mintSearchStart > 1 Then
strHTML = strHTML & "< A HREF=""" & mstrSearchFrameURL & "?Src=" & _
mobjServer.URLEncode(mobjRequest.QueryString("Src")) & _
"&Start=" & (mintSearchStart - (mintMaxSearchReturn)) & _
""" >back< /A > "
End If
注意要被發送回組件包含在文本域中的搜索查詢字符串編碼為:
Server.URLEncode(mobjRequest.QueryString("Src"))
如果不使用URLEncode ,瀏覽器就不能顯示或發送有一定字符的查詢字符串。
然后需要計算列表中的條目數和找到了多少條目:
"'''''Naviagation numbers
strHTML = strHTML & " " & CStr(mintSearchStart) & "-" & _
mintSearchStart + (intRecordsDisplayed - 1) & " of " & _
CStr(intRecordsMatched) & " "

next 按鈕與 back按鈕工作方法相同但方向相反:
"''''Navigation Next
If mintSearchStart + (intRecordsDisplayed - 1) < intRecordsMatched Then
strHTML = strHTML & " < A HREF=""" & mstrSearchFrameURL & "?Src=" & _
mobjServer.URLEncode(mobjRequest.QueryString("Src")) & _
"&Start=" & (mintSearchStart + intRecordsDisplayed) & _
""" >next< /A >"
End If

最后將字符串自變量返回到調用代碼中:
"''''Send Back the composed HTML code
NavigationBar = strHTML
End Function

回到ShowSearchFrame 方法第四部分
最后我們要顯示與查詢字符串相匹配的URL的列表。這就需要調用我們的第四個私用方法ListRecords :
"===== Narvigation bar
If Not intRecordsDisplayed = 0 Then
strHTML = strHTML & NavigationBar(intRecordsMatched, _
intRecordsDisplayed) & "< BR >< BR >"
End If
"===== URL Title list
strHTML = strHTML & ListRecords(astrTitleArray(), astrURLarray(), _
intRecordsDisplayed)
End If

ListRecords 方法
本方法接受兩個字符串數列,以及它們保存的條目數作為自變量:
Private Function ListRecords(astrTitleArray() As String, _
astrURLArray() As String, _
intRecordsDisplayed As Integer)
Dim strHTML As String
Dim intCount As Integer

首先要驗證存在可以列出的條目,在格式化我們的HTML代碼的時候在字符串數列中循環。在這種情況下,我們使用條目字符串作為可視文本,將URL字符串數列作為HREF 源:
If intRecordsDisplayed = 0 Then
"''''No records where found for this query
strHTML = strHTML & "Query not found"
Else
"''''List search titles with URL link results
For intCount = 1 to intRecordsDisplayed
strHTML = strHTML & "< A HREF=""" & astrURLarray(intCount) & """" _
& "TARGET=""" & mstrResultFrameName & """ >" & _
astrTitleArray(intCount) & "< /A >< BR >"
Next
End If

注意以mstrResultFrameName 變量給TARGET 賦值。回想起來這個變量可以從ASP主機文件設置。它決定在哪個畫面中顯示HREF:
然后所需要做的就是將HTML代碼返回字符串變量中:
"'''''Send back HTML code of the Title/URL list
ListRecords = strHTML
End Function

回到ShowSearchFrame 方法第五部分
實際上我們已經完成了這個方法,但是我還是想確保我們在同一頁上,下面是本方法的完整清單:
Public Function ShowSearchFrame() As String
"''''' Local variables
Dim strHTML As String
Dim astrTitleArray() As String
Dim astrURLArray() As String
Dim intRecordsDisplayed As Integer
Dim intRecordsMatched As Integer
"===== Search input field
strHTML = SearchInputField
If mobjRequest.QueryString("Src") = "" Then
"''''' No query was entered
strHTML = strHTML & "Enter a query"
Else
"[Search code here]
mintRecordsSearched = GetRecords(astrTitleArray(), astrURLArray(), _
intRecordsDisplayed, intRecordsMatched)
"''''Exit of a database error occurred
If mintRecordsSearched = -1 Then Exit Function
"===== NARVIGATION BAR
If Not intRecordsDisplayed = 0 Then
strHTML = strHTML & NavigationBar(intRecordsMatched, _
intRecordsDisplayed) & "< BR >< BR >"
End If
"===== URL Title list
strHTML = strHTML & ListRecords(astrTitleArray(), astrURLArray(), _
intRecordsDisplayed)
End If
"''''' Send html code to IIS for delivery to visitors browser
mobjResponse.Write (strHTML)
End Function
這就是全部了。現在可以編譯DLL,繼續下一步了。

進一步超越基礎

我使這些代碼盡可能地簡單,只有幾個數據庫處理和屬性程序這些必需的內容。但是為了增強代碼功能,還有許多可以做。

能夠想到并且也很好玩的一個功能是縮短構成列表的標題。盡管將標題列表放在一個表格內可以改善可視界面,但是過長的標題會削弱列表的可讀性。以下是進入ListRecords 方法縮短長標題的程序,它在標題結尾處加3個句號,表明它被刪節了:
Dim strTemp As String
strTemp = strTitleArray(intCount)
If Not Trim(Len(strTemp)) = intListTitleMax Then
strTemp = Trim(Left(strTemp, intListTitleMax))
If Trim(Len(strTemp)) = intListTitleMax Then
strTemp = strTemp & "..."
End If
End If
以上代碼將標題中超過一定字符長度的部分切斷。字符長度是intListTitleMax 的值。
另外一個增加包括了在指針窗口中查看web 站點描述的選擇。在一個非畫面版本中,站點可以在一個空白瀏覽器中啟動,以避免那些要求頂部畫面的瀏覽器、用戶粘貼新站點的能力、站點類別過濾、以字母或搜索的匹配程度為順序進行列表等等。

在ASP下重新編譯DLL

當我們第一次將組件存為DLL文件時,VB創建文件并在系統上注冊它時是沒有問題的。但是在ASP頁上使用過DLL對象之后,如果不完全關掉ASP系統的話,VB就不允許重新編譯DLL。
用Windows 9x 你可以關閉ASP、重新編譯DLL并用以下指令啟動ASP:
pws /sto p
pws /star t
在NT系統,用下列指令:
net stop iisadmin net start w3sv c
我不能肯定你怎么樣,但是當基本的代碼完成后,我對這個增強功能的過程很感興趣,因為我知道,即使它們不能正常工作,我的基本代碼部分是不受影響的。從這一點上來說,很難讓這個程序樣本保留這個樣子而不去做那些增強工作。所以如果你有興趣,隨便怎么使用這個程序都可以。

點擊本處下載本文相關鏈接。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗