《三层结构开发模式.doc》由会员分享,可在线阅读,更多相关《三层结构开发模式.doc(22页珍藏版)》请在三一办公上搜索。
1、第14章 三层结构开发模式14.1三层结构概述14.1.1两层结构及其局限性前面我们讲述的Web应用程序都是基于两层结构的,它们有如下特点:l 数据库访问和用户类型判断逻辑放在一起实现。l 用户界面层直接调用数据访问实现。l 整个系统功能放在同一项目中实现。传统的两层结构的特点是用户界面层直接与数据库进行交互,还要进行业务规则、合法性校验等工作。两层结构软件模型如图18-2所示。这种结构存在着很多局限性,比如:一旦用户的需求发生变化,应用程序都需要进行大量修改,甚至需要重新开发,给系统的维护和升级带来了极大的不便;用户界面层直接访问数据库,会带来很多安全隐患。为了克服两层结构的局限性提出了三层
2、结构。14.1.2什么是三层结构所谓三层体系结构,是在客户端与数据库之间加入了一个“中间层”,也叫组件层。这里所说的三层体系,不是指物理上的三层,不是简单地放置三台机器就是三层体系结构,也不仅仅有B/S应用才是三层体系结构,三层是指逻辑上的三层,即使这三个层放置到一台机器上。通用三层结构软件模型如图18-2所示。中间层通常包括业务逻辑层(Business Logic Layer,简称BLL)、数据访问层(Database Access Layer,简称DAL)和数据对象模型层(Database Object Model Layer,简称DOM)。此时的三层结构软件模型如图18-2所示。用户界面
3、(User Interface,简称UI),也称表示层,位于最上层,用于显示和接收用户提交的数据,为用户提供交互式的界面。表示层一般为Windows窗体应用程序或Web应用程序。业务逻辑层是表示层和数据访问层之间沟通的桥梁,主要负责数据的传递和处理。数据访问层主要实现对数据的读取、保存和更新等操作。数据对象模型层即业务实体层。主要用于表示数据存储的持久对象。在实际应用程序中的实体类是跟数据库中的表相对应的,也就是说一个表会有一个对应的实体类。当然有些三层结构并不包含单独的数据对象模型层,而将其功能分解到业务逻辑层和数据访问层之中。在三层结构中,表示层直接依赖于业务逻辑层;业务逻辑层直接依赖于数
4、据访问层;数据访问层直接依赖于数据对象模型层。14.1.3 三层结构的优点三层结构主要体现出对程序分而治之的思想:数据访问层只负责提供原原始数据,并不需要了解业务逻辑;业务逻辑层调用数据访问层提供的方法自定义一些业务逻辑,对数据进行加工,本身不需要了解数据访问层的实现;表示层直接调用业务逻辑提供的方法把数据呈现给用户。三层结构的优点在于不必为了业务逻辑上的微小变化而迁至整个程序的修改,只需要修改商业逻辑层中的一个函数或一个过程;增强了代码的可重用性;便于不同层次的开发人员之间的合作,只要遵循一定的接口标准就可以进行并行开发了,最终只要将各个部分拼接到一起构成最终的应用程序。三层结构的应用程序将
5、业务规则、数据访问、合法性校验等工作放到了中间层进行处理。通常情况下,客户端不直接与数据库进行交互,而是通过COM/DCOM通讯与中间层建立连接,再经由中间层与数据库进行交互,这样会大大提高系统的安全性。三层结构的应用程序更能够适应企业级应用日益增长的复杂度和灵活性的要求,并且通过软件分层的高内聚、低耦合的原则,实现扩展、维护和重用的要求,可以大大提高开发效率。14.2用ASP.NET搭建三层结构框架ASP.NET 可以使用.NET平台快速方便的搭建三层结构。ASP.NET革命性的变化是在网页中也使用基于事件的处理,可以指定处理的后台代码文件,可以使用C#、VB作为后台代码语言。.NET中可以
6、方便的实现组件的装配,后台代码通过命名控件可以方便的使用自己定义的组件。表示层放在 Web窗体中,业务逻辑层、数据访问层和数据对象模型层用类库来实现,这样就很方便的实现了三层结构。1新建解决方案打开VS 2008,新建一个空白解决方案,将其命名为ThreeLayers 。2搭建表示层(网站)(1)在解决方案资源管理器中,在解决方案名称上单击鼠标右键,在弹出的快捷菜单中选择添加新建网站命令,新建一个网站,其存放位置为解决方案文件夹下的MyWeb子文件夹。(2)在该网站下建一个数据库(简单起见可建Access数据库),以备存取数据。3搭建业务逻辑层(类库)在解决方案资源管理器中,新建一个类库项目。
7、填写项目的名称为 BusinessLogicLayer ,该项目用于实现业务逻辑。4搭建数据访问层(类库)在解决方案资源管理器中,新建一个类库项目。填写项目的名称为 DataAccessLayer ,该项目用于实现数据访问层。5搭建数据对象模型层(类库)在解决方案资源管理器中,新建一个类库项目。填写项目的名称为Models,该项目用于实现数据实体。至此,已搭建了三层结构(添加了4个项目)。5添加各层之间的依赖(引用)此时,虽然三层结构的基本框架已经搭建成功,但是各层之间是独立的。只有添加依赖关系,才能让它们相互协作。(1) 添加表示层对业务逻辑层、数据访问层和数据对象模型层的依赖。(2)添加业
8、务逻辑层对数据访问层和数据对象模型层的依赖。(3)添加业数据访问层对数据对象模型层的依赖。至此,三层结构及各层之间的依赖关系创建完毕。6将表示层设置为启动项目通过上述步骤,就已经成功部署了ASP.NET的三层架构。表示层MyWeb网站放置用于显示的Web页面;事务逻辑层BusinessLogicLayer项目,我们把所有的业务逻辑代码在该层实现;数据访问层DataAccessLayer项目主要处理数据库的操作,供事务逻辑层调用;数据对象模型层Models项目实现数据实体类,供其它各层调用。只要在各个层中实现具体的类就可以成功实施三层结构的应用程序了。14.3应用举例14.3.1系统分析本例的功
9、能非常简单,只是实现用户登录与注册的功能,用户信息存放在数据库中,旨在体现如何在ASP.NET实现三层结构。表示层MyWeb网站放置用于显示的Web页面;事务逻辑层BusinessLogicLayer项目,我们把所有的业务逻辑代码在该层实现;数据访问层DataAccessLayer项目主要处理数据库的操作,供事务逻辑层调用;数据对象模型层Models项目实现数据实体类,供其它各层调用。各层次之间的调用(引用)关系如表所示。层项目名称用途引用关系实例文件界面展示MyWeb(网站)Web页面和控件BusinessLogicLayerDataAccessLayerModelsDefault.aspx
10、Welcome.aspxRegister.aspx业务逻辑BusinessLogicLayer负责登录,注册用户,获取用户列表等业务操作DataAccessLayerModelsbllUser.cs UserRole.cs数据访问DataAccessLayer调用DataProvider相关方法修改或获取数据。ModelsDataProvider.csdalUser.cs业务实体Models定义对象实体类无TUser.cs14.3.2创建框架1. 建立数据库打开Access创建名为userinfo.mdb的数据库,并为其创建一个名为t_User的表,其结构如图所示。2. 新建解决方案打开VS
11、2008,依次选择文件新建项目命令,打开新建项目对话框中,然后选择项目类型为Visual Studio解决方案,选择模板为空白解决方案。然后填写解决方案的名称为ThreeLayers ,并指定保存位置,如图18-4所示。单击“确定”按钮,创建解决方案。3. 搭建表示层(1)在解决方案资源管理器中,在解决方案名称上单击鼠标右键,在弹出的快捷菜单中选择添加新建网站命令,如图18-8所示。(2)在打开的添加新网站对话框中,选择ASP.NET网站,选择位置为文件系统,并设置网站的路径,如图18-9所示。(3)设计Default.aspx如图所示。(4)添加一Web窗体,将其命名为Welcome.asp
12、x,其设计视图如图所示。(5)添加一Web窗体,将其命名为Register.aspx,其设计视图如图所示。(6)将建好的userinfo.mdb拷贝到站点的App_Data文件夹下。(7)添加Global.asax在其Application_Start()添加如下代码。void Application_Start(object sender, EventArgs e) /在应用程序启动时运行的代码 /应用程序运行时设置数据库路径。 string dbpath = this.Server.MapPath(/) + App_Datauserinfo.mdb; DataAccessLayer.Dat
13、aProvider.Instance.DBPath = dbpath; 4. 搭建业务逻辑层(类库)在解决方案资源管理器中,在解决方案名称上单击鼠标右键,在弹出的快捷菜单中选择添加新建项目命令,打开新建项目对话框中,然后选择项目类型为Visual C#,选择模板为类库。填写项目的名称为 BusinessLogicLayer ,该项目用于实现业务逻辑。此时项目的保存位置已经默认输入了,是刚才创建空白解决方案时产生的路径,如图18-6所示。5. 搭建数据访问层(类库)在解决方案资源管理器中,在解决方案名称上单击鼠标右键,在弹出的快捷菜单中选择添加新建项目命令,打开新建项目对话框中,然后选择项目类型
14、为Visual C#,选择模板为类库。填写项目的名称为DataAccessLayer,该项目用于实现数据访问层。此时项目的保存位置已经默认输入了,是刚才创建空白解决方案时产生的路径。6. 搭建数据对象模型层(类库)在解决方案资源管理器中,在解决方案名称上单击鼠标右键,在弹出的快捷菜单中选择添加新建项目命令,打开新建项目对话框中,然后选择项目类型为Visual C#,选择模板为类库。填写项目的名称为Models,该项目用于实现数据访问层。此时项目的保存位置已经默认输入了,是刚才创建空白解决方案时产生的路径,如图18-6所示。至此,已搭建了三层结构(添加了4个项目),此时的解决方案如图所示。7.
15、添加各层之间的引用(依赖)此时,虽然三层结构的基本框架已经搭建成功,但是各层之间是独立的。只有添加依赖关系,才能让它们相互协作。(1) 添加表示层对业务逻辑层、数据访问层和数据对象模型层的依赖。在解决方案资源管理器中,在表示层上单击鼠标右键,在弹出的快捷菜单中选择添加引用命令,打开添加引用对话框,然后选择项目选项卡,选中项目名称为 BusinessLogicLayer 的项目,单击确定按钮,如图18-13所示。同样添加对DataAccessLayer和Models的引用。(2)添加业务逻辑层对数据访问层和数据对象模型层的依赖。在解决方案资源管理器中,在业务逻辑层上单击鼠标右键,在弹出的快捷菜单
16、中选择添加引用命令,打开添加引用对话框,然后选择项目选项卡,选中项目名称为 DataAccessLayer 的项目,单击确定按钮。同样添加对Models的引用。(3)添加数据访问层对数据对象模型层的依赖。至此,三层结构及各层之间的依赖关系创建完毕。现在你的ThreeLayers解决方案资源管理器应该如图所示:8. 将表示层设置为启动项目运行程序前,还需设置启动项目。在解决方案资源管理器中的表示层上单击鼠标右键,在弹出的快捷菜单中选择设为启动项目命令,将表示层设置为启动项目。将表示层设置为启动项目后,表示层(站点)自动创建了Bin文件夹,该文件夹下生成了:BusinessLogicLayer.d
17、ll、BusinessLogicLayer.pdb、DataAccessLayer.dll、DataAccessLayer.pdb、Models.dll和Models.pdb等6个文件,如图所示。通过上述步骤,就已经成功部署了ASP.NET的三层架构。在MyWeb这一层我们放置用于显示的Web页面,在 Business层,我们把所有的业务逻辑代码在该层实现。DataAccess层主要处理数据库的操作,供Business层调用。只要在各个层中实现具体的类就可以成功实施三层结构的应用程序了。14.3.3在各个层中实现具体的类1. Models中的类Models中的类为实体类。实体类仅定义数据模型,
18、该模型应与数据表对应,属性定义应与数据表的字段名一致。一个表会有一个对应的实体类。本数据库只有一个表t_User,所以只需定义一个实体类TUser.cs。其代码如下: public class TUser private int _id = 0; private string _nickname; private string _name; private string _pwd; public int id get return _id; set _id = value; public string name get return _name; set _name = value; publ
19、ic string nickname get return _nickname; set _nickname = value; public string pwd get return _pwd; set _pwd = value; 2DataAccessLayer中的类DataAccessLayer中的类用于用户数据的存取。数据访问层是与数据库交互的层级。如获取数据,更新数据,插入记录等等。它的上一级是业务逻辑层。业务逻辑层需要操作某数据时,调用数据访问层的接口,数据访问层操作OleDb接口访问Access数据库,最后返回数据。 本例DataAccessLayer中共有如下两个类。(1)Da
20、taProvider.cs该类定义(重载)了许多方法来操作Access数据库,其方法供dalUser.cs调用,其代码如下。using System.Data.OleDb;/ 操作OleDb接口访问Access数据库public class DataProvider private static DataProvider _Instance = null; / / 数据提供者对象实例,因程序频繁请求数据,减少创建对象的次数。 / public static DataProvider Instance get if (_Instance = null) _Instance = new DataP
21、rovider(); return _Instance; private string _dbPath = ; / / Access数据库路径 / public string DBPath get return _dbPath; set _dbPath = value; / / 提供数据表 / / SQL 查询语句 / 数据表名 / public DataTable GetTable(string sql, string tableName) OleDbConnection conn = this.CreateConnection(); OleDbCommand cmd = new OleDb
22、Command(sql, conn); OleDbDataAdapter adp = new OleDbDataAdapter(cmd); DataTable dt = new DataTable(tableName); adp.Fill(dt); conn.Close(); conn.Dispose(); return dt; / / 执行查询,并返回查询所返回的结果集中第一行的第一列。忽略其他列或行。 / / / public object ExecScalar(string sql) OleDbConnection conn = this.CreateConnection(); OleD
23、bCommand cmd = new OleDbCommand(sql, conn); object o = cmd.ExecuteScalar(); conn.Close(); conn.Dispose(); return o; / / 针对System.Data.OleDb.OleDbCommand.Connection 执行SQL 语句并返回受影响的行数。 / / / public int ExecNoQuery(string sql) OleDbConnection conn = this.CreateConnection(); OleDbCommand cmd = new OleDb
24、Command(sql, conn); int ret = cmd.ExecuteNonQuery(); conn.Close(); conn.Dispose(); return ret; / / 创建一个OleDbConnection连接. / / private System.Data.OleDb.OleDbConnection CreateConnection() string connStr = Provider=Microsoft.Jet.OLEDB.4.0;Data Source= + DBPath; OleDbConnection conn = new OleDbConnecti
25、on(connStr); if (conn.State != ConnectionState.Connecting) conn.Open(); return conn; (2)dalUser.cs该类还调用TUser类对象,定义了获取所有用户列表、新增用户(注册)和检查用户是否存在(注册检查)等方法。该类通过调用DataProvider相关方法修改或获取数据,其代码如下。using Models;/引用数据对象模型层Modelspublic class dalUser private static dalUser _Instance = null; public static dalUser
26、Instance get if (_Instance = null) _Instance = new dalUser(); return _Instance; / / 获取所有用户列表 / / public DataTable GetUsers() string sql = select * from t_User; return DataProvider.Instance.GetTable(sql, t_User); / / 新增用户 / / 用户对象 / public bool AddUser(TUser user) /往数据库写入记录 string sql = insert into t
27、_User(name,nickname,pwd) values (0,1,2) ; sql = string.Format(sql, user.name, user.nickname, user.pwd); int i = DataProvider.Instance.ExecNoQuery(sql); return i 0; / / 用户登录 / / 登录帐号 / public bool Login(string name, string pwd) string sql = select count(*) from t_User where name= + name + and pwd= +
28、pwd + ; object o = DataProvider.Instance.ExecScalar(sql); return int.Parse(o.ToString() 0; / / 检查用户是否存在 / / 用户编号 / public bool ExistsUser(string name) string sql = select count(*) from t_User where name= + name + ; object o = DataProvider.Instance.ExecScalar(sql); return int.Parse(o.ToString() 0; 3B
29、usinessLogicLayer中的类BusinessLogicLayer中的类主要负责数据的传递和处理。共有如下两个类。(1)UserRole.cs该类调用TUser类对象和dalUser类对象,定义用户是否存在和用户是否合法的方法,制定用户规则,检查数据合法性。其代码如下。using Models;using DataAccessLayer;public class UserRole public static void Validate(TUser user) if (dalUser.Instance.ExistsUser(user.name) throw new Exception(
30、用户已经存在!); public static void ValidateLogin(string name, string pwd) if (name.Trim() = ) throw new Exception(用户编号不正确或不能为空!); if (pwd.Trim() = ) throw new Exception(密码不正确或不能为空!); (2)bllUser.cs该类调用TUser类对象、dalUser类对象和UserRole类的相关方法,负责登录,注册用户,获取用户列表等业务操作。其代码如下。using Models;using DataAccessLayer;using Bu
31、sinessLogicLayer.Roles;public class bllUser / / 新增用户 / / 用户对象 / public bool AddUser(TUser user) /向数据库写入数据之前,检查数据的合法性。比如SQL注入,暴力注入等业务操作。 /如果数据是合法的,可以写入数据了。这种逻辑性操作,是不是属于业务逻辑的范畴呢? UserRole.Validate(user); return dalUser.Instance.AddUser(user); public bool Login(string name, string pwd) /检查登录信息 UserRole
32、.ValidateLogin(name, pwd); /调用数据访问层的接口检查用户登录 return dalUser.Instance.Login(name, pwd); public DataTable GetUsers() return dalUser.Instance.GetUsers(); 14.3.4用户界面层中的事件代码1. Default.aspx.cs中的事件代码该页面调用业务逻辑层的接口bllUser().Login()方法,实现用户登录,或转到用户注册页面。using BusinessLogicLayer;protected void btnLogin_Click(obj
33、ect sender, EventArgs e) try /页面展示层调用业务逻辑层的接口. bool login = new bllUser().Login(TextBox1.Text, TextBox2.Text); if (login) /成功 this.Sessionuid = TextBox1.Text; this.Sessiontime = DateTime.Now; this.Response.Redirect(Welcome.aspx); else Msg.Show(this, 用户名或密码不正确!); catch (Exception ex) Msg.Show(this, e
34、x.Message); protected void ButtonRegister_Click(object sender, EventArgs e) this.Response.Redirect(Register.aspx); 2. Welcome.aspx.cs中的事件代码登录成功后,出现欢迎页面,同时通过Session对象将登录页面输入的用户信息通过显示在该页面中。 /显示登录名,Session获取 public string Getnickname() string uid = (string)this.Sessionuid; return uid = null ? 您还没有登录! :
35、 uid; /最后登录时间,Session获取 public string GetLastLogin() if (this.Sessiontime = null) return 您还没有登录!; else return this.Sessiontime.ToString();Welcome.aspx中的代码 您的昵称: 登录时间: 3. Register.aspx.cs中的事件代码该页面调用数据对象模型层TUser对象来创建用户对象;调用业务逻辑层的接口bllUser().AddUser()方法,实现用户注册,调用bllUser().GetUsers()方法显示用户列表。using Models;using BusinessLogicLayer;protected void Button1_Click(object sender, EventArgs e) /用户注册 if (TextBox1.Text.Trim() = | TextBox2.Text.Trim() = | TextBox3.Text.Trim() = ) Msg.Show(this, 请填写完整的注册信息!); return; if (TextBox3.Text!= T