主题:讲解三层代码讲解--第三课(*****) DATE:2004-05-28

主题:讲解三层代码讲解--第三课(*****)
主讲:A1
时间:2004-05-28 15:00

2004-05-28 15:02:12 烟灰缸
大家好。

2004-05-28 15:18:20 烟灰缸
我把Demo1简单的说一下,这样对下面才比较好讲。

2004-05-28 15:18:26 烟灰缸
procedure TForm1.Button3Click(Sender: TObject);
begin
  cdsDemo1.OpenStoreProc(100001);
end;

2004-05-28 15:19:03 烟灰缸
简单的说,cdsDemo1是通知swServer说:我要100001号数据。

2004-05-28 15:19:18 烟灰缸
这一点大家都应该看得明白吧。

2004-05-28 15:19:52 斜阳
100001好像让服务端执行的是一个存储过程啊

2004-05-28 15:21:24 烟灰缸
实际是返回的也是Data,只不过是统一由OpenStoreProc来做而已

2004-05-28 15:22:17 斜阳
我这里反不回来,因为没有那个表和那个存储过程

2004-05-28 15:22:37 烟灰缸
实际上也这下面这一段是一样的
  cdsDemo1.BeginOle;
  cdsDemo1.Ole.StoreProcIndex := 100001;
  cdsDemo1.Ole.Action := acOpenStoreProc;
  cdsDemo1.OpenData(dmDefault);

2004-05-28 15:25:23 烟灰缸
意思更明了,
(1).cdsDemo1清除参数
(2).Ole参数指定存取过的的序号为100001
(3).Ole参数指定服务层的“小规则”为acOpenStoreProc
(4).指定“规则”为dmDefault,并打开返回数据

2004-05-28 15:25:54 烟灰缸
dmDefault对应到dmDefault.dll

2004-05-28 15:26:06 八戒公子
噢,原来是调用了存储过程,然后返回数据。

2004-05-28 15:27:08 烟灰缸
存取过程不在SQLSERVER里,而是在服务层动态中生成。

2004-05-28 15:27:55 烟灰缸
第二个
  cdsDemo2.BeginOle;
  cdsDemo2.Ole['@mm_State'] := edit1.Text;
  cdsDemo2.OpenStoreProc(100002);

2004-05-28 15:28:04 八戒公子
存储过程应该是存储在服务器中的啊。

2004-05-28 15:28:27 斜阳
怪不得我得不到数据

2004-05-28 15:28:29 烟灰缸
跟上面的差不多,只是指定了参数。

2004-05-28 15:30:29 烟灰缸
  if cdsDemo3.Modified then cdsDemo3.Post;
  if cdsDemo3.ChangeCount > 0 then
    begin
      Cmd.BeginOle;
      Cmd.Ole['Delta'] := cdsDemo3.Delta;
      Cmd.Ole['KeyField'] := 'title_id';
      Cmd.Ole['TableName'] := 'titles';
      if Cmd.ApplyUpdates then
        begin
          cdsDemo3.MergeChangeLog;
          ShowMessage('Update Success');
        end;
    end;

2004-05-28 15:30:40 烟灰缸
这个第三点

2004-05-28 15:33:22 烟灰缸
第三点的意思是,更新cdsDemo3数据

2004-05-28 15:34:08 烟灰缸
最后,我们看看如何用到dmDemo.dll里的第一条规则

2004-05-28 15:34:16 烟灰缸
  Cmd.BeginOle;
  Cmd.Ole.Action:=1;
  Cmd.Execute(dmFirstDemo);
  ShowMessage(Cmd.LastMsg);

2004-05-28 15:34:45 llyygg
如果服务器端改变了客户端提交的数据,那客户端在提交以后会得到这个数据吗?

2004-05-28 15:35:51 烟灰缸
Cmd.Ole.Action指定“小规则”为1  (请参照dmDemo.prj)
Cmd.Execute(dmFirstDemo)指定规则模块,并执行

2004-05-28 15:36:15 烟灰缸
你是指那里改变了?

2004-05-28 15:36:55 llyygg
服务器端改变客户端提交的数据.就是提交的Delta

2004-05-28 15:38:02 llyygg
比如某条记录的操作时间在服务器端改变了,客户端提交完数据后MergeChangelog可以的到吗.

2004-05-28 15:39:16 烟灰缸
如果在规则中有改变Delta,则可以把改变后的数据返回,有一个技七在里面。

