基于MVC的权限管理系统设计

2021-03-28 04:43王建祥王洪泽
电子元器件与信息技术 2021年12期
关键词:实例代码模板

王建祥,王洪泽

(河南省济源钢铁(集团)有限公司 信息化仪表处, 河南 济源 454650)

0 引言

随着信息化技术的发展,管理信息系统得到普遍应用,而权限管理系统是各类管理信息系统的前提和基础。本文权限管理系统的设计按EF模型生成数据库、各层深度解耦、设计T4模板自动生成代码、设计前端等步骤进行[1-2]。

1 总体设计

1.1 权限管理系统的设计方案

根据ASP.Net MVC系统的特性,权限管理系统的设计目标是:

1.UserInfo---RoleInfo---ActionInfo;用户拥有角色,权限拥有角色,从而用户拥有权限。

2.UserInfo---R_UserInfo_ActionInfo;用户直接拥有特殊权限。

具体实现过程如图1所示。

图1 权限管理的目标

1.2 软件设计方案

本系统使用Visual Studio 2019 Enterprise 16.11版本软件进行权限管理软件开发和调试,使用ASP.NET MVC技术进行设计,其中DAL层到BLL层的解耦使用复杂工厂技术,BLL层到UI层的解耦使用Spring.Net技术[3]。

2 基于ASP.NET MVC的权限管理系统的软件设计

2.1 DAL层到BLL层的解耦实现

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类型,数据就会立即加载到内存,但在DAL层一般不需要数据,通常是在UI层、业务逻辑层才真正需要数据,在UI层查询时再加载到内存。因此返回值类型不能是List类型,应该使用IQueryable类型。

继续深入思考方法,F u n c是委托类型,使用委托类型执行查询时会查询表中的全部数据并加载到内存,再根据条件进行筛选。因此委托类型作为参数效率不高,应该使用Expression>类型,即用Expression<>对上述委托类型包裹但是却使查询性能发生质的变化,因为Expression>返回值类型为IQeryable,而IQeryable为延迟加载。对于用户来说,采用Expression>类型和Func类型作为参数,用户使用体验基本相同。

综上,DAL层使用如下方法实现查询:

2.1.3 设计封装数据访问层基类BaseDAL

DAL层的各个方法,经测试全部正确后,目前只是针对UserInfoDAL,针对OrderInfoDAL同样也有增删改查等类似方法,仅数据实体对象不同,还有其他实体都要写类似的增删改查方法,不经专门处理就会有很多重复工作。因此把相同的方法提出来,封装成一个基类,所有类似通用方法写在此基类里面,然后让子类去继承使用该基类的增删改查方法。

需要使用泛型类,即把BaseDAL类改成泛型类,然后加上泛型约束,

public class BaseDAL where T:class,new(),并且使用的是泛型约束,约束T使用类、公共构造函数new()约束等,子类在继承基类时就需要传入具体的T类型。

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 w here T:class,new()

接着让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,DBSession则是拥有所有DAL的实例。

接下来把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 BLL层到UI层的解耦

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 T4模板设计

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模板,所有层的相应代码就自动生成。

3 用户设计

3.1 使用JQuery EasyUI展示用户数据

1.打开UserInfo的View页面Index.cshtml,删除body中间的所有内容;

2.复制jquery-easyui-1.3.1文件到项目的Content文件夹下[6];

3.在前台添加展示数据表格的table元素;

4.添加添加样式和js脚本等;

4. 角色管理、权限管理设计

与上节用户管理设计类似进行角色管理、权限管理设计。整个权限管理系统的软件结构如图4所示。

图4 权限管理系统的软件结构

5 结语

系统权限管理测试方案:

1.给用户管理设置角色。用户管理:勾选“高级管理员”角色;

2.给权限管理设置角色。权限管理:勾选“高级管理员”“管理员”角色;

3.用户登录测试当以高级管理员admin登录时,桌面的图标有用户管理、权限管理、角色管理图标,可执行相关操作;当用户以管理员ZhangSan身份登录时,桌面的图标只有权限管理、角色管理可执行相关操作,没有用户管理图标,不能执行用户管理相关操作。

经上述操作测试和试运行,本项目基于MVC的权限管理系统实现了权限管理的功能。

猜你喜欢
实例代码模板
铝模板在高层建筑施工中的应用
铝模板在高层建筑施工中的应用
创世代码
创世代码
创世代码
创世代码
铝模板在高层建筑施工中的应用
城市综改 可推广的模板较少
完形填空Ⅱ
完形填空Ⅰ