ARW.CodeGenerator | ||
ARW.Common | ||
ARW.Model | ||
ARW.Repository | ||
ARW.Service | ||
ARW.Tasks | ||
ARW.WebApi | ||
document | ||
Infrastructure | ||
.gitattributes | ||
.gitignore | ||
.net_run.bat | ||
ARWAdmin.sln | ||
LICENSE | ||
README.md | ||
startup.bat |
.NET后端开发流程
基于.NET6 + vue3 前后端分离的.net快速开发框架
🍟 概述
- 本项目适合有一定NetCore和 vue基础的开发人员
- 基于**.NET6**实现的通用权限管理平台(RBAC模式)。整合最新技术高效快速开发,前后端分离模式,开箱即用。
🍀 后端技术
- 核心框架:.Net6.0 + Web API + sqlsugar + swagger + signalR + IpRateARWmit + Quartz.net + Redis
- 定时计划任务:Quartz.Net组件,支持执行程序集或者http网络请求,备份数据库
- 安全支持:过滤器(数据权限过滤)、Sql注入、请求伪造
- 日志管理:NLog、登录日志、操作日志、定时任务日志
- 工具类:验证码、丰富公共功能
- 接口限流:支持接口限流,避免恶意请求导致服务层压力过大
- 代码生成:高效率开发,代码生成器可以一键生成所有前后端代码
- 数据字典:支持数据字典,可以方便对一些状态进行管理
- 分库分表:使用orm sqlsugar可以很轻松的实现分库分库性能优越
- 多 租 户:支持多租户功能
- 缓存数据:内置内存缓存和Redis
🔧 配置
-
用 Vs 打开项目解决方案文件
ARWAdmin.sln
-
连接服务器数据库 (navicat)
-
修改数据库连接配置
ARW.WebApi
目录下的appsettings.json
配置
{
"ConnectionStrings": {
"conn_db": "Data Source=localhost;Initial Catalog=ARWAdmin;User ID=sa;Password=ARWadmin123;Trusted_Connection=SSPI", //当前项目连接数据库,
"conn_db_type": 1, //选择对应的数据库类型MySql = 0, SqlServer = 1。其他数据库自行添加基础数据
}
现在尝试启动项目吧 ~
🍻项目结构
├─Infrastructure ->[基础设施]:提供基础系统工具类。
├─ARW.WebApi ->[webapi接口]:为Vue版或其他三方系统提供接口服务。
├─ARW.Model ->[实体层类库]:提供项目中的数据库表、数据传输对象;
├─ARW.Common ->[常用工具]:提供项目中常用方法;
├─ARW.Repository ->[仓库层类库]:方便提供有执行存储过程的操作;
├─ARW.Service ->[服务层类库]:提供WebApi接口调用;
├─ARW.Tasks ->[定时任务类库]:提供项目定时任务实现功能;
├─ARW.CodeGenerator ->[代码生成功能]:包含代码生成的模板、方法、代码生成的下载。
🔍 开发规范
开发时 不管是 哪一个层
都要 按模块 分好文件夹
都要 写好注释!!!!
/// 使用这个注释
🧬 开发流程
1、创建模型 (Model层)
1.1 Model (数据交互)
数据交互:与数据库打交道的类,最后接收数据返回到这个类,
然后映射到数据库 ,数据库再把结果返回 (详细去了解ORM)
这里我们使用的是 SqlSugar 作为 ORM
官方文档:https://www.donet5.com/Home/Doc?typeId=1182
具体如何写实体类,可以参考实例实体
ARW.Model -> Models -> Business -> Student 或者 Class
- 需要注意的是:
- 业务表的前缀是 : tb_
- 系统表的前缀是 : sys_
- 记得继承 :BusinessBase
- Id 使用的是 雪花ID
- **时间(DateTime)**的需要进行转换
- excel导出 表头特要标记 EpplusTableColumn[ ]
1.2 Dto (数据传输)
只接收指定参数,更加清晰知道传入什么参数
// 接受的参数 是 Dto类型的
// [FromBody] 是 json请求体
public IActionResult AddStudent([FromBody] StudentDto parm)
传统Model层:
Dto层:更加清晰 知道传入什么值,方便前端对接~
1.3 Vo (数据展示)
展现需要的字段:
定义一个新的类,只展示我们需要的字段
使用 Select() 把实体值 赋值给 新的类就可以了。
var query = _studentRepository
.Queryable()
.LeftJoin<Class>((s, c) => s.ClassId == c.ClassId)
.Where(predicate.ToExpression())
.Select((s, c) => new StudentVo
{
StudentId = s.StudentId,
ClassId = c.ClassId,
ClassName = c.ClassName,
StudentName = s.StudentName,
Sex = s.Sex,
Age = s.Age,
StudentImg = s.StudentImg,
StudentTag = s.StudentTag,
StudentService= s.StudentService.ToString(),
StudentDescribe = s.StudentDescribe
});
2、创建接口和实现类 (Service层)
作用:
1、代码整洁
2、分层,好维护
3、可以注册服务,不需要实例化
2.1 创建接口
在 ARW.Service
-> Business
-> IBusinessService
中 创建接口 (interface)
注意:记得 继承 IBaseService<对应的数据实体类>
- 命名规范:IxxxService
- 前缀 I
- 后缀 Service
Interface(接口):
public interface IStudentService : IBaseService<Student>
{
/// <summary>
/// 获取学生分页列表
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
PagedInfo<StudentVo> GetStudentList(StudentQueryDto parm);
}
2.2 创建实现类
在 ARW.Service
-> Business
-> BusinessService
中 创建实现类 (Impl)
注意:记得 继承 BaseService<对应的数据实体类>,相对应的接口
添加服务到容器( 特性 ): [AppService(ServiceType = typeof( 相对应的接口
), ServiceLifetime = LifeTime.Transient)]
[AppService(ServiceType = typeof(IStudentService), ServiceLifetime = LifeTime.Transient)]
public class StudentServiceImpl : BaseService<Student>, IStudentService
实现类要实现 接口所定义的方法
// 写业务方法
public PagedInfo<StudentVo> GetStudentList(StudentQueryDto parm)
{
//开始拼装查询条件d
var predicate = Expressionable.Create<Student>();
//搜索条件查询语法参考Sqlsugar
predicate = predicate.AndIF(!string.IsNullOrEmpty(parm.StudentName), s => s.StudentName.Contains(parm.StudentName));
predicate = predicate.AndIF(parm.ClassId != null, s => s.ClassId == parm.ClassId);
var query = _studentRepository
.Queryable()
.LeftJoin<Class>((s, c) => s.ClassId == c.ClassId)
.Where(predicate.ToExpression())
.Select((s, c) => new StudentVo
{
StudentId = s.StudentId,
ClassId = c.ClassId,
ClassName = c.ClassName,
StudentName = s.StudentName,
Sex = s.Sex,
Age = s.Age,
StudentImg = s.StudentImg,
StudentTag = s.StudentTag,
StudentService= s.StudentService.ToString(),
StudentDescribe = s.StudentDescribe
});
return query.ToPage(parm);
}
3、创建仓储层(Repository层)
在 ARW.Repository
-> Business
中 创建仓储类 (Repository)、
作用:用于超级复杂的业务逻辑,当 接口实现类
都写的很乱时,可以使用这个层
一般走流程需要创建一个,所以参考以下模板创建:
[AppService(ServiceLifetime = LifeTime.Transient)]
public class StudentRepository : BaseRepository<Student>
{
/*
* 复杂的业务逻辑代码
*/
}
4、创建控制层 (Controller层)
-- 这里细节比较多,请注意看 --
控制器头部:
[Verify] // 身份认证
[Route("business/[controller]")] // 路由
public class StudentController : BaseController // 继承 BaseController
依赖注入(构造函数注入):
/// <summary>
/// 依赖注入
/// </summary>
/// <param name="studentService">学生服务</param>
/// <param name="classService">班级服务</param>
public StudentController(IStudentService studentService, IClassService classService)
{
_studentService = studentService;
_classService = classService;
}
方法:
- 请求参数格式:
**[FromBody]:**json请求体
[FromQuery]: url 获取参数
**[FromForm(Name = "xxx")] :**获取From表单中的参数
-
抛出异常:
throw new CustomException(" ")
-
返回结果:
SUCCESS("消息")
ToResponse(数据,"消息")
// 头部规范:
[HttpPost("addStudent")] // [请求方法("请求路由")]
[ActionPermissionFilter(Permission = "business:student:add")] // 权限标识符
[Log(Title = "学生添加", BusinessType = BusinessType.INSERT)] // 日志
public IActionResult AddStudent([FromBody] StudentDto parm)
{
// 抛出异常
if (parm == null)
{
throw new CustomException("请求参数错误");
}
// 模型映射:Dto层需要把接受的数据 给到 Model层,才能和数据库交互
var modal = parm.Adapt<Student>().ToCreate(HttpContext);
var response = _studentService.Insertable(modal).ExecuteReturnSnowflakeId();
return SUCCESS("添加成功!");
}
查询分页(联表)
查询树形
查询单条
添加
修改
删除
导入Excel
导出Excel
下载模板Excel
具体操作方法可参考:
ARW.WebApi
-> Business
-> StudentController(基础方法)
/ ProductTypeController(树形)