直播中
在一本ASP專著中討論客戶端數(shù)據(jù),這與服務(wù)器端的ASP編程是否矛盾?情況并非如此,因?yàn)槲覀冎两裆形磁龅街粡氖路?wù)器端編程的ASP程序員。雖然ASP是一項(xiàng)服務(wù)器端技術(shù),但可以想象,編程人員不可能僅僅使用ASP進(jìn)行編程。從事ASP編程的Web開發(fā)人員,仍然需要與客戶端數(shù)據(jù)進(jìn)行交互。
因此,圍繞著ASP構(gòu)建一個(gè)應(yīng)用程序時(shí)必須考慮整個(gè)應(yīng)用程序的情況,這也意味著必須考慮客戶端。為了獲得一個(gè)運(yùn)行良好、快速響應(yīng)的應(yīng)用程序,需要很好地使用客戶端數(shù)據(jù)。
本章將討論如何在客戶端使用數(shù)據(jù)。特別將著重研究:
· 遠(yuǎn)程數(shù)據(jù)服務(wù)(Remote Data Services,RDS),如何向客戶端傳送數(shù)據(jù)以及客戶端接收數(shù)據(jù)。
· 如何將ADO記錄集綁定到HTML控件。
· 如何利用用戶自定義組件提供數(shù)據(jù)。
· 如何更新客戶端數(shù)據(jù),并將其反饋到服務(wù)器。
· 如何從數(shù)據(jù)庫(kù)中獲取圖像并將其顯示在Web頁(yè)面中。
· 如何創(chuàng)建基于表格的Web頁(yè)面。
以上覆蓋的范圍相當(dāng)廣泛,同時(shí)有很多不同的方法可以取得相同的結(jié)果,但實(shí)際上實(shí)現(xiàn)起來(lái)并不是特別困難。
10.1 斷開連接的記錄集
首先需要掌握的是“斷開連接的數(shù)據(jù)”的概念。迄今為止,在研究ADO的過(guò)程中,已經(jīng)學(xué)習(xí)了獲取記錄集的方法,以及如何修改這些記錄集中的數(shù)據(jù)?;仡櫼幌拢覀兇蜷_一個(gè)記錄集,對(duì)數(shù)據(jù)做一些修改,然后再關(guān)閉這個(gè)記錄集,在操作記錄集的過(guò)程中,始終與服務(wù)器保持著連接。這是相當(dāng)明顯的,但別忘了Web在本質(zhì)上是無(wú)狀態(tài)的。如果想使用客戶端數(shù)據(jù),如何始終保持與服務(wù)器的連接?很簡(jiǎn)單,這是不可能實(shí)現(xiàn)的,這也是定義斷開連接的記錄集概念的緣由。
一個(gè)斷開連接的記錄集只是一個(gè)普通的記錄集,但解除了與服務(wù)器的連接,成為孤立的對(duì)象,可以像普通的記錄集那樣對(duì)其執(zhí)行更新、增加和刪除操作。但這些變化只發(fā)生在記錄集內(nèi)部,并不反饋到服務(wù)器,因?yàn)橛涗浖c服務(wù)器已不再保持著連接。這并不是缺點(diǎn),因?yàn)榭梢耘c服務(wù)器重新建立連接,同時(shí)服務(wù)器可以對(duì)任何修改進(jìn)行更新。即使服務(wù)器端的數(shù)據(jù)已經(jīng)改變了,ADO仍然有方法讓用戶及時(shí)發(fā)現(xiàn)這些變化,這樣用戶就能決定哪些數(shù)據(jù)是正確的。這稱為沖突處理(conflict resolution)。
斷開連接的記錄集使我們能在組件之間,包括服務(wù)器與客戶之間,傳送具有全部功能的記錄集。本章后面將探討如何在組件內(nèi)創(chuàng)建斷開連接的記錄集。但這里不準(zhǔn)備對(duì)此做過(guò)于詳細(xì)的研究,因?yàn)楸緯?3章至第18章已經(jīng)覆蓋這部分內(nèi)容,這里僅做簡(jiǎn)單的介紹,以便于了解組件是如何與遠(yuǎn)程數(shù)據(jù)服務(wù)交互的。
10.2 遠(yuǎn)程數(shù)據(jù)服務(wù)
遠(yuǎn)程數(shù)據(jù)服務(wù)(Remote Data Services,RDS)是允許我們處理客戶端數(shù)據(jù)的一系列服務(wù)的統(tǒng)稱。現(xiàn)在不用擔(dān)心這方面的問(wèn)題,因?yàn)镽DS本身就是ADO的一部分,只有在需要傳送和使用客戶端數(shù)據(jù)時(shí),才會(huì)使用。實(shí)際上RDS是由幾個(gè)組件構(gòu)成的。圖10-1說(shuō)明了這些組件以及它們之間是如何協(xié)同工作的。
圖10-1 RDS的組件構(gòu)成
組件似乎很多,但并不是所有的組件在每種情形下都被使用,實(shí)際上有一些不是RDS的一部分。然而這里還是把所有可能出現(xiàn)的組件都放在了圖上,以備需要時(shí)查看。圖10-1分成了兩部分,因?yàn)槭褂每蛻舳藬?shù)據(jù)需要一些向客戶端傳送數(shù)據(jù)的方法,同時(shí)數(shù)據(jù)一旦到達(dá)客戶端,也需要一些管理數(shù)據(jù)的方法。我們先從服務(wù)器端開始。
10.2.1 RDS服務(wù)器組件
雖然RDS用于傳送和訪問(wèn)客戶端數(shù)據(jù),但其確實(shí)有一些基于服務(wù)器的組件。這是必需的,因?yàn)榭隙ㄐ枰撤N方式將數(shù)據(jù)傳送到客戶端。因此有了一系列能訪問(wèn)數(shù)據(jù)并允許發(fā)送數(shù)據(jù)到客戶端的服務(wù)器組件。我們把實(shí)際的數(shù)據(jù)傳送稱為調(diào)度(marshal)。
服務(wù)器端組件圖的最上端是數(shù)據(jù)存儲(chǔ),由OLE DB提供者訪問(wèn)。它并不是RDS的一部分,但這表示只要有相應(yīng)的OLE DB提供者,就可以通過(guò)RDS在客戶端使用任何數(shù)據(jù)。至于如何處理服務(wù)器上的數(shù)據(jù),可以有兩種選擇:
· 數(shù)據(jù)工廠(DataFactory)是缺省的用于訪問(wèn)數(shù)據(jù)存儲(chǔ)的服務(wù)器端組件。它作為服務(wù)器端RDS組件的一部分安裝在計(jì)算機(jī)上,除了能從數(shù)據(jù)存儲(chǔ)中獲取數(shù)據(jù)外,還為服務(wù)器處理發(fā)送到客戶端以及從客戶端發(fā)送來(lái)的數(shù)據(jù)。
· 自定義組件只是一個(gè)普通的提供了數(shù)據(jù)傳送方法的COM組件。當(dāng)數(shù)據(jù)工廠不能提供所需的功能時(shí),可以使用自定義組件。本章將介紹一個(gè)簡(jiǎn)單的組件例子,在本書的后面還有一個(gè)更復(fù)雜的例子。
Web服務(wù)器使用這兩種組件作為客戶和服務(wù)器數(shù)據(jù)的接口。
10.2.2 RDS客戶組件
在客戶端先從底端的DataSpace對(duì)象開始,該對(duì)象作為客戶端的一部分與數(shù)據(jù)工廠或自定義對(duì)象協(xié)同工作。DataSpace對(duì)象是一個(gè)代理對(duì)象,負(fù)責(zé)與服務(wù)器進(jìn)行通信,同時(shí)也是數(shù)據(jù)傳輸?shù)耐ǖ溃ɑ蛘咄ǔKf(shuō)的調(diào)度)。DataSpace對(duì)象是用客戶端腳本語(yǔ)言或用HTML語(yǔ)言中的<OBJECT>標(biāo)記創(chuàng)建的COM對(duì)象。在本章后面會(huì)看到關(guān)于這方面的例子。
DataSpace對(duì)象上面是數(shù)據(jù)源對(duì)象(Data Source Object,DSO),負(fù)責(zé)存儲(chǔ)客戶端數(shù)據(jù)。一個(gè)數(shù)據(jù)源對(duì)象包含一個(gè)ADO數(shù)據(jù)記錄集,與客戶數(shù)據(jù)緩存共同管理數(shù)據(jù)??蛻魯?shù)據(jù)緩存只是一種管理客戶端數(shù)據(jù)的客戶光標(biāo)服務(wù)。同時(shí)數(shù)據(jù)源對(duì)象又是一個(gè)COM對(duì)象,與DataSpace對(duì)象類似,也可以通過(guò)客戶端腳本或使用HTML語(yǔ)言中的<OBJECT>標(biāo)記來(lái)創(chuàng)建。同樣,在本章稍后也會(huì)介紹關(guān)于這方面的一些例子。
數(shù)據(jù)源對(duì)象的上面是數(shù)據(jù)綁定管理器,任務(wù)是建立HTML控件與數(shù)據(jù)源對(duì)象的連接。這就是我們所知道的綁定,可以通過(guò)設(shè)置某些HTML控件的DATASRC和DATAFLD屬性來(lái)實(shí)現(xiàn)。下面將對(duì)這些內(nèi)容進(jìn)行討論,并示范如何在瀏覽器中方便地使用數(shù)據(jù)。
10.2.3 支持RDS的瀏覽器
要知道RDS是微軟的技術(shù),因此只能在微軟的瀏覽器上工作。實(shí)際上,只有在IE 4.0或更高版本的瀏覽器中才完全支持RDS。
當(dāng)編寫依賴于RDS的應(yīng)用程序時(shí),需要注意訪問(wèn)應(yīng)用程序的客戶的RDS版本可能與服務(wù)器端有所不同。舉例來(lái)說(shuō),IE 4中的是RDS 1.5版本,而IE 5、Office 2000和Visual Studio 6中的則是RDS 2.0版本。有兩種方法可以處理這種兼容性問(wèn)題:
· 確保所有用戶已經(jīng)升級(jí)到RDS的最新版本。如果客戶運(yùn)行的是Windows 2000,那么已經(jīng)在運(yùn)行最新版本的RDS了。否則,可以從網(wǎng)址www.microsoft.com/data處下載。RDS 2.5版本是目前最新的隨同Windows 2000一起發(fā)布的版本,同時(shí)也是一個(gè)可單獨(dú)下載的軟件包。
· 當(dāng)連接到數(shù)據(jù)源時(shí),指定數(shù)據(jù)工廠的模式。這可以指定使用的是哪一個(gè)版本的RDS組件,后面將介紹這方面的一個(gè)例子。
10.2.4 數(shù)據(jù)源對(duì)象
數(shù)據(jù)源對(duì)象是一個(gè)存儲(chǔ)和管理客戶端數(shù)據(jù)的客戶端對(duì)象。因?yàn)檫@是使用RDS最簡(jiǎn)單的一種方式,首先研究一下這些對(duì)象。
這里有幾個(gè)不同的數(shù)據(jù)源對(duì)象,每一個(gè)都針對(duì)不同類型的數(shù)據(jù):
· 表格數(shù)據(jù)控件(Tabular Data Control,TDC),用于處理表格形式或分隔形式的文本文件。
· RDS數(shù)據(jù)控件,用于連接OLE DB數(shù)據(jù)存儲(chǔ),能夠指定連接到哪個(gè)數(shù)據(jù)存儲(chǔ),以及返回哪些數(shù)據(jù)。
· Java數(shù)據(jù)庫(kù)連接器,這是一個(gè)通過(guò)Java數(shù)據(jù)庫(kù)控件(Java DataBase Control,JDBC)連接到數(shù)據(jù)存儲(chǔ)的Java小程序。這里我們不想討論JDBC,因?yàn)樗⒉惶峁┢渌丶o(wú)法實(shí)現(xiàn)的功能。
· 微軟的HTML(MSHTML)數(shù)據(jù)源對(duì)象用HTML標(biāo)記數(shù)據(jù),并把它作為數(shù)據(jù)源。
· XML數(shù)據(jù)源對(duì)象使用XML數(shù)據(jù),用于結(jié)構(gòu)化的或任意結(jié)構(gòu)的XML。
選用哪一種數(shù)據(jù)源對(duì)象取決于你想做什么,以及數(shù)據(jù)從哪里來(lái)。如果需要向客戶提供少量的數(shù)據(jù),并且不允許用戶修改數(shù)據(jù),那么表格數(shù)據(jù)控件(TDC)可能會(huì)比較適合。這種數(shù)據(jù)源是一個(gè)文本文件,不需要任何數(shù)據(jù)庫(kù),因此編輯起來(lái)比較簡(jiǎn)單。對(duì)于從數(shù)據(jù)庫(kù)中取出數(shù)據(jù)并且可能需要更新的情況,RDS數(shù)據(jù)控件是最合適的。而對(duì)于許多新數(shù)據(jù)源,會(huì)發(fā)現(xiàn)此時(shí)需要使用XML數(shù)據(jù)控件。這實(shí)際依賴于所使用的Web應(yīng)用程序的類型,以及用戶所需的功能。
我們將依次介紹這些數(shù)據(jù)控件,一旦了解了如何用它們把數(shù)據(jù)傳送到客戶端,將會(huì)介紹如何使用這些數(shù)據(jù)。
1. 表格數(shù)據(jù)控件
表格數(shù)據(jù)控件(Tabular Data Control,TDC)是最簡(jiǎn)單的數(shù)據(jù)源對(duì)象,主要用于少量的只讀數(shù)據(jù),特別是那些從不改變或很少修改的,不需要從客戶端進(jìn)行更新的靜態(tài)數(shù)據(jù)。例如,表格數(shù)據(jù)控件能提供一個(gè)網(wǎng)頁(yè)內(nèi)的菜單項(xiàng)或鏈接的列表。
通過(guò)在HTML代碼中使用<OBJECT>標(biāo)記可以創(chuàng)建一個(gè)表格數(shù)據(jù)控件。參數(shù)DataURL可以指定包含文本數(shù)據(jù)的文件名。
<OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
<PARAM NAME="DataURL" VALUE="Authors.csv">
</OBJECT>
TDC只讀取表格中的數(shù)據(jù)或標(biāo)記為表格形式的數(shù)據(jù),例如,可以處理逗號(hào)分隔形式的數(shù)據(jù)(Comma Separated Value, CSV),類似于下面的數(shù)據(jù):
"172-32-1176","White","Bob","408 496-7223"
"219-46-8915","Green","Marjorie","415 986-7020"
"238-95-7766","Carson","Cheryl","415 548-7723"
"267-41-2394","O'Leary","Michael","408 286-2428"
"274-80-9391","Straight","Dean","415 834-2919"
"341-22-1782","Smith","Meander","913 843-0462"
"409-56-7008","Bennet","Abraham","415 658-9932"
TDC也可以自由定義。除了DataURL外,TDC還有16個(gè)參數(shù),可以通過(guò)設(shè)置OBJECT標(biāo)記的參數(shù)項(xiàng)或編寫腳本代碼來(lái)配置這些參數(shù)。參數(shù)的說(shuō)明如表10-1所示:
表10-1 TDC的參數(shù)及說(shuō)明
屬 性
數(shù)據(jù)類型
說(shuō) 明
缺 省 值
AppendData
布爾型
確定新數(shù)據(jù)是替換還是追加到數(shù)據(jù)源對(duì)象中的現(xiàn)有數(shù)據(jù)
False
CaseSensitive
布爾型
指出字符串比較時(shí)是否大小寫敏感
True
CharSet
字符型
指出數(shù)據(jù)的字符集類型。附錄中字符集的列表
Windows-1252
DataURL
字符型
指出數(shù)據(jù)源文件的URL
EscapeChar
字符型
指定源文件中使用的轉(zhuǎn)義字符。這些字符位于其他字符的前面以避免與FieldDelim、RomDelim或TextQualifier混淆
FieldDelim
字符型
指定字段之間的分隔字符
,(逗號(hào))
Filter
字符型
設(shè)置過(guò)濾條件
Filtercolumn
字符型
設(shè)置過(guò)濾的列
FilterValue
字符型
設(shè)置過(guò)濾的列的值
Language
字符型
指定數(shù)據(jù)文件使用的語(yǔ)言
en-us(美國(guó)英語(yǔ))
ReadyState
長(zhǎng)整型
指出控件的當(dāng)前狀態(tài)??梢允且韵轮担篴dcReadyStateComplete(4)表明所有的數(shù)據(jù)都傳送完畢,或發(fā)生了一個(gè)錯(cuò)誤
adcReadyStateInteractive(3)表明數(shù)據(jù)正在傳送中
adcReadyStateLoaded(2)表明控件已被加載并等待數(shù)據(jù)傳輸
這個(gè)屬性是只讀的
RowDelim
字符型
指定文本文件中的行分隔符,缺省為回車符
一個(gè)新行字符
Sort
字符型
指出要排序的列的列表。列名前有減號(hào)表明是按降序排序,否則按升序排序
SortDirection
布爾型
如果排序是升序則為True,降序則為False
SortColumn
字符型
指定排序的列
TextQualifier
字符型
指定封閉文本字段的字符,缺省為雙引號(hào)
"(雙引號(hào))
UseHeader
布爾型
表明文本文件中首行是否包含列名
False
下面是使用參數(shù)創(chuàng)建TDC的一個(gè)例子。
<OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
<PARAM NAME="DataURL" VALUE="Authors.csv">
</OBJECT>
也可以在客戶端腳本中獲取數(shù)據(jù),下面的例子顯示了給TDC加載數(shù)據(jù)的JScript腳本。
function fillTDC()
{
dsoAuthors.dataURL = 'authors.csv';
dsoAuthors.Reset();
}
如果改變了TDC的DataURL參數(shù),必須使用Reset方法,這樣才能使新的URL起作用。當(dāng)介紹數(shù)據(jù)綁定時(shí),會(huì)更詳細(xì)地討論如何使用它。Reset方法是TDC唯一的一個(gè)方法。
2. RDS數(shù)據(jù)控件
RDS數(shù)據(jù)控件能夠訪問(wèn)一般的數(shù)據(jù)存儲(chǔ),而不是平面文件。它通常用于連接SQL數(shù)據(jù)庫(kù)以從表、查詢或存儲(chǔ)過(guò)程獲取數(shù)據(jù)。與TDC不同,RDS數(shù)據(jù)控件允許更新數(shù)據(jù)。在本章稍后通過(guò)示例說(shuō)明如何進(jìn)行數(shù)據(jù)更新。
類似于TDC,可以用HTML腳本中的OBJECT標(biāo)記來(lái)創(chuàng)建一個(gè)RDS數(shù)據(jù)控件,并以類似的方式設(shè)置其屬性。
<OBJECT CLASSID='clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID="dsoAuthors" WIDTH="0" HEIGHT="0">
<PARAM NAME="Connect" VALUE="Connection String">
<PARAM NAME="Server" VALUE="Server Name">
<PARAM NAME="SQL" VALUE="Query Text">
</OBJECT>
同樣,注意定制數(shù)據(jù)控件時(shí)參數(shù)的使用方法。上面的例子顯示了最常見的設(shè)置方法。和TDC一樣,還有很多其他可以設(shè)置的參數(shù),如表10-2所示:
表10-2 RDS數(shù)據(jù)控件的參數(shù)及說(shuō)明
屬 性
數(shù)據(jù)類型
說(shuō) 明
缺 省 值
Connect
字符型
一個(gè)標(biāo)識(shí)數(shù)據(jù)存儲(chǔ)的ADO連續(xù)字符串
ExecuteOptions
長(zhǎng)整型
指出命令是異步執(zhí)行還是同步執(zhí)行??梢允且韵轮抵唬?BR>adcExecSync(1)同步執(zhí)行(缺省值)
adcExecAsync(2)異步執(zhí)行
adExecAsync
FetchOptions
長(zhǎng)整型
獲取數(shù)據(jù)的方式,可以是以下值:
adcFetchUpFront(1)先取數(shù)據(jù),然后將控制交給應(yīng)用程序
adcFetchBackground(2)先立即取得第一批數(shù)據(jù),剩余的數(shù)據(jù)在后臺(tái)獲取
adcFetchAsync(3)在后臺(tái)獲取所有的數(shù)據(jù)
adcFetchAsync
FilterColumn
字符型
指定被過(guò)濾的列
FilterCriterion
字符型
指定過(guò)濾的條件。可以是以下運(yùn)算符:
<(小于)
<=(小于等于)
=(等于)
>=(大于等于)
>(大于)
<>(不等于)
FilterValue
字符型
過(guò)濾的值
Handler
字符型
自定義的數(shù)據(jù)處理器的名稱和參數(shù)
MSDFMAP.Handler
InternetTimeout
長(zhǎng)整型
在錯(cuò)誤發(fā)生前等待的時(shí)間(毫秒為單位)
300000
ReadyState
長(zhǎng)整型
控件的當(dāng)前狀態(tài),可以是以下值:
adcReadyStateComplete(4)表明所有的數(shù)據(jù)都傳送完畢,或發(fā)生了一個(gè)錯(cuò)誤
adcReadyStateInteractive(3)表明數(shù)據(jù)仍然在傳送中
adcReadyStateLoaded(2)表明控件已被加載并等待數(shù)據(jù)傳輸
Recordset
記錄集型
數(shù)據(jù)控件訪問(wèn)的ADO數(shù)據(jù)記錄集。該參數(shù)只讀
Server
字符型
數(shù)據(jù)所在的服務(wù)器的名稱。為了安全,必須與提供Web頁(yè)面的服務(wù)器同名??梢允且粋€(gè)標(biāo)準(zhǔn)URL,也可以是機(jī)器名稱(如果使用DCOM)
SortColumn
字符型
排序的列名
SortDirection
布爾型
表明排序是否為升序
SourceRecordset
字符型
將控件的基礎(chǔ)記錄集設(shè)置為一個(gè)現(xiàn)有的記錄集。該屬性只寫
SQL
字符型
獲取數(shù)據(jù)的SQL字符串
URL
字符型
數(shù)據(jù)源的URL