Delphi XE程式設計系列 1-主從架構, 多層到JSON和REST
從桌面開發,主從架構,一直到多層架構,雖然都是廣泛被接受的觀念和技術,但在資訊技術的實作上卻從 不是開放,相容的世界。Delphi從桌面開發到主從架構都是使用自己的資料傳遞格式以及通訊傳遞架構,到了多層架構雖然使用了Windows平台上的通 訊協定,例如COM/DCOM/COM+,但是在傳遞的資料格式方面仍然是使用自己的架構,COM/DCOM/COM+也是MS專屬的通訊協定,和其他平 台上使用的通訊協定也不一樣。當然,不光是Delphi/BCB,大部份的開發工具也是採用類似的方式,那就是都支援桌面開發,主從架構或是多層架構等通 用觀念的架構,但使用來傳遞資料和溝通通訊協定都是封閉的架構。
直到JSON和REST的出現以及Delphi/BCB確定走向原生,跨平台的道路之後,Delphi/BCB 從2010版便開始走向以JSON封裝資料,以REST做為通訊架構的方向。因此Delphi/BCB除了仍然支援原有的資料封裝格式以及通訊協定之外, 也允許開發人員選擇使用JSON和REST,使用JSON和REST的好處是除了可以讓JSON和REST擁抱最新的資訊技術之外,也可以讓 Delphi/BCB在不同的平台中使用相同的技術來開發主從架構,分散式多層以及Web應用,也可以更容易的和其他的程式語言,框架和技術整合在一起。 現在讓我們重溫舊夢一下,看看如何把一個簡單的主從架構應用程式轉換為使用JSON的架構。
主從架構
下圖是一個簡單的主從架構的主表單,
它藉由下圖的dbExpress元件從資料庫的FishFacts資料表中取得資料,並且使用資料感知元件顯示在應用程式的主表單中。
雖然從BDE到dbExpress都使用專屬的格式封裝資料,但BDE和dbExpress也可以把資料封裝成較開放的XML格式,因此要把上圖中TClientDataSet中的資料轉換為XML的格式,我們只需要存取它的XMLData特性值即可: dssmFishFact.cdsFishFact.XMLData;
XMLData特性值會回傳以下面格式封裝的XML資料:
fieldtype=』string』 WIDTH=』15″/> 0″/> 然而BDE/dbExpress雖然能夠把資料封裝成XML格式,但使用XML封裝資料時仍然會因為不同的資料存取使用不同的XML元素來封裝資 料,因此在交換資料時仍然會造成許多的困擾,而且使用XML格式封裝資料的成本比起JSON來要昂貴許多(XML使用較多元素,較為複雜的規則封裝資料所 致)。 因此Delphi/BCB要支援JSON/REST技術,其中一個工作就是必須能夠把資料封裝成JSON的格式,因此從Delphi/BCB 2010版開始便在VCL和RTL中加入了許多和JSON相關的類別以執行這項工作。到了XE版Delphi/BCB基本上不但能夠把資料封裝成JSON 的格式,甚至提供了REST的API允許Delphi,BCB和任何支援JSON和REST的用戶端和使用Delphi/BCB開發的DataSnap伺 服器整合在一起,下圖敘述了Delphi/BCB XE版支援的架構: OK,現在先讓我們看看Delphi/BCB XE如何能夠把資料封裝成JSON的格式,以及提供解析,處理JSON封包的相關類別。稍後我們再討論Delphi/BCB XE如何支援REST API的使用和呼叫。 其實要把dbExpress中的資料封裝成JSON非常的簡單,就以直覺來說,我們只需要一個單向,唯讀的資料集,這個單向,唯讀的資料集可以直接從dbExpress的資料集元件建立,接著再一一的從這個單向,唯讀的資料集中讀取資料,根據JSON規則封裝即可。 因此在VCL中提供了TDBXDataSetReader這個單向,唯讀的資料集,它可以從dbExpress資料集元件建立,接著在TDBXJSONTools類別中提供了TableToJSON類別方法,它接受一個TDBXReader物件為第一個參數,第二個參數為要從第一個參數中封裝的記錄筆數,最後一個參數則代表在TableToJSON執行完畢之後是否需要釋放第一個參數物件: class function TableToJSON(const Value: TDBXReader; const RowCount: Integer; const IsLocalConnection: Boolean): TJSONObject; static; 因此要封裝範例FishFacts資料表中的2筆資料為JSON格式,我們就可以使用下面的程式碼來完成這個工作。 在下面的程式碼中我們首先藉由資料模組中的TClientDataSet元件建立 TDBXDataSetReader元件,接著呼叫TDBXJSONTools類別的TableToJSON類別方法把資料封裝成JSON格式: procedure TForm1.btnToJSONClick(Sender: TObject); var aDBXReader : TDBXReader; aJSonObj : TJSONObject; begin aDBXReader := TDBXDataSetReader.Create(dssmFishFact.cdsFishFact, False); try aJSonObj := TDBXJSONTools.TableToJSON(aDBXReader, 2, False); Memo2.Lines.Text := aJSonObj.ToString; ParseData(aJSonObj); finally aJSonObj.Free; aDBXReader.Free; end; end; 下圖是執行 dssmFishFact.cdsFishFact.XMLData; 之後得到的XML格式的結果: 而下圖則是藉由TableToJSON轉換為JSON格式的結果: 如果我們觀察JSON格式的結果可以看到DataSnap是以JSON物件封裝資料,而每一個欄位則是以JSON陣列來封裝: {『table』:[[\Species Name\ 由於使用JSON格式封裝資料比較簡單而且在解析上也比XML容易,我們可以使用VCL中JSON相關的類別很容易的解析出其中封裝的資料。例如下面的 ParseData從前面TableToJSON建立的JSON物件中解析其中封裝的FishFacts資料表的資料: procedure TForm1.ParseData(aJSONObj: TJSONObject); var iPair : Integer; aPair : TJSONPair; begin for iPair := 0 to aJSONObj.Size – 1 do begin aPair := aJSONObj.Get(iPair); if (aPair.JsonString.ToString <> ‘』Graphic』‘) then Memo3.Lines.Add(Format(‘%s : %s’, [aPair.JsonString.ToString, aPair.JsonValue.ToString])); end; end; 下圖即是ParseData執行後的結果: