DA18 –
说明
MiniWH
范例
导论
MiniWH (WareHouse)
范例在
Data Abstract 3.0
中引入
,
展示了多层应用程序中的完成通常需求任务的例子
.
包含的主题
:
- MiniWH 功能
- 如果安装并开始
- 登陆
- 运行业务帮助类
- 自动处理
- 过滤和良好设计
- 跨数据的元素
- MSSQL和IB SQL的差异
- SQL 宏
- 服务文件综述
- 客户端文件综述
- 总结
注意
:
图片被压缩了
,
如果看不清请点击放大
.
其他
:
[
讨论了新的
TDADesigntimeCall
组件
.
这个组件可以在设计时拖放到窗体后设置其远程查询并运行
;
主要用于测试服务
]
MiniWH
功能
如何安装和启动
MiniWH
范例是
Data Abstract 3.0
自带的
,
存放于
/Samples/MiniWH
目录
,
启动项目组
(MiniWH.bpg).
Data Abstract
的一个最重要的特性就是可以透明的处理多种数据库
. MiniWh
配置了四个数据库连接
: ADO, IBX, IBO
和
SDAC.
然而
,
很多人不会使用后两个
,
它们被禁用或启用非常简单
.
查看支持文件
MiniWH.inc:
{.$DEFINE SDAC}
{.$DEFINE IBO}
要启用其中的一个或两个
,
只需要适当的删除
'.'.
接下来
,
我们要确信连接可用并使用了正确的连接路径等
.
有两种方式
:
使用
ConnectionManager
组件或通过
Schema(
其中提供了连接字符串向导
).
使用
ConnectionManager (
在
fServerDataModule
)
你只需要打开其连接集合并使用标准的连接编辑方式生成连接字符串
.
双击
Schema(
如在
LoginService_Impl
中的
LoginSchema
)
调用
Schema Modeler
你可能会发现使用连接字符串向导很简单
:
点击上面指向的按钮
:
登陆
这个主题讨论如何使用新的
DALoginService
服务对象创建一个登陆服务
.
当你运行
MiniWH
客户端
,
登陆界面如图
:
如果你输入匹配的用户名和密码
,
客户端创建将显示出来
.
输入三次错误密码客户端将退出
.
如何实现的呢
?
首先
,
禁用主窗体自动显示特性
:
在项目源文件
(MiniWHClient.dpr)
中设置
Application.ShowMainForm
为
FALSE:
begin
Application.Initialize;
Application.ShowMainForm := FALSE;
Application.Title :=
'MiniWH Client'
;
Application.CreateForm(TClientDataModule, ClientDataModule);
Application.CreateForm(TClientForm, ClientForm);
Application.Run;
end
.
在
fClientForm.FormCreate
事件中显示登陆窗体
:
procedure
TClientForm.FormCreate(Sender: TObject);
begin
Caption := Application.Title;
Application.OnHint := DisplayHint;
actLogin.Execute;
end
;
你将会注意到调用了
actLogin.Execute,
而且其也设置菜单和工具栏按钮
,
允许你不用退出客户端就可以切换用户
:
procedure
TClientForm.actLoginExecute(Sender: TObject);
begin
Visible := FALSE;
if Login then begin
Visible := TRUE;
ApplySecurity;
end
else
Application.Terminate;
end
;
Login
过程包含在
fLoginForm
之中
,
我们首先看一下
ApplySecurity
方法
:
procedure
TClientForm.ApplySecurity;
begin
with
ClientDataModule do begin
StatusBar.Panels[
0
].Text :=
'Logged in as '
+ UpperCase(ClientDataModule.LoginInfo.UserID)
+
', '
+UserRoleNames[UserRole];
actUsers.Enabled := (UserRole=rAdmin);
actStatistics.Enabled := (UserRole in [rAdmin, rPowerUser]);
end;
end
;
这里简单的向用户显示信息
.
很快就可以看到如何设置
Login.UserID
和
UserRole.
正如你想象的这是一个强大的集中存取控制方法
.
现在我们查看
fLoginForm
中的
Login
方法
:
function
Login : boolean;
begin
with
TLoginForm.Create(NIL) do try
result := (ShowModal=mrOK)
finally
Free;
end;
end
;
procedure
TLoginForm.bbOKClick(Sender: TObject);
begin
if
ClientDataModule.Login(eUserID.Text, ePassword.Text) then
ModalResult := mrOK
else begin
MessageDlg(
'Invalid login'
, mtWarning, [mbOK],
0
);
Dec(fTries);
if (fTries<=
0
) then ModalResult := mrCancel;
end;
end
;
procedure
TLoginForm.FormCreate(Sender: TObject);
begin
fTries :=
3
;
end
;
这个
Login
方法很普通
,
我们感兴趣的代码是
ClientDataModule.Login:
function
TClientDataModule.Login(const aUserID,
aPassword: string): boolean;
var
i : integer;
attrname, attrvalue : string;
begin
result := (svcLoginService as ILoginService).Login(
aUserID, aPassword, fLoginInfo);
if result then with fLoginInfo do begin
for
i :=
0
to
(Attributes.Count-
1
) do begin
attrname:=Copy(Attributes[i],
1
,Pos(
'='
,Attributes[i])-
1
);
attrvalue:=Copy(Attributes[i],Pos(
'='
,Attributes[i])+
1
,MaxInt);
if SameText(attrname, fld_GetUserInfoUserIdx)
then fUserIdx := StrToInt(attrvalue)
else if SameText(attrname, fld_GetUserInfoUserRole)
then fUserRole := StrToUserRole(attrvalue);
end;
LoadLookupData;
end;
end
;
这里实际上调用了
DALOginService
服务
. svcLoginService
是一个
dmClientDataModule
中的
TRORemoteService
组件
:
切换到服务端项目查看
Service Builder (
通过
RemObjects | Edit Service Library)
我们将看到
:
注意
LoginService
继承自新的
DALoginService,
这里不需要做任何变动
.
当然也可以在这里按需增加一些方法和参数
. DALoginService
定义如下
:
查看参数列表
,
你将看到一个声明为
Out
的
TDALoginInfo
类型的
LoginInfo
参数
.
记得客户端调用的
svcLoginService
服务吗
?
那里有一个声明为
TDALoginInfo
类型的
fLoginInfo
参数
,
客户端从服务端接收的
LoginInfo
就是这里声明的
. TDALoginInfo
定义如下
:
LoginInfo
由
DALoginService.Login
处理
(
在
DA3
源码目录的
DALoginService_Impl
中
),
实际上调用了
DoLogin
方法
:
function
TDALoginService.DoLogin(
const UserID: String; const Password: String;
out LoginInfo: TDALoginInfo): boolean;
var
ds : IDADataset;
i : integer;
begin
result := FALSE;
LoginInfo := NIL;
ds := ServiceSchema.NewDataset(
Connection, LoginDataset,
[ParamNameUserID, ParamNamePassword],
[UserID, Password]);
if ds.EOF then Exit;
LoginInfo := TDALoginInfo.Create;
LoginInfo.UserID := UserID;
LoginInfo.SessionID := GUIDToString(Session.SessionID);
for i :=
0
to
(ds.FieldCount-
1
) do begin
Session[ds.Fields[i].Name] := ds.Fields[i].Value;
LoginInfo.Attributes.Add(
ds.Fields[i].Name+
'='
+ds.Fields[i].AsString);
end;
result := TRUE;
end
;
注意是如何处理
UserID, SessionID
字段属性的
.
你可以重写
DoLogin
方法提供自己的处理
Privileges
和数据字段的方法
.
服务也提供了一些事件
:
OnLogin
包含
:
procedure
TLoginService.DALoginServiceLogin(Sender: TDALoginService;
var aUserID, aPassword: String);
begin
aPassword := EncryptPassword(aPassword);
{
The select statement that returns the user record should not be
case sensitive in respect of the UserID. Different databases handle
case sensitivity in different ways.
For instance, SQL Server would return "John" even if your WHERE
statement said "WHERE Name='JoHn'".
Interbase, however, wouldn't return any rows.
In order to handle database differences, make use of DA's Macros
(such as "UpperCase" - check it out using the Schema Modeler).
The SQL is converted into the appropriate dialect at runtime.
}
aUserID := UpperCase(aUserID);
end
;
从而总结了
DALOginService
处理常用需求以及提供的自定义控制
.
运行业务帮助类
自动处理
autoinc
[DA3
新特性
]
筛选和良好的设计
[
本范例涉及很多常见问题
]
跨数据库要素
[
集中于跨数据库要素以及如何无代码实现
]
MSSQL
和
IB
的
SQL
差异
SQL
宏
[
讨论
]
服务端文件综述
截图中高亮文件也用于客户端项目
.
注意如何将这些业务文件
(
可能要在其中编码的
)
放置在不同的目录
.
AdminService_Impl
同所有的
'..._Impl'
文件一样
,
这个单元在读取项目相关的
RODL
文件后由
RemObjects SDK
自动生成
,
并在这里编写实现代码
.
其中包含
ChangePassword
逻辑
.
BaseMiniWHService_Impl
这是除了
LoginService
外都要继承的基础服务
.
父类与使用什么连接什么时候调用方法等具体逻辑隔离开
.
查看
TBaseMiniWHService.DoOnActivate
的说明
.
此外
, BINAdapter
连接到数据模块中的
SessionManage.
fServerDataModule
这个单元包含所有以单例模式实例化组件并在程序运行中维护其生命周期
..
HTTPServer
和
BINMessage
负责接收通过
HTTP
及具体方法调用传递的远程消息
.
客户端第一个要调用的方法是
LoginService
的
Login
方法
.
DriverManager, ADODriver
和
IBXDriver
与数据库连接的组件
.
将他们作为拖放后就遗忘的组件
.
从来不会在代码中直接存取他们
,
他们基本上就是在
Data Abstract
单元中加一个引用指示连接到
ADOExpress, Interbase Express
或
Data Abstract
引擎单元
.
我们要将所有的数据库连接放置于
ConnectionManager
组件中
.
点击这个组件查看其
Connections
属性
,
将看到当前定义的连接
.
这些默认配置可以在运行时通过修改
DBConnections.xml
文件而做出调整
.
点击
TServerDataModule.DataModuleCreate
查看这里的特殊实现代码
.
这时服务端可以使用
ADO
连接到
MSSQL
数据库或
SDAC(
假设你在
MiniWH.inc
中激活了
SDAC
定义
)
通过
Interbase Express/ IBObjects
连接到
Interbase(
这些也是在
MiniWH.inc
中控制
).
以后将向这个范例加入
Oracle, Sybase
等数据库支持
.
SessionManager
组件将维护一个内存的用户
Session
列表
,
我们可以从中存取如用户
ID,
角色等信息
.
在
TLoginService
的
DALoginServiceLoginSuccess
方法中可以查看我们能在
Session
存储什么信息
.
最后
DataDictionary
组件包含一下可夸
Schema
使用的字段属性
(
例如
, Address1, Zip
和
City).
每个服务的
Schema
都指向这个主要的数据字典
.
当我们使用数据字典条目的时候可在
Schema
中检查各种字段
.
fServerForm
这个主服务窗口在服务启动是显示
.
其中包含了一个
ComboBox
组件允许你在运行时修改连接
.
LoginSchemaClient_Intf
这个自动生成的单元包含客户端服务端都使用的常量信息
.
你可以修改这些值为
DataTable
的规则
ID
指定一个更可读的值
,
但是必须保证在你的应用程序中唯一
.
LoginSchemaServer_Intf
这个生成的单元包含服务端使用的常量
.
可以修改这些值为
Delta
规则
ID
指定更可读的值
,
但是必须保证在你的应用程序中唯一
.
LoginService_Impl
这个单元中包含了继承自
Data Abstract
基础类
TDALoginService
的
LoginService
的实现
.
TDALoginService
提供了一个包含
Login
和
Logout
方法的简单接口
.
更多信息见这个单元的注释
.
MiniWHLibrary_Intf
这个单元是自动生成的
,
你不需要修改它
.
MiniWHLibrary_Invk
这个单元是自动生成的
,
你不需要修改它
.
ProductsSchemaClient_Intf
这个生成的单元中包含用于服务端和客户端的常量信息
.
你可以在这里为
DataTable
的规则
ID
修改为一个更可读的值
,
但是必须保证在你的应用程序中唯一
.
ProductsSchemaServer_Intf
这个生成的单元包含服务端使用的常量信息
.
你可以在这里为
DataTable
的规则
ID
修改为一个更可读的值
,
但是必须保证在你的应用程序中唯一
.
ProductsService_Impl
在这个服务中检查
Schema
中声明的
UpdateRules
.
这里不需要一行代码就能实现原来的
BasicDADemo
范例的功能
!
uBizLogin.pas
这里包含登陆处理相关的业务逻辑
.
定义了两个方法
: EncryptPassword
和
StrToUserRole.
注意
:
为了范例便于理解这里也很简单
.
客户端文件综述
上面截图中高亮文件也用于服务端项目
.
AdminSchemaClient_Intf
Summary