.NET Core前后端分离快速开发框架(Core.3.0+AntdVue)
.net core前后端分离快速开发框架(core.3.0+antdvue)
目录
引言
时间真快,转眼今年又要过去了。回想今年,依次开源发布了colder.fx.net.adminlte(254star)、colder.fx.core.adminlte(335star)、dotnettysocket(82star)、idhelper(47star),这些框架及组件都是本着以实际出发,实事求是的态度,力求提高开发效率(我自己都是第一个使用者),目前来看反响不错。但是随着前端和后端技术的不断变革,尤其是前端,目前大环境已经是前后端完全分离为主的开发模式,在这样的大环境和必然趋势之下,传统的mvc就显得有些落伍了。在这样的背景下,一款前后端分离的.net开发框架就显得尤为必要,由此便定了框架的升级目标:前后端分离。
首先后端技术的选择,从目前的数据来看,.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,理由便是简洁方便,十分符合我的设计理念。
技术选型完毕之后便进入研发,由于鄙人前端比较菜,因此需要从头学vue2.x全家桶,从开始到现在差不多经历3个月,在预期之内。其实学习并使用前端的vue2.x全家桶并不难,还是比较容易上手的,所以在此给没有前后端分离开发经验的老哥打一记预防针,不要退缩,要知难而上,学习永无止境。
某些老哥可能比较直接粗暴,嫌我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,囊亏了从快速开发到自动化部署一条龙,开源免费并具有高性能、高移植性、高拓展性(小公司创业选型+个人接单利器)
简介
本框架为.net core3.0+ant design vue版
本框架旨在极大的提高开发效率
使用技术栈:
后端:采用.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权限控制,支持操作权限、接口权限以及数据权限
框架主要功能及特色如下
功能 | 详细描述 |
---|---|
用户登录 | 用户登录、密码修改 |
系统用户管理 | 系统用户管理 |
角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及以上
基础数据库构建:
数据库创建
目录"/docs/初始化文件"中有所需的数据库资料
先手动创建数据库,然后执行对应的sql脚本即可连接字符串配置
打开src目录下colder.admin.antdvue的解决方案,如下图
如下图所示依次展开05.coldairarrow.api/appsettings.json,配置数据库连接字符串,name不用修改,connectionstring改为上述创建的数据库(若不清楚数据库连接字符串请自行百度搜索教程)
数据库设计规范
由于本框架支持自动生成代码的核心功能,此功能是根据数据库的表结构来生成代码的
因此规定每张表都有一个主键,列名为id,类型为字符串,实际添加数据时默认使用snowflakeid(雪花id,twitter设计的分布式趋势自增id,若不清楚请自行百度相关资料),表中的每个列都需要有描述信息(建议这样操作,若不按照这个标准则需要一些额外的改动才能够成功运行)。每张表都需要id、createtime、creatorid、creatorrealname这几个必带字段
运行
后端:打开解决方案=>还原nuget包=>配置数据库=>运行(05.coldairarrow.api设为启动项目)
后台成功运行后会自动打开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、分页、统计(数量、最大值、最小值、平均值),支持跨库(表分散在不同的数据库中,不同类型数据库也支持)。具体如何使用如下:
- sharding配置
首先、要进行分库分表操作,那么必要的配置必不可少。配置代码如下:
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
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
博客园欢迎点赞:
qq群2:579202910
个人qq:862520575(欢迎技术支持及商务合作,提供.net core + linux + nginx+ jenkins + git整套持续集成快速开发平台)
本人将会对这个快速开发框架不断完善与维护,希望能够帮助到各位
若遇到任何问题或需要技术支持,请联系我。
------学习永无止境,技术永无上限,代码就是艺术------
权限管理>推荐阅读
-
从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十三 || DTOs 对象映射使用,项目部署Windows+Linux完整版,
-
详解.net core webapi 前后端开发分离后的配置和部署
-
详解.net core webapi 前后端开发分离后的配置和部署
-
Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之二 || 后端项目搭建
-
.NET Core前后端分离快速开发框架(Core.3.0+AntdVue)
-
一个基于 .NET Core 2.0 开发的简单易用的快速开发框架 - LinFx
-
Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之二 || 后端项目搭建
-
OsharpNS轻量级.net core快速开发框架简明入门教程-从零开始启动Osharp
-
.NET Core开源快速开发框架Colder发布 (NET Core2.1+AdminLTE版)
-
dotnetcore+vue+elementUI 前后端分离---支持前端、后台业务代码扩展的快速开发框架