2004-05-28 15:41:34 烟灰缸
这一点还是晚一点再说,要不就会象竹子一样,越讲就越长了。。。

2004-05-28 15:43:05 烟灰缸
课间休息5分钟,大家可以先问问关于这个Demo1.prj的问题,但先别问swServer的问题,因为下面会开始讲。

2004-05-28 15:44:31 llyygg
我觉得应该先讲服务器端的,客户端涉及的都是调用,服务器端明白了,客户端其实就很简单了,没有什么内容,我觉得.

2004-05-28 15:45:34 烟灰缸
这里就是先要知道,客户端是如何得到数据的,服务层才好开讲。

2004-05-28 15:46:51 烟灰缸
新来的朋友可以先看看以往的记录,之前有讨论过了。

2004-05-28 15:47:19 dana
为什么你不用Clientdataset 而要用你写的HMClientCommand ?

2004-05-28 15:47:49 llyygg
封装了很多操作,不用写重复的代码.

2004-05-28 15:47:55 烟灰缸
你可以不用HMClientCommand,我只是为了方便而已。

2004-05-28 15:48:22 松鼠
封装了哪些东东,比如呢

2004-05-28 15:49:02 烟灰缸
一时也说不清楚,打开原代码看一下吧。

2004-05-28 15:50:26 烟灰缸
下面,继续讲dmDemo.prj

2004-05-28 15:50:41 烟灰缸
请大家打开。

2004-05-28 15:52:31 烟灰缸
其实,我总的思路是,让后台开发人员只关心“规则”而不用去关心“事务和数据库”

2004-05-28 15:54:01 烟灰缸
请大家看看我们的第一条“小规则”Action1

2004-05-28 15:54:56 烟灰缸
刚才我们要讲到客户端的
  Cmd.Ole.Action:=1;
  Cmd.Execute(dmFirstDemo);
 

2004-05-28 15:55:06 烟灰缸
它指的就是这里。

2004-05-28 15:55:29 烟灰缸
    Service.BeginTrans;
    StoreProc.LoadFromStore(100006);
    StoreProc['@mm_id'] := '1389';
    StoreProc['@mm_pay'] := 1.15;
    Service.Execute(StoreProc.SqlLanguage);
    StoreProc['@mm_id'] := '0877';
    StoreProc['@mm_pay'] := 0.88;
    Service.Execute(StoreProc.SqlLanguage);
    Service.CommitTrans;
    Service.ReceiveDataWithNoData;

2004-05-28 15:56:40 烟灰缸
StoreProc是存取过程生成器,他取得100006号语句,并在些规则里指定参数

2004-05-28 15:57:37 烟灰缸
客户端并不知道此规则给的是什么样的参数,而且它也不关心

2004-05-28 15:58:43 烟灰缸
所以,这里的
 StoreProc['@mm_id'] := '1389';
    StoreProc['@mm_pay'] := 1.15;
就类似于我们所说的“意义”上的规则了

2004-05-28 16:00:01 dana
是不是传入给存储过程的两个参数?
 
2004-05-28 16:00:11 烟灰缸
是。

2004-05-28 16:00:57 dana
    StoreProc.LoadFromStore(100006);
这句是生成存储过程是吧?

2004-05-28 16:01:11 烟灰缸
Action2和Action3的示例我下个星期写了之后再放上来。

2004-05-28 16:01:14 烟灰缸

2004-05-28 16:01:34 烟灰缸
 StoreProc.LoadFromStore(100006);是取得语句,还没生成。
StoreProc.SqlLanguage才是生成

2004-05-28 16:02:09 dana
明白了.

2004-05-28 16:03:01 烟灰缸
请大家打开dmDefault.prj

2004-05-28 16:03:36 烟灰缸
都打开了吗?

2004-05-28 16:03:44 松鼠
等等
Service.ReceiveDataWithNoData;这个作什么用的

2004-05-28 16:04:11 烟灰缸
通知服务层,此规则没有返回数据。

2004-05-28 16:04:45 烟灰缸
function TdmDefault.ActionList(CmdIndex: integer; var Data, Msg: OleVariant): WordBool;
 
2004-05-28 16:04:53 烟灰缸
看看这个实现部分。

2004-05-28 16:05:55 烟灰缸
有没有发现,实际上,这里也是一个个小规则,只不过是有特定的意义。

2004-05-28 16:06:33 烟灰缸
它可以让前台人员和后台人员都少作一些事情。

