• REST easy with kbmMW #21 – Delphi client stubs


    在之前的博文中,我提到了存根生成器框架,将具有生成Delphi客户端存根代码的能力,使得开发Delphi智能客户端变的更容易,完全支持编译时的类型检查和IDE类/属性帮助。

    本不想把这个新功能包含在即将发布的kbmMW版本中,但我无法自控.... 必须添加它才能生成相当完整的客户端存根代码。

    存根生成器将生成普通的Delphi代码,需要kbmMW智能客户端功能进行编译。但代码已完成,并包含所需的所有单元引用。如果您使用的是包含对象的自定义单元,则必须将这些单元与生成的存根代码一起提供给Delphi客户端开发人员。

    除OpenAPI支持外,SimpleInvocation服务器还支持通过REST接口直接返回Delphi存根代码。

    让我们称之为:http://localhost:888/myserver/delphi

    这将返回给你一个类似于这样的对话框:

    保存它,将得一个单元文件:

    unit uSMARTDEMO;
    
    interface
    
    uses
      kbmMWGlobal,
      kbmMWSmartUtils,
      kbmMWSmartClient,
      kbmMWClient,
      kbmMWClientDataset
      ,uObjects
      ,System.Generics.Collections
      ,kbmMWDateTime
      ,kbmMemTable
      ;
    
    type
      // Name.......: SMARTDEMO
      // Version....: kbmMW_1.0
      // Abstract...: HTTP smart service supp. FastCGI
      // Description: Smart HTTP service (with optional FastCGI and URL rewrite support) which use annotations for publishing methods for both regular clients and REST clients.
      //-------------------------------------
      TSMARTDEMO = class
      private
         FClient:IkbmMWSmartClient;
      public
         constructor Create(const ATransport:TkbmMWCustomClientTransport); overload; virtual;
         constructor Create(const AConnectionPool:TkbmMWClientConnectionPool); overload; virtual;
         constructor Create(const AClient:IkbmMWSmartClient); overload; virtual;
         function StorePerson(const APerson:TPerson):Integer;
         function EchoPerson(const APerson:TPerson):TPerson;
         function EchoURL:string;
         function AddNumbers(const AValue1:Integer; const AValue2:Integer):Integer;
         function EchoString(const AString:string):string;
         function GetPersons:TObjectList<uObjects.TPerson>;
         function GetPerson(const id:Integer):TPerson;
         function ServerNow1:TkbmMWDateTime;
         function ServerNow2:TDateTime;
         function GetPerson3:TPerson3;
         function StorePerson3(const APerson:IPerson2):Integer;
         function StorePerson2(const APerson:TPerson):Integer;
         function ReverseString(const AString:string):string;
         function EchoBytes(const ABytes:TArray<System.Byte>):TArray<System.Byte>;
         function GetMemTable:TkbmMemTable;
         function ReverseStringFromConfig:string;
      end;
    
    implementation
    
    constructor TSMARTDEMO.Create(const ATransport:TkbmMWCustomClientTransport);
    begin
         inherited Create;
         FClient:=TkbmMWSmartRemoteClientFactory.GetClient(ATransport,'SMARTDEMO');
    end;
    
    constructor TSMARTDEMO.Create(const AConnectionPool:TkbmMWClientConnectionPool);
    begin
         inherited Create;
         FClient:=TkbmMWSmartRemoteClientFactory.GetClient(AConnectionPool,'SMARTDEMO');
    end;
    
    constructor TSMARTDEMO.Create(const AClient:IkbmMWSmartClient);
    begin
         inherited Create;
         FClient:=AClient;
    end;
    
    function TSMARTDEMO.StorePerson(const APerson:TPerson):Integer;
    var
       v0:variant;
    begin
         v0:=Use.AsVariant(APerson,false);
         Result:=FClient.Service.StorePerson(v0);
    end;
    
    function TSMARTDEMO.EchoPerson(const APerson:TPerson):TPerson;
    var
       v0:variant;
    begin
         v0:=Use.AsVariant(APerson,false);
         Result:=Use.AsMyObject<TPerson>(FClient.Service.EchoPerson(v0));
    end;
    
    function TSMARTDEMO.EchoURL:string;
    begin
         Result:=FClient.Service.EchoURL;
    end;
    
    function TSMARTDEMO.AddNumbers(const AValue1:Integer; const AValue2:Integer):Integer;
    begin
         Result:=FClient.Service.AddNumbers(AValue1,AValue2);
    end;
    
    function TSMARTDEMO.EchoString(const AString:string):string;
    begin
         Result:=FClient.Service.EchoString(AString);
    end;
    
    function TSMARTDEMO.GetPersons:TObjectList<uObjects.TPerson>;
    begin
         Result:=Use.AsMyObject<TObjectList<uObjects.TPerson>>(FClient.Service.GetPersons);
    end;
    
    function TSMARTDEMO.GetPerson(const id:Integer):TPerson;
    begin
         Result:=Use.AsMyObject<TPerson>(FClient.Service.GetPerson(id));
    end;
    
    function TSMARTDEMO.ServerNow1:TkbmMWDateTime;
    begin
         Result:=Use.AsType<TkbmMWDateTime>(FClient.Service.ServerNow1);
    end;
    
    function TSMARTDEMO.ServerNow2:TDateTime;
    begin
         Result:=FClient.Service.ServerNow2;
    end;
    
    function TSMARTDEMO.GetPerson3:TPerson3;
    begin
         Result:=Use.AsMyObject<TPerson3>(FClient.Service.GetPerson3);
    end;
    
    function TSMARTDEMO.StorePerson3(const APerson:IPerson2):Integer;
    var
       v0:variant;
    begin
         v0:=Use.AsVariant(APerson);
         Result:=FClient.Service.StorePerson3(v0);
    end;
    
    function TSMARTDEMO.StorePerson2(const APerson:TPerson):Integer;
    var
       v0:variant;
    begin
         v0:=Use.AsVariant(APerson,false);
         Result:=FClient.Service.StorePerson2(v0);
    end;
    
    function TSMARTDEMO.ReverseString(const AString:string):string;
    begin
         Result:=FClient.Service.ReverseString(AString);
    end;
    
    function TSMARTDEMO.EchoBytes(const ABytes:TArray<System.Byte>):TArray<System.Byte>;
    var
       v0:variant;
    begin
         v0:=Use.AsVariant(ABytes);
         Result:=Use.AsBytes(FClient.Service.EchoBytes(v0));
    end;
    
    function TSMARTDEMO.GetMemTable:TkbmMemTable;
    begin
         Result:=Use.AsMyObject<TkbmMemTable>(FClient.Service.GetMemTable);
    end;
    
    function TSMARTDEMO.ReverseStringFromConfig:string;
    begin
         Result:=FClient.Service.ReverseStringFromConfig;
    end;
    
    end.

    您可能已经注意到,SmartInvocation服务中已使用kbmMW_Method属性标记的所有方法都在存根代码中生成了。

    存根生成器自动检测编译所需的各种其他单元,如kbmMemTable和uObjects,并添加到uses子句中。

    那么我们是如何从REST接口返回存根代码的呢?

    在包含REST服务的单元中,我们只添加了一个返回字符串的函数,并使其可以从REST访问。

         [kbmMW_Rest('method:get, path: "delphi", responseMimeType:"text/plain"')]
         function DelphiAPI:string;

    功能实现非常简单

    // Return Delphi stub.
    function TkbmMWCustomService2.DelphiAPI:string;
    var
       unitName:string;
    begin
         // Return Delphi client stub unit for all methods in this service marked with
         // kbmMW_Method attribute.
         // Add 'servers: [ "url1", "url2",.. "urln" ]' to ASettings if you want to
         // embed server location information in the comments of the returned unit.
         Result:=TkbmMWSmartDelphiStubGenerator.GenerateDelphi('',self,unitName);
         SetResponseFileName(unitName);
    end;

    显然你可以从你想要的任何单位调用GenerateDelphi,你可以参考任何kbmMW Smartservice。GenerateDelphi的第一个参数是可选的单元命名前缀。如果未指定任何内容,则单元名将以“u”开头。在这种情况下,我们将收到一个名为uSMARTDEMO.pas的文件,因为它是在Delphi客户端存根中描述的SMARTDEMO服务。

    让我们尝试在客户端中使用生成的代码。我们创建了一个基于VCL的标准客户端(kbmMW也可以与Firemonkey一起使用,以便跨平台使用)。我们添加了一个客户端传输(在本例中为TkbmMWTCPIPIndyClientTransport),一个客户端连接池和一些将激活这些调用的按钮。此外,还有一个编辑框,用于键入我们要连接的服务器的IP地址(如果它未在本地主机上运行)。

    然后确保将uSMARTDEMO.pas添加到单元的uses子句中。现在我们可以访问存根代码,这样可以轻松调用kbmMW应用程序服务器托管的智能服务。

    StorePerson 1的事件处理程序可能如下所示:

    procedure TForm1.Button1Click(Sender: TObject);
    var
       i:integer;
       person:IPerson2;
       demo:TSMARTDEMO;
    begin
         Transport.Host:=eIP.Text;
    
         demo:=TSMARTDEMO.Create(Transport);
         try
            person:=TPerson2.Create;
            person.Name:='Frank Borland Jr';
            person.Address:='California';
            person.Age:=45;
            i:=demo.StorePerson3(person);
         finally
            demo.Free;
         end;
    end;

    这里的示例使用我们想要使用的传输实例化TSMARTDEMO实例。如果我们愿意,我们可以提供连接池或智能客户端。存根代码支持所有3种变体。

    此按钮显示如何将接口对象发送到服务器。

    StorePerson 2的事件处理程序可能如下所示:

    procedure TForm1.Button2Click(Sender: TObject);
    var
       person:TPerson;
       i:integer;
       demo:TSMARTDEMO;
    begin
         Transport.Host:=eIP.Text;
    
         demo:=TSMARTDEMO.Create(Transport);
         try
            person:=TPerson.Create;
            try
               person.Name:='Trudy Borland';
               person.Address:='California';
               person.Age:=45;
               i:=demo.StorePerson(person);
            finally
               person.Free;
            end;
         finally
            demo.Free;
         end;
    end;

    略有不同的是,我们为呼叫提供了一个对象。通话结束后,我们释放了对象。所有完全正常的Delphi代码。

    Simple Calls的事件处理程序可能如下所示:

    procedure TForm1.Button3Click(Sender: TObject);
    var
       dt1:TkbmMWDateTime;
       dt2:TDateTime;
       s:string;
       i:integer;
       demo:TSMARTDEMO;
       ba,ba1:TArray<System.Byte>;
    begin
         Transport.Host:=eIP.Text;
    
         demo:=TSMARTDEMO.Create(Transport);
         try
            s:=demo.EchoString('abc');
    
            SetLength(ba1,5);
            ba1[0]:=99;
            ba1[1]:=98;
            ba1[2]:=97;
            ba1[3]:=96;
            ba1[4]:=95;
            ba:=demo.EchoBytes(ba1);
    
            i:=demo.AddNumbers(34,7);
            dt1:=demo.ServerNow1;
            dt2:=demo.ServerNow2;
         finally
            demo.Free;
         end;
    end;

    它显示了发送和接收的各种类型。

    GetPerson的事件处理程序可能如下所示:

    procedure TForm1.Button4Click(Sender: TObject);
    var
       person:TPerson;
       person3:TPerson3;
       persons:TObjectList<TPerson>;
       demo:TSMARTDEMO;
    begin
         Transport.Host:=eIP.Text;
    
         demo:=TSMARTDEMO.Create(Transport);
         try
            person:=demo.GetPerson(1);
            person.Free;
    
            person3:=demo.GetPerson3;
            person3.Free;
    
            persons:=demo.GetPersons;
            persons.Free;
         finally
            demo.Free;
         end;
    end;

    再次......只显示如何接收各种类型的对象(不使用kbmMWNullable的常规对象,使用kbmMWNullable的对象和对象列表)。

    最后,事件处理程序GetMemTable可能如下所示:

    procedure TForm1.Button5Click(Sender: TObject);
    var
       mt:TkbmMemtable;
       demo:TSMARTDEMO;
    begin
         Transport.Host:=eIP.Text;
    
         demo:=TSMARTDEMO.Create(Transport);
         try
            mt:=demo.GetMemTable;
            mt.Free;
         finally
            demo.Free;
         end;
    end;

    此示例显示如何在服务器上生成包含5条记录的内存表实例,从服务器返回到客户端。

    在Delphi中制作高级应用程序服务器是否更容易?Delphi通过REST或本机Delphi代码支持各种客户端?我不这么认为

    所以......如果你喜欢你所看到的,请分享这个词。转发博客帖子,让其他人了解该产品!

    https://components4developers.blog/2019/01/13/rest-easy-with-kbmmw-21-delphi_client_stubs/

  • 相关阅读:
    java包装类的缓存机制(转)
    分布式事务的思考(转)
    分布式事务框架介绍与使用案例
    java 内部类、匿名内部类
    spring cloud应用
    Oralce学习笔记(六)
    部署CentOS虚拟机集群
    商品详情页系统架构
    Oracle学习笔记(五)
    hystrix完成对redis访问的资源隔离
  • 原文地址:https://www.cnblogs.com/kinglandsoft/p/rest-easy-with-kbmmw-21-delphi-client-stubs.html
Copyright © 2020-2023  润新知