Delphi XE程序设计系列 2-开发DataSnap/REST服务器

简介: 在上次的文章中讨论了如何把传统的Delphi 主从架构应用程序逐渐转换为DataSnap JSON服务器,在本篇文章中让我们正式讨论如何使用Delphi XE开发DataSnap/REST服务器,由于这其中牵涉到非常多的技术,因此我们将花数篇的篇幅来讨论。

在上次的文章中讨论了如何把传统的Delphi 主从架构应用程序逐渐转换为DataSnap JSON服务器,在本篇文章中让我们正式讨论如何使用Delphi XE开发DataSnap/REST服务器,由于这其中牵涉到非常多的技术,因此我们将花数篇的篇幅来讨论。现在就让我们从DataSnap/REST服务器开始。

开发DataSnap服务器

    Delphi XE版的DataSnap允许开发人员同时在DataSnap服务器中实作RESTful架构的服务器,如此一来DataSnap服务器不但可以在网络内 部做为多层的服务服务器,也可以让网络外部的客户端使用REST的方式来存取服务。 要在Delphi XE中建立DataSnap/REST服务器,请点选Files|New菜单,在DataSnap Server选项中选择DataSnap Server图像,如下图所示:

 

 

 

    Delphi XE提供三种不同的服务器型态,分别是以VCL应用程序实作的服务器,实作为主控程序的服务器以及实作成Windows服务应用程序的服务器,开发人员可根据自己的需求选择建立适当的服务器型态,在本篇文章中让我们建立VCL应用程序型态的服务器:

 

 

    点选Next按钮之后DataSnap精灵会如下图询问需要支持的通讯协议,是否使用安全验证功能以及是否要预先建立范例服务方法,让我们点选下方的Select All以选择建立所有的功能,如下图所示:

 

 

 

 

 

 

    点选Next按钮,DataSnap精灵会如下图询问TCP/IPHTTP使用的通信埠,内定上TCP/IP使用211HTTP则使用 8080,开发人员可根据自己的需求设定这两个通信埠,或是点选Find Open Port按钮让DataSnap精灵帮忙搜寻可使用的通信埠:

 

 

 

    接着DataSnap精灵会询问开发人员实作服务方法的类别,开发人员可以选择实作于TComponent类别,TDataModule类别或是TDSServerModule类别,在本文章中我们选择实作于TDSServerModule:

 

 

    点选Finish按钮之后,Delphi XE便会建立相对应的项目,我们开启ServerContainerUnit的话就可以看到其中包含了如下组件,其中的 TDSServerTDSTCPServerTransport以及TDSServerClass类别组件在Delphi 2010中就存在了,新的TDSHTTPService类别组件则提供了HTTP/HTTPS通讯协议的支持,而新的 TDSAuthenticationManager类别组件则提供安全验证功能,在稍后的文章中我们会说明如何使用它。

 

 

 

 

 

    现在DataSnap精灵会在项目的ServerMethodsUnit程序单元中产生两个范例方法,EchoStringReverseString。现在让我们在这个程序单元中加入一个新的服务方法『取得部落格文章名称』,如下所示:

public

{ Public declarations }

function EchoString(Value: string): string;

function ReverseString(Value: string): string;

function 取得部落格文章名称 : TJSONArray;

 

接着实作『取得部落格文章名称』方法,如下所示:

function TServerMethods2.取得部落格文章名称: TJSONArray;

begin

Result := TJSONArray.Create;

Result.AddElement(TJSONString.Create(‘Delphi XE程序设计系列 1-主从架构, 多层到JSONREST’));

Result.AddElement(TJSONString.Create(‘从原生APIREST API – 使用C++Builder XE开发REST应用程序’));

Result.AddElement(TJSONString.Create(‘Delphi XE程序设计系列 2-DataSnap/REST服务器’));

