WebService的一些设计

原来做过webservice,后来忘记了,今天又学了一下,做个笔记,以供以后浏览。

WebService是以服务端给用户端提供接口来调用的。用Delphi开发WebService时有以下几个步骤:

以下为DelphiXE3开发的WebService,服务端提供目录下的文件让客户端查询,在客户端会显示所选择的文件,以图像文件为例

一、服务端

  1.在菜单"File"->"New"->"Other"->"WebService"中点选,如下图

WebService的一些设计_第1张图片

2.建立服务端模型,我们先以第一种为例,这样可以调试,以后可以改成其它格式

   WebService的一些设计_第2张图片WebService的一些设计_第3张图片

3.建立对外接口模板(Soaptest)

WebService的一些设计_第4张图片

4.在接口和实现接口的类中加入以下函数并实现它(GetFileNames是列出所有目录下的png文件,GetFile是把要显示的文件传递给客户端)

WebService的一些设计_第5张图片

接口实现的代码:

{ 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的文件

WebService的一些设计_第6张图片WebService的一些设计_第7张图片

点击ISoapTest[WSDL]连接得到如下图片

WebService的一些设计_第8张图片

 

6.保存上面的网页并命名为wsdl格式的文件,用于客户端调用

二、开发客户端

1.建立普通的应用程序,并在界面上放上HTTPRIO组件,用于调用服务端接口函数。如下图:listbox显示客户端的文件名,右边为image用于显示点选 的图片

WebService的一些设计_第9张图片

2.在菜单“Component->Import WSDL”打开一界面,在location中选择你刚才保存的wsdl文件,用于产生接口单元(记着一定要打开服务端),并保存到客户端,让客户端引用

WebService的一些设计_第10张图片

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

 

如有不正确敬请指正。

 

 

你可能感兴趣的:(webservice)