王建祥,王洪泽
(河南省济源钢铁(集团)有限公司 信息化仪表处, 河南 济源 454650)
随着信息化技术的发展,管理信息系统得到普遍应用,而权限管理系统是各类管理信息系统的前提和基础。本文权限管理系统的设计按EF模型生成数据库、各层深度解耦、设计T4模板自动生成代码、设计前端等步骤进行[1-2]。
根据ASP.Net MVC系统的特性,权限管理系统的设计目标是:
1.UserInfo---RoleInfo---ActionInfo;用户拥有角色,权限拥有角色,从而用户拥有权限。
2.UserInfo---R_UserInfo_ActionInfo;用户直接拥有特殊权限。
具体实现过程如图1所示。
图1 权限管理的目标
本系统使用Visual Studio 2019 Enterprise 16.11版本软件进行权限管理软件开发和调试,使用ASP.NET MVC技术进行设计,其中DAL层到BLL层的解耦使用复杂工厂技术,BLL层到UI层的解耦使用Spring.Net技术[3]。
2.1.1 建立方案并组织管理各层项目
新建解决方案文件夹: 解决方案文件夹是虚拟文件夹,其作用是便于项目的管理。
表现层——项目类型w e b 应用程序---.N E T Framework
jygt.AutoWeightSystem.UI.Portal
2.1.2 Model 层添加实体数据模型并生成数据库
使用EF技术的Model First方式生成数据库: 项目开始没有数据库,根据EF设计模型,进行模型同步完成数据库及表的创建。
添加ADO.NET实体数据模型---空EF设计器,命名DataModel
1、在EF设计器DataModel中添加实体及属性、关联
(1) 添加实体模型UserInfo
(2) 添加实体模型OrderInfo
(3) 建立实体UserInfo与实体OrderInfo两个实体之间1对多的关联。
2、根据模型生成数据库
右击EF设计器空白处---添加代码生成项,把名称改成DataModel.tt,即生成上述实体模型UserInfo、实体模型OrderInfo对应的实体类文件。
右击EF设计器空白处---根据模型生成数据库,生成DataModel.edmx.sql文件,执行DataModel.edmx.sql文件生成数据库及表。EF技术生成的数据库如图2所示。
图2 EF 技术生成的数据库
2.1.2 设计DAL 数据访问层
查询方法的设计思路:
1.方法选择。方法需能接受用户输入的任意条件,返回值应是b o o l 类型,因此可以用委托Func
2.方法返回值类型选择。返回值是用户,由于返回的用户个数不确定,不能用UserInfo类型,可使用List
3.继续深入考虑,如果返回值是List
继续深入思考方法,F u n c
综上,DAL层使用如下方法实现查询:
2.1.3 设计封装数据访问层基类BaseDAL
DAL层的各个方法,经测试全部正确后,目前只是针对UserInfoDAL,针对OrderInfoDAL同样也有增删改查等类似方法,仅数据实体对象不同,还有其他实体都要写类似的增删改查方法,不经专门处理就会有很多重复工作。因此把相同的方法提出来,封装成一个基类,所有类似通用方法写在此基类里面,然后让子类去继承使用该基类的增删改查方法。
需要使用泛型类,即把BaseDAL类改成泛型类,然后加上泛型约束,
public class BaseDAL
2.1.4 添加数据访问层的接口IDAL
在数据访问层建立的基础上,创建业务逻辑层(BLL)类库。在jygt.AutoWeightSystem.BLL层中新建一个类UserInfoBLL,然后添加方法,
上述做法需要改进的地方:
1.上述做法会使jygt.AutoWeightSystem.BLL层与jygt.AutoWeightSystem.EFDAL层紧密耦合在一起,EFDAL层发生变化BLL层就必须跟着变,比如UserInfoDAL的名称变了,BLL层必须跟着变。
2.DAL层的可能变化点:(1)跨数据库,如SqlServer、Oracle、 mysql,对于采用EF技术,本身就支持跨数据库(2)数据库访问驱动层驱动变化,比如不采用EFDAL,采用ADODAL或者NHDAL。
3.项目设计原则:模块内高内聚,模块间低耦合。期望DAL层变化的情况下,BLL层不需要变化或者变化最小。
于是进行如下改进:
D A L 层中就添加一个类库项目j y g t .AutoWeightSystem.IDAL(注意命名规范),表示DAL层的接口,创建IuserInfoDAL接口。
然后在IuserInfoDAL接口里定义抽象的增删改查的方法。同理,添加OrderInfoDAL等实体的DAL接口IOrderInfoDAL,里面同样添加抽象的增删改查方法。这时由IuserInfoDAL接口和IOrderInfoDAL接口可以抽象出一个基类接口。
2.1.5 抽象出数据访问层的基类接口
p u blic interf ace IBaseD A L
接着让IUserInfoDAL、IOrderInfaDAL继承IBaseDAL,原有的方法结构注释或删除,IorderInfaDAL类不存在就新建,并导入Model命名空间。然后修改EFDAL层下的UserInfoDAL和OrderInfoDAL,让其分别实现IUserInfoDAL、IOrderInfaDAL,同时添加对IDAL层jygt.AutoWeightSystem. IDAL的引用。这样UserInfoDAL实例用接口IUserInfoDAL来接收,使用接口接收就可以做到不依赖具体实现。
2.1.6 用接口隔离业务逻辑层BLL 对DAL 的依赖
切换到业务逻辑层UserInfoBLL,用接口类型来接收new UserInfoDAL(),这个前提是UserInfoDAL类要实现IUserInfoDAL接口,否则不能接收,其好处是下面的方法依赖的是接口,因为接口中的成员都是抽象的,具体实现发生变化不影响接口。如此new UserInfoDAL()即数据访问驱动层采用其他技术来实现对数据库的访问,下面的方法代码不发生变化。UserInfoDAL();//具体实现方法;
例如,数据访问驱动层改用Nhibernate实现对数据库的访问。实现方法如下。
添加类库项目,命名为jygt.AutoWeightSystem.NHDAL,在该类库项目下添加NHUserInfoDAL类,让其去实现IUserInfoDAL接口。
2.1.7 通过简单工厂进一步隔离BLL 层对DAL 的依赖
在DAL层下新建类库项目jygt.AutoWeightSystem.DALFactory,下面新建静态的StaticDALFactory类,类下面创建GetUserInfoDAL方法,因为下面new UserInfoDAL()、new NhUserInfoDAL等都可以接受,即能接受下面的变化。
即由:
简单工厂的优势在于,如果数据访问驱动层的实现技术发生改变,只需更改简单工厂中的return new UserInfoDAL(),而BLL层程序不需要做修改。如果程序已经发布,只需要把简单工厂的程序集重新生成后,把服务器上的相应的程序集替换即可,BLL层代码等不做改动。
2.1.8 通过抽象工厂实现BLL 层与DAL 层彻底解耦
至此,通过简单工厂使业务逻辑层与数据访问层已经解耦,即通过简单工厂隔离了BLL层对DAL层的依赖。但是依然需要修改程序,即通过修改配置文件其他程序不做修改,不通过new实例化对象。这时要实现BLL层与DAL层彻底解耦,可使用抽象工厂的反射方式来实现。要使用反射就要使用当前程序集。
数据访问驱动层的不同实现方法其实就是程序集名称不同,前提是不同数据访问驱动层封装同一个实体的DAL名称相同,比如都为UserInfoDAL,不要一个是UserInfoDAL,另一个是NhUserInfoDAL,所以这里把jygt.AutoWeightSystem.NHDAL层下的NhUserInfoDAL重命名为UserInfoDAL与jygt.AutoWeightSystem.EFDAL下的名称相同,这就是约定大于配置的思想。
以后如果实现数据访问驱动层的技术改变,只要修改配置文件web.Config中的
2.1.9 保证线程内共享一个上下文实例
数据访问层BaseDAL中上下文实例通过new方法产生,语句如下:
只要执行这句代码就会产生一个上下文实例,不能保证线程内共享一个上下文实例。
这时也需要把new方法去掉,不通过new 来实例化出一个上下文对象。也可以用一个单独类来产生上下文实例,由于本项目DAL主要用EF来实现,所以在jygt.AutoWeightSystem.E F D A L 层下单独再新建一个D b C o n te n t F a c t o r y类,专门用来保证线程内共享一个上下文实例。
由于使用DbContext作为返回值类型,Model层中如果还有其他的上下文对象,只要把new 后面的具体上下文对象名称做对应修改就可以实现切换上下文对象。
然后在BaseDAL中的
2.1.10 封装数据访问层的统一入口DbSession 类
封装DBSession类,让其拥有所有DAL的实例(或者说是用来生成DAL实例对象的类/工厂)和更新到数据库的方法,也即是让DBSession类封装成整个数据访问层与数据库的会话类,像EF上下文封装了所有表对应实体集合DbSet
接下来把BaseDAL.cs中所有DB.SaveChanges()代码全部删除或注释掉,即不在数据访问层使每一操作都与数据库交互。
优势:数据提交的权利从数据库访问层提到了业务逻辑层。批量操作可以一次性提交到数据库,如果在数据库访问层每个方法都有SaveChanges()方法,那么每操作一次都会与数据库发生交互。而到了业务层来了就非常灵活,可以批量操作后一起提交,需要时也可以一个操作结束就提交,只需加上DBSession.SaveChanges();即可。
2.1.11 建立IDBSession 接口,让业务层依赖接口
建立IDBSession接口,让业务层依赖接口,保证一次请求共用一个dbsession实例
上面业务逻辑层中有语句:DBSession dbsession =new DBSession();
即DBSession所在层与BLL层之间紧密依赖。项目一般要求层与层之间的调用最好通过接口隔离,不要依赖于具体实现,即使这个接口没有其他意义。
因此再定义一个IDBSession,用来隔离DBSession所在层与BLL层之间的依赖。
在数据访问接口层jygt.AutoWeightSystem.IDAL中添加新项目接口IDbSession,代码如下:
这样整个设计方案程序代码在抽象与解耦方面性能得以很大改善。
2.2.1 Spring.Net 与MVC 配合使用
目的是把控制器下的生成B L L 实例的代码,如userInfoBLL由
2.2.2 配置UI 层下的web.config 文件
2.2.3 修改UI 层下的Global.asax 文件的继承类先添加Spring.net的引用。
2.2.4 在Config 文件夹下新建BLLs.xml
其配置如下。
这两个X M L 配置语句顺序不能对调,因为controllers.x ml中用到B L Ls.x ml中的内容,即controllers.xml配置文件需要引用(ref="UserInfoBLL")UserInfoBLL类,而UserInfoBLL类在BLLs.xml中配置。
综上,由2.1节和2.2节,基于DAL层到BLL层的解耦、BLL层到UI层的解耦,如图3所示。
图3 DAL 层到BLL 层及BLL 层到UI 层的解耦过程示意图
2.3.1 设计IDAL 的T4 模板IDALs.tt[5]
2.3.2 设计DAL层下的T4模板IDbSession.tt
2.3.3 设计EFDAL 的T4 模板DALs.tt
复制IDALs.tt一份到jygt.AutoWeightSystem.EFDAL项目下,并重命名为DALs.tt。修改DALs.tt文件如下。
2.3.4 设计DbSession 的T4 模板DbSession.tt
复制DALs.tt一份到jygt.AutoWeightSystem.DALFactoty项目下,并重命名为Dbsession.tt。修改Dbsession.tt文件代码,方法与设计DALs.tt类似,代码省略。
2.3.5 设计StaticDALFactory的 T4 模板StaticDALFactory.tt代码省略。
2.3.6 设计IBLL 的T4 模板IBLL.tt
复制一份DbSession.tt到jygt.AutoWeightSystem.IBLL项目下,重命名为IBLL.tt并修改代码。方法与设计DALs.tt类似,代码省略。
保存下模板,即可生成相应的类。
2.3.7 设计BLL 的T4 模板BLL.tt
复制一份IBLL.tt到jygt.AutoWeightSystem.BLL项目下,把那个重命名为BLL.tt并修改代码,方法与设计DALs.tt类似,代码省略。
2.3.8 设计UI层下controllers.xml的T4 模板BLLxmlSpring.tt
到jygt.AutoWeightSystem.IBLL项目复制一份IBLL.tt到当前项目jygt.AutoWeightSystem.IBLL下,并重命名为BLLxmlSpring.tt并进行修改,方法与设计DALs.tt类似,代码省略。
保存下模板,即可生成相应的XML文件。
最后,单击生成---转换所有T4模板,所有层的相应代码就自动生成。
1.打开UserInfo的View页面Index.cshtml,删除body中间的所有内容;
2.复制jquery-easyui-1.3.1文件到项目的Content文件夹下[6];
3.在前台添加展示数据表格的table元素;
4.添加添加样式和js脚本等;
4. 角色管理、权限管理设计
与上节用户管理设计类似进行角色管理、权限管理设计。整个权限管理系统的软件结构如图4所示。
图4 权限管理系统的软件结构
系统权限管理测试方案:
1.给用户管理设置角色。用户管理:勾选“高级管理员”角色;
2.给权限管理设置角色。权限管理:勾选“高级管理员”“管理员”角色;
3.用户登录测试当以高级管理员admin登录时,桌面的图标有用户管理、权限管理、角色管理图标,可执行相关操作;当用户以管理员ZhangSan身份登录时,桌面的图标只有权限管理、角色管理可执行相关操作,没有用户管理图标,不能执行用户管理相关操作。
经上述操作测试和试运行,本项目基于MVC的权限管理系统实现了权限管理的功能。