需要从两方面来说: 一方面,需要稳定、强大、开发简便、维护方便的“服务端业务容器”,有的又称“软总线”、“插件框架”、“插件容器”等等; 另一方面,客户端,则需要对应封装到位、适用面广、使用简单的调用手段——Delphi VCL控件/FireMonkey控件/JsonRPC/XmlRPC/AJAX等。 在这方面,QuickBurro自然也是走在前列,若干年前就已经很强大,如今更是: 一、服务端支持C/S三层插件、Web插件、移动服务插件、WebSocket服务插件等多种类型的插件;支持单线程/多线程调用方式;支持同步/异步调用模式;支持计划任务形式的主动激发;支持立即返回/驻留模式;支持预加载/延迟卸载机制;支持插件API入口注册与横向调用;支持调用大量的主服务API函数;支持热插拔/远程插拔;支持HTTP/HTTPS/TCP/WebSocket多种通信协议... 二、客户端控件:VCL下提供专门的基于TCP协议和HTTP协议的RPC控件TDllPlugin、提供基于HTTPS实现的Web插件调用控件TQBHttps,只要给出服务端部署的插件名、设定好控件属性、准备好调用参数,就可以方便调用,调用结果也可以方便进行反序列化处理; FireMonkey下,提供TMBRpc/TMBHttps两个专门进行远过程调用的控件,也一样能轻松进行BinaryRPC/JsonRPC/XmlRPC等调用; 而Web前端,通过AJAX进行RPC调用,一样简单方便。 三层的概念一直有争议。我个人的看法是从负载均衡,数据库隔离来说,三层有它 的价值。至于传SQL也未尝不可,只是要防止sql注入的问题。 曾有一个时期,言必称三层,把一些简单的局域网应用也硬生生抽一个三层出来,我觉得还不如直接传sql呢。 倒是web程序就是天然的三层,你不会在客户端直接传sql吧。 我觉得要考虑的是用三层解决什么问题。而不是为三层而三层 我觉得要考虑的是用三层解决什么问题?我认为主要是解决数据库连接池和网络安全域两方面的考虑,兼顾两层、三层语法尽量一直(两层易于改为三层),中间层只转发sql而不进行逻辑编程(降低程序复杂度、避免总改中间层而出现bug),没有上真三层、假三层之分。 http://download.csdn.net/detail/runsheng678/4812549 以前的例子,已改到Delphi 10 seattle下了 1、业务逻辑经常变而接口形式不变的、或后续可能有新的替代方案的处理过程 2、需要与大量数据打交道、不适合客户端进行的处理过程(比如汇总、报表生成等) 3、需要加强安全性控制、保护知识产权等权益的处理过程 4、需要排队处理的业务逻辑 5、需要与服务端数据库之外的其他资源有交互的过程 6、相对通用、适合服务端封装为可复用模块的 7、涉及服务端系统集成、与周边系统有接口的业务 8、需要服务端主动处理并反向推送信息给客户端的任务 9、服务端实现对提高系统性能、减少消耗、提高可靠性有利的业务逻辑 ... ---------- 类似这些,我都会做服务端业务逻辑模块,客户端来调用。 至于是否客户端写SQL语句,感觉没必要纠结,非常简单明确的业务处理,没必要迂腐地要弄个专用的服务端模块再来调用实现,毕竟研发成本也是重要的考虑因素。 而注入什么的,对于编译型开发工具Delphi来说,感觉不是个很严重的问题。 ---------------------------------------------- 我的做法,是把 SQL语句写在 服务器端(其实是保存到数据库中); 客户端只需要 传递一个 序号(对应某SQL语句在数据表的序号),和一些参数传到服务器端就好。其它的交给服务器处理了,然后再把结果返回来; 例从服务器获取数据: function dm_sys.GetData(const SQL_XH: Integer ;Param:array of string): _Recordset; var V,SendV:OLEVariant; i,n : Integer; AR:_Recordset; AStream:_Stream; MS1:TMemoryStream; P:Pointer; begin n := Length(Param); SendV := VarArrayCreate([0,n],varOleStr); for I := Low(Param) to High(Param) do SendV[i] := Param[i]; try V:=Disp_Fun.ProF_ReadAdoData2(SQL_XH,n,SendV); MS1:=TMemoryStream.Create; try MS1.Size:=VarArrayHighBound(V,1)+1; P:=VarArrayLock(V); try Move(P^,MS1.Memory^,MS1.Size); finally VarArrayUnLock(V); end; V:=VarArrayCreate([0,MS1.Size-1],varByte); P:=VarArrayLock(V); try Move(MS1.Memory^,P^,MS1.Size); finally VarArrayUnLock(V); end; finally FreeAndNil(MS1); end; AStream:=CoStream.Create; AStream.Open(EmptyParam,adModeUnknown,adOpenStreamUnspecified, '', ''); AStream.Type_:=adTypeBinary; AStream.Write(V); AR:=_Recordset(CoRecordset.Create); AStream.Position:=0; AR.Open(AStream,EmptyParam,adOpenUnspecified, adLockUnspecified, -1); Result:=ADOInt._Recordset(AR); except on E:Exception do begin ShowErrorMessage(E.Message); end; end; end; 如果有那种特殊情况在要客户端传递SQL语句的,就加密传去就好。 |
|