2004-05-28 16:09:31 烟灰缸
function TdmDefault.OpenStoreProc(var Data, Msg: OleVariant): WordBool;
 
2004-05-28 16:09:43 dana
刚才dmDemo也有 ActionList这个,
跟现在这个有什么区别?

2004-05-28 16:09:50 烟灰缸
请大家看看这一个实现。

2004-05-28 16:10:14 烟灰缸
ActionList是“规则”DLL的“小规则列表”

2004-05-28 16:11:13 烟灰缸
类似TComponent的Override一样。

2004-05-28 16:11:34 烟灰缸
    LoadStoreProcWithParam(Ole.StoreProcIndex);
    Service.Query.LoadSql(StoreProc.SqlLanguage);
    Service.ReceiveDataWithDefault;
 

2004-05-28 16:12:32 烟灰缸
这一段和客户端cdsDemo1.OpenStoreProc(100001)对应

2004-05-28 16:13:47 烟灰缸
他是让服务层的Query打开存取过程的数据并返回的Client

2004-05-28 16:16:27 Jackey
不明。cdsDemo1.OpenStoreProc调用的是thmclientdataset的OpenStoreProc. dmDafault如何知是哪个action?  thmclientdataset的OpenStoreProc. 用了acOpenStoreProc?

2004-05-28 16:17:18 烟灰缸
To Jackey 打开thmclientdataset 看看就知道了。

2004-05-28 16:22:18 Jackey
还真是将902封装在了hmclientdataset中了..

2004-05-28 16:23:13 烟灰缸
课间休息,大家问问和这个相关的问题。

2004-05-28 16:24:02 断翅
最后执行Sql语句的地方在哪里啊

2004-05-28 16:24:27 烟灰缸
Service.Execute和Service.Query

2004-05-28 16:24:56 松鼠
IBaseService这个是什么组件?

2004-05-28 16:25:18 烟灰缸
不是组件,而是服务层接口。

2004-05-28 16:25:19 Jackey
IBaseService是接口不是组件

2004-05-28 16:26:27 烟灰缸
有个问题问问大家。

2004-05-28 16:27:16 烟灰缸
客户端输入了很多数据,还没ApplyUdates,但停电了,怎么办?

2004-05-28 16:27:46 八戒公子
用事务进行处理就可以了吧,

2004-05-28 16:27:57 llyygg
从新录入,装UPS.:)

2004-05-28 16:28:09 烟灰缸
我都把这个QQ组信息放到最大并开着来看,不关它。

2004-05-28 16:28:26 烟灰缸
UPS也没电了呢?

2004-05-28 16:28:27 Jackey
save./ load.

2004-05-28 16:28:36 llyygg
输入一条,保存一条(本地)

2004-05-28 16:28:49 烟灰缸
怎么Save,他都不知几时停电。

2004-05-28 16:28:52 八戒公子
提交数据是用事务处理了吗?

2004-05-28 16:29:02 Jackey
save到本地.

2004-05-28 16:29:14 烟灰缸
几时Save?

2004-05-28 16:29:29 llyygg
输入一条,保存一条,Post的时候

2004-05-28 16:29:36 八戒公子
就是采用事务回滚处理啊。

2004-05-28 16:29:56 斜阳
可不可以这样讲课啊,讲一笔数据的获得的过程。
从客户端提交请求开始,到客户端获得数据为止。先讲整个流程,等大家都明白后再逐一展开了讲

2004-05-28 16:30:21 Jackey
输一条save一条,最后update.如果掉电。 开机后再load出来。

2004-05-28 16:30:22 斜阳
这样可能会清晰点

2004-05-28 16:30:23 烟灰缸
好。

2004-05-28 16:30:59 烟灰缸
To Jackey,这办法可行,这就是我下一个版本要加入的功能。N

2004-05-28 16:31:41 烟灰缸
下一个版本可能在9月份出来,会有很多新东西和大家见面。N

2004-05-28 16:32:26 烟灰缸
继续讨论。。。。。。。。

2004-05-28 16:32:47 斜阳
比如,我在客户端点击了第一页的第一个按钮,然后谁响应了它?这个请求在服务端是如何被转来转去的,然后是谁负责响应请求的等等

2004-05-28 16:32:48 烟灰缸
按斜阳的说法来说。

2004-05-28 16:33:25 烟灰缸
请大家再打开一个Delphi,并打开Demo1.prj

