首页 > 代码库 > WebService的一些设计

WebService的一些设计

原来做过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;interfaceuses 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;interfaceuses  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可在客户端产生的接口单元中找到,也可以省去最后的接口名称。

 

如有不正确敬请指正。

WebService的一些设计