版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基于Docker的云计算快速开发测试架构(完整资料)(可以直接使用,可编辑优秀版资料,欢迎下载)
基于Docker的云计算快速开发测试架构(完整资料)(可以直接使用,可编辑优秀版资料,欢迎下载)基于Docker的云计算快速开发测试架构中国邮政集团公司山东省信息技术局马岩概述随着山东邮政业务转型的深入和业务种类的多样化发展,迫切需要邮政IT部门的支撑和引领作用,特别是在当前业务发展迅速,各业务功能开发和上线频繁的情况下,对我们的系统开发能力提出了更高的要求,而现有的开发测试环境存在资源利用效率低,测试版本管理复杂,迁移成本高等诸多缺点.以Docker为代表的容器云计算技术自去年起逐步成长起来,容器技术以它轻量,快速,隔离的优势,迅速在IT学术界和企业界引起了广泛的关注。本文在概述Docker容器核心技术理念基础上,着重介绍了我们利用Docker容器云计算技术优化系统开发过程的思路,并搭建了一个以docker技术为基础的开发测试框架。该框架有效整合了开发和测试环境,显著提高了我们开发测试的速度和质量,使我们能更好的服务于业务的发展。Docker容器云计算技术2。1Docker核心技术Docker是以Linux的cgroup、namespace等容器技术为基础的开源容器引擎,目前已经获得包括微软,Google,红旗等主流IT厂商的支持.Docker利用轻量级的虚拟化技术,有效的封装了操作系统底层的隔离,进程独立等功能,实现了各种依赖环境和应用的打包,方便了项目的开发测试和部署过程。Docker与传统虚拟机技术的对比:传统的虚拟化技术例如vmware公司的vsphere目标是建立一个从硬件到软件模拟化的虚拟机,具有整套的操作系统环境,而Docker技术则是基于操作系统的底层容器API,他没有模拟完整的操作系统环境,从进程上看,docker虚拟机里只有应用的进程而没有其他的操作系统进程,它将项目的源码,依赖和环境配置打包成一个隔离独立的运行环境,所以它具有快速轻量的特点。2.2Docker解决的主要问题2.2.1减轻虚拟化的成本传统的虚拟机技术要安装操作系统后才能使用,而操作系统本身会占用大量的系统资源,是一种极大的浪费。而Docker容器不需要操作系统安装也能运行,在提供了进程隔离的同时,为应用的运行提供了有效的运行环境。2。2.2应用的快速运行和部署Docker独有的镜像技术,使各种环境依赖和应用打包后形成镜像存储在Docker仓库中,当需要部署运行的时候,只要从仓库获取运行镜像即可得到相应的功能,docker将复杂的部署过程,简化为复制加运行,不需要中间多余的工作.2.2.3资源的有效度量Docker利用操作系统的容器API可以对cpu,网络,内存等各种资源进行有效的定制和度量,减少了单个应用死循环对其他应用的影响.2。2.4复杂环境依赖的有效隔离应用的运行环境需要多种第三方插件和运行中间件的支持,这给应用的开发测试带来了很大的复杂性,往往新环境的搭建要耗费大量的时间和精力。Docker通过将多种依赖库和中间件打包成镜像的方法,有效减轻了环境搭建和移植的复杂性,同时Docker支持镜像的叠加,容器的网络等功能,从而进一步简化了环境构建的工作。2.3Docker的主要部件Docker主要部件包括Docker客户端,docker后台进程,docker镜像仓库和docker容器进程四个部分。2。3.1Docker客户端用户通过Docker客户端与docker后台守护进程进行通讯,通过Docker客户端命令行工具,发起对Docker各种功能的操作指令.Docker通讯支持tcp,unixsocket等多种通讯方式。2.3.2Docker后台守护进程Docker后台守护进程包含两个模块,Docker服务和Docker引擎。Docker服务接受来自Docker客户端发送的命令,并交由Docker引擎中相应的处理程序进行处理。Docker引擎是实际完成工作的核心进程。2。3.3Docker仓库Docker仓库用于存放Docker镜像。镜像类似虚拟机的快照概念,是Docker容器运行的代码基础。Docker仓库可以使用公有仓库DockerHub,也可以搭建企业内部的私有仓库。2。3.4DockerFile构建文件DockerFile描述了一个完整的镜像的构建过程,包括依赖软件和中间件的安装,目录,环境变量,暴露端口,端口映射等。基于Docker容器的云计算快速开发测试框架3。1现有开发测试环境及存在的问题下图是一个开发测试和部署的过程,传统的开发测试过程存在如下几个问题:1、资源利用效率低2、单物理机多应用无法有效隔离(进程空间,cpu资源,磁盘)3、运维部署不便4、测试、版本管理复杂5、迁移成本高6、传统虚拟机,空间占用大,启动慢,管理复杂一个IT系统应该包含如下几个层次:应用程序运行时平台(bin/framework/lib)操作系统硬件(基础设施)开发人员的主要工作是应用程序的编码、构建、测试和发布,涉及应用程序和运行时平台这两层.而运维人员的工作则涉及从硬件、操作系统到运行时平台的安装、配置、运行监控、升级和优化等工作。docker提供了一种运行时环境,隔离了上层应用于下层操作系统和硬件的关联,使得术业有专攻。3。2Docker容器的云计算快速开发测试框架框架流程图如下:如上图所示,通过创建镜像仓库群,开发用户从仓库获取标准镜像,进行开发测试,完成后将结果镜像保存在Docker镜像仓库中,测试机从仓库中获取开发完成的镜像,并进行验证测试,测试通过后,生产环境可以获取最新的镜像进行部署,同时对原有镜像进行备份处理。3.2.1框架部署结构图框架部署图如下所示:我们通过vmware公司的vsphere软件建立虚拟化集群,在虚拟化集群服务中建立云端Docker仓库服务器,测试机和生产服务器,开发人员通过网络连接Docker镜像仓库,下载需要开发的环境镜像文件,同时可以根据生产备份和测试备份,直接获取生产版本或者测试版本,开发后在生产环境进行部署.3.3关键技术及过程1、容器创建容器的创建过程类似于快照中创建虚拟机,可以把容器看做是一个简易版的Linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序.容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台.如上图所示,我们从#0号镜像创建了tomcat容器2、端口映射端口映射功能提供了一种容器之间通讯的一种手段,如下图所示:容器myapp1将内部的80端口映射成8080端口对外提供服务3、数据卷共享数据卷是一个可供一个或多个容器使用的特殊目录,完成进程和数据的分离,实际保存在容器之外,从而允许你在不影响数据的情况下销毁、重建、修改、丢弃容器,可用于数据持久化。数据卷的使用,类似于Linux下对目录或文件进行mount.数据卷的共享,可以在多个容器之间共享数据卷上图中深绿色表示数据卷以及数据卷在各容器之间的共享4、链接容器容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式.在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息,Docker在两个互联的容器之间创建了一个安全隧道,而且不用映射它们的端口到宿主主机上。从而避免了暴露关键系统(如数据库)端口到外部网络上。如上图所示,web容器与myapp_db容器之间通过链接方式将数据库的端口开放给web应用。5、仓库创建及注册仓库是集中存放镜像文件的场所,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签,仓库分为公开仓库(Public)和私有仓库(Private)两种形式,可以push镜像到仓库或者从仓库pull下镜像。总结创新点与成效比较传统的开发测试流程和以docker为基础的开发测试框架,提出了三处创新:简化了环境搭建的步骤以往开发环境的搭建,需要自己安装操作系统,安装各种中间件软件和依赖库,采用docker容器后,我们需要的仅仅是复制运行,中间环节全部去除,并且保证了各个开发人员环境的一致性。提高了资源利用效率为了减少各个应用之间互相影响,业务测试都需要一台独立的物理主机或者虚拟机进行测试,,采用docker技术后,各个应用可以共用一台主机,由于进程,内存,cpu,网络等资源的隔离,应用之间的影响降为最低。降低了迁移成本旧开发模式下,完成的代码要上线到生产环境,需要在生产环境安装需要的依赖软件和库文件,采用docker技术后,我们只需要将开发完成的镜像文件放到生产环境中运行即可,因为镜像本身就带有自己的依赖文件和环境参数,不需要运维人员进行修改和调整。基于Docker云计算的开发测试环境的应用成效:采用该框架后,我们的开发测试工作中的环境搭建任务大为减轻,开发质量和交付速度显著提高,有效支撑了业务的发展通过浏览博客园的文章发现,很多朋友对分层架构特别感兴趣,刚好我刚做完的毕业设计就是专门研究.NET平台上分层架构的(题目叫“基于.NET平台的分层架构与设计模式应用研究”).通过做这篇论文,我对分层架构有了一定的了解,所以,就萌发了想写一个文章系列,详述一下分层架构。然而,论文的理论性太强,不适合在网上发布,尤其不适合初学者理解,所以,我想在这个文章系列中,少讲理论,而是通过做一个完整的案例来讨论分层架构的基本方法,这样会直观很多。希望在这个文章系列的写作过程中,能和朋友们一起学习,一起进步。
为了让朋友们把主要精力放在理解分层架构而不是案例本身,我准备选择一个相对简单的留言本系统作为Demo,这个系统的名字就叫做NGuestBook。
ﻫ
初步计划将这个文章系列分为以下几篇:
1.综述ﻫ
2.系统需求分析及数据库设计ﻫ
3.架构概要设计
4.实体类的实现ﻫ
5。接口的设计与实现
6。依赖注入及IoC的设计与实现
7。数据访问层的第一种实现——Access+动态生成SQL语言ﻫ
8.数据访问层的第二种实现——SQLServer+存储过程ﻫ
9.数据访问层的第三种实现——基于NBear框架的ORM实现ﻫ
10.业务逻辑层的实现
11。表示层的实现ﻫ
12。使用ASP.NETAJAX框架对表示层进行改进
13.总结
当然,以上只是初步计划,在写文章的过程中可能会根据具体情况适当调整,但是内容大体就是这些。
这个文章系列不会对所用到的技术进行详细讲解,具体请参考相关文献,阅读文章前最好能对以下技术有一个了解:ﻫ
1.C#语言ﻫ
2。ASP.NETﻫ
3.设计模式
4.关系数据库基础知识ﻫ
5.软件架构基本原则与软件工程基础知识ﻫ
6。基于NBear框架的ORM技术
7。JavaScript,Ajax
8。ASP.NETAJAX框架(特别是客户端编程)ﻫ
9.HTML,CSS,标准化布局ﻫﻫ
另外,本文章系列是基于.NETframework2.0框架平台进行讨论,3。5平台的新特性(如LINQ、ASP.NETMVC等)不会讨论,IDE使用VisualStudio2005,数据库会用到SQLServer2005Express和Access2003。在实际的项目中,需求分析和数据库的设计是很重要的一个环节,这个环节会直接影响项目的开发过程和质量。实际中,这个环节不但需要系统分析师、软件工程师等计算机方面的专家,还需要相关领域的领域专家参与才能完成。ﻫﻫ
但是,在这个文章系列中,所要使用的Demo仅仅是一个例子,而且其业务极为简单,因此,这里并不是真正的需求分析和数据库设计,而是将Demo的需求和数据库罗列至此,使朋友们对Demo有一个大体的了解,方便后续文章中开发过程的理解。
需求分析:
这个项目是一个留言本,其业务极为简单,现将其描述如下。
1.任何访问者可以进行留言,留言完成后,不会立即显示正文,而是要经过管理员验证后才可显示。
2。任何访问者可以对留言发表评论,未通过验证的留言不可以评论。ﻫ
3.管理员可以对留言进行回复(这个回复不同于评论,是直接显示在正文下面,而且是一个留言只能有一个回复),并可对留言与评论实行删除,以及对留言进行通过验证操作。ﻫ
4.管理员分为超级管理员和普通管理员。超级管理员只有一个,负责对普通管理员实行添加、删除操作.普通管理员可偶多个,负责对留言的管理,并可以修改自己的登录密码.
ﻫ
这个项目的用例图如下:ﻫ
数据库设计:ﻫ
设计数据表之前,首先进行实体和关系的识别与确定。ﻫ
通过需求分析,可以观察得出,本项目的实体有:管理员(不包括超级管理员),留言,评论。本项目的关系有:留言与评论间的一对多关系.ﻫﻫ
进一步,数据库各表的设计如下:
ﻫ
管理员表(TAdmin)ﻫ
ID
int
管理员ID
NotNull
主键,自增
Name
varchar(20)
登录名
NotNull
Password
varchar(50)
登录密码
NotNull
使用MD5加密ﻫﻫ
留言表(TMessage)
ID
int
留言ID
NotNull
主键,自增
GuestName
varchar(20)
留言者用户名
NotNull
GuestEmail
varchar(100)
留言者E-mail
Null
Content
text
留言内容
NotNullﻫ
Time
datetime
发表留言时间
NotNull
ﻫ
Reply
text
回复
Null
IsPass
varchar(10)
是否通过验证
NotNull
ﻫ
评论表(TComment)
Content
text
评论内容
NotNullﻫ
Time
datetime
发表评论时间
NotNull
MessageID
int
所属留言的ID
外键基于。NET平台的分层架构实战(三)—架构概要设计
本文主要是对将要实现的架构进行一个总体的描述,使朋友们对这个架构有个宏观上的认识。这篇文章理论性的东西会偏多一点,从下篇开始,将进行实际项目的开发.这篇文章的许多内容摘自我的毕业论文.架构基本原则:这里,将描述一些在这个架构设计中的基本原则,其中很多都是经典的设计原则,不过针对分层架构的特点,用我自己的语言进行了描述。其中也有我自己提出的原则。逐层调用原则及单向调用原则现在约定将N层架构的各层依次编号为1、2、…、K、…、N-1、N,其中层的编号越大,则越处在上层.那么,我们设计的架构应该满足以下两个原则:1.第K(12.如果P层依赖Q层,则P的编号一定大于Q。其中第一个原则,保证了依赖的逐层性,及整个架构的依赖是逐层向下的,而不能跨层依赖。第二个原则,则保证了依赖的单向性,及只能上层依赖底层,而不能底层反过来依赖上层。针对接口编程,而不是针对实现编程
这里所指的接口,不是特指编程语言中的具体语言元素(如C#中由Interface定义的语言接口),而是指一种抽象的,在语义层面上起着接合作用语义体。它的具体实现,可能是接口,可能是抽象类,甚至可能是具体类。我认为,从不同的视角,接口可以有以下两种定义:1.接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。2。接口是在一定粒度视图上同类事物的抽象表示。注意这里我强调了在一定粒度视图上,因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。具体到N层架构中,针对接口编程的意义在部分上是这样的:ﻫ现仍约定将N层架构的各层依次编号为1、2、…、K、…、N-1、N,其中层的编号越大,则越处在上层,那么第K层不应该依赖具体一个K-1层,而应该依赖一个K-1层的接口,即在第K层中不应该有K—1层中的某个具体类.依赖倒置原则在软件设计原则中,有一种重要的思想叫做依赖倒置。它的核心思想是:不能让高层组件依赖底层组件,而且,不管高层组件和底层组件,两者都应依赖于抽象。那么,这个原则和我们上面的原则是否矛盾呢?其实并不矛盾。因为这个原则定义中的“依赖”是指“具体依赖",而上面定义中的依赖全部指“抽象依赖”。我对这两种依赖的定义如下:具体依赖——如果P层中有一个或一个以上的地方实例化了Q层中某个具体类,则说P层具体依赖于Q层。抽象依赖—-如果P层没有实例化Q层中的具体类,而是在一个或一个以上的地方实例化了Q层中某个接口,则说P层抽象依赖于Q层,也叫接口依赖于Q层。从这两个定义可以看到,所谓的依赖倒置原则,正是上面提到针对接口编程,而不是针对实现编程,两者在本质上是统一的.综上所述,可以看出,本课题设计的分层架构,应该是这样一种架构:ﻫ1。N层架构的各层依次编号为1、2、…、K、…、N—1、N,其中层的编号越大,则越处在上层。2.架构中仅存在一种依赖,即第K层接口依赖第K—1层,其中1封装变化原则封装变化的原则定义为:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混杂在一起。开放-关闭原则开发-关闭原则定义为:对扩展开放,对修改关闭.具体到N层架构中,可以描述为:当某一层有了一个新的具体实现时,它应该可以在不修改其他层的情况下,与此新实现无缝连接,顺利交互。单一归属原则在这个架构中,任何一个操作类都应该有单一的职责,属于单独的一层,而不能同时担负两种职责或属于多个层次(实体类及辅助类可以被多个层使用,但它们不属于任何一个层,而是独立存在)。层次划分:目前,典型的分层架构是三层架构,即自底向上依次是数据访问层、业务逻辑层和表示层.这种经典架构经历了时间的考验和实践的多次检验,被认为是合理、有效的分层设计,所以,在本文中,将沿袭这种经典架构,使用数据访问层、业务逻辑层和表示层的三层架构体系.职责划分:
目前,在典型的三层架构中,对层次各自的职责划分并没有一个统一的规范,综合现有的成功实践和.NET平台的特殊性,在本文中将三层架构的职责划分如下:
数据访问层--负责与数据源的交互,即数据的插入、删除、修改以及从数据库中读出数据等操作。对数据的正确性和有效性不负责,对数据的用途不了解,不负担任何业务逻辑。业务逻辑层--负责系统领域业务的处理,负责逻辑性数据的生成、处理及转换。对流入的逻辑性数据的正确性及有效性负责,对流出的逻辑性数据及用户性数据不负责,对数据的呈现样式不负责。表示层-—负责接收用户的输入、将输出呈现给用户以及访问安全性验证。对流入的数据的正确性和有效性负责,对呈现样式负责,对流出的数据正确性不负责,但负责在数据不正确时给出相应的异常信息。模块划分及交互设计:综合以上分析,可在宏观上将整个系统分为一下几个模块:实体类模块-—一组实体类的集合,负责整个系统中数据的封装及传递。数据访问层接口族——一组接口的集合,表示数据访问层的接口。业务逻辑层接口族--一组接口的集合,表示业务逻辑层的接口。数据访问层模块——一组类的集合,完成数据访问层的具体功能,实现数据访问层接口族。业务逻辑层模块——一组类的集合,完成业务逻辑层的具体功能,实现业务逻辑层接口族。表示层模块——程序及可视元素的集合,负责完成表示层的具体功能。IoC容器模块——负责依赖注入的实现。辅助类模块——完成全局辅助性功能。各模块见交互关系如下:
图1这篇中理论比较多,但是它是整个架构的基础,可以帮助朋友们对将要实现的项目架构及要遵循的原则有一个整体的了解.当然,在后续文章中,将主要讨论Demo项目的实际开发过程,那时,这些思想和理论性的东西将得到体现。实体类是现实实体在计算机中的表示。它贯穿于整个架构,负担着在各层次及模块间传递数据的职责。一般来说,实体类可以分为“贫血实体类”和“充血实体类”,前者仅仅保存实体的属性,而后者还包含一些实体间的关系与逻辑.我们在这个Demo中用的实体类将是“贫血实体类"。ﻫﻫ
大多情况下,实体类和数据库中的表(这里指实体表,不包括表示多对多对应的关系表)是一一对应的,但这并不是一个限制,在复杂的数据库设计中,有可能出现一个实体类对应多个表,或者交叉对应的情况。在本文的Demo中,实体类和表是一一对应的,并且实体类中的属性和表中的字段也是对应的。
ﻫ
在看实体类的代码前,先看一下系统的工程结构。
如上图所示,在初始阶段,整个系统包括6个工程,它们的职责是这样的:ﻫ
Web—-表示层
Entity——存放实体类
Factory——存放和依赖注入及IoC相关的类
IBLL——存放业务逻辑层接口族ﻫ
IDAL-—存放数据访问层接口族ﻫ
Utility--存放各种工具类及辅助类
ﻫ
这只是一个初期架构,主要是将整个系统搭一个框架,在后续开发中,将会有其他工程被陆陆续续添加进来.
我们的实体类将放在Entity工程下,这里包括三个文件:AdminInfo.cs,MessageInfo。cs,CommentInfo。cs,分别是管理员实体类、留言实体类和评论实体类。具体代码如下:
AdminInfo。cs:
1using
System;
2
3namespace
NGuestBook.Entity
4{ﻫ
5
///
<summary>
6
///
实体类—管理员ﻫ
7
///
</summary>
8
[Serializable]ﻫ
9
public
class
AdminInfoﻫ10
{
11
private
int
id;
12
private
string
name;
13
private
string
password;
1415
public
int
IDﻫ16
{
17
get
{
return
this.id;
}
18
set
{
this。id
=
value;
}ﻫ19
}ﻫ2021
public
string
Name
22
{
23
get
{
return
this.name;
}
24
set
{
this.name
=
value;
}
25
}ﻫ2627
public
string
Passwordﻫ28
{
29
get
{
return
this.password;
}ﻫ30
set
{
this.password
=
value;
}
31
}ﻫ32
}
33}
34
MessageInfo.cs:
1using
System;
2
3namespace
NGuestBook。Entity
4{
5
///
〈summary>
6
///
实体类-留言ﻫ
7
///
〈/summary〉
8
[Serializable]
9
public
class
MessageInfoﻫ10
{
11
private
int
id;
12
private
string
guestName;
13
private
string
guestEmail;
14
private
string
content;
15
private
DateTime
time;ﻫ16
private
string
reply;ﻫ17
private
string
isPass;ﻫ1819
public
int
IDﻫ20
{
21
get
{
return
this.id;
}ﻫ22
set
{
this.id
=
value;
}
23
}
2425
public
string
GuestNameﻫ26
{
27
get
{
return
this.guestName;
}ﻫ28
set
{
this.guestName
=
value;
}ﻫ29
}ﻫ3031
public
string
GuestEmailﻫ32
{ﻫ33
get
{
return
this.guestEmail;
}ﻫ34
set
{
this.guestEmail
=
value;
}
35
}ﻫ3637
public
string
Contentﻫ38
{ﻫ39
get
{
return
this。content;
}ﻫ40
set
{
this.content
=
value;
}
41
}
4243
public
DateTime
Time
44
{ﻫ45
get
{
return
this。time;
}ﻫ46
set
{
this.time
=
value;
}
47
}ﻫ4849
public
string
Replyﻫ50
{
51
get
{
return
this。reply;
}
52
set
{
this.reply
=
value;
}
53
}ﻫ5455
public
string
IsPassﻫ56
{
57
get
{
return
this.isPass;
}ﻫ58
set
{
this.isPass
=
value;
}
59
}ﻫ60
}
61}ﻫ62
CommentInfo.cs:
1using
System;ﻫ
2
3namespace
NGuestBook。Entity
4{ﻫ
5
///
〈summary>
6
///
实体类-评论ﻫ
7
///
〈/summary〉
8
[Serializable]
9
public
class
CommentInfoﻫ10
{ﻫ11
private
int
id;ﻫ12
private
string
content;
13
private
DateTime
time;ﻫ14
private
int
message;ﻫ1516
public
int
ID
17
{ﻫ18
get
{
return
this.id;
}ﻫ19
set
{
this.id
=
value;
}
20
}
2122
public
string
Contentﻫ23
{ﻫ24
get
{
return
this.content;
}
25
set
{
this.content
=
value;
}
26
}
2728
public
DateTime
Timeﻫ29
{
30
get
{
return
this.time;
}ﻫ31
set
{
this.time
=
value;
}ﻫ32
}
3334
public
int
Message
35
{ﻫ36
get
{
return
this.message;
}
37
set
{
this。message
=
value;
}
38
}ﻫ39
}
40}ﻫ41
大家可以看出,实体类的代码很简单,仅仅是负责实体的表示和数据的传递,不包含任何逻辑性内容。下篇将介绍接口的设计。接下来,将进行接口的设计。这里包括数据访问层接口和业务逻辑层接口.在分层架构中,接口扮演着非常重要的角色,它不但直接决定了各层中的各个操作类需要实现何种操作,而且它明确了各个层次的职责。接口也是系统实现依赖注入机制不可缺少的部分。
ﻫ
本项目的接口设计将按如下顺序进行:ﻫ
1.首先由前文的需求分析,列出主要的UI部分.
2.分析各个UI需要什么业务逻辑支持,从而确定业务逻辑层接口。ﻫ
3。分析业务逻辑层接口需要何种数据访问操作,从而确定数据访问层接口。ﻫ
另外,为保证完全的面向对象特性,接口之间的数据传递主要靠实体类或实体类集合,禁止使用DataTable等对象传递数据。
由需求分析,列出主要UI
需求分析部分,请参看基于。NET平台的分层架构实战(二)——需求分析与数据库设计。有需求分析,可以列出系统中主要应包括以下UI:ﻫ
UI01——主页面,列出全部的留言及相应评论,支持分页显示.留言按发表时间逆序显示,评论紧跟在相应留言下.管理员可以通过相应链接对留言执行通过验证、删除、回复以及对评论进行删除操作。游客可通过相应连接进入发表留言评论页面。ﻫ
UI02—-发表留言页面,供游客发表新留言.
UI03--发表评论页面,供游客发表评论。
UI04-—回复留言页面,供管理员回复留言.
UI05—-管理员登录页面。
UI06-—管理员修改个人密码的页面。
UI07——超级管理员登录后的页面,主要提供管理员列表。可以通过相应链接将指定管理员删除。ﻫ
UI08—-添加新管理员的页面。
UI09-—操作成功完成后的跳转提示页面。
UI10——系统出现异常时显示友好出错信息的页面。ﻫ
由UI识别业务逻辑操作
UI01:按分页取得留言,按指定留言取得全部评论,将指定留言通过验证,将指定留言删除,将指定评论删除
UI02:添加新留言
UI03:添加新评论
UI04:回复留言
UI05:管理员登录ﻫ
UI06:修改管理员密码ﻫ
UI07:取得全部管理员信息,删除管理员ﻫ
UI08:添加新管理员ﻫ
经过整理,可得以下接口操作:
IAdminBLL:Add(添加管理员),Remove(删除管理员),ChangePassword(修改管理员密码),Login(管理员登录),GetAll(取得全部管理员)
IMessageBLL:Add(添加留言),Remove(删除留言),Revert(回复留言),Pass(将留言通过验证),GetByPage(按分页取得留言)ﻫ
ICommentBLL:Add(添加评论),Remove(删除评论),GetByMessage(按留言取得全部评论)
这三个接口文件都放在IBLL工程下,具体代码如下:
ﻫIAdminBLL.cs:
1using
System;ﻫ
2using
System.Collections.Generic;ﻫ
3using
System.Text;
4using
NGuestBook。Entity;ﻫ
5
6namespace
NGuestBook.IBLLﻫ
7{
8
///
〈summary>
9
///
业务逻辑层接口—管理员ﻫ10
///
〈/summary〉11
public
interface
IAdminBLLﻫ12
{
13
///
<summary〉14
///
添加管理员
15
///
</summary〉16
///
〈param
name=”admin">新管理员实体类</param〉17
///
<returns>是否成功</returns>18
bool
Add(AdminInfo
admin);ﻫ1920
///
〈summary>21
///
删除管理员ﻫ22
///
</summary>23
///
<param
name="id”〉欲删除的管理员的ID</param>24
///
<returns>是否成功〈/returns>25
bool
Remove(int
id);
2627
///
〈summary>28
///
修改管理员密码
29
///
</summary>30
///
<param
name=”id”>欲修改密码的管理员的ID</param>31
///
〈param
name="password">新密码〈/param〉32
///
<returns〉是否成功</returns>33
bool
ChangePassword(int
id,string
password);
3435
///
<summary〉36
///
管理员登录
37
///
</summary>38
///
〈param
name=”name"〉管理员登录名〈/param〉39
///
<param
name=”password">管理员密码〈/param>40
///
〈returns〉如果登录成功,则返回相应管理员的实体类,否则返回null</returns>41
AdminInfo
Login(string
name,string
password);ﻫ4243
///
<summary〉44
///
取得全部管理员信息ﻫ45
///
</summary>46
///
<returns〉管理员实体类集合</returns〉47
IList〈AdminInfo>
GetAll();
48
}ﻫ49}ﻫIMessageBLL.cs:
1using
System;
2using
System.Collections。Generic;
3using
System。Text;
4using
NGuestBook.Entity;
5
6namespace
NGuestBook.IBLLﻫ
7{
8
///
〈summary〉
9
///
业务逻辑层接口—留言ﻫ10
///
</summary>11
public
interface
IMessageBLLﻫ12
{ﻫ13
///
<summary>14
///
添加留言ﻫ15
///
〈/summary>16
///
〈param
name=”message">新留言实体类〈/param>17
///
<returns>是否成功〈/returns>18
bool
Add(MessageInfo
message);ﻫ1920
///
〈summary〉21
///
删除留言ﻫ22
///
</summary>23
///
<param
name="id"〉欲删除的留言的ID</param>24
///
<returns>是否成功</returns>25
bool
Remove(int
id);
2627
///
〈summary>28
///
回复留言ﻫ29
///
</summary>30
///
〈param
name="id”〉要回复的留言的ID</param>31
///
<param
name=”reply">回复信息</param〉32
///
<returns>是否成功〈/returns>33
bool
Revert(int
id,
string
reply);ﻫ3435
///
<summary〉36
///
将留言通过验证
37
///
〈/summary>38
///
<param
name=”id">通过验证的留言的ID</param>39
///
<returns〉是否成功</returns〉40
bool
Pass(int
id);ﻫ4142
///
<summary〉43
///
按分页取得留言信息ﻫ44
///
〈/summary〉45
///
〈param
name=”pageSize"〉每页显示几条留言〈/param〉46
///
<param
name="pageNumber"〉当前页码</param>47
///
<returns>留言实体类集合</returns〉48
IList〈MessageInfo>
GetByPage(int
pageSize,int
pageNumber);ﻫ49
}ﻫ50}
ICommentBLL。cs
1using
System;
2using
System。Collections。Generic;
3using
System.Text;
4using
NGuestBook.Entity;ﻫ
5
6namespace
NGuestBook.IBLL
7{
8
///
〈summary>
9
///
业务逻辑层接口-评论
10
///
</summary>11
public
interface
ICommentBLLﻫ12
{ﻫ13
///
<summary〉14
///
添加评论
15
///
</summary>16
///
<param
name="comment”〉新评论实体类</param>17
///
<returns>是否成功</returns>18
bool
Add(CommentInfo
comment);
1920
///
〈summary〉21
///
删除评论ﻫ22
///
〈/summary〉23
///
〈param
name="id"〉欲删除的评论的ID</param〉24
///
<returns〉是否成功</returns>25
bool
Remove(int
id);
2627
///
<summary〉28
///
取得指定留言的全部评论ﻫ29
///
</summary>30
///
<param
name="messageId”>指定留言的ID</param〉31
///
〈returns>评论实体类集合</returns〉32
IList〈CommentInfo>
GetByMessage(int
messageId);
33
}ﻫ34}ﻫ
ﻫ
由业务逻辑确定数据访问操作
IAdminBLL需要的数据访问操作:插入管理员,删除管理员,更新管理员信息,按ID取得管理员信息,按登录名与密码取得管理员,取得全部管理员
IMessageBLL需要的数据访问操作:插入留言,删除留言,更新留言信息,按ID取得留言信息,按分页取得留言ﻫ
ICommentBLL需要的数据访问操作:插入评论,删除评论,按留言取得全部评论
另外,添加管理员时需要验证是否存在同名管理员,所以需要添加一个“按登录名取得管理员”.
对以上操作进行整理,的如下接口操作:
IAdminDAL:Insert,Delete,Update,GetByID,GetByNameAndPassword,GetAllﻫ
IMessageDAL:Insert,Delete,Update,GetByID,GetByPageﻫ
ICommentDAL:Insert,Delete,GetByMessage
这三个接口文件放在IDAL工程下,具体代码如下:ﻫﻫIAdminDAL。cs:
1using
System;ﻫ
2using
System.Collections。Generic;
3using
System.Text;ﻫ
4using
NGuestBook.Entity;ﻫ
5
6namespace
NGuestBook.IDAL
7{ﻫ
8
///
〈summary>
9
///
数据访问层接口-管理员ﻫ10
///
</summary〉11
public
interface
IAdminDAL
12
{
13
///
<summary>14
///
插入管理员
15
///
</summary〉16
///
<param
name="admin">管理员实体类</param〉17
///
<returns〉是否成功〈/returns〉18
bool
Insert(AdminInfo
admin);ﻫ1920
///
<summary>21
///
删除管理员ﻫ22
///
</summary〉23
///
〈param
name="id">欲删除的管理员的ID</param>24
///
〈returns>是否成功</returns>25
bool
Delete(int
id);
2627
///
<summary〉28
///
更新管理员信息ﻫ29
///
</summary>30
///
〈param
name="admin">管理员实体类〈/param〉31
///
〈returns>是否成功</returns〉32
bool
Update(AdminInfo
admin);ﻫ3334
///
<summary〉35
///
按ID取得管理员信息ﻫ36
///
</summary〉37
///
<param
name=”id">管理员ID</param〉38
///
<returns〉管理员实体类</returns〉39
AdminInfo
GetByID(int
id);
4041
///
〈summary〉42
///
按管理员名取得管理员信息
43
///
〈/summary>44
///
<param
name="name"〉管理员名〈/param〉45
///
<returns〉管理员实体类</returns〉46
AdminInfo
GetByName(string
name);
4748
///
<summary>49
///
按用户名及密码取得管理员信息
50
///
</summary>51
///
<param
name="name”>用户名</param>52
///
<param
name=”password">密码</param>53
///
<returns>管理员实体类,不存在时返回null</returns>54
AdminInfo
GetByNameAndPassword(string
name,string
password);
5556
///
〈summary>57
///
取得全部管理员信息
58
///
〈/summary>59
///
<returns〉管理员实体类集合</returns〉60
IList<AdminInfo>
GetAll();ﻫ61
}
62}
IMessageDAL.cs:
1using
System;
2using
System.Collections。Generic;
3using
System.Text;ﻫ
4using
NGuestBook。Entity;
5
6namespace
NGuestBook.IDAL
7{ﻫ
8
///
<summary〉
9
///
数据访问层接口-留言ﻫ10
///
</summary〉11
public
interface
IMessageDALﻫ12
{
13
///
〈summary>14
///
插入留言
15
///
〈/summary〉16
///
<param
name="message">留言实体类</param>17
///
〈returns>是否成功〈/returns>18
bool
Insert(MessageInfo
message);
1920
///
<summary>21
///
删除留言
22
///
</summary>23
///
〈param
name=”id">欲删除的留言的ID</param〉24
///
〈returns〉是否成功〈/returns〉25
bool
Delete(int
id);
2627
///
<summary〉28
///
更新留言信息ﻫ29
///
</summary〉30
///
<param
name="message”〉留言实体类〈/param>31
///
〈returns〉是否成功〈/returns>32
bool
Update(MessageInfo
message);
3334
///
<summary〉35
///
按ID取得留言信息ﻫ36
///
</summary>37
///
〈param
name="id”〉留言ID〈/param〉38
///
<returns>留言实体类〈/returns>39
MessageInfo
GetByID(int
id);ﻫ4041
///
<summary〉42
///
按分页取得留言信息ﻫ43
///
</summary>44
///
〈param
name="pageSize"〉每页显示几条留言</param〉45
///
〈param
name="pageNumber"〉当前页码</param>46
///
<returns>留言实体类集合</returns>47
IList<MessageInfo>
GetByPage(int
pageSize,int
pageNumber);
48
}
49}ﻫICommentDAL。cs:
1using
System;
2using
System.Collections.Generic;
3using
System.Text;
4using
NGuestBook.Entity;ﻫ
5
6namespace
NGuestBook.IDALﻫ
7{
8
///
〈summary>
9
///
数据访问层接口-评论ﻫ10
///
</summary>11
public
interface
ICommentDALﻫ12
{
13
///
<summary>14
///
插入评论
15
///
〈/summary>16
///
〈param
name="comment"〉评论实体类〈/param>17
///
〈returns>是否成功</returns〉18
bool
Insert(CommentInfo
comment);
1920
///
〈summary〉21
///
删除评论ﻫ22
///
〈/summary>23
///
<param
name=”id”〉欲删除的评论的ID</param>24
///
〈returns>是否成功</returns〉25
bool
Delete(int
id);
2627
///
〈summary〉28
///
取得指定留言的全部评论
29
///
〈/summary〉30
///
〈param
name=”messageId”>指定留言的ID</param>31
///
<returns〉评论实体类集合</returns>32
IList〈CommentInfo〉
GetByMessage(int
messageId);
33
}
34}我们设计的分层架构,层与层之间应该是松散耦合的。因为是单向单一调用,所以,这里的“松散耦合”实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口.这样,上层类不能直接实例化下层中的类,而只持有接口,至于接口所指变量最终究竟是哪一个类,则由依赖注入机制决定。ﻫﻫ
之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式实现数据访问层,只要这个实现遵循了前面定义的数据访问层接口,业务逻辑层和表示层不需要做任何改动,只需要改一下配置文件系统即可正常运行.另外,基于这种结构的系统,还可以实现并行开发。即不同开发人员可以专注于自己的层次,只有接口被定义好了,开发出来的东西就可以无缝连接。ﻫ
在J2EE平台上,主要使用Spring框架实现依赖注入。这里,我们将自己做一个依赖注入容器。
ﻫ
依赖注入的理论基础是AbstractFactory设计模式,这里结合具体实例简单介绍一下。ﻫ
上图以数据访问层为例,展示了AbstractFactory模式的应用。如图,现假设有针对Access和SQLServer两种数据库的数据访问层,它们都实现了数据访问层接口。每个数据访问层有自己的工厂,所有工厂都实现自IDALFactory接口。而客户类(这里就是业务逻辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件确定实例化哪个工厂,就可以得到不同的数据访问层.
ﻫ
然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,。NET平台引入的反射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置文件中读出程序集的名称,动态加载相应类。另外,为了提高依赖注入机制的效率,这里引入缓存机制。下面来看具体实现。
ﻫ
配置
首先,需要在Web工程的Web.config文件的〈appSettings〉节点下添加如下两个项:
<addkey="DAL"value="”/>ﻫ
〈addkey=”BLL"value=""/〉
这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value目前是空,是因为目前还没有各个层次的具体实现。
ﻫ
实现缓存操作辅助类
为实现缓存操作,我们将缓存操作封装成一个辅助类,放在Utility工程下,具体代码如下:
ﻫCacheAccess.cs:
封装依赖注入代码
因为很多依赖注入代码非常相似,为了减少重复性代码,我们将可复用的代码先封装在一个类中。具体代码如下(这个类放在Factory工程下):
DependencyInjector.cs:
1using
System;
2using
System。Web;ﻫ
3using
System.Web.Caching;ﻫ
4
5namespace
NGuestBook.Utilityﻫ
6{
7
///
<summary〉
8
///
辅助类,用于缓存操作ﻫ
9
///
〈/summary〉10
public
sealed
class
CacheAccess
11
{ﻫ12
///
<summary〉13
///
将对象加入到缓存中ﻫ14
///
〈/summary〉15
///
<param
name=”cacheKey"〉缓存键</param〉16
///
<param
name="cacheObject"〉缓存对象</param>17
///
〈param
name="dependency"〉缓存依赖项</param〉18
public
static
void
SaveToCache(string
cacheKey,
object
cacheObject,
CacheDependency
dependency)ﻫ19
{
20
Cache
cache
=
HttpRuntime。Cache;
21
cache。Insert(cacheKey,
cacheObject,
dependency);
22
}ﻫ2324
///
<summary>25
///
从缓存中取得对象,不存在则返回null
26
///
〈/summary>27
///
〈param
name="cacheKey"〉缓存键</param>28
///
<returns>获取的缓存对象</returns>29
public
static
object
GetFromCache(string
cacheKey)ﻫ30
{ﻫ31
Cache
cache
=
HttpRuntime。Cache;ﻫ3233
return
cache[cacheKey];ﻫ34
}
35
}ﻫ36}
1using
System;ﻫ
2using
System。Configuration;ﻫ
3using
System.Reflection;ﻫ
4using
System.Web;ﻫ
5using
System.Web.Caching;
6using
NGuestBook.Utility;ﻫ
7
8namespace
NGuestBook。Factoryﻫ
9{ﻫ10
///
〈summary〉11
///
依赖注入提供者ﻫ12
///
使用反射机制实现ﻫ13
///
</summary>14
public
sealed
class
DependencyInjectorﻫ15
{ﻫ16
///
<summary>17
///
取得数据访问层对象ﻫ18
///
首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象
19
///
</summary〉20
///
〈param
name=”className">数据访问类名称</param〉21
///
<returns>数据访问层对象〈/returns〉22
public
static
object
GetDALObject(string
className)
23
{ﻫ24
///
〈summary>25
///
取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取
26
///
缓存依赖项为Web.Config文件
27
///
〈/summary>28
object
dal
=
CacheAccess.GetFromCache(”DAL");ﻫ29
if
(dal
==
null)
30
{ﻫ31
CacheDependency
fileDependency
=
new
CacheDependency(HttpContext.Current。Server.MapPath(”Web.Config"));
32
dal
=
ConfigurationManager.AppSettings["DAL”];ﻫ33
CacheAccess.SaveToCache(”DAL",
dal,
fileDependency);
34
}
3536
///
<summary>37
///
取得数据访问层对象ﻫ38
///
〈/summary>39
string
dalName
=
(string)dal;ﻫ40
string
fullClassName
=
dalName
+
"。"
+
className;
41
object
dalObject
=
CacheAccess.GetFromCache(className);ﻫ42
if
(dalObject
==
null)ﻫ43
{
44
CacheDependency
fileDependency
=
new
CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
45
dalObject
=
Assembly。Load(dalName)。CreateInstance(fullClassName);ﻫ46
CacheAccess.SaveToCache(className,
dalObject,
fileDependency);ﻫ47
}ﻫ4849
return
dalObject;ﻫ50
}
5152
///
〈summary〉53
///
取得业务逻辑层对象
54
///
首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象ﻫ55
///
〈/summary〉56
///
<param
name=”className">业务逻辑类名称</param>57
///
<returns〉业务逻辑层对象</returns>58
public
static
object
GetBLLObject(string
className)
59
{
60
///
<summary>61
///
取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取ﻫ62
///
缓存依赖项为Web。Config文件ﻫ63
///
〈/summary>64
object
bll
=
CacheAccess.GetFromCache(”BLL");ﻫ65
if
(bll
==
null)
66
{
67
CacheDependency
fileDependency
=
new
CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
68
bll
=
ConfigurationManager.AppSettings[”BLL"];ﻫ69
CacheAccess.SaveToCache("BLL",
bll,
fileDependency);
70
}
7172
///
<summary>73
///
取得业务逻辑层对象
74
///
</summary>75
string
bllName
=
(string)bll;ﻫ76
string
fullClassName
=
bllName
+
”."
+
className;
77
object
bllObject
=
CacheAccess。GetFromCache(className);
78
if
(bllObject
==
null)
79
{ﻫ80
CacheDependency
fileDependency
=
new
CacheDependency(HttpContext。Current.Server.MapPath("Web.Config"));
81
bllObject
=
Assembly.Load(bllName).CreateInstance(fullClassName);
82
CacheAccess.SaveToCache(class
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 茶文化传承与推广规划方案书
- 售楼处方案分析
- 初中语文古文阅读理解训练方案
- 跨领域合作诚实守信承诺书范文8篇
- 审慎经营财务承诺书(8篇)
- 小学语文教师学期教学计划范例
- 2026年成都市人北实验小学校聘教师招聘备考题库及参考答案详解1套
- 2026年凯里市华鑫高级中学教师招聘备考题库及完整答案详解1套
- 2026年宁波市江北区史志中心招聘备考题库附答案详解
- 2026年北京赛迪出版传媒有限公司招聘备考题库及一套答案详解
- 污水站亮化工程施工方案
- 星间激光链路构建-洞察及研究
- 个人形象风格诊断与穿搭指南
- 旅游行程规划表模板
- “十三五”规划重点-锑矿石及精锑项目建议书(立项报告)
- 环卫公司内部管理制度
- 第3章 同位素示踪技术课件
- 创伤骨科患者深静脉血栓形成筛查与治疗的专家共识
- x线胸片诊断试题及答案
- 2024-2025学年高一上学期英语期末模拟卷(沪教版)含答案解析
- 火灾理论常识
评论
0/150
提交评论