📄 210.htm
字号:
<p>用VB和XML建立集中式应用程序</p>
<p></p>
<p> 很长一段时间以来,Visual Basic程序员都是在编写客户机/服务器程序,这些程序工作在私有网络上。但是这种在一台PC机上安装一个独立应用程序的时代正在很快地结束,客户机/服务器结构不再能满足需要,现在的大多数商用程序需要共享数据。 </p>
<p></p>
<p>为什么要建立基于Intranet和Internet的应用程序 </p>
<p> 编写基于Intranet和Internet的应用程序或修改C/S结构的程序为工作于Intranet和Internet上的程序的原因至少有以下几点: </p>
<p></p>
<p> 首先,每天都在增加的远程雇员需要访问公司的数据。 </p>
<p></p>
<p> 其次,通过集中应用程序里的数据能监控对它们的访问和使用。 </p>
<p></p>
<p> 第三,使用本文谈及的技术,在应用程序启动时从一个中心位置查找全局设置信息,就能方便地维护和更新这些设置,有助于最大程度地降低对桌面应用程序的更新。 </p>
<p></p>
<p> 第四,通过Web服务器而不是从远程客户端来进行数据库操作,可以避免通过网络传递数据库的登录口令。 </p>
<p></p>
<p> 最后,如果使用Internet Explorer,通过后台查询数据,就能避免在修改部分内容时重画整个页面。 </p>
<p></p>
<p>右图是在Internet Explorer中看到的一个应用程序实例。图中,应用程序显示了Northwind数据库中的信息。左边是客户名列表和两个链接:购买历史情况和最近的购买情况。当用户点击链接时,数据在右边的Details栏里显示出来。这个应用程序使用DHTML显示Details中的数据而不用刷新整个页面,而且没有使用框架。 </p>
<p>实现思路 </p>
<p> 创建基于HTTP的VB应用程序的关键是XML和XMLHTTPRequest对象,XMLHTTPRequest对象是Microsoft的XML语法分析器 (msxml.dll)的一部分,它让你能通过HTTP向远端服务器发送GET和POST请求。运行在远端服务器上的程序(我们将要使用的是 ASP页面,但应用程序可以使用任何服务器端脚本机制)接受请求、解释内容,并向调用它的应用程序返回数据或错误消息。你可能会觉得这和对SOAP的描述差不多,实际上也是如此,但这里我们不使用SOAP,因为它会使代码变得复杂。无论如何,重要的是:要理解这里所用的技术背后的思想,它和SOAP的思想是一样的,但不像SOAP那样复杂。 </p>
<p></p>
<p> 将不停改变的客户端应用程序完全隔离起来是不可能的,但通过从中心服务器而不是从本地INI文件或Windows注册表中来加载应用程序设置,就能在很高程度上建立应用程序的独立性。例如,假定有一个流动的销售团队,他们需要访问集中管理的数据以便进行有效的电话推销。过去,这些数据是集中采集的,每天通过电子邮件提供给销售人员。然而,市场的压力和快速变化的销售情况迫使销售人员必须能访问需要的最新数据。不幸的是,IT经理们坚决拒绝允许远程用户访问数据库服务器,因为他们不希望通过公用的Internet发送用户名和口令。不过不要担心,我们将采取方法使大家都满意。 </p>
<p></p>
<p> 在标准的客户机/服务器程序中,你可能需要在应用程序启动时初始化数据库连接串,这意味着客户机必须能访问连接串信息,包括用户名和口令。但是,当不允许通过网络传送那些信息时,就需要在客户端和数据库之间不建立直接连接的情况下获取数据。 </p>
<p></p>
<p> 解决办法是在服务器上建立一个ASP页面,在示例代码中它的名字是getData.asp,它接受特定形式的POST数据,它等待一个 XML字符串,这个字符串里包含着建立ADO Command对象并运行存储过程或动态SQL语句所需的命令信息。如果信息充分,getData.asp执行存储过程并返回一个XML字符串,这个字符串里包含以XML格式表述的Recordset、一系列返回值或一个错误消息。对于返回数据的命令,客户端或者将返回的Recordset对象重新表述,或者使用XML文档对象模型(DOM)来查找返回值或错误消息。 </p>
<p></p>
<p>ASP代码和所需接收的数据 </p>
<p> getData.asp页面的动作有特定的次序。首先,它创建一个DOMDocument对象以保存从客户端传来的数据: </p>
<p></p>
<p> 注释: 创建 DOMDocument 对象 </p>
<p></p>
<p> Set xml = Server.CreateObject _ </p>
<p></p>
<p> ("msxml2.DOMDocument") </p>
<p></p>
<p> xml.async = False </p>
<p></p>
<p> 然后,它加载POST数据,并检测格式错误的请求: </p>
<p></p>
<p> 注释: 加载 POST 数据 </p>
<p></p>
<p> xml.Load Request </p>
<p></p>
<p> If xml.parseError.errorCode <> 0 Then </p>
<p></p>
<p> Call responseError _ </p>
<p></p>
<p> ("Could not load XML message." & _ </p>
<p></p>
<p> "Description: " & _ </p>
<p></p>
<p> xml.parseError.reason & _ </p>
<p></p>
<p> "<br>Line: " & xml.parseError.Line) </p>
<p></p>
<p> End If </p>
<p></p>
<p> 它查找元素commandtext的取值或元素returnsdata、returnsvalues的取值。因为查找这些元素取值的代码是相似的,因此这里只给出查找元素commandtext取值的代码: </p>
<p></p>
<p> Set N = xml.selectSingleNode _ </p>
<p></p>
<p> ("command/commandtext") </p>
<p></p>
<p> If N Is Nothing Then </p>
<p></p>
<p> Call responseError _ </p>
<p></p>
<p> ("Missing <sp_name> parameter.") </p>
<p></p>
<p> Else </p>
<p></p>
<p> sp_name = N.Text </p>
<p></p>
<p> End If </p>
<p></p>
<p> 然后,页面创建一个Command对象,读取所有<param>元素,并为请求中存在的每一个元素创建一个参数,代码如下: </p>
<p></p>
<p> 注释: create parameters, if any </p>
<p></p>
<p> set nodes = xml.selectNodes("command/param") </p>
<p></p>
<p> if nodes is nothing then </p>
<p></p>
<p> 注释: no parameters </p>
<p></p>
<p> elseif nodes.length = 0 then </p>
<p></p>
<p> 注释: no parameters </p>
<p></p>
<p> else </p>
<p></p>
<p> for each param in nodes </p>
<p></p>
<p> 注释: Response.Write server.HTMLEncode(param.xml) & "<br>" </p>
<p></p>
<p> on error resume next </p>
<p></p>
<p> paramName = param.selectSingleNode("name").text </p>
<p></p>
<p> if err.number <> 0 then </p>
<p></p>
<p> call responseError("Parameter creation: " & _ </p>
<p></p>
<p> "Unable to find the name " & "tag.") </p>
<p></p>
<p> end if </p>
<p></p>
<p> paramType = param.selectSingleNode("type").text </p>
<p></p>
<p> paramDirection = param.selectSingleNode("direction").text </p>
<p></p>
<p> paramSize = param.selectSingleNode("size").text </p>
<p></p>
<p> paramValue = param.selectSingleNode("value").text </p>
<p></p>
<p> if err.number <> 0 then </p>
<p></p>
<p> call responseError("The parameter named 注释:" & _ </p>
<p></p>
<p> paramName & "注释: was " & "missing one or more " & "required fields.") </p>
<p></p>
<p> end if </p>
<p></p>
<p> cm.Parameters.Append cm.CreateParameter(paramName,paramType, _ </p>
<p></p>
<p> paramDirection,paramSize,paramValue) </p>
<p></p>
<p> if err.number <> 0 then </p>
<p></p>
<p> call responseError("Unable to create or " & "append the parameter " & _ </p>
<p></p>
<p> "named 注释:" & paramName & ".注释: " & err.description) </p>
<p></p>
<p> Response.end </p>
<p></p>
<p> end if </p>
<p></p>
<p> next </p>
<p></p>
<p> on error goto 0 </p>
<p></p>
<p> end if </p>
<p></p>
<p> 最后,页面打开一个链接并执行请求,对于存储过程,它使用不返回数据的adExecuteNoRecords选项。 </p>
<p></p>
<p> set conn = </p>
<p></p>
<p> Server.CreateObject_ </p>
<p></p>
<p> ("ADODB.Connection") </p>
<p></p>
<p> conn.Mode=adModeReadWrite </p>
<p></p>
<p> conn.open _ </p>
<p></p>
<p> Application("ConnectionString") </p>
<p></p>
<p> set cm.ActiveConnection=conn </p>
<p></p>
<p> 注释: retrieve the data </p>
<p></p>
<p> if not returnsData then </p>
<p></p>
<p> cm.Execute </p>
<p></p>
<p> else </p>
<p></p>
<p> set R = server.CreateObject _ </p>
<p></p>
<p> ("ADODB.Recordset") </p>
<p></p>
<p> R.CursorLocation = adUseClient </p>
<p></p>
<p> R.Open cm, ,adOpenStatic, _ </p>
<p></p>
<p> adLockReadOnly </p>
<p></p>
<p> end if </p>
<p></p>
<p> 如果命令返回数据,变量returnsData的值将为True,页面以XML文档方式将recordset的结果返回给客户机: </p>
<p></p>
<p> 注释: return the data, if required </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -