原来做过webservice,后来忘记了,今天又学了一下,做个笔记,以供以后浏览。
WebService是以服务端给用户端提供接口来调用的。用Delphi开发WebService时有以下几个步骤:
以下为DelphiXE3开发的WebService,服务端提供目录下的文件让客户端查询,在客户端会显示所选择的文件,以图像文件为例
一、服务端
1.在菜单"File"->"New"->"Other"->"WebService"中点选,如下图
2.建立服务端模型,我们先以第一种为例,这样可以调试,以后可以改成其它格式
3.建立对外接口模板(Soaptest)
4.在接口和实现接口的类中加入以下函数并实现它(GetFileNames是列出所有目录下的png文件,GetFile是把要显示的文件传递给客户端)
接口实现的代码:
{ Invokable implementation File for TSoapTest which implements ISoapTest } unit uSoapTestImpl; interface uses Soap.InvokeRegistry, System.Types, Soap.XSBuiltIns, uSoapTestIntf,SysUtils, Vcl.Forms,System.Classes,System.IOUtils ; type { TSoapTest } TSoapTest = class(TInvokableClass, ISoapTest) private function GetServerPath:string; public function GetFileNames(out icount:Integer):TStringDynArray;stdcall; function GetFile(const AFile:string; out isize:integer):TByteDynArray;stdcall; end; implementation { TSoapTest } function TSoapTest.GetFile(const AFile: string; out isize: integer): TByteDynArray; var mem:TMemoryStream; AtmpFile:string; begin isize:=0; SetLength(Result,isize); AtmpFile:=GetServerPath+AFile; if not FileExists(AtmpFile) then raise Exception.Create('Cou''t find the AFile'); mem:=TMemoryStream.Create; try mem.LoadFromFile(AtmpFile); isize:=mem.Size; SetLength(Result,isize); Move(mem.Memory^,result[0],isize); finally mem.Free; end; end; function TSoapTest.GetFileNames(out icount: Integer): TStringDynArray; var i:integer; begin Result:= TDirectory.GetFiles(GetServerPath,'*.png',TSearchOption.soTopDirectoryOnly); icount:=Length(Result); for i := 0 to icount-1 do Result[i]:=ExtractFileName(Result[i]); end; function TSoapTest.GetServerPath: string; begin result:='..\imgs\'; end; initialization { Invokable classes must be registered } InvRegistry.RegisterInvokableClass(TSoapTest); end.
5.运行服务端,如下图,打开浏览器后,得到wsdl的文件
点击ISoapTest[WSDL]连接得到如下图片
6.保存上面的网页并命名为wsdl格式的文件,用于客户端调用
二、开发客户端
1.建立普通的应用程序,并在界面上放上HTTPRIO组件,用于调用服务端接口函数。如下图:listbox显示客户端的文件名,右边为image用于显示点选 的图片
2.在菜单“Component->Import WSDL”打开一界面,在location中选择你刚才保存的wsdl文件,用于产生接口单元(记着一定要打开服务端),并保存到客户端,让客户端引用
3.在客户端中写入以下代码即可
unit UMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,Vcl.Imaging.pngimage, Vcl.ExtCtrls, Vcl.StdCtrls, Soap.InvokeRegistry, Soap.Rio, Soap.SOAPHTTPClient,SoapTest; type TForm2 = class(TForm) ListBox1: TListBox; Image1: TImage; HTTPRIO1: THTTPRIO; Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ListBox1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form2: TForm2; implementation uses System.Types; {$R *.dfm} procedure TForm2.Button1Click(Sender: TObject); var FilesArr:TStringDynArray; i:integer; str:string; begin ListBox1.Clear; FilesArr:=(HTTPRIO1 as isoaptest).GetFileNames(i); Caption:='The total Files is :'+inttostr(i); for str in FilesArr do ListBox1.Items.Add(str); end; procedure TForm2.FormCreate(Sender: TObject); begin // with HTTPRIO1 do // begin // WSDLLocation:='SoapTest.wsdl' ; // Service:='ISoapTestservice'; // Port:='ISoapTestPort'; // end; HTTPRIO1.URL:='http://localhost:8080/soap/'; end; procedure Showimg(const i:integer); var mem:TMemoryStream; bytearr:TByteDynArray; AFile:string; isize:integer; begin AFile:=Form2.ListBox1.Items.Strings[i]; bytearr:=(Form2.HTTPRIO1 as ISoapTest).GetFile(AFile,isize); mem:=TMemoryStream.Create; try mem.SetSize(isize); Move(bytearr[0],mem.Memory^,isize); mem.SaveToFile(Afile); Form2.Image1.Picture.LoadFromFile(AFile); finally mem.Free; end; end; procedure TForm2.ListBox1Click(Sender: TObject); var i:integer; begin i:=ListBox1.ItemIndex; Showimg(i); end; end.
说明:
在开发webserver时,尽量减少网络流量,最好不要在HTTPRIO的WSDLLocation属性中直接输入服务端的网址,否则会产生get和post的两次网络回路。
把网页保存下来的wsdl文件放在客户端让HTTPRIO来调用即可,如下面的代码,Service和Port可以查看在客户端生成的单元文件,区分大小写。这样可以减少一次网络回路,调用其它语言写的webservice就可以这样。
with HTTPRIO1 do begin WSDLLocation:='SoapTest.wsdl' ; Service:='ISoapTestservice'; Port:='ISoapTestPort'; end;
另外如果是Delphi写的WebService,则最好把HTTPRIO的 URL写进去,URL和WSDLLocation是互斥的,URL调用时soap已做优化了,所以相对于WSDL,对网络的压力要小些,如果是用URL的话, 则不用写入Service和Port属性。URL的最后可以不带接口名称
WSDL的格式为:http(s)://主机名:端口/运行的程序(虚拟目录名)/wsdl/接口名称, 如示例的WSDL: http://localhot:8080/wsdl/Isoaptest
URL的格式为:http(s)://主机名:端口/运行的程序(虚拟目录名)/Soap/接口名称,如示例的URL:http://localhost:8080/Soap/ISoaptest,其实可以把最后的接口名称消去即可,即http://localhost:8080/soap
如果要处理数据库方面的,则在服务端可以增加 Soap server data module数据模块,放上要访问数据库的组件,如sqlconnection,sqldataset等,在客户端上放上SoapConnection的连接组件,主要是用来连接服务端的数据组件的。soapconnection的url可在客户端产生的接口单元中找到,也可以省去最后的接口名称。
如有不正确敬请指正。