end;

 

    『取得部落格文章名称』方法建立TJSONArray对象,并且把三篇文章名称以TJSONString对象储存在元素中,最后回传TJSONArray对象给客户端。

 

    最后开启ServerMethodsUnit程序单元的设计接口,在其中放入dbExpress组件以存取储存在MS SQL Server数据库中的范例数据表FishFacts,稍后我们将说明这个DataSnap/REST服务器如何同时以传统DataSnap的架构让用户端使用dbExpress组件存取数据,以及如何以REST的架构让客户端存取它提供的服务。

 

 

 

 

    现在编译并且执行这个DataSnap/REST服务器。

    由于现在这个服务器同时可提供DataSnapREST服务器的功能,因此现在我们可以试着使用浏览器来使用存取这个服务器的服务。让我们使用下面的URI来呼叫『取得部落格文章名称』方法:

http://localhost:8085/datasnap/rest/TServerMethods2/取得部落格文章名称

 

    我们可以在下图中看到,我们果然可以在浏览器中使用上面的URI成功的呼叫服务器的服务:

 

 

 

 

    而且我们从上图中可以清楚的看到回传的结果是使用JSON格式封装的JSON数组,每一个数组元素是Unicode编码的JSON字符串

连结使用DataSnap服务器

    现在让我们建立一个客户端VCL应用程序项目,放入TSQLConnection组件,然后设定它的特性值如下(此时DataSnap/REST服务器必须是在执行状态):

 

特性

特性值

Driver

Datasnap

Connected

True

 

 

    点选鼠标右键,选择建立『Generate DataSnap Client Classes』菜单,如下所示,再把产生的程序单元储存为ServerProxy程序单元。

 

 

 

 

然后在主窗体中放入如下的dbExpressVCL组件:

 

 

 

 

设定TDSProviderConnection组件的特性值如下:

 

特性

特性值

SQLConnection

SQLConnection1

ServerClassName

TServerMethods2

 

再设定TClientDataSet的特性值如下:

特性

特性值

RemoteServer

DSProviderConnection1

Provider

dspFishFacts

 

 

    当我们在设定TClientDataSetProvider特性值时,客户端应用程序就会连结到DataSnap/REST服务器并且显示ServerMethodsUnit程序单元中输出的TDataSetProvider组件。

 

    让我们在『更新』按钮的OnClick事件处理函式中撰写如下的程序代码:

procedure TForm10.Button3Click(Sender: TObject);

begin

if (cdsFishFacts.ChangeCount > 0) then

cdsFishFacts.ApplyUpdates(0);

end;

 

 

     编译并且执行客户端应用程序,我们就可以看到类似如下的画面:

 

 

 

 

    DataSnap/REST服务器就如同以前的DataSnap/Midas服务器一样可以提供二层和多层的开发架构,客户端应用程序也可以使用dbExpress组件来异动DataSnap/REST服务器中的数据。

现在我们已经展示了这个DataSnap/REST服务器可以同时使用二层/多层和REST的架构来使用它。

现在再让我们看看如何在客户端使用程序代码来存取服务器的服务。在前面我们已经藉由TSQLConnection组件自动产生了ServerProxy程序单元,如果我们开启ServerProxy,便会看到下面的类别宣告:

 

TServerMethods2Client = class(TDSAdminClient)

private

FEchoStringCommand: TDBXCommand;

FReverseStringCommand: TDBXCommand;

F取得部落格文章名称Command: TDBXCommand;

public

constructor Create(ADBXConnection: TDBXConnection); overload;

constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload;

destructor Destroy; override;

function EchoString(Value: string): string;

function ReverseString(Value: string): string;

function 取得部落格文章名称: TJSONArray;

end;

 

如果我们观察ServerProxy程序单元中的『取得部落格文章名称』方法,就可以看到它也使用dbExpress技术来存取服务器的服务:

function TServerMethods2Client.取得部落格文章名称: TJSONArray;

begin

if F取得部落格文章名称Command = nil then

begin

F取得部落格文章名称Command := FDBXConnection.CreateCommand;

F取得部落格文章名称Command.CommandType := TDBXCommandTypes.DSServerMethod;

F取得部落格文章名称Command.Text := ‘TServerMethods2.取得部落格文章名称’;

F取得部落格文章名称Command.Prepare;

end;

F取得部落格文章名称Command.ExecuteUpdate;

Result := TJSONArray(F取得部落格文章名称Command.Parameters[0].Value.GetJSONValue(FInstanceOwner));

end;

 

