时间真快,转眼今年又要过去了。回想今年,依次开源发布了Colder.Fx.Net.AdminLTE(254Star)、Colder.Fx.Core.AdminLTE(335Star)、DotNettySocket(82Star)、IdHelper(47Star),这些框架及组件都是本着以实际出发,实事求是的态度,力求提升开发效率(我本身都是第一个使用者),目前来看反响不错。可是随着前端和后端技术的不断变革,尤为是前端,目前大环境已是先后端彻底分离为主的开发模式,在这样的大环境和必然趋势之下,传统的MVC就显得有些落伍了。在这样的背景下,一款先后端分离的.NET开发框架就显得尤其必要,由此便定了框架的升级目标:先后端分离。html
首前后端技术的选择,从目前的数据来看,.NET Core的发展远远快于.NET Framework,最简单的分析就是Colder.Fx.Core.AdminLTE发布比Colder.Fx.Net.AdminLTE晚,可是星星却后来居上并且比前者多30%,而且这个差距在不断扩大,由点及面的分析能够看出咱们广大.NET开发人员学习的热情和积极向上的态度,并非某些人所认为的那么不堪(走本身的路,让别人说去吧)。大环境上微软积极拥抱开源,大力发展.NET Core, 能够说前途一片光明。所以后端决定采用 .NET Core3.0 ,再也不浪费精力去支持.NET Framework。前端
而后是前端技术选择,首选是三大js框架选择,也是从实际出发,Vue相对其它而言更加容易上手,而且功能也绝不逊色,深得各类大小公司喜欢,若是偏要说缺点的话,那就是对TS支持不行,可是即将发布Vue3.0确定会改变这一缺陷。选择了Vue以后,而后就是UI框架的选择了,这里的选择更多了,我选择了Ant Design Vue,理由即是简洁方便,十分符合个人设计理念。vue
技术选型完毕以后便进入研发,因为鄙人前端比较菜,所以须要从头学Vue2.x全家桶,从开始到如今差很少经历3个月,在预期以内。其实学习并使用前端的Vue2.x全家桶并不难,仍是比较容易上手的,因此在此给没有先后端分离开发经验的老哥打一记预防针,不要退缩,要知难而上,学习永无止境。node
某些老哥可能比较直接粗暴,嫌我BBB唠叨,下面直接上地址
代码(GitHub):https://github.com/Coldairarrow/Colder.Admin.AntdVue
文档(GitHub):https://github.com/Coldairarrow/Colder.Admin.AntdVue/wiki
代码(码云镜像):https://gitee.com/Coldairarrow/Colder.Admin.AntdVue
文档(码云镜像):https://gitee.com/Coldairarrow/Colder.Admin.AntdVue/wikis
在线预览地址:http://coldairarrow.gitee.io/coler.antdvue.preview/#/Home/Introduce
因为服务器是阿里云的86服务器,带宽1M小水管,所以将前端部署到码云上了,在此多谢码云,后端部署在阿里云86服务器CentOS7上。整个技术栈使用.NET Core + PostggreSQL+ Ant Design Vue + CentOS7+Nginx+Dokcer+jenkins,囊亏了从快速开发到自动化部署一条龙,开源免费并具备高性能、高移植性、高拓展性(小公司创业选型+我的接单利器)git
本框架为.NET Core3.0+Ant Design Vue版github
本框架旨在极大的提升开发效率算法
使用技术栈:
后端:采用.NET Core平台,ASP.NET Core3.0,C#语言(使用反射等高级技术),Entity FrameworkCore(数据库ORM框架)。
使用数据仓储模式,抽象化数据库操做(CRUD等)、支持事务处理以及分布式事务处理(跨库)
支持数据库读写分离、分库分表及事务(仅支持单表操做,不支持多表) 全面采用Autofac做为IOC容器,面向接口编程,全面解耦
集成多种工具类库以及操做拓展
数据库:支持SqlServer,PostgreSQL,MySQL,Oracle(框架使用简单工厂,工厂方法,抽象工厂,可轻松更换数据库),Redis做为分布式缓存
前端:Vue2.x全家桶+Ant Design Vue,其中集成经常使用组件,力求方便项目开发。数据库
具体技术实施:
项目采用先后端彻底分离模式,并采用严格分层模式,极大的增长聚合度,下降耦合度,
提升代码的健壮性,可维护性。
先后端经过JWT进行身份验证,经过数据接口操做数据,统一使用JSON做为数据格式,并使用默认接口签名算法保证接口的安全性。编程
功能架构部分详解:
快速开发:此功能为框架的核心,经过选择数据库中的表,就能自动生成对应的实体层、业务逻辑层、控制器、前端页面Vue文件,无需编写代码便可生成基本的CRUD操做。
接口密钥管理:管理接口的密钥,若开启接口签名的规则,则前端须要经过给接口签名才可以正常访问后台接口。
权限管理:使用基本的RBAC权限控制,支持操做权限、接口权限以及数据权限json
框架主要功能及特点以下
功能 | 详细描述 |
---|---|
用户登陆 | 用户登陆、密码修改 |
系统用户管理 | 系统用户管理 |
角1色管理 | 角色管理 |
部门管理 | 部门管理、自然多级 |
权限管理 | 使用RBAC权限体系,基于角色的权限管理,支持菜单权限、操做权限(按钮权限)、接口权限、数据权限 |
系统日志 | 支持多彩控制台、文件、数据库和ElasticSearch记录日志,框架全局异常自动捕捉,多级别记录 |
快速开发 | 经过数据库直接生成实体层、业务逻辑层、控制器层以及前端页面Vue代码,无需编码便可实现CURD |
数据库操做封装 | 使用基于EF的仓储模式、封装经常使用的CURD,支持单库事物和分布式事物 |
多数据库支持 | 使用基于EF的仓储模式,支持各大主流关系型数据库(SQLServer、MySQL、PostgreSQL和Oracle) |
超强移植性 | 使用抽象工厂封装数据库操做层,切换数据库0代码修改 |
支持软删除 | 一键切换删除模式,支持物理删除和软删除,对业务操做透明 |
缓存支持 | 支持系统自带缓存和Redis缓存、封装操做接口、简单易用 |
先后端彻底分离 | 前端使用Vue2.x全家桶+Ant Design Vue,界面简洁美观,组件化开发 |
集成JWT验证 | 框架使用JWT做为身份验证,摆脱Cookie苦海,分布式拓展毫无压力 |
集成对外接口签名算法 | 框架对外接口能够开启超强严格签名校验(防抵赖、防伪造、防重复调用),保障系统安全性 |
页面响应式 | 前端为单页应用,无iframe,各大主流浏览器支持友好 |
拓展 | 其它各类帮助类库及插件 |
其相关版本请看下表:
.NET版本 | 前端UI | 地址 |
---|---|---|
Core3.0 | Ant Design Vue | https://github.com/Coldairarrow/Colder.Admin.AntdVue |
Core2.2 | AdminLTE | https://github.com/Coldairarrow/Colder.Fx.Core.AdminLTE |
.NET4.72 | AdminLTE | https://github.com/Coldairarrow/Colder.Fx.Net.AdminLTE |
.NET4.52 | Easyui | https://github.com/Coldairarrow/Coldairarrow.Fx.Net.Easyui.GitHub |
Core2.1 | Easyui | https://github.com/Coldairarrow/Coldairarrow.Fx.Core.Easyui.GitHub |
.NET4.0 | Easyui | https://github.com/Coldairarrow/Coldairarrow.Fx.Net40.Easyui.GitHub |
后台效果展现以下:
操做系统:Windows 10
后端开发工具:Visual Studio 2019+
前端开发工具:Visual Studio Code,安装nodejs,yarn
SDK:安装.NET Core SKD 3.0 及以上
数据库:SQLServer2008 R2及以上
以下图所示依次展开05.Coldairarrow.Api/appsettings.json,配置数据库链接字符串,name不用修改,connectionString改成上述建立的数据库(若不清楚数据库链接字符串请自行百度搜索教程)
因为本框架支持自动生成代码的核心功能,此功能是根据数据库的表结构来生成代码的
所以规定每张表都有一个主键,列名为Id,类型为字符串,实际添加数据时默认使用SnowflakeId(雪花Id,Twitter设计的分布式趋势自增Id,若不清楚请自行百度相关资料),表中的每一个列都须要有描述信息(建议这样操做,若不按照这个标准则须要一些额外的改动才可以成功运行)。每张表都须要Id、CreateTime、CreatorId、CreatorRealName这几个必带字段
后端:打开解决方案=>还原nuget包=>配置数据库=>运行(05.Coldairarrow.Web设为启动项目)
后台成功运行后会自动打开swagger
前端: 确保已安装nodejs和yarn
用VS Code 打开文件夹src\Coldairarrow.Web
输入命令:yarn
输入命令:yarn run serve
成功运行后便可打开登陆页面
输入帐号:Admin,密码:123456进入后台主页
在01.Coldairarrow.Util中的GlobalSwitch类中,设置了各个参数,其中RunModel与DatabaseType须要重点关注一下,其它参数请看注释。
此功能为本框架的核心功能,可以自动生产完整的可运行代码,具体使用以下:
首选须要有数据库源,由于代码生成是根据数据库表来生成的。
菜单:开发=>数据库链接
若列表中没有目标数据源,则添加数据库链接
数据链接名、链接字符串、数据库类型便可。添加完成后便可看到链接字符串信息。
有了数据库链接以后,便可进行代码生成。
菜单:开发=>代码生成
选择数据库,而后勾选须要生成代码的数据库表,点击生成代码会弹出生成选项(这里演示勾选 Base_BuildTest,其他表全是系统基础表,不要勾选,不然会被覆盖,致使异常,请勾选本身的业务表进行生成):
生成选项中能够选择须要生成的类型,默认生成所有:实体层、业务层、接口层(即控制器)和页面(Vue前端页面代码)。
生成区域请输入业务模块名(例如系统叫Base_Manage),请按具体业务填入(必填)
这里示例填写TestManage,点击生成按钮,便可完成代码生成。生成后的代码在项目解决方案中,将代码文件包括进入项目
默认生成后的文件会被自动包括到解决方案中,若没有则须要点击显示全部文件按钮,便可看到生成后的新文件
生成的实体层、业务逻辑层、控制器层代码:
前端生成的代码:
后端代码添加后须要从新编译下(F7),编译后好能够看到有新的接口
前端生成代码后会自动保存并编译(别的文件修改保存也会自动编译,毕竟编译一次挺慢的),不放心能够Ctrl+C中止,而后再yarn run serve从新运行
代码生成完毕,可是要展现到菜单上须要进行配置,而且全部业务菜单都是动态的(权限控制)
打开菜单:系统管理=>权限管理=>新建
菜单名:即须要显示的菜单名
上级菜单:菜单是多级树状的,能够放在某个菜单下面
类型:能够选择菜单或页面,这里是具体的页面,因此选页面
路径:页面的路径,菜单能够不配置,这里配置为/TestManage/Base_BuildTest/List,这里设置规则为:views文件夹为根路径(即"/"),向下展开依次为/TestManage/Base_BuildTest/List,最后真正的列表页为List.vue文件,表单页为EditForm.vue文件
是否须要权限:若为“否”,则此页面不限制权限,即全部人都能看
图标:菜单显示图标,具体到开发=>图标选择页进行选择
排序:若须要须要对菜单进行排序则设置,默认0,类型为int
页面权限:页面拥有的权限(权限值惟一,做为操做权限即接口权限的依据),详见权限管理
确认保存,而后刷新整个页面(F5),便可看到全新生成的菜单“生成测试”
整个代码生成过程,无需编写代码便可完成一张表的CRUD,固然须要根据具体业务中进行相应的修改,本次示例中字段比较少,可是当一张表的字段不少时,那么此功能可以将开发效率提升几个档次。
默认超级管理员帐号为:Admin
密码为:123456
管理系统登陆的用户
菜单:系统=>用户管理
点击右侧设置权限
管理系统角色,角色是权限的载体,合理分配角色有利于权限管理
菜单:系统=>角色管理
操做中能够设置角色的权限,详情见 <权限管理> 模块
通常状况下,后台管理系统多少会涉及权限管理,所以本框架提供了一个灵活、高效、简洁的权限管理系统。
首先,权限分为两种,即操做权限和数据权限,其中操做权限主要包括菜单权限和按钮权限,在角色编辑表单中,给角色勾选须要的权限便可,用户能够分配多个角色,继承全部角色的权限。
如上图,按需勾选,有人会疑问为何只有增、改和删的权限而没有查的权限,其实这里考虑到了当勾选“用户管理”时,就已经默认拥有“查”的权限了,这里再设置“查”权限岂不是画蛇添足,能够根据实际业务需求添加诸如申请、审核等权限,灵活应用。
这里的树状是和菜单一一对应的,勾选哪些菜单就拥有哪些菜单
下面介绍下最经常使用的按钮权限
如上图,在须要控制权限的按钮使用v-if="hasPerm('Base_User.Add')",表示只有当用户拥有权限值Base_User.Add才显示此按钮,权限值就是权限表单中配置的权限值
这里的按钮级权限控制只可以在前端控制操做入口,若系统对安全性要求较高,则须要控制接口权限
如上图,在须要权限控制的接口加上ApiPermission特性便可,参数也为权限值,只有拥有此权限才能访问此接口
数据权限比较复杂,若采用纯SQL方式,那么会更加复杂,本框架全程采用EF做为ORM框架,经过对IQueryable< T >进行过滤,便可完成数据权限控制,详细使用方式见用户管理。
更详细的使用方式,请参考源代码中的用户管理模块(菜单权限、操做权限、数据权限、联表查询、业务层AOP等使用方式都可参考此模块)。
做为对外接口签名的AppId和AppSecret管理
菜单:系统=>接口秘钥管理
菜单:系统=>系统日志
使用方式以下:
BaseBusiness<Base_UnitTest> _baseBus = new BaseBusiness<Base_UnitTest>(); /*RunTransaction传入执行具体数据库操做的Action,操做中若出现异常会自动回滚事务,业务只需根据返回的transActionRes进行处理,返回类型为元组(bool Success, Exception ex),Success表示事务是否成功,ex为事务失败异常信息*/ var transActionRes = _baseBus.RunTransaction(() => { var newData = _newData.DeepClone(); newData.Id = Guid.NewGuid().ToString(); newData.UserId = IdHelper.GetId(); newData.UserName = IdHelper.GetId(); _baseBus.Insert(_newData); _baseBus.Insert(newData); });
使用方式以下:
//第一个数据库 IRepository _bus1 = DbFactory.GetRepository(); //另外一个数据库 IRepository _bus2 = DbFactory.GetRepository("BaseDb_Test"); _bus1.DeleteAll<Base_UnitTest>(); _bus2.DeleteAll<Base_UnitTest>(); Base_UnitTest data1 = new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "1", UserName = Guid.NewGuid().ToString() }; Base_UnitTest data2 = new Base_UnitTest { Id = data1.Id, UserId = "1", UserName = Guid.NewGuid().ToString() }; Base_UnitTest data3 = new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "2", UserName = Guid.NewGuid().ToString() }; new Action(() => { //建立并执行事务,使用方式与单库一致 var succcess = DistributedTransactionFactory.GetDistributedTransaction(_bus1, _bus2) .RunTransaction(() => { _bus1.ExecuteSql("insert into Base_UnitTest(Id) values('10') "); _bus1.Insert(data1); _bus1.Insert(data2); _bus2.Insert(data1); _bus2.Insert(data3); }); Assert.AreEqual(succcess.Success, false); Assert.AreEqual(_bus1.GetIQueryable<Base_UnitTest>().Count(), 0); Assert.AreEqual(_bus2.GetIQueryable<Base_UnitTest>().Count(), 0); })();
本框架支持数据库读写分离分库分表(即Sharding),而且支持主流关系型数据库(SQLServer、Oracle、MySQL、PostgreSQL),理论上只要EF支持那么本框架支持。
因为技术缘由以及结合实际状况,目前本框架仅支持单表的Sharding,即支持单表的CRUD、分页、统计(数量、最大值、最小值、平均值),支持跨库(表分散在不一样的数据库中,不一样类型数据库也支持)。具体如何使用以下:
ShardingConfigBootstrapper.Bootstrap() //添加数据源 .AddDataSource("BaseDb", DatabaseType.SqlServer, dbBuilder => { //添加物理数据库 dbBuilder.AddPhsicDb("BaseDb", ReadWriteType.ReadAndWrite); }) //添加抽象数据库 .AddAbsDb("BaseDb", absTableBuilder => { //添加抽象数据表 absTableBuilder.AddAbsTable("Base_UnitTest", tableBuilder => { //添加物理数据表 tableBuilder.AddPhsicTable("Base_UnitTest_0", "BaseDb"); tableBuilder.AddPhsicTable("Base_UnitTest_1", "BaseDb"); tableBuilder.AddPhsicTable("Base_UnitTest_2", "BaseDb"); }, new ModShardingRule("Base_UnitTest", "Id", 3)); });
上述代码中完成了Sharding的配置:
ShardingConfigBootstrapper.Bootstrap()在一个项目中只能执行一次,因此建议放到Application_Start中(ASP.NET Core中的Startup)
AddDataSource是指添加数据源,数据源能够看作抽象数据库,一个数据源包含了一组同类型的物理数据库,即实际的数据库。一个数据源至少包含一个物理数据库,多个物理数据库须要开启主从复制或主主复制,经过ReadWriteType(写、读、写和读)参数来指定数据库的操做类型,一般将写库做为主库,读库做为从库。同一个数据源中的物理数据库类型相同,表结构也相同。
配置好数据源后就能够经过AddAbsDb来添加抽象数据库,抽象数据库中须要添加抽象数据表。如上抽象表Base_UnitTest对应的物理表就是Base_UnitTest_0、Base_UnitTest_1与Base_UnitTest_2,而且这三张表都属于数据源BaseDb。分表配置固然须要分表规则(即经过一种规则找到具体数据在哪张表中)。
上述代码中使用了最简单的取模分片规则,
源码以下:
能够看到其使用方式及优缺点。
另外还有一致性HASH分片规则
雪花Id的mod分片规则
上述的分片规则各有优劣,都实现IShardingRule接口,实际上只须要实现FindTable方法便可实现自定义分片规则。
实际使用中我的推荐使用雪花Id的mod分片规,这也是为何前面数据库设计规范中默认使用雪花Id做为数据库主键的缘由(PS,以前版本使用GUID做为主键被各类嫌弃,此次看大家怎么说)
IShardingRepository _db = DbFactory.GetRepository().ToSharding();
而后便可进行数据操做:
Base_UnitTest _newData = new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin", UserName = "超级管理员", Age = 22 }; List<Base_UnitTest> _insertList = new List<Base_UnitTest> { new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin1", UserName = "超级管理员1", Age = 22 }, new Base_UnitTest { Id = Guid.NewGuid().ToString(), UserId = "Admin2", UserName = "超级管理员2", Age = 22 } }; //添加单条数据 _db.Insert(_newData); //添加多条数据 _db.Insert(_insertList); //清空表 _db.DeleteAll<Base_UnitTest>(); //删除单条数据 _db.Delete(_newData); //删除多条数据 _db.Delete(_insertList); //删除指定数据 _db.Delete<Base_UnitTest>(x => x.UserId == "Admin2"); //更新单条数据 _db.Update(_newData); //更新多条数据 _db.Update(_insertList); //更新单条数据指定属性 _db.UpdateAny(_newData, new List<string> { "UserName", "Age" }); //更新多条数据指定属性 _db.UpdateAny(_insertList, new List<string> { "UserName", "Age" }); //更新指定条件数据 _db.UpdateWhere<Base_UnitTest>(x => x.UserId == "Admin", x => { x.UserId = "Admin2"; }); //GetList获取表的全部数据 var list=_db.GetList<Base_UnitTest>(); //GetIQPagination获取分页后的数据 var list=_db.GetIShardingQueryable<Base_UnitTest>().GetPagination(pagination); //Max var max=_db.GetIShardingQueryable<Base_UnitTest>().Max(x => x.Age); //Min var min=_db.GetIShardingQueryable<Base_UnitTest>().Min(x => x.Age); //Average var min=_db.GetIShardingQueryable<Base_UnitTest>().Average(x => x.Age); //Count var min=_db.GetIShardingQueryable<Base_UnitTest>().Count(); //事务,使用方式与普通事务一致 bool succcess = _db.RunTransaction(() => { _db.Insert(_newData); var newData2 = _newData.DeepClone(); _db.Insert(newData2); }).Success; Assert.AreEqual(succcess, false);
上述操做中表面上是操做Base_UnitTest表,实际上却在按照必定规则使用Base_UnitTest_0~2三张表,使分片对业务操做透明,极大提升开发效率
具体使用方式请参考单元测试源码:
"\src\Coldairarrow.UnitTests\DataRepository\ShardingTest.cs"
框架使用EF+LINQ进行联表操做,核心在于对IQueryable< T >的使用,另可网上搜EF+LINQ的相关教程。
示例以下:
Base_User表左链接Base_Department表获取DepartmentName属性
//定义数据模型类 public class Base_UserTestDTO : Base_User { public string DepartmentName { get; set; } } //即BaseBusiness中的Service var db = DbFactory.GetRepository(); Expression<Func<Base_User, Base_Department, Base_UserTestDTO>> select = (a, b) => new Base_UserTestDTO { DepartmentName = b.Name }; select = select.BuildExtendSelectExpre(); var q = from a in db.GetIQueryable<Base_User>().AsExpandable() join b in db.GetIQueryable<Base_Department>() on a.DepartmentId equals b.Id into ab from b in ab.DefaultIfEmpty() select @select.Invoke(a, b); //筛选 var where = LinqHelper.True<Base_UserTestDTO>(); where = where.And(x => x.UserName == "Admin"); //筛选并获取分页数据 var list = q.Where(where).GetPagination(new Pagination()).ToList();
源码可参考Base_UserBusiness.GetDataList
在01.Coldairarrow.Util项目中的GlobalSwitch,将DatabaseType改成须要的便可,对应的数据库链接字符串固然也要改成对应数据库的
在具体的Business类中重写父类BaseBusiness的构造函数便可,按照本身的需求重写对应的构造函数,同时须要确保数据库链接字符串已添加
若须要同时使用多个数据库,或者须要多线程操做数据库,须要使用
欢迎使用本框架,若以为不错,请比心
Github欢迎星星:https://github.com/Coldairarrow
博客园欢迎点赞:https://www.cnblogs.com/coldairarrow/
QQ群2:579202910
我的QQ:862520575(欢迎技术支持及商务合做,提供.NET Core + Linux + Nginx+ jenkins + git整套持续集成快速开发平台)
本人将会对这个快速开发框架不断完善与维护,但愿可以帮助到各位
若遇到任何问题或须要技术支持,请联系我。
------学习永无止境,技术永无上限,代码就是艺术------