.NET分层登陆——机房收费系统再总结
去年的时候,我写过一篇机房收费系统登陆的总结文章,那是站在VB的基础上,直接查询数据库实现的登陆。是很初期的知识。如果想了解详情,请看VB查询数据库之登陆窗体——机房收费系统总结(一)。
今天,我要换一个角度,换一个方式,来实现登陆。首先,我选择的开发工具是VB.NET,数据库是SQLSever2008。其次,我用的是三层的思想,把界面,逻辑和数据都分开,减少相互之间的影响。在次,界面层尽量简洁,所有的算法和业务逻辑都写到逻辑层,同时使用了接口和工厂模式以及外观模式,减少了相互之间的依赖,降低了耦合。最后,通过文档和UML图,写出代码,实现登陆。
首先,看看我设计的登陆时序图(如有错误,欢迎指出,不胜感激):
看到图之后,如果你拥有一定的经验,相信对你来说,代码就不是问题了吧。下面,我把我的代码放在下面,仅供参考哦!(对了,U层界面没有变,如果想知道,请看连接博客)。
首先是实体层代码:
用户实体层:
Public Class UserInfo
Private _userid As String
Private _password As String Public Property UserID As String
Get
Return _userid
End Get
Set(value As String)
_userid = value End Set
End Property Public Property PassWord As String
Get
Return _password
End Get
Set(ByVal value As String)
_password = value
End Set
End Property End Class
工作表实体层:
<span style="font-size:18px;">Imports System
Imports System.Data ''' <summary>
''' 数据库表OpeLineRecord所对应的实体类
''' </summary>
Public Class OpeLineRecordEntity Private m_Opercomprecordid As String
Private m_Operatorid As String
Private m_Landdate As String
Private m_Landtime As String
Private m_Outdate As String
Private m_Outtime As String
Private m_Status As String
Private m_Computerid As String Public Sub OpeLineRecordEntity()
m_Opercomprecordid = ""
m_Operatorid = ""
m_Landdate = ""
m_Landtime = ""
m_Outdate = ""
m_Outtime = "" m_Status = ""
m_Computerid = "" End Sub
''' <summary>
'''设置或返回值Opercomprecordid
''' </summary>
Public Property Opercomprecordid As String
Get
Return m_Opercomprecordid
End Get
Set(value As String)
m_Opercomprecordid = value
End Set
End Property ''' <summary>
'''设置或返回值Operatorid
''' </summary>
Public Property Operatorid As String
Get
Return m_Operatorid
End Get
Set(value As String)
m_Operatorid = value
End Set
End Property ''' <summary>
'''设置或返回值Landdate
''' </summary>
Public Property Landdate As String
Get
Return m_Landdate
End Get
Set(value As String)
m_Landdate = value
End Set
End Property ''' <summary>
'''设置或返回值Landtime
''' </summary>
Public Property Landtime As String
Get
Return m_Landtime
End Get
Set(value As String)
m_Landtime = value
End Set
End Property ''' <summary>
'''设置或返回值Outdate
''' </summary>
Public Property Outdate As String
Get
Return m_Outdate
End Get
Set(value As String)
m_Outdate = value
End Set
End Property ''' <summary>
'''设置或返回值Outtime
''' </summary>
Public Property Outtime As String
Get
Return m_Outtime
End Get
Set(value As String)
m_Outtime = value
End Set
End Property ''' <summary>
'''设置或返回值Status
''' </summary>
Public Property Status As String
Get
Return m_Status
End Get
Set(value As String)
m_Status = value
End Set
End Property ''' <summary>
'''设置或返回值Computerid
''' </summary>
Public Property Computerid As String
Get
Return m_Computerid
End Get
Set(value As String)
m_Computerid = value
End Set
End Property End Class</span>
将Datatable转换为泛型
<span style="font-size:18px;">Imports System.Collections.Generic '增加泛型的命名空间
Imports System.Reflection
Public Class EntityHelper
Public Shared Function convertTolist(Of T As {New})(ByVal dt As DataTable) As IList(Of T) '将DataTable转化为泛型集合 '注意:1,convertToList(Of T As {New} 这里的New是用来约束T的,必须有,不然new T 的时候会出现错误
''2,new约束在C#和VB.NET里面的写法是不一样的,C#里面用的是where来为T加上约束的 Dim myList As New List(Of T) '定义最终返回的集合 Dim myType As Type = GetType(T) '得到实体类的类型么
Dim dr As DataRow '定义行集 Dim tempName As String = String.Empty '定义一个临时变量 '遍历DataTable的所有数据行
For Each dr In dt.Rows Dim myT As New T '定义一个实体类的对象
Dim propertys() As PropertyInfo = myT.GetType().GetProperties() '定义属性集合
Dim Pr As PropertyInfo '遍历该对象的所有属性
For Each Pr In propertys
tempName = Pr.Name '将属性名称赋值给临时变量 '检查DataTable是否包含此列(列名==对象的属性名)
If (dt.Columns.Contains(tempName)) Then '将此属性与DataTable里的列名比较,查看DataTable是否包含此属性 '判断此属性是否有Setter
If (Pr.CanWrite = False) Then '判断此属性是否可写,如果不可写,跳出本次循环
Continue For
End If Dim value As Object = dr(tempName) '定义一个对象型的变量来保存列的值 If (value.ToString <> DBNull.Value.ToString()) Then '如果非空,则赋给对象的属性
Pr.SetValue(myT, value, Nothing) '在运行期间,通过反射,动态的访问一个对象的属性
End If
End If
Next myList.Add(myT) '添加到集合
Next Return myList '返回实体集合
End Function
End Class
</span>
然后是接口层IDAL:
<span style="font-size:18px;">Public Interface IUser
Function SelectUser(ByVal user As entity.UserInfo) As List(Of UserInfo) End Interface</span>
D层:
<span style="font-size:18px;">Imports IDAL
Imports entity
Imports System.Data.SqlClient
Public Class UserDAL : Implements IDAL.IUser Public Function SelectUser(user As UserInfo) As List(Of UserInfo) Implements IUser.SelectUser
Dim strUserID As String = user.UserID
Dim helper As New Helper.Sqlhelper
Dim dt As New DataTable
Dim mylist As List(Of UserInfo) Dim strSql As String = "select * from OperatorInfo where OperatorID=@UserID and state='使用'"
Dim sqlParams As SqlParameter() = {New SqlParameter("@UserID", strUserID)} '声明并实例化参数
dt = helper.ExecuteNonQuery(strSql, CommandType.Text, sqlParams) '调用SqlHelper类中的ExecSelect()方法来执行查询,并获取返回值
mylist = EntityHelper.convertTolist(Of UserInfo)(dt) '将dt转换为泛型集合 Return mylist
End Function End Function
End Class
</span>
增加记录
<span style="font-size:18px;">Imports IDAL
Imports entity
Imports System.Data.SqlClient
Public Class UserWorklogDAL : Implements IDAL.IUserWorklog Public Function AddUserworklog(worklog As OpeLineRecordEntity) As Boolean Implements IUserWorklog.AddUserworklog
'声明一个SqlHelper类型的helper
Dim helper As New Helper.Sqlhelper
Dim dt As New Integer
'声明并实例化需要执行的SQL语句
Dim strSql As String = "Insert into OpeLineRecord (OperatorID,landDate,landTime,ComputerID,Status) values (@OperatorID,@landDate,@landTime,@ComputerID,@Status)" '声明兵实例化参数数组
Dim sqlParams As SqlParameter() = {New SqlParameter("@OperatorID", worklog.Operatorid),
New SqlParameter("@LandDate", worklog.Landdate),
New SqlParameter("@LandTime", worklog.Landtime),
New SqlParameter("@ComputerID", worklog.Computerid),
New SqlParameter("@Status", worklog.Status)} '调用SqlHelper类中的ExecAddDeleteUser()方法来执行添加信息,获取返回值并Return
dt = helper.ExecAddDelUpdate(strSql, CommandType.Text, sqlParams)
Return dt
If dt > 0 Then
Return True
Else
Return False
End If End Function</span>
外观:
<span style="font-size:18px;">Public Class LoginFAC
Public Function Login(ByVal user As entity.UserInfo) As String Dim userlogin As New BLL.UserManager
userlogin.IsUserExit(user) If Not userlogin.IsUserExit(user) Then
Throw New Exception("密码不正确") End If userlogin.CheckPWDIsRight(user)
If userlogin.CheckPWDIsRight(user) = False Then
Throw New Exception("密码不正确")
End If '判断用户是否登录了系统
Dim userwork As New entity.OpeLineRecordEntity
Dim workbll As New BLL.UserWorklogManager
userwork.Operatorid = user.UserID
userwork.Landdate = DateTime.Now.ToString("yyyy/MM/dd")
userwork.Landtime = DateTime.Now.ToString("HH:mm")
userwork.Computerid = System.Net.Dns.GetHostName()
userwork.Status = "正在值班" '添加登录信息
workbll.AddWorklog(userwork) End Function
End Class</span>
SQLhelper层:
<span style="font-size:18px;">'通过配置文件获取连接字符串
Imports System.Data
Imports System.Data.SqlClient
'Imports System.Configuration '添加对配置文件的引用 Public Class Sqlhelper '调用配置文件
Private ReadOnly strConnection As String = Configuration.ConfigurationManager.AppSettings("ConnStr").ToString '有参数的查询
'return DataTable 查询出的表格
Public Function ExecuteNonQuery(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal sqlParams As SqlParameter()) As DataTable
Using conn As New SqlConnection(strConnection) '使用连接池,可以在使用完成后自动关闭连接
Dim cmd As SqlCommand = conn.CreateCommand() '
Dim adp As SqlDataAdapter
Dim ds As New DataSet
cmd.CommandText = cmdText '需要执行的SQL语句
cmd.CommandType = cmdType '给出Sql语句的类型
cmd.Parameters.AddRange(sqlParams) '参数数组,参数个数根据实际情况而定
adp = New SqlDataAdapter(cmd)
Try
conn.Open()
adp.Fill(ds)
'Return cmd.ExecuteNonQuery()
Return ds.Tables(0)
Catch ex As Exception
Return Nothing
Throw ex
End Try
End Using
End Function '有参数的增删改
Public Function ExecAddDelUpdate(ByVal cmdText As String, ByVal cmdType As CommandType, ByVal sqlParams As SqlParameter()) As Integer
Using conn As New SqlConnection(strConnection)
Dim cmd As SqlCommand = conn.CreateCommand()
Dim adp As SqlDataAdapter
Dim ds As New DataSet
cmd.CommandText = cmdText
cmd.CommandType = cmdType
cmd.Parameters.AddRange(sqlParams)
adp = New SqlDataAdapter(cmd)
Try
conn.Open()
adp.Fill(ds)
Return ds.Tables.Count
Catch ex As Exception
Return Nothing
Throw ex
End Try
End Using
End Function End Class
</span>
工厂层:
<span style="font-size:18px;">Imports System.Reflection
Imports [IDAL]
Public Class BDFactory
'Private Shared ReadOnly db As String = Configuration.ConfigurationManager.AppSettings("DBString")
'Private Shared ReadOnly assemblyName = db + "DAL"
Private Shared ReadOnly assemblyName = "SQLDAL" Public Function CreateUserDAO() As IDAL.IUser 'Dim className As String = assemblyName + "." + db + "UserDAL"
Dim className As String = assemblyName + "." + "UserDAL"
Return CType(Assembly.Load(assemblyName).CreateInstance(className), IUser) '返回IUser End Function </span>
<span style="font-size:18px;">Public Function CreateUserworklogDAO() As IDAL.IUserWorklog
Dim strInstance As String = assemblyName + "." + "UserWorklogDAL" '所要实例化的对象(程序集与命名空间同名)
Return CType(Assembly.Load(assemblyName).CreateInstance(strInstance), IUserWorklog) '返回IUserWorklog
End Function</span>
B层:
添加上机记录
<span style="font-size:18px;">Imports Factory
Imports entity Public Class UserWorklogManager
Private ReadOnly factory As Factory.BDFactory = New Factory.BDFactory
Dim iu As IDAL.IUserWorklog '声明并实例化变量iuser为:调用factory.CreateUserDAO()方法所返回来的IUser '添加用户工作记录
Public Function AddWorklog(ByVal worklog As entity.OpeLineRecordEntity) As Boolean
iu = factory.CreateUserworklogDAO()
Dim dt As Integer
dt = iu.AddUserworklog(worklog) If dt > 0 Then
Return True
Else
Return False
End If
End Function
</span>
查询用户是否存在 密码是否正确
<span style="font-size:18px;">Imports entity
Public Class UserManager
Private ReadOnly factory As Factory.BDFactory = New Factory.BDFactory()
Dim iuser As IDAL.IUser Public Function IsUserExit(ByVal user As entity.UserInfo) As Boolean
Dim iu As IDAL.IUser
Dim mylist As List(Of UserInfo) iu = factory.CreateUserDAO()
mylist = iu.SelectUser(user) If mylist.Count = 0 Then
Return False
Else
Return True
End If End Function Public Function CheckPWDIsRight(ByVal user As entity.UserInfo) As Boolean
Dim iu As IDAL.IUser
Dim mylist As List(Of UserInfo)
iu = factory.CreateUserDAO()
mylist = iu.SelectUser(user) If Trim(mylist(0).PassWord) <> user.PassWord Then
Throw New Exception("输入密码不正确")
Return False
Else
Return True
End If
End Function</span>
最后是U层
<span style="font-size:18px;">Public Class frmlogin Private Sub BtnOK_Click(sender As Object, e As EventArgs) Handles BtnOK.Click
Dim user As New entity.UserInfo '实例化User
user.UserID = txtUserName.Text
user.PassWord = txtPassword.Text
If txtUserName.Text.Trim().Length > 20 Then
MessageBox.Show("不能超过20位数字", "提示")
Exit Sub
End If
If txtUserName.Text.Trim() = "" Then
MessageBox.Show("请输入用户名", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
ElseIf txtPassword.Text.Trim() = "" Then
MessageBox.Show("请输入用密码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Exit Sub
End If
Try
'调用外观
Dim loginfac As Facade.LoginFAC = New Facade.LoginFAC()
loginfac.Login(user)
Me.Hide() ForMain.Show()
Catch ex As Exception
MsgBox(ex.Message, CType(vbOKOnly + MsgBoxStyle.Information, MsgBoxStyle), "提示")
End Try End Sub End Class
</span>
Ok 系统结束,可能会有轻微的问题,细心就一定会解决(因为在粘贴的过程中,可能一不留神,你懂得……),相对第一次来说,代码和逻辑上,并没有简单,而且反倒难了,那我们为什么还有继续呢?
不知道读者是否有这样的疑问。其实,很简单,虽然代码和逻辑麻烦了,但是系统的性能更好了,逻辑也更清楚了,同时,减少了U层的负担,工作具体化。同样,兼容性扩展性更好了,健壮性也有所提高。更加适合合作开发。这是一个小系统,如果是大系统,是不是优势就会更明显呢!
版权声明:本文为博主原创文章,未经博主允许不得转载。
.NET分层登陆——机房收费系统再总结的更多相关文章
- 小结:VB.NET机房收费系统个人版
经过几天的缝缝补补,自己的个人版最终OK了,!或许是由于有第一次的机房收费系统的经验,这次做,感觉很亲切. 在业务逻辑方面,沿袭曾经的逻辑.做了一点升级.可是修改不大. 在数据库方面,感觉自己从一个小 ...
- 机房收费系统(VB.NET)个人版总结
重构版个人机房收费系统大概从暑假开学開始进行.花了不到一个半月的时间才完毕.以下对我在重构过程中的一写理解. 1.系统设计一个非常重要的目的就是重用.而要做到重用,低耦合是最有效的手段回想一下我们C/ ...
- 机房收费系统之【只允许一个MDI窗体 错误:426】 标签: vb 2014-08-15 10:36 1149人阅读 评论(23)
机房收费系统的主窗体是MDI窗体,为了在这个窗体上添加控件,所以我们在窗体上添加了picture控件,在MDI窗体中,子窗体实际上位于MDIClient里,即子窗体的父窗体就是MDIClient,而放 ...
- 机房收费系统(VB.NET)——存储过程实战
最初接触存储过程是在耿建玲老师的视频里,当初仅仅是草草过了一遍.仅仅是有了个印象.知道了这个名词:大二时也有SqlServer数据库这门课,只是老师没讲,自己也没看:真正对存储过程的了解来自于自学考试 ...
- VB.NET版机房收费系统---七仙女之系统登录
VB.NET第一版机房收费系统,告一段落,验收的时候.问题也是大大的存在,没实用上设计模式,什么触发器.存储过程,都没实用上.看看其她小伙伴的,七层实现登录?那是什么东东,相比較我的三层而言,多了两倍 ...
- 机房收费系统——在VB中将MSHFlexGrid控件中的数据导出到Excel
机房收费系统中,好多查询的窗体都包含同一个功能:将数据库中查询到的数据显示在MSHFlexGrid控件中,然后再把MSHFlexGrid控件中的数据导出到Excel表格中. 虽然之前做过学生信息管理系 ...
- 机房收费系统总结之4——VB.NET 轻松解决判断文本框、组合框为空问题
纵观机房收费系统,判断文本框.组合框为空问题无非两种情况.第一种:判断窗体中所有文本框.组合框是否为空.第二种:判断一部分文本框.组合框是否为空.下面看看是如何实现这两种情况的. 第一种:判断窗体中所 ...
- VB.NET版机房收费系统---外观层如何写
外观设计模式,<大话设计模式>第103页详细讲解,不记得这块知识的小伙伴可以翻阅翻阅,看过设计模式,敲过书上的例子,只是学习的第一步,接着,如果在我们的项目中灵活应用,把设计模式用出花儿来 ...
- VB.NET版机房收费系统---报表
报表,即报告情况的表格,简单的说:报表就是用表格.图表等格式来动态显示数据,可以用公式表示为:"报表 = 多样的格式 + 动态的数据". 在没有计算机以前,人们利用纸和笔来记录数据 ...
随机推荐
- JS之document例题讲解1(两张表之间数据转移、日期时间选择、子菜单下拉、用div做下拉菜单、事件总结)
作业一:两个列表之间数据从一个列表移动到另一个列表 <div style="width:600px; height:500px; margin-top:20px"> & ...
- 暑假集训——cf热身赛部分题有感加其题解
刚刚开始集训,集训队队长暂时还没有拉专题,而是拉了部分codeforces上过题人数在2000左右的题组成了一场热身赛(其实就是一场练习),花了一天时间终于把它刷完了,其中很多题让我学到了很多骚操作, ...
- HDU 2084 数塔 (dp)
题目链接 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数 ...
- 20151024_001_C#基础知识(静态与非静态的区别,值类型和引用类型,堆和栈的区别,字符串的不可变性,命名空间)
1:我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念. 类就是个模子,确定了对象应该具有的属性和方法. 对象是根据类创建出来的. 2:类:语法 [public] class ...
- js中三种定义变量 const, var, let 的区别
js中三种定义变量的方式const, var, let的区别 1.const定义的变量不可以修改,而且必须初始化. 1 const b = 2;//正确 2 // const b;//错误,必须初始化 ...
- 【HNOI】 小A的树 tree-dp
[题目描述]给定一颗树,每个点有各自的权值,任意选取两个点,要求算出这两个点路径上所有点的and,or,xor的期望值. [数据范围]n<=10^5 首先期望可以转化为求树上所有点对的and,o ...
- bzoj 1050 并查集
先按边长排序,假设s与t连通,那么我们可以枚举s与t的路径中最短的一条边,通过类似与kruskal的方法找到s与t的路径在当前最小边权情况下尽量小的最大边权,用这个比值更新答案. 特别的,我们对于某一 ...
- MySQL:Can't create test file XXX.lowe-test
问题说明 今天部署MySQL,在使用mysql_install_db,初始化数据库时报如下错误 180622 11:36:38 mysqld_safe Starting mysqld daemon w ...
- gpio子系统和pinctrl子系统(下)
情景分析 打算从两个角度来情景分析,先从bsp驱动工程师的角度,然后是驱动工程师的角度,下面以三星s3c6410 Pinctrl-samsung.c为例看看pinctrl输入参数的初始化过程(最开始的 ...
- Linux 入门记录:一、命令行 Bash 的基本操作
为了以后长期的线上测试和服务器的性能考量,要用 Linux 服务器了.昨晚装了个 CentOS 6.9,今天开始学学 Linux 基础,扫扫盲.ok,小本本记 ing... 一.Shell简介 She ...