自定义用户与权限管理之二
一般用户请忽略本节内容。
上一节已经
讲述了如何自己设计用户管理系统,由于完全使用SQL语句来实现,对于一般的用户来说,可能有些困难。
本节实现完全一模一样的功能,但是基本上不使用SQL语句,而是采用Foxtable自己的后台数据处理函数,所以更简单,更适合一般用户掌握。
还是要申明一下,因为内置的用户数据可以存储在外部数据表中,所以多数情况下并没有必要自定义用户管理,只是通过这两个例子,让大家可以演练一下SQL语句和后台数据处理函数的使用方法。
本节内容可以参考CaseStudy目录下的文件"自定义用户管理之二.Table",用户信息保存在一个Access文件"用户.mdb"中。
设计步骤
一、在文件“用户.mdb”新建一个名为“Users”的表,包括Name、Group、Password三列,分别用于保存用户名、用户分组和密码 ,其中Name列设置为主键。
二、建立一个外部数据源,连接到文件“用户.mdb”,数据源的名称设置为“User”。
三、打开Foxtable的用户管理,增加一个用户,并将其设置为默认用户,这样打开项目的时候,将不会出现foxtable的用户登录窗口。
提示:示例文件“自定义用户管理.Table"”菜单中的用户管理和用户登录,已经被自定义的用户管理和登录代替,必须先按Ctrl+Shift+F12回到系统菜单,才能打开Foxtable的用户管理。
四、在全局代码中定义两个变量:
Public
_UserName As
String
'用户名
Public
_UserGroup As
String
'用户分组
Public
_UserTable As
DataTable
'用户表
_UserName用户保存当前登录用户的名称,_UserGroup用于保存该用户的分组,_UserTable是一个临时表,后面将基于此表读写后台的用户表。
五、在项目事件AfterOpenProject加上代码:
Dim
cmd As
New
SQLCommand
cmd.ConnectionName
= "User"
cmd.CommandText
= "SELECT * From {Users} Where
[Name] Is Null"
_UserTable =
cmd.ExecuteReader(True)
上面的代码基于后台的用户表生成一个临时表,这个临时表没有加载数据,后面将基于此表和后台的用户表进行交互。
注意这里要将ExecuteReader的参数设置为True,因为我们需要增加、删除和修改用户
,也就是说,不仅要读用户表,还要写用户表。
六、新建一个窗口名为“用户管理”窗口:
窗口的AfterLoad事件代码为:
Dim
lst As
WinForm.ListBox
= e.Form.Controls("ListBox1")
lst.ComboList
= _UserTable.SQLGetComboListString("Name")
If
Lst.Items.Count
> 0 Then
lst.SelectedIndex
= 0
End
If
"增加用户"按钮的代码为:
Forms(
"增加用户").Open()"更改用户"按钮的代码为:
If
e.Form.Controls("ListBox1").SelectedIndex >=0 Then"删除用户“按钮的代码为:
Dim
lst As
WinForm.ListBox
= e.Form.Controls("ListBox1")
If
lst.SelectedIndex
>=0 Then
Dim
UserName As
String = lst.SelectedItem
_UserTable.SQLDeleteFor("[Name]
= '" &
UserName & "'")
_UserTable.RemoveFor("[Name]
= '" &
UserName & "'")
lst.Items.RemoveAt(lst.SelectedIndex)
lst.Select()
End
If
七、新建一个名为"增加用户"的窗口:
"确定"按钮的代码设置为:
Dim
UserName As
String = e.Form.Controls("UserName").Value
Dim
UserGroup As
String = e.Form.Controls("UserGroup").Value
Dim
PassWord As
String = e.Form.Controls("PassWord").Value
Dim
dr As
DataRow
If
UserName = ""
OrElse UserGroup
= "" Then
Messagebox.show("请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
Return
End
If
If
_UserTable.SQLFind("[Name]
= '" &
UserName & "'")
IsNot Nothing
Then
Messagebox.show("增加用户失败,已经能存在同名用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
Return
End
If
dr =
_UserTable.AddNew()
dr("Name")
= UserName
dr("Group")
= UserGroup
dr("Password")
= PassWord
_UserTable.Save()
e.Form.Close()
If
Forms("用户管理").Opened
Then
With Forms("用户管理").Controls("ListBox1")
.Items.Add(UserName)
.SelectedIndex = .Items.Count
-1
End
With
End
If
八、新建一个名为“更改用户”的窗口:
窗口的AfterLoad事件代码为:
Dim
UserName As
String
Dim
UserGroup As
String
Dim
PassWord As
String
Dim
dr As
DataRow
If
Forms("用户管理").Opened
Then
'正常打开
UserName = Forms("用户管理").Controls("ListBox1").SelectedItem
Else
UserName = _UserName
'_UserName为全局变量,用于保存当前用户名
e.Form.Controls("UserName").Enabled
= False
e.Form.Controls("UserGroup").Enabled
= False
End
If
e.Form.Text
= e.Form.Text
& "-"
& UserName
'将要更改的用户名保存在窗口标题中,方便其他事件调用
dr =
_UserTable.SQLFind("[Name]
= '" &
UserName & "'")
If
dr IsNot
Nothing Then
e.Form.Controls("UserName").Value
= UserName
e.Form.Controls("UserGroup").Value
= dr("Group")
e.Form.Controls("PassWord").Value
= dr("PassWord")
Else
MessageBox.Show("用户不存在或者已经被删除!","提示",MessageBoxButtons.OK)
上面的代码在打开“更改用户”窗口之前,先判断“用户管理”窗口是否已经打开,如果已经打开,则更改“用户管理”窗口中选定的用户;否则更改当前登录的用户,且禁止更改用户名和用户分组,只能更改用户密码。
这样当我们需要给登录用户提供更改密码功能的时候,只需增加一个菜单按钮,按钮代码设置为:Forms("更改用户").Open()
"确定"按钮的代码为:
Dim
UserName As
String = e.Form.Controls("UserName").Value
Dim
UserGroup As
String = e.Form.Controls("UserGroup").Value
Dim
PassWord As
String = e.Form.Controls("PassWord").Value
Dim
OldUserName As
String
Dim
Parts() As
String = e.Form.Text.Split("-"c)
OldUserName = Parts(Parts.Length -1)
If UserName = ""
OrElse UserGroup
= "" Then
Messagebox.show("请输入用户名和用户分组!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
Return
End
If
Dim
dr As
DataRow = _UserTable.SQLFind("[Name]=
'" &
OldUserName &
"'")
If
dr IsNot
Nothing Then
dr("Name")
= UserName
dr("Group")
= UserGroup
dr("Password")
= PassWord
dr.Save()
If Forms("用户管理").Opened
Then
With
Forms("用户管理").Controls("ListBox1")
.Items(.SelectedIndex)
= UserName
End With
End If
e.Form.Close
Else
Messagebox.show("更改用户失败!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
End
If
九、增加一个名为“用户登录”的窗口:
窗口的AfterLoad事件代码为:
Dim
cmb As
WinForm.ComboBox
= e.Form.Controls("UserName")
cmb.ComboList
= _UserTable.SQLGetComboListString("Name")
"确定"按钮的代码为:
Dim
UserName As
String = e.Form.Controls("UserName").Value
Dim
dr As
DataRow
If
UserName = ""
Then
Messagebox.show("请选择用户!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
Return
End
If
dr =
_UserTable.SQLFind("[Name]
= '" &
UserName & "'")
If
dr Is
Nothing Then
Messagebox.show("此用户不存在!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
Return
End
If
If
e.Form.Controls("PassWord").Value
= dr("Password")
Then
_UserName =
UserName
_UserGroup =
dr("Group")
e.Form.Close
Else
Messagebox.show("密码错误!","提示",MessageBoxButtons.OK,MessageBoxIcon.Information)
End
If
为了防止用户跳过确定和取消按钮,直接关闭窗口,请将窗口的“显示控制框”属性设置为False。
十、将项目事件AfterOpenProject的代码改为:
Dim
cmd As
New
SQLCommand
cmd.ConnectionName
= "User"
cmd.CommandText
= "SELECT * From {Users} Where
[Name] Is Null"
_UserTable
= cmd.ExecuteReader(True)
Forms("用户登录").Open()
If
_UserName = ""
Then
Syscmd.Project.Exit()
Return
'这个要加上,因为既然要退出,就不应该再执行后面的初始化代码了,否则会出错
End
If
'后续初始化代码
第一段是之前已经写好的代码,第二段是新加上去的,为的是打开项目后能出现登录窗口。
为确保用户登录窗口为第一个打开的窗口,登录窗口的窗口类型必须设置为“模式”,且应该将其他所有独立或模式窗口的“自动打开”属性设置为False。
十一、最后修改菜单中的"用户管理"和"切换用户"按钮的代码,启用"用户管理"按钮的代码为:
Forms(
"用户管理").Open()"切换用户"按钮的代码为:
Forms(
"用户登录").Open()你可以先应用系统菜单“system.ribbon”,然后再修改。
如果需要,还可以增加一个更改密码的按钮,代码设置为:
Forms("更改用户").Open()
总结
经过上述11个步骤的设计,我们已经建立了自己的用户管理和登录系统,用户登录后,用户名保存在全局变量_User中,用户分组保存在全局变量_UserGroup中。
我们只需对原来的权限代码稍作修改,即可适用自定义的用户管理系统,例如原来的代码为:
If User.Group =
"经理" Then
DataTables("表A").AllowEdit
= True
Else
DataTables("表A").AllowEdit
= False
End
If
现在只需改为:
If _UserGroup =
"经理" Then
DataTables("表A").AllowEdit
= True
Else
DataTables("表A").AllowEdit
= False
End
If
可以看出,自定义的用户管理系统,在应用上和内置的不会有任何差别。
不过使用自定义用户管理系统的时候,需要注意
事件触发顺序,由于自定义的用户登录窗口是在AfterOpenProject事件中打开,意味着在此事件之前触发执行的事件,是不能使用_UserName和_UserGroup变量的。
例如有的用户希望使用动态加载功能,在用户登录后,订单表只加载业务员为登录用户的订单,所有在项目事件BeforeLoadInnerTable设置了代码:
If
e.DataTableName = "订单" Then结果重新打开项目后,发现订单表根本没有加载任何数据,如果在代码中用MessageBox显示一下合成的加载条件:
If e.DataTableName
= "订单"
Then
e.Filter = "业务员 = '"
& _UserName & "'"
MessageBox.Show(e.Filter)
End If
会发现合成的加载条件为:
业务员 = ''
为什么会这样呢?
这是因为BeforeLoadInnerTable是在AfterOpenProject事件之前触发执行,此时_UserName还是空值。
显然 要实现我们的目标,得使用新的设计方法:
1、首先在BeforeLoadInnerTable事件加入下面的代码,确保订单表初始状态不会加载任何数据:
If
e.DataTableName = "订单" Then2、然后修改用户登录窗口的“确定”按钮的代码,在后面加上加载数据的代码:
Dim
UserName As String = e.Form.Controls("UserName").Value上面代码的最后两行,就是用于根据登录用户名动态加载订单表数据的:
DataTables("订单").LoadFilter
= "业务员 = '" & _UserName
& "'"
DataTables("订单").Load()
以下几个事件在AfterOpenProject事件之前触发执行:
BeforeOpenProject
BeforeConnectOuterDataSource
BeforeLoadInnerTable
BeforeLoadOuterTable
Initialize
另外
由于设置了默认用户,绕开了内置的登录窗口,而且菜单中的登录命令已经改为自定义的登录命令,所以用户将无法以开发者和管理员身份登录系统。
如果希望以开发者或管理员身份登录系统,可以在打开项目的过程中始终按住Ctrl键。
也可以考虑在菜单中另外加入一个系统登录命令,代码设置为:Syscmd.Project.Switchuser()
最后自定义用户登录显然不会触发LoadUserSetting事件,所以该事件中的代码应该移植到自定义用户登录窗口的"确定"按钮中。