xml|程式|互連網|xml|互連網 使用ASP、VB和XML建立運行於互連網上的應用程式(1)
在個人電腦上使用單機版應用軟體的時代很快就要過去了,現在大部分的應用程式都開發出網路版或大都需要共用網路上豐富的資料資源。我們雖然寫了很長時間基於用戶端/伺服器的應用程式,但是這些程式大部分只是運行在小型的區域網路內部。然而,有很多客觀的原因要求我們要修改這些程式以使它們能夠運行在一個企業的內部網甚至是國際互連網。
是什麼原因迫使我們做呢?首先,隨著一個企業的規模逐漸擴大,公司可能會跨地區甚至跨國經營,每個分公司的員工的數量也會逐年增多,這些在外地的員工肯定需要頻繁地訪問總公司的資料庫資源;其次,集中應用程式的資料資源,能夠使你更好的監控資料庫的訪問和使用方式。第三,你可以通過從一個集中的位置擷取全域應用程式設定,從而維護和更新它們,最終達到緩減應用程式更新的目的。第四,盡量從Web伺服器上訪問資料庫而不是從用戶端上訪問資料庫,這樣可以避免通過網路傳送登入資訊和客戶密碼,從而避免安全隱患;而且,使用瀏覽器從後台擷取資料,這樣能夠避免重新整理整個頁面。
這就要求我們建立一個運行於互連網上的應用程式,而假如想建立一個運行在HTTP協議上的VB程式,那麼關鍵就是使用XML和XMLHTTPRequest對象。這個對象是Microsoft XML分析器(msxml.dll)的一部分,XMLHTTPRequest對象可以讓你通過HTTP向遠程伺服器發送GET和POST請求,運行在遠程伺服器上的程式接收這個請求,翻譯出它的內容,返回資料或者一個錯誤頁面到調用它的應用程式。對網路編程有一些研究的朋友會看出我這個設想很象SOAP,但是在這裡我不想使用SOAP,因為如果那樣的話會使程式變得很複雜。
想要改變一個完全獨立的用戶端單機版程式是不太現實的,但即使如此,從一個集中的伺服器上下載應用程式設定也比使用本地的INI檔案或Windows註冊標有更大的獨立性和靈活性。舉例來說,假設你有一支手機銷售隊伍,他們需要訪問集中化的資訊來更有效銷售手機,每天,總公司集中收集資料,然後用電子郵件的形式發送給銷售人員。然而,市場的壓力和迅速變化的銷售形式勢必使銷售人員要訪問最新的資料資訊。但是,網路系統管理員卻堅持拒絕讓在遠程用戶端的銷售人員訪問總公司資料庫伺服器,因為他們不想通過公用的網路發送使用者名稱和登入密碼。因此勢必要使用一種新的技術代替基於用戶端/伺服器的技術,不要著急,我想看完本文你就會解決這個問題的。
讓我們先分析一下用戶端/伺服器應用程式。在一個標準的用戶端/伺服器應用程式中,在應用程式開始時,你能夠初始化資料庫連接字串,這就意味著,客戶有使用資料庫連接字串的權利,這包括使用者名稱和口令。但是客觀情況如果不允許你在網路上發送這些資訊的話,你就必需在不聯結資料庫的情況下直接從用戶端取得資料發送給客戶。那麼解決方案之一就是在伺服器上建立一個ASP頁(在本例中稱為getData.asp)接收特定格式的POST資料,它要求一個包含XML字串,用來建立ADO對象並運行預存程序或動態SQL語句命令。如果資訊有效話,getData.asp執行預存程序,並返回一個XML格式的資料集、傳回值列表或錯誤頁面資訊的XML字串。對於返回資料的命令,用戶端要麼重新執行個體化要麼傳回值或使用XML DOM(Document Object Model文件物件模型)格式的錯誤頁面。
好,下面就讓我們來討論一下如何?這個頁面吧!
getData.asp頁面首先使用一個DOMDocument對象來儲存用戶端發送的資料:
'建立DOMDocument對象
Set xml = Server.CreateObject ("msxml2.DOMDocument")
xml.async = False
然後,它裝載POST資料
'裝載POST資料
xml.Load Request
If xml.parseError.errorCode <> 0 Then
Call responseError ("不能裝載XML資訊。" & "Description: " & xml.parseError.reason & "<br>Line: " & xml.parseError.Line)
End If
它能夠返回commandtext元素值和returndata或returnvalue元素值。下面我只給出返回commandtext元素值的代碼,其餘代碼請參看我下面所附的來源程式。
Set N = xml.selectSingleNode("command/commandtext")
If N Is Nothing Then
Call responseError ("缺少 <sp_name> 參數。")
Else sp_name = N.Text
End If
接著,應該讓頁面建立一個Command對象,讀入所有<param>元素,並且為request中的每一個元素建立一個參數。最後,讓頁面開啟一個串連使用預存程序adExecuteNoRecords選項來執行request。
set conn = Server.CreateObject("ADODB.Connection")
conn.Mode=adModeReadWrite
conn.open Application("ConnectionString")
set cm.ActiveConnection=conn
' 返回資料
if not returnsData then
cm.Execute
else
set R = server.CreateObject("ADODB.Recordset")
R.CursorLocation = adUseClient
R.Open cm, ,adOpenStatic, adLockReadOnly
end if
如果能夠返回資料的話,那麼returnData變數就為真值,並且把結果資料集返回到用戶端,仍然是一個XML文檔。
if returnsData then
R.Save Response, adPersistXML
if err.number <> 0 then
call responseError ("資料集發生儲存錯誤" & "在命令'" & CommandText & "': " & Err.Description)
Response.end
end if
如果輸出參數傳回值,那麼這個頁面將返回一個包含這些值的XML字串。文檔的根項目是一個<values>標記,每一個傳回值都有其相應的子項目,如果發生任何錯誤,頁面都會格式化並返回一個包含錯誤資訊的XML字串:
Sub responseError(sDescription)
Response.Write "<response><data>錯誤: " & sDescription & "</data></response>"
Response.end
End Sub
假設在我們前面所說的例子中,我們想在應用程式中顯示地區的左半邊顯示客戶的姓名列表,再在每個客戶姓名後面加上兩個連結:Purchase History和Recent Purchase。當使用者點擊其中的一個連結,客戶程式就會運行一個預存程序並在右邊地區顯示出結果。 為了顯示這個想法的靈活性,我想讓用於返回資料的三個操作單元執行不同的工作過程,它們都調用getData.asp。首先,通過調用CustOrderHist來運行一個預存程序,返回客戶的Purchase History,它搜尋Northwind資料庫(為了方便起見我使用MS SQL中內建的資料庫)並返回一個資料集。用於返回Recent Purchase 的查詢語句運行一個叫RecentPurchaseByCustomerID的預存程序,來接收輸入的CustomerID參數並通過ProductName參數返回最近顧客購買的商品名。定義其處理過程相應SQL語句如下:
CREATE PROCEDURE RecentPurchaseByCustomerID @CustomerID nchar(5), @ProductName nchar(40) output AS SELECT @ProductName = (SELECT top 1 ProductName FROM Products INNER JOIN ([Order Details] INNER JOIN Orders ON Orders.OrderID=[Order Details].OrderID) ON Products.ProductID = [Order Details].ProductID WHERE Orders.OrderDate = (SELECT MAX(orders.orderdate) FROM Orders
where CustomerID=@CustomerID) AND Orders.CustomerID=@CustomerID) GO
不管你的查詢語句中含有動態SQL語句還是含有返回記錄集的預存程序或是輸出一個傳回值,其處理POST訊息的方法是一樣的:
set xhttp = createObject ("msxml2.XMLHTTP")
xhttp.open "POST", "http://localhost/myWeb/ getData.asp", False
xhttp.send s
好了,現在讓我們看一看如何發送和接收資料
用戶端的XML資訊是由一個<command>元素和一些子項目組成:<commandtext>元素包含了預存程序的名稱,<returnsdata>元素告訴伺服器,用戶端是否要求接收返回資料,<param>元素包含參數資訊。如果不使用參數的話,那麼最簡單的發送字串查詢就象下面這樣:
<command>
<commandtext>
預存程序或動態SQL語句
</commandtext>
<returnsvalues>True</returnsvalues>
</command>
你可以為每一個參數使用一個<param>元素,來添加參數。每個<param>元素有五個子項目:name,type,direction,size和value。子項目的順序可以隨意調換,但是所有的元素都應當有不能缺少,我通常按照定義一個ADO對象的值的順序來定義它們。舉例來說,CustOrderHist預存程序需要一個CustomID參數,所以用來建立發送到getData.asp的XML字串的代碼為:
dim s
s = "<?xml version=""1.0