2004-05-28 16:33:42 斜阳
还有啊,建议大家把这4个工程建一个工程组,免得还的跳来跳去的打开这个关闭那个的

2004-05-28 16:34:11 llyygg
好主意.o

2004-05-28 16:35:35 Jackey
偶早建了.N没提醒大家.?

2004-05-28 16:35:54 烟灰缸
procedure TForm1.Button2Click(Sender: TObject);
 
2004-05-28 16:35:58 烟灰缸
先看看这里。

2004-05-28 16:36:24 斜阳
还有啊,老师讲课的时候最好能告诉代码在那个单元里,要不然容易找不到的。

2004-05-28 16:36:56 Jackey
demo1 的test1_form 82 line

2004-05-28 16:37:05 Jackey
line 74

2004-05-28 16:38:13 斜阳
行号就算了,因为如果有人改过代码(比如我),那就乱套了

2004-05-28 16:39:14 烟灰缸
  cdsDemo1.Ole.StoreProcIndex := 100001;
  cdsDemo1.Ole.Action := acOpenStoreProc;
  cdsDemo1.OpenData(dmDefault);

2004-05-28 16:40:47 烟灰缸
cdsDemo1已经指明是Action是acOpenStoreProc

2004-05-28 16:41:11 斜阳
上面三句目的是什么呢?

2004-05-28 16:41:23 烟灰缸
而且,ModuleIndex是dmDefault

2004-05-28 16:41:25 斜阳
总体目的

2004-05-28 16:41:51 烟灰缸
是让服务层明白,我要的“规则”所在地点。

2004-05-28 16:42:18 烟灰缸
请大家打开swServer2.prj

2004-05-28 16:42:38 斜阳
不要说规则啊服务啊什么的有些抽象。
我理解是客户端向服务器端请求数据

2004-05-28 16:43:06 烟灰缸
现在来了,这里就有方向了。

2004-05-28 16:43:47 Jackey
目的是取到在pubs中的发行者资料

2004-05-28 16:43:56 烟灰缸
unit DataServer_form;

2004-05-28 16:44:15 烟灰缸
function TDataServer2.DataModule(ModuleIndex: Integer; Param: OleVariant; var Data, Msg: OleVariant): WordBool;
 
2004-05-28 16:45:10 烟灰缸
看看客户过来的数据参数是怎么走的。

2004-05-28 16:45:51 斜阳
我还是觉得你没有把问题说的很清楚

2004-05-28 16:45:59 烟灰缸
(Server) ModuleIndex  =  (Client) dmDefault 

2004-05-28 16:46:41 斜阳
客户端到底要向服务器请求什么?

2004-05-28 16:47:05 斜阳
难到仅仅就是向服务器发指令?
意义何在啊?

2004-05-28 16:47:53 烟灰缸
前面已经说了,cdsDemo1要向服务层取得100001号数据

2004-05-28 16:49:06 烟灰缸
  cdsDemo1.Ole.Action := acOpenStoreProc;意思是取得服务层的数据,

2004-05-28 16:49:21 斜阳
我觉得,应该是这样的,客户端向服务器请求100001号数据
向谁请求呢?向 dmDefault 请求,以什么方式请求呢?以 acOpenStoreProc 方式

2004-05-28 16:49:49 斜阳
可能理解的不对,但是至少这样明朗些

2004-05-28 16:50:33 斜阳
这样我们就会始终记得,我是要将信息通过服务器中转到 dmDefault 中,如何中转呢?那就看看服务器吧

2004-05-28 16:51:03 烟灰缸
好,继续看看服务层那边。

2004-05-28 16:51:08 斜阳
这样讲不是很好吗?条理清晰,始终跟着数据流走

2004-05-28 16:51:29 Jackey
我来解释一下. 用户想取得出版者的资料,而这个资料在pubs中。 现在方法是.在pubs定义了一个sql,.id为100001, 在client调用这个10001.服务器取到10001的sql,解析出来。 再根据此sql取到数据传给client。是不是这样?

2004-05-28 16:51:48 断翅
斜阳,说出了我的急需啊
 
2004-05-28 16:52:20 Jackey
10001的sql就是取出版者资料的(猜的,还未看).

2004-05-28 16:52:48 Jackey
有不清楚或不对的吗?

2004-05-28 16:53:02 烟灰缸
完全正确。o