因此在客户端,我们可以使用下面的程序代码藉由ServerProxy程序单元中的『取得部落格文章名称』方法来取得部落格文章信息:

 

procedure TForm10.Button1Click(Sender: TObject);

var

aServer: TServerMethods2Client;

ja : TJSONArray;

iIndex: Integer;

begin

aServer := TServerMethods2Client.Create(Self.SQLConnection1.DBXConnection);

try

ja := aServer.取得部落格文章名称;

for iIndex := 0 to ja.Size – 1 do

ListBox1.Items.Add(ja.Get(iIndex).ToString);

finally

aServer.Free;

end;

end;

 

    下图是客户端应用程序执行上面程序代码的结果:

 

 

 

    但是除了dbExpress技术之外,我们也可以使用RESTJavaScript等技术来存取服务器服务,因为这个服务器就是一个REST服务器。因此让我们更深入的讨论一下如何在客户端自动产生程序代码来支持RESTJavaScript等技术。

客户端程序代码产生器

    DataSnap XE版目前可自动产生四种客户端程序代码让不同的客户端能够连结和使用DataSnap/REST服务器,这四种是:

DataSnap XE支持的四种客户端程序代码

说明

Delphi DBX

使用dbExpress技术呼叫DataSnap/REST服务器的客户端Delphi程序代码

C++Builder DBX

使用dbExpress技术呼叫DataSnap/REST服务器的客户端C/C++程序代码

Java Script REST

使用REST/JSON技术呼叫DataSnap/REST服务器的客户端JavaScript程序代码

Delphi REST

使用REST/JSON技术呼叫DataSnap/REST服务器的客户端Delphi程序代码

 

 

 

 

    我们可以轻易的使用下面的程序代码来取得目前能够产生的客户端程序代码:

 

 

procedure TForm10.ListRegisteredWriter;

 

var

sa : TDBXStringArray;

iIndex : Integer;

begin

sa := DSProxyWriter.TDSProxyWriterFactory.RegisteredWritersList;

for iIndex := 0 to Length(sa) – 1 do

ComboBox1.Items.Add(sa[iIndex]);

ComboBox1.ItemIndex := 0;

end;

 

 

    DSProxyWriter程序单元中 TDSProxyWriterFactory类别的类别方法RegisteredWritersList可以回传目前注册的客户端程序代码种类,目前上表列出的四种客户端程序代码产生器分别位于DSProxyDelphiDSProxyCpp DSProxyJavaScriptDSProxyDelphiRest程序单元中。

 

 

 

    当我们要产生上表四种客户端程序代码以呼叫特定的DataSnap/REST服务器时,我们需要使用IDSProxyMetaDataLoader接口以及TDSProxyGenerator类别。

    IDSProxyMetaDataLoader接口是由TDSProxyMetaDataLoader类别实作的,我们可以使用 TDBXConnection对象建立TDSProxyMetaDataLoader对象,取得它的IDSProxyMetaDataLoader接口, 再建立TDSProxyGenerator对象,设定要产生的特定客户端程序代码目标,最后呼叫TDSProxyGenerator对象的Write方法, 如此一来DataSnap框架就会自动产生连结特定DataSnap/REST服务器的客户端程序代码。

    例如,现在让我们来看看如何能够要求DataSnap框架自动产生Delphi REST或是JavaScript的客户端程序代码。

 

    下面的程序代码首先呼叫GetMetaDataLoader方法取得IDSProxyMetaDataLoader接口,再呼叫GenerateFile藉由IDSProxyMetaDataLoader接口产生使用者特定的客户端程序代码:

procedure TForm10.Button2Click(Sender: TObject);

var

LMetaDataLoader: IDSProxyMetaDataLoader;

begin

LMetaDataLoader := GetMetaDataLoader;

GenerateFile(LMetaDataLoader);

ShowGeneratedFiles;

end;

 

    GetMetaDataLoader方法藉由程序中的 TSQLConnectionTDBXConnection对象建立TDSProxyMetaDataLoader对象,再回传 TDSProxyMetaDataLoader对象实作的IDSProxyMetaDataLoader接口:

 

 

function TForm10.GetMetaDataLoader : IDSProxyMetaDataLoader;

begin

