DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: jaytang
今日帖子: 1
在线用户: 12
导航: 论坛 -> 文档资料 斑竹:liumazi,ruralboy  
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2013/10/21 14:29:17
标题:
为手机应用开发提供新服务的插件框架 浏览:3119
加入我的收藏
楼主: 1、概述
    服务端插件框架是三层架构中非常有用的一种技术方法,使用此方法可以有效提高业务逻辑层的设计开发效率、增强三层架构系统的适应性和灵活度、更有利于软件的分发部署及维护。另外,使用这种方法进行业务逻辑的设计更有利于团队分工协作开发。
    无论客户端是普通桌面程序,还是web浏览器,或者是移动设备,我们都可以在服务端插件框架的统一规范下,通过设计开发一系列的“插件”(也就是一般所称的“业务逻辑部件”)来为客户端提供有效的服务。如下图所示:
此帖子包含附件:
JPEG 图像
大小:68.8K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2013/10/21 14:31:11
1楼: 2、中间层示例插件代码
   本文给出一个中间层服务端插件为Android手机提供服务的编程示例,供参考、借鉴:

//
// mymobileplugin.pas -- 移动开发服务端插件示例
//          Date: 2013.10.18.
//          Author: Jopher(W.G.Z)
//          Homepage: http://www.quickburro.com/
//
library mymobileplugin;

uses
  FastMM4,
  FastMove,
  SysUtils,
  Classes,
  Windows,
  AnsiStrings,
  QBParcel,
  DllSpread,
  NodeServiceAPI,
  mbpluginapi,
  mbparcel,
  dbclient,
  ADODB,
  DB,
  qbcommon;

{$R *.RES}

//
// 主函数...
function MainFunction(RequestParcel: TQBParcel; ResponseParcel: TQBParcel): boolean;
var
   MBParcel,RetParcel: TMBParcel;
   FunctionId,i,j,k: integer;
   ok: boolean;
   //
   GetList: TGetWebSessionList;
   Cds: TClientDataset;
   Stream: TMemoryStream;
   //
   RawConn: _Connection;
   SysConn: TAdoConnection;
   PoolId,ConnId: integer;
   SysDataset: TAdoDataset;
   DatabaseId,TableName,condition: string;
begin
//
// 读参数...
   MBParcel:=TMBParcel.Create;
   Result:=GetMBRequest(RequestParcel,MBParcel);
   if not Result then
      begin
         FreeAndNil(MBParcel);
         exit;
      end;
   RetParcel:=TMBParcel.Create;
//
// 取功能号并切换...
   FunctionId:=MBParcel.GetIntegerGoods('FunctionId');
   case functionid of
      //
      // 功能1:取在线手机端列表...
      1: begin
          //
          // 调用主服务程序API函数,得到移动会话列表到Cds...
          GetList:=Get_GetWebSessionList(RequestParcel);
          Cds:=TClientDataset.Create(nil);
          Cds.DisableControls;
          try
          ok:=GetList(j);
          except
          ok:=false;
          end;
          if ok then
          begin
          Stream:=mem2Stream(j);
          FreeMemory(j);
          try
          Stream.Position:=0;
          Cds.LoadFromStream(Stream);
          except
          ok:=false;
          end;
          FreeAndNil(Stream);
          end;
          //
          // 写Cds到返回的数据包裹中...
          try
          if ok then
          ok:=RetParcel.PutCdsGoods('WebSessionList',cds);
          RetParcel.PutBooleanGoods('ProcessResult',ok);
          result:=PutMBResponse(RetParcel,ResponseParcel);
          except
          result:=false;
          end;
          FreeAndNil(Cds);
         end;
      //
      // 功能2:计算一个数的阶乘...
      2: begin
          //
          // 取数并计算它的阶乘...
          j:=MBParcel.GetIntegerGoods('X');
          k:=1;
          for i:=1 to j do
          k:=k*i;
          //
          // 返回结果...
          try
          RetParcel.PutIntegerGoods('Y',k);
          RetParcel.PutBooleanGoods('ProcessResult',true);
          result:=PutMBResponse(RetParcel,ResponseParcel);
          except
          result:=false;
          end;
         end;
      //
      // 功能3:读一个数据集...
      3: begin
          //
          // 取参数...
          DatabaseId:=MBParcel.GetStringGoods('DatabaseId');
          TableName:=MBParcel.GetStringGoods('TableName');
          Condition:=MBParcel.GetStringGoods('Condition');
          //
          // 通过主服务程序的API函数分配数据源...
          ok:=GetAdoConnection(RequestParcel,ansistring(DatabaseId),sysconn,rawconn,poolid,connid);
          if not ok then
          begin
          try
          RetParcel.PutBooleanGoods('ProcessResult',ok);
          result:=PutMBResponse(RetParcel,ResponseParcel);
          except
          result:=false;
          end;
          FreeAndNil(RetParcel);
          FreeAndNil(MBParcel);
          exit;
          end;
          //
          // 读数据集...
          SysDataset:=TAdoDataset.Create(nil);
          SysDataset.DisableControls;
          SysDataset.Connection:=SysConn;
          SysDataset.CommandTimeout:=60;
          SysDataset.EnableBCD:=false;
          if Condition='' then
          SysDataset.CommandText:='SELECT * FROM '+tablename
          else
          SysDataset.CommandText:='SELECT * FROM '+tablename+' WHERE '+condition;
          try
          SysDataset.Active:=true;
          ok:=true;
          except
          ok:=false;
          end;
          //
          // 数据集转Cds...
          if ok then
          begin
          Cds:=TClientDataset.Create(nil);
          try
          Cds.Data:=qbcommon.DatasetToCdsData(SysDataset);
          ok:=true;
          except
          ok:=qbcommon.GetCdsFromAdo(SysDataset,Cds);
          end;
          if not ok then
          FreeAndNil(Cds);
          end;
          FreeAndNil(SysDataset);
          FreeAdoConnection(RequestParcel,SysConn,RawConn,PoolId,ConnId);
          //
          // 返回结果...
          try
          if ok then
          begin
          ok:=RetParcel.PutCdsGoods('ClientDataset',cds);
          FreeAndNil(Cds);
          end;
          RetParcel.PutBooleanGoods('ProcessResult',ok);
          result:=PutMBResponse(RetParcel,ResponseParcel);
          except
          result:=false;
          end;
         end;
   end;