2004-05-28 16:53:46 斜阳
要说100001只是一个取某一批数据的代号,也可以理解成某启动一个业务流程代码,服务器看到这个代码就会启动相应的流程来完成客户的请求

2004-05-28 16:54:06 烟灰缸
Righto

2004-05-28 16:55:32 Jackey
yes.

2004-05-28 16:55:41 断翅
服务器取到10001的sql,解析出来
中间过程如何跟踪,希望指点
 

2004-05-28 16:55:50 斜阳
把客户端的调用分开来看,就是
  cdsDemo1.Ole.StoreProcIndex := 100001;
是启动那个业务流程的标志
  cdsDemo1.Ole.Action := acOpenStoreProc;
是以什么方式启动
  cdsDemo1.OpenData(dmDefault);
是启动谁

//

2004-05-28 16:56:07 Jackey
现在client提出了需要.
  cdsDemo1.BeginOle;
  cdsDemo1.Ole.StoreProcIndex := 100001;
  cdsDemo1.Ole.Action := acOpenStoreProc;
  cdsDemo1.OpenData(dmDefault);

2004-05-28 16:56:32 斜阳
这样理解如果正确的话,那客户端的请求部分就基本清新了,可以开始服务器了

2004-05-28 16:57:11 Jackey
OpenData请求服务器响应了。如何响应?且听老师分解...

2004-05-28 16:57:17 烟灰缸
好,继续服务层,不过讲不清楚的话还是请大家来给讲一下。

2004-05-28 16:58:03 Jackey
OpenData调用....?

2004-05-28 16:58:10 斜阳
服务器是怎么响应客户的请求呢?
是OpenData函数,在这个函数中,调用了
      Result := RemoteServer.AppServer.DataModule(ModuleIndex, vParam, vData, Msg);
函数

2004-05-28 16:58:56 烟灰缸
对,现在我们看看服务层的
function TDataServer2.DataModule(ModuleIndex: Integer; Param: OleVariant; var Data, Msg: OleVariant): WordBool;
是如何反应的。
 

2004-05-28 16:58:56 斜阳
而 AppServer.DataModule 整好是服务器开放给客户端的一个接口函数

2004-05-28 16:59:49 斜阳
看看服务端的 IDataServer2 接口,其中就有 DefaultModule 函数

2004-05-28 17:00:54 斜阳
具体实现这个函数的类是那个呢?TDataServer2
现在看看 TDataServer2 中的 DefaultModule
在 unit DataServer_form 单元中

我的理解就到这里了,请老师继续吧

2004-05-28 17:01:08 烟灰缸
感谢斜阳的讲解,有你的讲解会更精彩。o

2004-05-28 17:01:57 斜阳
我只不过把我的理解同大家分享罢了,还是要感谢你提供了这个学习的好机会和软件

2004-05-28 17:02:08 斜阳
继续讲吧,老师

2004-05-28 17:02:55 烟灰缸
因为function TDataServer2.DefaultModule
也是调用了DataModule,所以我们就只讨论DataModule。
 

2004-05-28 17:03:13 烟灰缸
function TDataServer2.DataModule(ModuleIndex: Integer; Param: OleVariant; var Data, Msg: OleVariant): WordBool;
 

2004-05-28 17:03:36 斜阳
刚刚粘贴错了,不是DefaultModule是DataModule,不好意思

2004-05-28 17:04:22 烟灰缸
从Client调用的接口可以看到,它是启动了DataModule

2004-05-28 17:05:05 烟灰缸
其中,Param是从hmClientDataSet中Ole生成的

2004-05-28 17:05:22 烟灰缸
Data则是要返回给它的数据

2004-05-28 17:05:30 烟灰缸
Msg是返回信息。

2004-05-28 17:05:42 烟灰缸
然后,我们看看它怎么走。

2004-05-28 17:06:46 烟灰缸
        FdmModule := CreateModule(FBaseService, ModuleIndex);
 
2004-05-28 17:07:42 烟灰缸
  if not mdLibrary.Locate('md_ModuleIndex', ModuleIndex, []) then
    Exception.Create('服务器装载出错:DataMoudule(' + inttostr(ModuleIndex) + ') not found.');
 
2004-05-28 17:09:21 烟灰缸
如果,找不到客户需求的规则模块,就返回出错。

2004-05-28 17:10:25 烟灰缸
实际上,上面那一段也“定位”了DLL的内存位置。

2004-05-28 17:11:01 斜阳
在 CreateModule 函数中,查询是否加载了客户请求的业务逻辑,也就是负责这个请求的动态库

