zoukankan      html  css  js  c++  java
  • 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;
    
    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可在客户端产生的接口单元中找到,也可以省去最后的接口名称。

    如有不正确敬请指正。

  • 相关阅读:
    2021-4-1 日报博客
    2021-3-31 日报博客
    2021-3-30 日报博客
    2021-3-29 日报博客
    2021-3-27 周报博客
    java
    周末总结六
    java
    java
    java
  • 原文地址:https://www.cnblogs.com/yagzh2000/p/3018679.html
Copyright © 2011-2022 走看看