Result := TDSProxyMetaDataLoader.Create(

function: TDBXConnection

begin

OpenConnection;

Result := SQLConnection1.DBXConnection;

end,

procedure(AConnection: TDBXConnection)

begin

SQLConnection1.Close;

end

);

end;

 

 

    而GenerateFile方法先建立 TDSProxyGenerator对象,设定它的Writer特性值为稍后使用者在程序中设定的特定的客户端程序代码的名称,例如是『Delphi DBX』产生使用dbExpress技术的客户端程序代码,或是『Java Script REST』产生使用REST/JSONJavaScript程序代码,最后呼叫Write方法实际的产生客户端程序代码:

 

 

procedure TForm10.GenerateFile(AMetaDataLoader: IDSProxyMetaDataLoader);

var

LProxyGenerator: TDSProxyGenerator;

begin

LProxyGenerator := TDSProxyGenerator.Create(nil);

try

LProxyGenerator.Writer := ComboBox1.Text;

LProxyGenerator.TargetUnitName := ‘GeneratedServerProxy’;

LProxyGenerator.ExcludeMethods := ;

LProxyGenerator.ExcludeClasses := ;

LProxyGenerator.TargetDirectory := ‘.’;

LProxyGenerator.OnCreatingFiles := ACreatingFiles;

LProxyGenerator.OnCreatedFiles := ACreatedFiles;

LProxyGenerator.Write(AMetaDataLoader);

finally

LProxyGenerator.Free;

end;

end;

 

 

    现在如果我们执行客户端应用程序,可以看到如下的画面,在下面中我选择产生Delphi REST的客户端程序代码:

 

 

 

 

    那么这个范例客户端应用程序便会自动产生使用REST的客户端Delphi程序代码,例如它产生的呼叫范例DataSnap/REST服务器的『取得部落格文章名称』方法的程序代码如下:

 

function TServerMethods2Client.取得部落格文章名称(const ARequestFilter: string): TJSONArray;

begin

if F取得部落格文章名称Command = nil then

begin

F取得部落格文章名称Command := FConnection.CreateCommand;

F取得部落格文章名称Command.RequestType := ‘GET’;

F取得部落格文章名称Command.Text := ‘TServerMethods2.取得部落格文章名称’;

F取得部落格文章名称Command.Prepare(TServerMethods2_取得部落格文章名称);

end;

F取得部落格文章名称Command.Execute(ARequestFilter);

Result := TJSONArray(F取得部落格文章名称Command.Parameters[0].Value.GetJSONValue(FInstanceOwner));

end;

 

 

    看到现在它是使用HTTPGet命令,藉由REST呼叫惯例来呼叫DataSnap/REST服务器的『取得部落格文章名称』方法了。

 

    如果我是选择产生Java Script REST

 

 

 

 

    那么下面就是DataSnap框架自动产生的客户端JavaScript程序代码:

/*

* @return result – Type on server: TJSONArray

*/

this.取得部落格文章名称 = function() {

var returnObject = this.executor.executeMethod(‘取得部落格文章名称’, GET, [], arguments[0], true, arguments[1], arguments[2]);

if (arguments[0] == null) {

if (returnObject != null && returnObject.result != null && isArray(returnObject.result)) {

var resultArray = returnObject.result;

var resultObject = new Object();

resultObject.result = resultArray[0];

if (returnObject.cacheId != null && returnObject.cmdIndex != null) {

resultObject._cacheId = returnObject.cacheId;

resultObject._cmdIndex = returnObject.cmdIndex;

}

return resultObject;

}

return returnObject;

}

};

this.取得部落格文章名称_URL = function() {

return this.executor.getMethodURL(『取得部落格文章名称』, GET, [], arguments[0])[0];

};

}

