前面我們已經介紹了使用ASP和XML混合編程,那是因為ASP頁面能夠很容易讓我們看清應用程序正在做什么,但是你如果你不想使用ASP的話,你也可以使用任何你熟悉的技術去創建一個客戶端程序。下面,我提供了一段VB代碼,它的功能和ASP頁面一樣,也可以顯示相同的數據,但是這個VB程序不會創建發送到服務器的XML字符串。它通過運行一個名叫Initialize的存儲過程,從服務器取回XML字符串,來查詢ClientCommands表的內容。
ClientCommands表包括兩個域:command_name域和command_xml域。客戶端程序需要三個特定的command_name域:getCustomerList,CustOrderHist和RecentPurchaseByCustomerID。每一個命令的command_xml域包括程序發送到getData.asp頁面的XML字符串,這樣,就可以集中控制XML字符串了,就象存儲過程名字所表現的意思一樣,在發送XML字符串到getData.asp之前,客戶端程序使用XML DOM來設置存儲過程的參數值。我提供的代碼,包含了用于定義Initialize過程和用于創建ClientCommands表的SQL語句。
我提供的例程中還說明了如何使用XHTTPRequest對象實現我在本文一開始時許下的承諾:任何遠程的機器上的應用程序都可以訪問getData.asp;當然,你也可以通過設置IIS和NTFS權限來限制訪問ASP頁面;你可以在服務器上而不是客戶機上存儲全局應用程序設置;你可以避免通過網絡發送數據庫用戶名和密碼所帶來的隱患性。還有,在IE中,應用程序可以只顯示需要的數據而不用刷新整個頁面。
在實際的編程過程中,你們應當使用一些方法使應用程序更加有高效性。你可以把ASP中的關于取得數據的代碼端搬到一個COM應用程序中去然后創建一個XSLT變換來顯示返回的數據。好,我不多說了,現在你所要做的就是試一試吧!
Option Explicit Private RCommands As Recordset Private RCustomers As Recordset Private RCust As Recordset Private sCustListCommand As String Private Const dataURL = "http://localhost/XHTTPRequest/getData.asp" Private arrCustomerIDs() As String Private Enum ActionEnum VIEW_HISTORY = 0 VIEW_RECENT_PRODUCT = 1 End Enum
Private Sub dgCustomers_Click() Dim CustomerID As String CustomerID = RCustomers("CustomerID").Value If CustomerID <> "" Then If optAction(VIEW_HISTORY).Value Then Call getCustomerDetail(CustomerID) Else Call getRecentProduct(CustomerID) End If End If End Sub
Private Sub Form_Load() Call initialize Call getCustomerList End Sub
Sub initialize() ' 從數據庫返回命令名和相應的值
Dim sXML As String Dim vRet As Variant Dim F As Field sXML = "<?xml version=""1.0""?>" sXML = sXML & "<command><commandtext>Initialize</commandtext>" sXML = sXML & "<returnsdata>True</returnsdata>" sXML = sXML & "</command>" Set RCommands = getRecordset(sXML) Do While Not RCommands.EOF For Each F In RCommands.Fields Debug.Print F.Name & "=" & F.Value Next RCommands.MoveNext Loop End Sub
Function getCommandXML(command_name As String) As String RCommands.MoveFirst RCommands.Find "command_name='" & command_name & "'", , adSearchForward, 1 If RCommands.EOF Then MsgBox "Cannot find any command associated with the name '" & command_name & "'." Exit Function Else getCommandXML = RCommands("command_xml") End If End Function
Sub getRecentProduct(CustomerID As String) Dim sXML As String Dim xml As DOMDocument Dim N As IXMLDOMNode Dim productName As String sXML = getCommandXML("RecentPurchaseByCustomerID") Set xml = New DOMDocument xml.loadXML sXML Set N = xml.selectSingleNode("command/param[name='CustomerID']/value") N.Text = CustomerID Set xml = executeSPWithReturn(xml.xml) productName = xml.selectSingleNode("values/ProductName").Text ' 顯示text域 txtResult.Text = "" Me.txtResult.Visible = True dgResult.Visible = False ' 顯示product名 txtResult.Text = "最近的產品是: " & productName End Sub
Sub getCustomerList() Dim sXML As String Dim i As Integer Dim s As String sXML = getCommandXML("getCustomerList") Set RCustomers = getRecordset(sXML) Set dgCustomers.DataSource = RCustomers End Sub
Sub getCustomerDetail(CustomerID As String) ' 找出列表中相關聯的ID號 Dim sXML As String Dim R As Recordset Dim F As Field Dim s As String Dim N As IXMLDOMNode Dim xml As DOMDocument sXML = getCommandXML("CustOrderHist") Set xml = New DOMDocument xml.loadXML sXML Set N = xml.selectSingleNode("command/param[name='CustomerID']/value") N.Text = CustomerID Set R = getRecordset(xml.xml) ' 隱藏 text , 因為它是一個記錄集 txtResult.Visible = False
dgResult.Visible = True Set dgResult.DataSource = R End Sub
Function getRecordset(sXML As String) As Recordset Dim R As Recordset Dim xml As DOMDocument Set xml = getData(sXML) Debug.Print TypeName(xml) On Error Resume Next Set R = New Recordset R.Open xml If Err.Number <> 0 Then MsgBox Err.Description Exit Function Else Set getRecordset = R End If End Function
Function executeSPWithReturn(sXML As String) As DOMDocument Dim d As New Dictionary Dim xml As DOMDocument Dim nodes As IXMLDOMNodeList Dim N As IXMLDOMNode Set xml = getData(sXML) If xml.documentElement.nodeName = "values" Then Set executeSPWithReturn = xml Else '發生錯誤 Set N = xml.selectSingleNode("response/data") If Not N Is Nothing Then MsgBox N.Text Exit Function Else MsgBox xml.xml Exit Function End If End If End Function
Function getData(sXML As String) As DOMDocument Dim xhttp As New XMLHTTP30 xhttp.Open "POST", dataURL, False xhttp.send sXML Debug.Print xhttp.responseText Set getData = xhttp.responseXML End Function
Private Sub optAction_Click(Index As Integer) Call dgCustomers_Click End Sub
代碼二、getData.asp
<%@ Language=VBScript %> <% option explicit %> <% Sub responseError(sDescription) Response.Write "<response><data>Error: " & sDescription & "</data></response>" Response.end End Sub
Response.ContentType="text/xml" dim xml dim commandText dim returnsData dim returnsValues dim recordsAffected dim param dim paramName dim paramType dim paramDirection dim paramSize dim paramValue dim N dim nodeName dim nodes dim conn dim sXML dim R dim cm
' 創建DOMDocument對象 Set xml = Server.CreateObject("msxml2.DOMDocument") xml.async = False
' 裝載POST數據 xml.Load Request If xml.parseError.errorCode <> 0 Then Call responseError("不能裝載 XML信息。 描述: " & xml.parseError.reason & "<br>行數: " & xml.parseError.Line) End If
' 客戶端必須發送一個commandText元素 Set N = xml.selectSingleNode("command/commandtext") If N Is Nothing Then Call responseError("Missing <commandText> parameter.") Else commandText = N.Text End If
' 客戶端必須發送一個returnsdata或者returnsvalue元素 set N = xml.selectSingleNode("command/returnsdata") if N is nothing then set N = xml.selectSingleNode("command/returnsvalues") if N is nothing then call responseError("Missing <returnsdata> or <returnsValues> parameter.") else returnsValues = (lcase(N.Text)="true") end if else returnsData=(lcase(N.Text)="true") end if
set cm = server.CreateObject("ADODB.Command") cm.CommandText = commandText if instr(1, commandText, " ", vbBinaryCompare) > 0 then cm.CommandType=adCmdText else cm.CommandType = adCmdStoredProc end if
' 創建參數 set nodes = xml.selectNodes("command/param") if nodes is nothing then ' 如果沒有參數 elseif nodes.length = 0 then ' 如果沒有參數 else for each param in nodes ' Response.Write server.HTMLEncode(param.xml) & "<br>" on error resume next paramName = param.selectSingleNode("name").text if err.number <> 0 then call responseError("創建參數: 不能發現名稱標簽。") end if paramType = param.selectSingleNode("type").text paramDirection = param.selectSingleNode("direction").text paramSize = param.selectSingleNode("size").text paramValue = param.selectSingleNode("value").text if err.number <> 0 then call responseError("參數名為 '" & paramName & "'的參數缺少必要的域") end if cm.Parameters.Append cm.CreateParameter(paramName,paramType,paramDirection,paramSize,paramValue) if err.number <> 0 then call responseError("不能創建或添加名為 '" & paramName & "的參數.' " & err.description) Response.end end if next on error goto 0 end if
'打開連結 set conn = Server.CreateObject("ADODB.Connection") conn.Mode=adModeReadWrite conn.open Application("ConnectionString") if err.number <> 0 then call responseError("連結出錯: " & Err.Description) Response.end end if
' 連結Command對象 set cm.ActiveConnection = conn
' 執行命令 if returnsData then ' 用命令打開一個Recordset set R = server.CreateObject("ADODB.Recordset") R.CursorLocation = adUseClient R.Open cm,,adOpenStatic,adLockReadOnly else cm.Execute recordsAffected, ,adExecuteNoRecords end if if err.number <> 0 then call responseError("執行命令錯誤 '" & Commandtext & "': " & Err.Description) Response.end end if
if returnsData then R.Save Response, adPersistXML if err.number <> 0 then call responseError("數據集發生存儲錯誤,在命令'" & CommandText & "': " & Err.Description) Response.end end if elseif returnsValues then sXML = "<?xml version=""1.0"" encoding=""gb2312""?>" & vbcrlf & "<values>" set nodes = xml.selectNodes("command/param[direction='2']") for each N in nodes nodeName = N.selectSingleNode("name").text sXML = sXML & "<" & nodename & ">" & cm.Parameters(nodename).Value & "" & "</" & nodename & ">" next sXML = sXML & "</values>" Response.Write sXML end if
set cm = nothing conn.Close set R = nothing set conn = nothing Response.end %>
|