//
// 完成,释放对象...
   FreeAndNil(RetParcel);
   FreeAndNil(MBParcel);
end;

//
// 导出函数,应用程序员不用改动...
function WebpageProcess(InParcelPtr: integer; var OutParcelPtr: integer): boolean; stdcall;
var
   aInParcel: TQBParcel;
   aOutParcel: TQBParcel;
begin
   try
      aInParcel:=TQBParcel(InParcelPtr);
   except
      result:=false;
      exit;
   end;
   aOutParcel:=TQBParcel.Create;
   Result:=MainFunction(aInParcel,aOutParcel);
   if aOutParcel.GoodsCount<=0 then
      OutParcelPtr:=0
   else
      OutParcelPtr:=Parcel2Mem(aOutParcel);
   aOutParcel.free;
end;

exports
   WebpageProcess;

begin
end.

对此程序build后面生成.dll文件,复制到中间件的插件目录下,即可被手机端程序调用


3、来看客户端测试程序设计时界面
此帖子包含附件:
JPEG 图像
大小:105.3K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2013/10/21 14:32:07
2楼: 4、客户端测试程序代码

unit main;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  mbcommon, MBConnection, FMX.Layouts, FMX.Memo, MBParcel, Data.DB,
  Datasnap.DBClient;

type
  TForm1 = class(TForm)
    StyleBook1: TStyleBook;
    Panel1: TPanel;
    CornerButton1: TCornerButton;
    CornerButton2: TCornerButton;
    CornerButton3: TCornerButton;
    Panel2: TPanel;
    CornerButton5: TCornerButton;
    CornerButton6: TCornerButton;
    CornerButton4: TCornerButton;
    Memo1: TMemo;
    MBConn: TMBConnection;
    RPC: TMobileRPC;
    Cds: TClientDataSet;
    procedure CornerButton3Click(Sender: TObject);
    procedure CornerButton5Click(Sender: TObject);
    procedure CornerButton2Click(Sender: TObject);
    procedure CornerButton4Click(Sender: TObject);
    procedure CornerButton6Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

//
// 退出...
procedure TForm1.CornerButton2Click(Sender: TObject);
begin
   if mbconn.Connected then
      mbconn.Disconnect;
   halt;
end;

//
// 连接、断开...
procedure TForm1.CornerButton3Click(Sender: TObject);
begin
   if CornerButton3.text='连接' then
      begin
         if mbconn.connect then
          begin
          CornerButton3.text:='断开';
          memo1.lines.add('连接服务器成功,请继续测试!');
          memo1.lines.add('SessionId='+MBConn.WebSessionId);
          memo1.Lines.Add('');
          end
         else
          memo1.lines.add('连接服务器失败,无法继续测试!');
      end
   else
      begin
         mbconn.disconnect;
         CornerButton3.text:='连接';
         memo1.lines.add('与服务器断开!');
      end;
end;

//
// 功能测试2:计算阶乘...
procedure TForm1.CornerButton4Click(Sender: TObject);
var
   InParcel,OutParcel: TMBParcel;
   y: integer;
