?? 210.htm
字號(hào):
<p></p>
<p> if returnsData then </p>
<p></p>
<p> R.Save Response, adPersistXML </p>
<p></p>
<p> if err.number <> 0 then </p>
<p></p>
<p> call responseError _ </p>
<p></p>
<p> ("Recordset Save Error " & _ </p>
<p></p>
<p> "on command 注釋:" & CommandText & _ </p>
<p></p>
<p> "注釋:: " & Err.Description) </p>
<p></p>
<p> Response.end </p>
<p></p>
<p> end if </p>
<p></p>
<p> ... </p>
<p></p>
<p>如果命令以輸出參數(shù)返回值,頁(yè)面將返回包含這些值的XML字符串。該文檔的根是一個(gè),每一個(gè)返回值對(duì)應(yīng)一個(gè)子元素(參見(jiàn)本文可下載例程代碼)。 </p>
<p> 如果產(chǎn)生錯(cuò)誤,頁(yè)面使用responseError子程序格式化并返回一個(gè)XML字符串。參數(shù)sDescription中包含了錯(cuò)誤文本: </p>
<p></p>
<p> Sub responseError(sDescription) </p>
<p></p>
<p> Response.Write _ </p>
<p></p>
<p> "<response><data>Error: " & sDescription & "</data></response>" </p>
<p></p>
<p> Response.end </p>
<p></p>
<p> End Sub </p>
<p></p>
<p> 上面的圖中顯示了運(yùn)行中的一個(gè)實(shí)例。應(yīng)用程序在左邊的<div>標(biāo)記里顯示一個(gè)客戶名列表。每個(gè)客戶旁邊有兩個(gè)鏈接:Purchase History和Recent Purchase。當(dāng)用戶點(diǎn)擊其中之一時(shí),客戶端程序運(yùn)行一個(gè)存儲(chǔ)過(guò)程并在右邊的<div>標(biāo)記里顯示結(jié)果。 </p>
<p></p>
<p> 為了顯示這一方案的靈活性,雖然都使用到getData.asp,但三個(gè)返回?cái)?shù)據(jù)的操作以互不相同的方式工作。對(duì)客戶列表的查詢涉及到動(dòng)態(tài)SQL。對(duì)Purchase History的查詢運(yùn)行了一個(gè)稱為CustOrderHist的存儲(chǔ)過(guò)程,它附帶在Northwind數(shù)據(jù)庫(kù)中,并且返回一個(gè)recordset。對(duì)Recent Purchase的查詢運(yùn)行了一個(gè)稱為RecentPurchaseByCustomerID的存儲(chǔ)過(guò)程,它接受一個(gè)輸入?yún)?shù)CustomerID并在一個(gè)輸出參數(shù)ProductName中返回該客戶最近購(gòu)買(mǎi)的產(chǎn)品的名稱。過(guò)程的定義是: </p>
<p></p>
<p> CREATE PROCEDURE RecentPurchaseByCustomerID </p>
<p></p>
<p> @CustomerID nchar(5), </p>
<p></p>
<p> @ProductName nchar(40) output </p>
<p></p>
<p> AS </p>
<p></p>
<p> SELECT @ProductName = </p>
<p></p>
<p> (SELECT top 1 ProductName _ </p>
<p></p>
<p> FROM Products </p>
<p></p>
<p> INNER JOIN ([Order Details] </p>
<p></p>
<p> INNER JOIN Orders ON_ </p>
<p></p>
<p> Orders.OrderID=[Order_ </p>
<p></p>
<p> Details].OrderID) </p>
<p></p>
<p> ON Products.ProductID = </p>
<p></p>
<p> [Order Details].ProductID </p>
<p></p>
<p> WHERE Orders.OrderDate = </p>
<p></p>
<p> (SELECT MAX(orders.orderdate)_ </p>
<p></p>
<p> FROM Orders </p>
<p></p>
<p> where CustomerID=@CustomerID) </p>
<p></p>
<p> AND Orders.CustomerID=@CustomerID) </p>
<p></p>
<p> GO </p>
<p></p>
<p> 無(wú)論查詢中包含的是動(dòng)態(tài)SQL、返回recordset的存儲(chǔ)過(guò)程、還是在輸出參數(shù)中返回值的存儲(chǔ)過(guò)程,設(shè)置POST消息的過(guò)程差不多都完全相同。客戶頁(yè)面創(chuàng)建XML字符串<command>、創(chuàng)建XMLHTTPRequest對(duì)象,用Open方法將它設(shè)置為對(duì)getData.asp 頁(yè)面中的URL使用POST方法、并制定對(duì)象以異步方式工作(Open方法中的False參數(shù))。它使用Send方法發(fā)送字符串: </p>
<p></p>
<p> set xhttp = createObject("msxml2.XMLHTTP") </p>
<p></p>
<p> xhttp.open "POST", "http://localhost/myWeb/getData.asp", False </p>
<p></p>
<p> xhttp.send s </p>
<p></p>
<p> 注意:在Open方法中使用的URL必須是一個(gè)完整的URL,而不是一個(gè)相對(duì)URL。換句話說(shuō),下面的代碼不能工作,因?yàn)閁RL是不完整的: </p>
<p></p>
<p> xhttp.open "POST", "getData.asp", False </p>
<p></p>
<p>用VB和XML建立集中式應(yīng)用程序(下)</p>
<p>(作者:青蘋(píng)果工作室編譯 2001年03月19日 15:41)</p>
<p></p>
<p>傳送消息及接收數(shù)據(jù) </p>
<p> 客戶端的XML消息由一個(gè)帶有幾個(gè)子元素的<command>元素構(gòu)成:一個(gè)包含著存儲(chǔ)過(guò)程名稱的<commandtext>元素;一個(gè)<returnsdata> 元素,它告訴服務(wù)器客戶端是否期待返回?cái)?shù)據(jù);返回零個(gè)還是多個(gè)包含著參數(shù)信息的<param>元素。在這個(gè)最簡(jiǎn)單的沒(méi)有參數(shù)的情況下,傳送的字符串查詢類似于: </p>
<p></p>
<p> <command> </p>
<p></p>
<p> <commandtext> </p>
<p></p>
<p> StoredProc or Dynamic SQL </p>
<p></p>
<p> </commandtext> </p>
<p></p>
<p> <returnsvalues>True</returnsvalues> </p>
<p></p>
<p> </command> </p>
<p></p>
<p> 要添加參數(shù),就需要為每一個(gè)參數(shù)添加一個(gè)<param>元素。每個(gè)<param>元素有五個(gè)子元素:<name>、<type>、<direction>、<size>和<value>。五個(gè)子元素的先后次序無(wú)關(guān)緊要,但都是必須的。通常,依照定義ADO Parameter對(duì)象所需的次序定義它們。例如,存儲(chǔ)過(guò)程CustOrderHist需要一個(gè)CustomerID參數(shù),所以創(chuàng)建傳送到 detData.asp的XML字符串的代碼就是: </p>
<p></p>
<p> dim s </p>
<p></p>
<p> s = "<?xml version=""1.0""?>" & vbcrlf </p>
<p></p>
<p> s = s & "<command><commandtext>" </p>
<p></p>
<p> s = s & "CustOrderHist" </p>
<p></p>
<p> s = s & "</commandtext>" </p>
<p></p>
<p> s = s & "<returnsdata>" & "True</returnsdata>" </p>
<p></p>
<p> s = s & "<param>" </p>
<p></p>
<p> s = s & "<name>CustomerID</name>" </p>
<p></p>
<p> s = s & "<type><%=adVarChar%></type>" </p>
<p></p>
<p> s = s & "<direction>" & "<%=adParamInput%></direction>" </p>
<p></p>
<p> s = s & "<size>" & len(CustomerID) & "</size>" </p>
<p></p>
<p> s = s & "<value>" & CustomerID & "</value>" </p>
<p></p>
<p> s = s & "</param>" </p>
<p></p>
<p> s = s & "</command>" </p>
<p></p>
<p> 注意前面的代碼是在客戶端的;ADO常量沒(méi)有在客戶端定義,這是它們必須用<% %>標(biāo)記括起來(lái)的原因。在發(fā)送應(yīng)答之前,服務(wù)器用正確的值替換它們。頁(yè)面getData.asp有一個(gè)Response.ContentType屬性,其數(shù)值為"text/xml";因此,我們就能使用ResponseXML屬性查詢結(jié)果。當(dāng)查詢返回一個(gè)記錄集合時(shí),可以創(chuàng)建一個(gè)Recordset對(duì)象并像以下代碼那樣使用XMLHTTP-Request對(duì)象的responseXML屬性來(lái)打開(kāi)它: </p>
<p></p>
<p> Dim R </p>
<p></p>
<p> set R = createObject("ADODB.Recordset") </p>
<p></p>
<p> R.open xhttp.responseXML </p>
<p></p>
<p> 當(dāng)通過(guò)輸出參數(shù)返回查詢數(shù)據(jù)時(shí),可以通過(guò)將一個(gè)變量設(shè)置為XMLHTTPRequest對(duì)象的responseXML屬性來(lái)創(chuàng)建一個(gè)DOMDocument: </p>
<p></p>
<p> Dim xml </p>
<p></p>
<p> set xml = xhttp.responseXML </p>
<p></p>
<p> 使用輸出參數(shù)時(shí),XML字符串包含和每個(gè)返回值相對(duì)應(yīng)的一個(gè)元素。每個(gè)元素都是<values>根元素的一個(gè)子元素。例如: </p>
<p></p>
<p> <?xml version=""1.0"" </p>
<p></p>
<p> encoding=""ISO-8859-1""?> </p>
<p></p>
<p> <values> </p>
<p></p>
<p> <paramname>value</paramname> </p>
<p></p>
<p> <paramname>value</paramname> </p>
<p></p>
<p> </values> </p>
<p></p>
<p> 如果數(shù)據(jù)包含外語(yǔ)字符,就有可能需要修改encoding屬性。ISO-8859-1編碼能很好地支持大多數(shù)西歐語(yǔ)言。 </p>
<p></p>
<p> 各種情況下,客戶端頁(yè)面都會(huì)使用返回值來(lái)格式化一個(gè)HTML字符串,這個(gè)字符串放在屏幕右側(cè)的div標(biāo)記里的。客戶端頁(yè)面使用div對(duì)象的innerHTML屬性來(lái)進(jìn)行顯示: </p>
<p></p>
<p> document.all("details").innerHTML = </p>
<p></p>
<p> <some formatted html string> </p>
<p></p>
<p>為不同類型的客戶端服務(wù) </p>
<p> ASP頁(yè)面讓我們方便地看到應(yīng)用程序到底都做了些什么,但你能用相同的技術(shù)建立使用任何技術(shù)的客戶端程序。可下載代碼中包含了像ASP頁(yè)面一樣地顯示數(shù)據(jù)的Visual Basic工程文件,但是VB工程并不創(chuàng)建它傳送到服務(wù)器上的XML字符串。相反,在啟動(dòng)時(shí)它通過(guò)一個(gè)稱為Initialize的存儲(chǔ)過(guò)程從服務(wù)器查詢它們,這個(gè)過(guò)程簡(jiǎn)單地從叫做ClientCommands的數(shù)據(jù)表里查找這些內(nèi)容。 </p>
<p></p>
<p> 數(shù)據(jù)表ClientCommands包含兩個(gè)字段:command_name和command_xml字段。客戶端程序接收三個(gè)特定的command_name:getCustomerList、CustOrderHist和recentPurchaseByCustomerID。這些命令的command_xml字段包含了程序發(fā)送到getData.asp頁(yè)面的XML字符串,如此就集中地控制了XML字符串的格式以及存儲(chǔ)過(guò)程的“真實(shí)”名稱。在將XML字符串發(fā)送到getData.asp前,客戶端程序使用XML DOM來(lái)設(shè)置存儲(chǔ)過(guò)程的參數(shù)值。可下載的代碼包含定義Initialize過(guò)程和創(chuàng)建并維護(hù)數(shù)據(jù)表ClientCommands的SQL代碼。 </p>
<p></p>
<p>右圖顯示了 VB客戶端程序。圖中,示例程序的VB版本顯示了同基于瀏覽器版本大致相同的信息,只不過(guò)它使用的是bound data grid控件,而不是 HTML。 </p>
<p> 示例應(yīng)用程序演示了使用XHTTPRequest對(duì)象來(lái)兌現(xiàn)本文開(kāi)頭中所做的許諾。應(yīng)用程序工作在能訪問(wèn)getData.asp的任何遠(yuǎn)程計(jì)算機(jī)內(nèi)。我們能通過(guò)IIS或NTSF權(quán)限設(shè)置限制對(duì)ASP頁(yè)面的訪問(wèn),并且能在服務(wù)器而不是客戶機(jī)上保存應(yīng)用程序的全局設(shè)置。這樣就避免了通過(guò)網(wǎng)絡(luò)發(fā)送數(shù)據(jù)庫(kù)的用戶名和口令,而且在IE中應(yīng)用程序按照需要顯示數(shù)據(jù)而不是刷新整個(gè)頁(yè)面。 </p>
<p></p>
<p>結(jié)語(yǔ) </p>
<p> 在該應(yīng)用的正式產(chǎn)品代碼中,我們能用很多種方法使應(yīng)用程序更有效。比如,我們能從ASP頁(yè)面中去掉數(shù)據(jù)查詢代碼,并將其放到一個(gè)COM應(yīng)用程序中;或者,我們還可以創(chuàng)建XSLT變換器以顯示返回的數(shù)據(jù)。最后,通過(guò)放棄動(dòng)態(tài)頁(yè)面更新,并在服務(wù)器上進(jìn)行XSLT變換,我們能夠擴(kuò)大客戶端程序的應(yīng)用范圍。現(xiàn)在需要的做的,就是去嘗試。 </p>
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -