delphi面向服务开发解决方案
delphi面向服务开发解决方案
1)服务接口设计
基于openapi3进行接口设计。面向服务设计的接口,支持跨平台和跨语言,支持任何终端设备。
以《商品资料》资源为例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | unit server.resources.goods; /// <author>cxg 2022-6-8</author> interface uses System.SysUtils, WiRL.Core.Registry, WiRL.Core.Attributes, WiRL.http.Accept.MediaType; type [Path( 'goods' )] TGoods = class [post, path( '/select/{dbid}' ), Produces(TMediaType.APPLICATION_JSON)] function select ( const [PathParam( 'dbid' )] dbid: string ): string ; [post, path( '/insert/{dbid}' ), Produces(TMediaType.APPLICATION_JSON)] function insert( const [PathParam( 'dbid' )] dbid: string ; const [BodyParam] body: TBytes): string ; [post, path( '/update/{dbid}/{goodsid}' ), Produces(TMediaType.APPLICATION_JSON)] function update( const [PathParam( 'dbid' )] dbid: string ; const [PathParam( 'goodsid' )] goodsid: string ; const [BodyParam] body: TBytes): string ; [post, path( '/delete/{dbid}/{goodsid}' ), Produces(TMediaType.APPLICATION_JSON)] function delete( const [PathParam( 'dbid' )] dbid: string ; const [PathParam( 'goodsid' )] goodsid: string ): string ; end; implementation { TGoods } function TGoods.delete( const dbid, goodsid: string ): string ; begin end; function TGoods.insert( const dbid: string ; const body: TBytes): string ; begin end; function TGoods. select ( const dbid: string ): string ; begin end; function TGoods.update( const dbid, goodsid: string ; const body: TBytes): string ; begin end; initialization TWiRLResourceRegistry.Instance.RegisterResource<TGoods>; end. |
从上面的《商品资料》接口可以看出,接口设计完全不依赖框架,即使是不懂技术的产品经理也能设计接口。
在云服务器上部署《服务接口中间件》
客户端浏览器打开:http://42.193.160.160:8080/rest/app/openapi/
即可以在浏览器里面在线查看设计好的服务接口。
2)中间件实现《商品资料》业务逻辑
接口设计好以后,就开始实现《商品资料》的业务逻辑。
首先实现《商品资料》的data-model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //protobuf模板文件 syntax= "proto3" ; package goods; //商品资料 message Goods { string goodsid = 1; //商品编号 string goodsname = 2; //商品名称 double price = 3; //价格 } //商品资料数组 message GoodsArr { repeated Goods Goodss = 1; } //查询条件 message GoodsQuery { string goodsid = 1; //商品编号 string goodsname = 2; //商品名称 } |
用google protobuf实现data-model,目的是为了支持跨语言。目前所有的主流语言都提供工具,根据 .proto模型文件,自动生成本语言的代码。
运行codegen.bat,根据商品资料model文件goods.proto,自动生成对应的PASCAL code。
自动生成的PASCAL商品资料 model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | { Unit pbGoodsMessages.pas } { Generated from goods.proto } { Package Goods } unit pbGoodsMessages; interface uses Grijjy.ProtocolBuffers, SysUtils; { TGoodsRecord } type TGoodsRecord = record [Serialize(1)] Goodsid : String; [Serialize(2)] Goodsname : String; [Serialize(3)] Price : Double; end; { TDynArrayGoodsRecord } type TDynArrayGoodsRecord = array of TGoodsRecord; { TGoodsArrRecord } type TGoodsArrRecord = record [Serialize(1)] Goodss : TDynArrayGoodsRecord; end; { TGoodsQueryRecord } type TGoodsQueryRecord = record [Serialize(1)] Goodsid : String; [Serialize(2)] Goodsname : String; end; implementation end. |
中间件编写业务逻辑,以商品资料查询为例,下面是json序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function goodsQry(url: string ; body: rawbytestring): string ; var db: tdb; pool: tdbpool; arr: tarray< string >; serial: TJsonSerializer; sp: TGoodsrecord; sps: TDynArrayGoodsRecord; i: Integer; err: TResRecord; begin serial := TJsonSerializer.Create; try try arr := url.Split([ '/' ]); pool := GetDBPool(arr[4]); db := pool.Lock; db.qry.Close; db.qry.SQL.Clear; db.qry.SQL.Text := 'select * from tgoods' ; db.qry.Open; SetLength(sps, db.qry.RecordCount); db.qry.First; i := 0; while not db.qry.Eof do begin sp.goodsid := db.qry.FieldByName( 'goodsid' ).AsString; sp.goodsname := db.qry.FieldByName( 'goodsname' ).AsString; sps[i] := sp; inc(i); db.qry.Next; end; Result := serial.Serialize<TDynArrayGoodsRecord>(sps); except on E: Exception do begin err.ok := False; err.err := e.Message; Result := serial.Serialize<TResRecord>(err); end; end; finally pool.Unlock(db); serial.Free; end; end; |
下面是protobuf序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function goodsQry(url: string ; body: tbytes): tbytes; var db: tdb; pool: tdbpool; serial: TgoProtocolBuffer; arr: tarray< string >; dw: TUnitsRecord; sp: TGoodsRecord; sps: pbGoodsMessages.TGoodsArrRecord; i: integer; err: TresRecord; begin serial := TgoProtocolBuffer.Create; try try arr := url.Split([ '/' ]); pool := GetDBPool(arr[4]); db := pool.Lock; db.qry.Close; db.qry.SQL.Clear; db.qry.SQL.Text := 'select * from tgoods' ; db.qry.Open; SetLength(sps.Goodss, db.qry.RecordCount); db.qry.First; i := 0; while not db.qry.Eof do begin sps.Goodss[i].Goodsid := db.qry.FieldByName( 'goodsid' ).AsString; sps.Goodss[i].Goodsname := db.qry.FieldByName( 'goodsname' ).AsString; inc(i); db.qry.Next; end; Result := serial.Serialize<pbGoodsMessages.TGoodsArrRecord>(sps); except on E: Exception do begin err.ok := False; err.err := e.Message; Result := serial.Serialize<TresRecord>(err); end; end; finally pool.Unlock(db); serial.Free; end; end; |
客户端查询
json查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | procedure TForm1.Button1Click(Sender: TObject); //查询 json begin var t: TTablesRecord := TRest.qryJson<TTablesRecord>( '/rest/tables/qry/1' ); //计量单位 FDMemTable1.EmptyDataSet; FDMemTable1.DisableControls; for var dw: TUnitsRecord in t.Unitss do FDMemTable1.AppendRecord([dw.Unitid, dw.Unitname]); FDMemTable1.First; FDMemTable1.EnableControls; //商品资料 ClientDataSet1.EmptyDataSet; ClientDataSet1.DisableControls; for var sp: TGoodsRecord in t.Goodss do ClientDataSet1.AppendRecord([sp.Goodsid, sp.Goodsname]); ClientDataSet1.First; ClientDataSet1.EnableControls; end; |
google protobuf查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | procedure TForm1.Button2Click(Sender: TObject); //查询 protobuf begin var t: TTablesRecord := TRest.qryPB<TTablesRecord>( '/protobuf/tables/qry/1' ); //计量单位 FDMemTable1.EmptyDataSet; FDMemTable1.DisableControls; for var dw: TUnitsRecord in t.Unitss do FDMemTable1.AppendRecord([dw.Unitid, dw.Unitname]); FDMemTable1.First; FDMemTable1.EnableControls; //商品资料 ClientDataSet1.EmptyDataSet; ClientDataSet1.DisableControls; for var sp: TGoodsRecord in t.Goodss do ClientDataSet1.AppendRecord([sp.Goodsid, sp.Goodsname]); ClientDataSet1.First; ClientDataSet1.EnableControls; end; |
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/16358008.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?