begin
   InParcel:=TMBParcel.Create;
   InParcel.PutIntegerGoods('FunctionId',2);
   InParcel.PutIntegerGoods('X',10);
   OutParcel:=TMBParcel.Create;
   if RPC.Call('mymobileplugin.asq',inparcel,outparcel) then
      begin
         if OutParcel.GetBooleanGoods('ProcessResult') then
          begin
          y:=OutParcel.GetIntegerGoods('Y');
          memo1.Lines.Add('远程计算成功!');
          memo1.Lines.Add('10的阶乘='+inttostr(y));
          memo1.Lines.Add('');
          end
         else
          memo1.Lines.Add('插件处理任务失败!');
      end
   else
      memo1.Lines.Add('远过程调用失败!'+RPC.LastError);
   FreeAndNil(InParcel);
   FreeAndNil(OutParcel);
end;

//
// 功能调用测试1:取会话列表...
procedure TForm1.CornerButton5Click(Sender: TObject);
var
   InParcel,OutParcel: TMBParcel;
begin
   InParcel:=TMBParcel.Create;
   InParcel.PutIntegerGoods('FunctionId',1);
   OutParcel:=TMBParcel.Create;
   if RPC.Call('mymobileplugin.asq',inparcel,outparcel) then
      begin
         if OutParcel.GetBooleanGoods('ProcessResult') then
          begin
          OutParcel.GetCDSGoods('WebSessionList',Cds);
          memo1.Lines.Add('取会话列表成功!会话数='+inttostr(cds.RecordCount));
          while not cds.Eof do
          begin
          memo1.Lines.Add('SessionId='+trim(Cds.FieldByName('WebSessionId').AsString));
          memo1.Lines.Add(trim(Cds.FieldByName('AppName').AsString)+'|'+trim(Cds.FieldByName('ClientName').AsString)+'|'+trim(Cds.FieldByName('ClientAddress').AsString));
          memo1.Lines.Add('');
          Cds.Next;
          end;
          Cds.Close;
          end
         else
          memo1.Lines.Add('插件处理任务失败!');
      end
   else
      memo1.Lines.Add('远过程调用失败!'+RPC.LastError);
   FreeAndNil(InParcel);
   FreeAndNil(OutParcel);
end;

//
// 功能测试3:读数据表...
procedure TForm1.CornerButton6Click(Sender: TObject);
var
   InParcel,OutParcel: TMBParcel;
begin
   InParcel:=TMBParcel.Create;
   InParcel.PutIntegerGoods('FunctionId',3);
   InParcel.PutStringGoods('DatabaseId','testdb');
   InParcel.PutStringGoods('TableName','Customers');
   InParcel.PutStringGoods('Condition','');
   OutParcel:=TMBParcel.Create;
   if RPC.Call('mymobileplugin.asq',inparcel,outparcel) then
      begin
         if OutParcel.GetBooleanGoods('ProcessResult') then
          begin
          OutParcel.GetCDSGoods('ClientDataset',Cds);
          memo1.Lines.Add('读数据表成功!记录数='+inttostr(cds.RecordCount));
          memo1.Lines.Add('首记录:CustomerId='+trim(Cds.FieldByName('CustomerId').AsString));
          memo1.Lines.Add('CompanyName='+trim(Cds.FieldByName('CompanyName').AsString));
          memo1.Lines.Add('');
          Cds.Close;
          end
         else
          memo1.Lines.Add('插件处理任务失败!');
      end
   else
      memo1.Lines.Add('远过程调用失败!'+RPC.LastError);
   FreeAndNil(InParcel);
   FreeAndNil(OutParcel);
end;

end.


5、运行效果
此帖子包含附件:
JPEG 图像
大小:53.8K
----------------------------------------------
樵夫的大马甲
作者:
男 jopher3 (樵夫的马六甲) ▲▲▲▲▲ -
普通会员
2013/10/21 14:32:32
3楼: 6、结语

1)、可使用此方法不断为移动开发提供新的、相同通用的服务,故越到后来,开发的效率越高

2)、可使用此方法封装应用项目相关的业务逻辑处理过程,让手机端程序设计更简单

3)、由于Web插件只要复制到插件目录即可调用,故所谓插件的“热插拔”问题迎刃而解

4)、通过TMBParcel类传递入口参数、出口参数,无需再自己作参数组装和解析,开发效率和可靠性更高
----------------------------------------------
樵夫的大马甲
作者:
男 msfm (清洁工) ★☆☆☆☆ -
盒子活跃会员
2013/10/22 8:25:46
4楼: mark
----------------------------------------------
-
作者:
男 shileizi (sl) ★☆☆☆☆ -
普通会员
2014/3/18 11:01:49
5楼: mark
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行128.9063毫秒 RSS