接下来开始讲解如何用三层架构来建立用户登录过程.
这个过程用一般的编程方式写起来很简单,从这里入手来讲解三层架构的实例,想必大家都会更容易了解其中的逻辑结构.
首先我们做一些准备工作,构造这个业务需要用到的几个类,其中包括三个部分:
User部分的实体类MOD_User,单表数据访问类DAL_User
UserLog部分的单表数据访问类DAL_UserLog
User业务相关的业务逻辑类BLL_User,多表数据访问类MUL_User
好,我们开始准备第一部分.
[User] 表的结构如下
[UserID] [int] IDENTITY(1,1) NOT NULL,
[UserAccount] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
[UserPassword] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,
[UserName] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NULL,
[UserPower] [int] NOT NULL,
[LogCount] [int] NULL,
[UserDate] [datetime] NULL,
以[User]表生成一个实体类MOD_User,文件名为MOD_User.asp,放在/Class/MOD/目录下,内容如下,请大家熟悉一下property的写法
class MOD_User
' ******[User] database field
private lngUserID '[int] NOT NULL
private strUserAccount '[ntext] 用户登录名
private strUserPassword '[ntext] 密码
private strUserName '[ntext] 用户名称
private intUserPower '[int] 权限
' ==============================================================================
' Class Initialize, Terminate
' ==============================================================================
Private Sub Class_Initialize
End Sub
Private Sub Class_Terminate
End Sub
' ==============================================================================
' property in/out
' ==============================================================================
Public Property Let UserID(ByVal Value )
lngUserID = Convert.ToLng(Value)
End Property
Public Property Get UserID
UserID = lngUserID
End Property
Public Property Let UserAccount(ByVal Value )
strUserAccount = trim(Value)
End Property
Public Property Get UserAccount
UserAccount = strUserAccount
End Property
Public Property Let UserPassword(ByVal Value )
strUserPassword = trim(Value)
End Property
Public Property Get UserPassword
UserPassword = strUserPassword
End Property
Public Property Let UserName(ByVal Value )
strUserName = trim(Value)
End Property
Public Property Get UserName
UserName = strUserName
End Property
Public Property Let UserPower(ByVal Value )
intUserPower = Convert.ToInt(Value)
End Property
Public Property Get UserPower
UserPower = intUserPower
End Property
end class
Convert 对象在此出现的比较多.
实体类的好处之一就在这里,把值填充到类的属性中,可以将变量转换的工作完全交给这个实体类,在程序中使用的时候就不用再来来去去地转换了.
所以鼓励大家用Property代替Public操作.
Appdb系统会有一个功能,通过已有的数据表,直接生成对应的MOD类的代码,它会自己用Property构造如上同样的实体类,而且会根据字段类型不同自己选择不同的Convert方法进行转换. 有了这个工具,就可以节省大量的重复性的基础工作了,这个工具也是为三层架构而产生的,其他语言的编程工具中都有这样的功能,咱也不能缺.
以[User]表生成一个单表数据访问类DAL_User,文件名为DAL_User.asp,放在/Class/DAL/目录下,内容如下:
class DAL_User
' ******[User] database field
private lngUserID '[int] NOT NULL
private strUserAccount '[ntext]
private strUserPassword '[ntext]
private strUserName '[ntext]
private intUserPower '[int]
private strSql 'Sql query
private rs_User 'Dataset for poheader
' ==============================================================================
' Class Initialize, Terminate
' ==============================================================================
Private Sub Class_Initialize
set rs_User=server.createobject("adodb.recordset")
End Sub
Private Sub Class_Terminate
set rs_User=nothing
End Sub
' ///
' Get Data / dataset
' ///
Public Function CheckLogin(ByRef vMUser)
strSql = " select top 1 * from [User] where UserAccount='" & page.ToSql(vMUser.UserAccount) & "'"
rs_User.Open strSql,Data.conn,1,1
if rs_User.bof and rs_User.eof then
e.Add " This User does not exit ! "
CheckLogin = false
else
if rs_User("UserPassword") = vMUser.UserPassword then
vMUser.UserID = rs_User("UserID")
vMUser.UserName = rs_User("UserName")
vMUser.UserPower = rs_User("UserPower")
CheckLogin = true
else
e.Add " Wrong password ! "
CheckLogin = false
end if
end if
rs_User.close
End Function
' ///
' Update Table
' ///
' ///
' Show UI / Show-select
' ///
end class
需要解说一下的是DAL_User类中的CheckLogin方法.
这个方法接纳一个参数(ByRef vMUser), vMUser 是一个MOD_User实例化之后一个实体对象,实例化语句为:
set MUser = new MOD_User
在BLL_User中会调用上面这个CheckLogin方法,将MUser传递给DAL_User.CheckLogin, 就是这里的ByRef vMUser了,习惯上我把函数的参数名前面加一个v.
具体的实现过程请看后面的用户登录过程的实施阶段.
这个地方有个需要讨论的疑点,就是实体类作为传值参数时,是应该用ByRef还是ByVal.
在vbscript中,一个实例化的对象在被set给另外一个实例名以后,虽然名称不同,但是仍然是指向同一个内存地址,换了汤没换药. 所以在这里用ByRef ByVal效果是一模一样的.
但是为了在程序的逻辑上的清晰,在此使用ByRef,以示这个vMUser实体类在这里被加工后,仍然会被调用它的程序继续使用.
Private Sub Class_Initialize 和 Private Sub Class_Terminate应该不用解释了吧,如果不甚了解,可以去看看vbscript语法
不知道你有没有注意到这句: page.ToSql(vMUser.UserAccount)
page是另一个比较重要的通用类,用来处理页面上常用的操作,例如这里的ToSql就是将一个字符串加工成为安全的SQL参数,实施单引号替换为两个单引号等操作. 这个类我还没有完善,所以就不贴出来献丑了,也算作为大家来学习三层架构的作业,自己构造一个CON_Page类来用吧
还有两个通用对象的身影:
Data.conn
e.Add " Wrong password ! "
大家可以对照前面几章熟悉一下这两个通用类.
另外有个注释,如下:
' ///
' Get Data / dataset
' ///
这个给类中的不同的方法进行分组的大分隔符,代码中还有2个类似的.
原因是,我发现单表数据访问类中的方法,其功能上基本上只有3组:
1.获取单值或单记录集
2.更新数据表的内容
3.产生出放在UI上的HTML段,例如....之类
把这三组分开以后,再来查找某一个方法,比较容易定位.
只是一个个人习惯,大家可以各自发挥.