Public Class frmLogin
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click
'输入不能为空
If txtUserID.Text = "" Then
MsgBox("请输入用户ID号", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtUserID.Focus()
End If
If txtPassWord.Text = "" Then
MsgBox("请输入密码", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtPassWord.Focus()
End If
Try
'实体获得窗体信息
Dim user As New Entity.UserInfo
Dim facade As New Facade.LoginFacade
user.userID = txtUserID.Text.Trim()
user.passWord = txtPassWord.Text.Trim()
'将U层信息传入外观层
Dim flag As Boolean
Dim flagPSW As Boolean
flag = facade.CheckUserID(user)
'flagPSW = facade.CheckPassWord(user)
'显示结果,先判断用户是否存在,存在再判断密码,密码正确则登录成功,否则提示密码错误
If flag = False Then
MsgBox("用户不存在,请重新输入", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtUserID.Text = ""
txtPassWord.Text = ""
txtUserID.Select()
txtUserID.Focus()
Else
flagPSW = facade.CheckPassWord(user)
If flagPSW = False Then
MsgBox("密码错误,请重新输入!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtPassWord.Text = ""
txtPassWord.Select()
txtPassWord.Focus()
Else
MsgBox("登录成功!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
txtUserID.Text = ""
txtPassWord.Text = ""
Me.Hide()
End If
End If
Catch ex As Exception
MsgBox("未知错误")
End Try
End Sub
End Class
Imports System.Reflection '添加反射引用
Imports System.Configuration '添加配置文件的引用
Imports System.Data
Imports IDAL
'反射+配置文件+抽象工厂实现数据访问
Public Class LoginFactory
Private Shared ReadOnly AssemblyName As String = "DAL" '数据程序集名称&命名空间DAL
Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("DB") '使用配置文件
Public Function CreateIUser() As ILoginUser
Dim classname As String = "DAL" + "." + strDB + "LoginDAL" '要实例化的D层类的名称
Dim IUser As ILoginUser
'CType函数将返回表达式显示的转换为指定数据类型、对象、结构、类或接口后的结果
IUser = CType(Assembly.Load(AssemblyName).CreateInstance(classname), ILoginUser)
Return IUser
End Function
End Class
Public Class LoginService
Dim table As New DataTable
Dim flag As Boolean
Dim Factory As New Factory.LoginFactory
Dim IUser As IDAL.ILoginUser
Public Function CheckUserID(ByVal user As Entity.UserInfo) As Boolean
IUser = Factory.CreateIUser() '调用工厂的CreateIUser方法创建IUser接口实例
table = IUser.SelectUser(user)
If table.Rows.Count = 0 Then
flag = False
Else
flag = True
End If
Return flag
End Function
Public Function CheckPassWord(ByVal user As Entity.UserInfo) As Boolean
'逻辑判断都在B 层做,U层只负责显示
IUser = Factory.CreateIUser()
table = IUser.SelectUser(user)
If table.Rows(0).Item(2) = user.passWord Then
flag = True
Else
flag = False
End If
Return flag
End Function
End Class
Imports System.Reflection '添加反射引用
Imports System.Configuration '添加配置文件的引用
Imports System.Data
Imports IDAL
'反射+配置文件+抽象工厂实现数据访问
Public Class LoginFactory
Private Shared ReadOnly AssemblyName As String = "DAL" '数据程序集名称&命名空间DAL
Dim strDB As String = System.Configuration.ConfigurationSettings.AppSettings("DB") '使用配置文件
Public Function CreateIUser() As ILoginUser
Dim classname As String = "DAL" + "." + strDB + "LoginDAL" '要实例化的D层类的名称
Dim IUser As ILoginUser
'CType函数将返回表达式显示的转换为指定数据类型、对象、结构、类或接口后的结果
IUser = CType(Assembly.Load(AssemblyName).CreateInstance(classname), ILoginUser)
Return IUser
End Function
End Class
Public Interface ILoginUser
Function SelectUser(ByVal user As Entity.UserInfo) As DataTable
End Interface
Imports System.Configuration
Imports IDAL
Imports System.Data.SqlClient
Public Class LoginDAL : Implements IDAL.ILoginUser
Private SqlFavor As New SqlHelper.SqlFavor
'判断用户名是否存在
Public Function SelectUser(ByVal user As Entity.UserInfo) As DataTable Implements IDAL.ILoginUser.SelectUser
Dim sql As String '储存查询语句
Dim table As DataTable
'声明并实例化参数数组
Dim paras As SqlParameter() = {New SqlParameter("@userID", user.userID), New SqlParameter("@passWord", user.passWord)}
'数组
'sql = "select * from Users where ID = @userID and PassWord = @passWord"
sql = "select * from Users where ID = @userID"
'调用SQLHelper中的ExecSelect方法来查询,并获取返回值
table = SqlFavor.ExecSelect(sql, CommandType.Text, paras)
Return table
End Function
End Class
Imports System.Data
Imports System.Data.SqlClient
Imports System.Configuration '配置文件的引用
Public Class SqlFavor
'数据库连接
Dim strConnection As String = "Server = jf; Database = Login; User ID = sa; PassWord = summer"
Dim conn As New SqlConnection(strConnection)
Dim cmd As New SqlCommand
Public Function ExecSelect(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal paras As SqlParameter()) As DataTable
Dim sqlAdapter As SqlDataAdapter
Dim dt As New DataTable
Dim ds As New DataSet
'给cmd 赋值
cmd.CommandText = cmdText
cmd.CommandType = cmdType
cmd.Connection = conn
cmd.Parameters.AddRange(paras) '添加参数
sqlAdapter = New SqlDataAdapter(cmd) '实例化Adapter
Try
sqlAdapter.Fill(ds) '用adapter将dataset填充
dt = ds.Tables(0) 'datatable是dataset的第一个表
cmd.Parameters.Clear() '清除参数
Catch ex As Exception
MsgBox("数据库操作")
Finally
Call CloseCmd(cmd) '关闭cmd命令
End Try
Return dt
End Function
Public Sub CloseCmd(ByVal cmd As SqlCommand)
If Not IsNothing(cmd) Then '如果cmd存在
cmd.Dispose() '销毁
cmd = Nothing
End If
End Sub
End Class
Public Class UserInfo
Private _userid As String
Private _username As String
Private _password As String
Private _level As String
Public Property userID As String
Get
Return _userid
End Get
Set(value As String)
_userid = value
End Set
End Property
Public Property userName As String
Get
Return _username
End Get
Set(value As String)
_username = value
End Set
End Property
Public Property passWord As String
Get
Return _password
End Get
Set(value As String)
_password = value
End Set
End Property
Public Property level As String
Get
Return _level
End Get
Set(value As String)
_level = value
End Set
End Property
End Class
Public Function ExecSelect(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal paras As ***SqlParameter()***) As DataTable
之前三层时传参数是这样用的
cmd.Parameters.Add(New SqlParameter("@ID", user.ID))
cmd.Parameters.Add(New SqlParameter("@PassWord", user.PSW))
现在把DAL层里连接数据库和公共性的东西抽出来形成sqlHelper。所以要把D层中的sql,parameter等参数都传给sqlHelper,但是parameter中往往有好几个,所以就用到了数组。
反射的一个原则:一切皆以UI层的bin文件夹中的dll名称为中心。(原因很简单:.net类加载的机制就是默认从本程序集的bin文件中找,所以bin文件夹中一定要有要加载的程序集的dll)。UI层中bin文件夹中dll叫什么名字AssemblyPath就使用什么名字,bin内部类的全名叫什么,className就写成什么全名。.net中的引用:加入对某个程序集的引用就能在程序集有变化时自动拷贝dll。
以上摘自王雪娜的博客 机房重构七层登录之问题总结
总而言之,各层中的dll名称都以UI层的bin文件里的dLL名称为准,所以方法就是把D层属性里 生成 ——输出路径 改成UI层就OK了。
我写七层的时候主要借鉴的是同学的博客,并做了一些小改动。同学的B层的返回值类型是datatable,然后在U层把窗体上的密码与table里的密码进行比较。感觉逻辑判断应该放在B层,就把这些判断都写到B层,然后B层和Facade层的返回值类型都是boolean。
在U层做判断的时候也做了一些小改动:写了一个嵌套的if语句来判断用户名和密码是不是正确,用户名正确但密码不正确就提示“密码错误”。试了试360 云盘遇到这种情况会给什么提示,它就是提示“密码错误”,感觉这样对用户比较方便。
以前遇到错误心里就犯怵,不过还是在错误中收获最多。这次最欣慰的就是在巨人的肩膀上加上了自己的想法,虽然都是一些简单的想法,但是完全自己设计创造一个东西都是要这样慢慢成长的。不要想太多,像老师说的,做吧,做着做着可能就理解了。在这样的精神指导下,我就要开始机房重构了。