2004-05-28 17:12:59 烟灰缸
简单的说,mdLibrary存放在所有DLL的内存地址,和是否已经启动服务了。

2004-05-28 17:13:37 烟灰缸
而且,所有的DLL序号(ModuleIndex)也在这里查找。

2004-05-28 17:13:41 斜阳
简单说,你上面个的那个查询语句中的mdLibrary是一个表名,这个表是在服务端启动的时候动态创建的,这个表中存放了一些系统信息,包括系统加载了哪些动态库

2004-05-28 17:14:01 烟灰缸
Rigjht

2004-05-28 17:14:29 斜阳
以及这些动态库和客户请求的指令有着对应的关系

2004-05-28 17:14:46 烟灰缸
Right

2004-05-28 17:15:08 烟灰缸
所以这里  if mdLibrary.FieldByName('md_State').AsInteger <> 1 then
    Exception.Create('服务器装载出错:DataMoudule(' + inttostr(ModuleIndex) + ') not start.');
 

2004-05-28 17:15:55 烟灰缸
就指明了,如果DLL没有启动(或是程序正在更新,或是人为暂停了),也返回错误信息。

2004-05-28 17:15:59 斜阳
mdLibrary 是一个TQuery,他就是打开这个临时创建的表的数据集

2004-05-28 17:16:45 烟灰缸
  Module := Pointer(mdLibrary.FieldByName('md_ModuleAddr').AsInteger);
  if (Module <> nil) then
    Result := Module^.CreateDataModule(BaseService)
  else
    raise
      Exception.Create('服务器装载出错:DataMoudule(' + inttostr(ModuleIndex) + ') not found.');
 

2004-05-28 17:17:25 烟灰缸
这里的Module是把mdLibrary表中的DLL内存地址转换出来

2004-05-28 17:18:36 烟灰缸
并调用初始函数CreateDataModule,并把本身的服务接口给他。

2004-05-28 17:19:22 斜阳
这个临时表很重要的,他就是起到将客户的请求分派到不同的业务动态库的对照表的作用,所以服务器一接到客户的请求,就先到这个表里查有没有能完成客户的请求的业务逻辑被加载,如果没有,就返回异常,并将异常放在Msg中返回给客户,如果有相关的动态库,那么就激活这个动态库

2004-05-28 17:20:45 烟灰缸
大家要感谢斜阳对我们做了详细的解释。?

2004-05-28 17:20:56 Jackey
 Result := Module^.CreateDataModule(BaseService). 详细。

2004-05-28 17:21:04 斜阳
并调用动态库中实现的CreateDataModule方法(每个业务规则动态库必须引出这个方法供服务器调用)

2004-05-28 17:22:19 烟灰缸
CreateDataModule 返回的是DLL的接口IBaseDataModule;

2004-05-28 17:23:04 烟灰缸
有个这个接口,服务层就可以把参数给他并调用它的方法了。

2004-05-28 17:23:39 烟灰缸
Module^是一个内存地址。

2004-05-28 17:23:44 斜阳
这个方法完成了加载各个业务动态库的数据模块等工作,这个等到讲到业务动态库的时候会详细说的,现在只要知道经过CreateDataModule方法,服务器就获得了业务规则动态库的某个约定的接口,这样就可以通过这个接口把相关的信息传给这个动态库了

2004-05-28 17:23:54 斜阳
是这样吧

2004-05-28 17:23:59 烟灰缸
YES!

2004-05-28 17:24:39 烟灰缸
今天的课真精彩,大家要好好SAVE

2004-05-28 17:25:14 烟灰缸
        FdmModule := CreateModule(FBaseService, ModuleIndex);
        FdmModule.Module := ModuleIndex;
 

2004-05-28 17:25:49 斜阳
继续这个中转服务器讲,现在,通过CreateModule方法找到了相关的业务动态库,并从这个动态库中获得了约定的接口 IBaseDataModule
(每个业务规则动态库必须实现这个接口)

2004-05-28 17:26:04 烟灰缸
实际上这一句已经没多大用处了,只是和旧版本兼容    FdmModule.Module := ModuleIndex;

2004-05-28 17:26:40 烟灰缸
        FdmModule := CreateModule(FBaseService, ModuleIndex);
获得了约定的接口 IBaseDataModule
 