var JSProxyClassList = {

TServerMethods2″: ["DSServerModuleCreate","DSServerModuleDestroy","EchoString","ReverseString","取得部落格文章名称"]

};

 

 

 

 

    最后我试着同时使用Delphi客户端应用程序以及浏览器两个不同的客户端来呼叫和使用范例DataSnap/REST服务器,看起来一切都非常的美好:

 

 

 

 

 

    当然,我也可以使用纯粹的Web客户端应用程序来呼叫和使用范例DataSnap/REST服务器,例如下图就是我使用VCL For Web XI来使用范例DataSnap/REST服务器的结果,所有的服务仍然工作良好:

 

 

 

 

 

 

 

    DataSnap XE版藉由扩充多层架构到RESTJSON的技术领域,让DataSnap XE瞬间突破了平台的限制,允许DelphiC/C++BuilderJavaScriptPHPRuby和移动设备等各种客户端能够使用它的服 务,再次赋予了DataSnap框架无限的发展潜能。

好了,时间已晚,我们也下次再见了。

 

相关文章
|
1月前
|
关系型数据库 API 数据库
后端开发的艺术:从零到一构建高效服务器
在数字化时代,后端开发是支撑现代互联网应用的基石。本文旨在探讨后端开发的核心概念、关键技术以及如何构建一个高效的服务器。我们将从基础的编程语言选择开始,逐步深入到数据库设计、API开发和性能优化等关键领域。通过实际案例分析,我们将揭示后端开发的复杂性和挑战性,同时提供实用的解决方案和最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和启发。
|
2月前
|
网络安全 Docker 容器
VScode远程服务器之远程 远程容器 进行开发(五)
VScode远程服务器之远程 远程容器 进行开发(五)
39 1
|
2月前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
50 3
|
2月前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
|
2月前
|
Kubernetes 网络安全 容器
VScode远程服务器进行开发(三)
VScode远程服务器进行开发(三)
44 0
|
3月前
|
开发框架 JavaScript 前端开发
|
4月前
|
前端开发 大数据 数据库
🔥大数据洪流下的决战:JSF 表格组件如何做到毫秒级响应?揭秘背后的性能魔法!💪
【8月更文挑战第31天】在 Web 应用中,表格组件常用于展示和操作数据,但在大数据量下性能会成瓶颈。本文介绍在 JavaServer Faces(JSF)中优化表格组件的方法,包括数据处理、分页及懒加载等技术。通过后端分页或懒加载按需加载数据,减少不必要的数据加载和优化数据库查询,并利用缓存机制减少数据库访问次数,从而提高表格组件的响应速度和整体性能。掌握这些最佳实践对开发高性能 JSF 应用至关重要。
72 0
|
19天前
|
人工智能 弹性计算 编解码
阿里云GPU云服务器性能、应用场景及收费标准和活动价格参考
GPU云服务器作为阿里云提供的一种高性能计算服务,通过结合GPU与CPU的计算能力,为用户在人工智能、高性能计算等领域提供了强大的支持。其具备覆盖范围广、超强计算能力、网络性能出色等优势,且计费方式灵活多样,能够满足不同用户的需求。目前用户购买阿里云gpu云服务器gn5 规格族(P100-16G)、gn6i 规格族(T4-16G)、gn6v 规格族(V100-16G)有优惠,本文为大家详细介绍阿里云gpu云服务器的相关性能及收费标准与最新活动价格情况,以供参考和选择。
|
25天前
|
机器学习/深度学习 人工智能 弹性计算
什么是阿里云GPU云服务器?GPU服务器优势、使用和租赁费用整理
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等多种场景。作为亚太领先的云服务提供商,阿里云的GPU云服务器具备灵活的资源配置、高安全性和易用性,支持多种计费模式,帮助企业高效应对计算密集型任务。
|
26天前
|
存储 分布式计算 固态存储
阿里云2核16G、4核32G、8核64G配置云服务器租用收费标准与活动价格参考
2核16G、8核64G、4核32G配置的云服务器处理器与内存比为1:8,这种配比的云服务器一般适用于数据分析与挖掘,Hadoop、Spark集群和数据库,缓存等内存密集型场景,因此,多为企业级用户选择。目前2核16G配置按量收费最低收费标准为0.54元/小时,按月租用标准收费标准为260.44元/1个月。4核32G配置的阿里云服务器按量收费标准最低为1.08元/小时,按月租用标准收费标准为520.88元/1个月。8核64G配置的阿里云服务器按量收费标准最低为2.17元/小时,按月租用标准收费标准为1041.77元/1个月。本文介绍这些配置的最新租用收费标准与活动价格情况,以供参考。