2004-05-28 17:27:06 斜阳
现在 烟灰缸 老师可以简单解释以下 IBaseDataModule 这个接口都约定了哪些规则吗

2004-05-28 17:27:16 烟灰缸
好。

2004-05-28 17:27:29 烟灰缸
unit dmBaseModule;

2004-05-28 17:27:45 烟灰缸
  IBaseDataModule = interface
 
2004-05-28 17:29:04 烟灰缸
  IBaseDataModule = interface
  IDataModuleInfo = interface
 
2004-05-28 17:29:36 烟灰缸
DLL必须Expers这个两个接口

2004-05-28 17:30:15 烟灰缸
IDataModuleInfo 是本DLL的一些信息。供swMMC用

2004-05-28 17:30:37 斜阳
不完全是导出这两个接口,而是必须实现这两个接口

2004-05-28 17:30:55 烟灰缸
对。

2004-05-28 17:31:20 烟灰缸
其中IDataModuleInfo就不多讲了,大家应该看得明。

2004-05-28 17:31:27 Jackey
yes

2004-05-28 17:31:56 斜阳
然后导出能创建实现了这两个接口的实例的函数

2004-05-28 17:32:42 斜阳
这样中转服务器就可以用这两个接口操纵所有业务规则动态库了,对吧

2004-05-28 17:32:47 烟灰缸
对。

2004-05-28 17:33:20 斜阳
你能解释一下 IBaseDataModule 接口的作用和其中的关键函数吗

2004-05-28 17:33:33 烟灰缸
好。

2004-05-28 17:34:34 烟灰缸
    property BaseService: IBaseService read GetBaseService write SetBaseService;
    property Module: integer read GetModule write SetModule;
    property ModuleInfo: WideString read GetModuleInfo;
 

2004-05-28 17:35:39 烟灰缸
BaseServer是服务层给它的接口,在服务层创建它时给的。

2004-05-28 17:36:02 烟灰缸
Module是旧版本的东西

2004-05-28 17:36:16 斜阳
那个服务层,是中转的那个吗

2004-05-28 17:36:23 烟灰缸
ModuleInfo也是旧版本的东西。

2004-05-28 17:36:51 斜阳
中转服务层给他这个接口干吗?

2004-05-28 17:36:52 烟灰缸
我们约定服务层指swServer

2004-05-28 17:37:04 烟灰缸
规则层指这些DLL

2004-05-28 17:37:12 烟灰缸
客户端指DEMO1

2004-05-28 17:37:57 烟灰缸
中转服务层给他这个接口为了让它可以使用服务层的“事务”

2004-05-28 17:39:01 斜阳
是不是把中转服务层的数据源传给业务规则动态库

2004-05-28 17:39:10 烟灰缸
不是

2004-05-28 17:39:43 斜阳
那是什么呢?在业务规则动态库中还自己创建数据库链接吗?

2004-05-28 17:39:58 烟灰缸
而是在服务层中定义许多操作方式,让规则DLL去用它就可以了。

2004-05-28 17:40:19 烟灰缸
DLL不创建任何数据控件。

2004-05-28 17:40:27 斜阳
噢,好吧,讲业务动态库的时候会说明吧

2004-05-28 17:40:34 烟灰缸
会。

2004-05-28 17:40:42 Jackey
要解说了IBaseService = interface可能才说的清

///---Bookmark
应该不会,
2004-05-28 17:41:18 烟灰缸
最重要的两个是
    function Operation(var Data, Msg: OleVariant): WordBool; stdcall;
    procedure LoadOleParam(const Param: OleVariant); stdcall;
 
2004-05-28 17:42:35 烟灰缸
服务层调用它时,会先把客户的Param通过LoadOleParam给入DLL

2004-05-28 17:43:34 烟灰缸
然后,再执行Operation来取得数据。

2004-05-28 17:44:19 烟灰缸
当Operation执行正确,没有出现Exception时,返回True,否则为False

2004-05-28 17:44:34 烟灰缸
当然,也可以人为False

2004-05-28 17:45:23 Jackey
哪个地方有实现.?

2004-05-28 17:45:33 烟灰缸
Operation执行完毕,Data 可能有东西,可能没有,MSG也一样。

2004-05-28 17:45:56 烟灰缸
unit dmBaseModuleImp;里有实现

2004-05-28 17:47:01 烟灰缸
今天只能讲到这了。。。。。。。

2004-05-28 17:47:21 斜阳
Operation 的功能是不是这样的:
中转服务器把客户端请求的参数传通过Operation中转给业务规则层,并利用这些参数调用业务规则动态库中的子规则,所有的子规则执行完毕后把返回的信息通过 BaseService 接口传回个中转服务器

2004-05-28 17:47:35 烟灰缸
对。

2004-05-28 17:48:28 斜阳
然后中转服务器再把从业务规则动态库中获得的数据回传给客户端

2004-05-28 17:48:36 烟灰缸
对。

2004-05-28 17:49:03 斜阳
当然如果不能成功执行,就回传错误信息到Msg中,也回传给客户端

2004-05-28 17:49:10 烟灰缸

2004-05-28 17:50:02 烟灰缸
有其它朋友不明白的吗?

2004-05-28 17:50:44 斜阳
今天基本上把客户端和服务器交互的过程简单理清了点了,明天是不是要将业务规则动态库了,看看是如何根据中转服务器中转过来的东西逐步调用子规则并合成数据的,是吧

2004-05-28 17:51:22 烟灰缸
下次开课讨论时间为下个星期二,请大家记得。

2004-05-28 17:51:58 斜阳
这样说也头晕啊!其实只要你紧紧跟住数据流这条线,就应该有点思路的

2004-05-28 17:52:25 烟灰缸
是对,跟住数据流这条线是最好理解的。

2004-05-28 17:53:56 Jackey
我是从头跟下来的.都还有点晕.

2004-05-28 17:54:11 烟灰缸
呵呵,难为你了。

2004-05-28 17:54:14 斜阳
(客户端)请求数据流(如何请求的)->(如何到服务器的)->服务器(如何接收、中转的)->(如何返回的)->数据数据流(客户端)

2004-05-28 17:54:44 斜阳
跟着数据流的线,就会明白为什么服务器会这样作

2004-05-28 17:54:52 烟灰缸
今天只是讲到服务器(如何接收、中转的)

2004-05-28 17:55:15 斜阳
还有客户端如何请求的是吧N

2004-05-28 17:55:27 烟灰缸
是N

2004-05-28 18:00:01 Jackey
TCreateDataModule = function(const BaseService: IBaseService): IBaseDataModule; stdcall;

2004-05-28 18:00:42 Jackey
谁能讲解一下.

2004-05-28 18:01:14 斜阳
没找到啊

2004-05-28 18:01:38 Jackey
dmBaseService. 

2004-05-28 18:01:40 斜阳
噢,你看看 TModuleLibrary 这个结构

2004-05-28 18:02:55 斜阳
这个结构中有
 动态加载的动态库的句柄(LibHandle)
  动态库中的两个导出的过程(CreateDataModule和CreateDataModuleInfo)

2004-05-28 18:03:23 斜阳
CreateDataModule方法就是刚刚提到的那个方法

2004-05-28 18:04:02 斜阳

type
  TCreateDataModule = function(const BaseService: IBaseService): IBaseDataModule; stdcall;
就是定义一个过程型的类型

2004-05-28 18:04:55 Jackey
对.

2004-05-28 18:05:18 斜阳
然后在 TModuleLibrary 中用TCreateDataModule类型定义过程型变量CreateDataModule

2004-05-28 17:55:58 斜阳
上面我写的那些可是我昨天跟了三个多小时才整明白的啊

2004-05-28 17:56:20 烟灰缸
给你来杯€

2004-05-28 17:56:50 斜阳
到不是特意跟的,只是我将数据库改成Access时出错,结果就调试啊调试啊,就跟下来了

2004-05-28 17:57:30 烟灰缸
要下班吃饭了,大家星期二见好不,有问题和想法请到留言系统留言给我好不,可能我QQ不在线。

2004-05-28 17:58:09 斜阳
因为Access不能执行存储过程,所以我在客户端看不到数据,但是从逻辑上应该可以正常运行了

2004-05-28 17:58:40 斜阳
今天都周五了啊,好快啊

2004-05-28 17:58:58 烟灰缸
没关系,我找个时间也来试试,星期二见。?

2004-05-28 17:59:04 斜阳
我们周六上班,周日才休息,有比我更惨的吗?

2004-05-28 17:59:14 Jackey
我就为了个大小写整了我好长时间.

2004-05-28 17:59:34 Jackey
没有. 我周一都只上半天班.

2004-05-28 17:59:54 斜阳
啊!不公平啊!

转载于:https://www.cnblogs.com/DKSoft/articles/42094.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值