一、速通一图流
二、系统架构功能、作用分析
1. Furion:框架核心层
- 功能:这是 Furion 框架的核心层,通常包含框架本身的基本功能和配置。这一层应该是比较稳定的,不应该包含业务逻辑,而是提供项目其他部分需要依赖的基础设施功能。
- 作用:为整个应用程序提供通用的功能支持和框架级别的配置。例如,依赖注入配置、全局异常处理、日志管理等。
2. Furion.Application:业务应用层
- 功能:这一层主要负责业务逻辑的实现,是应用程序的核心部分。所有与业务相关的代码,比如服务层、用例逻辑、应用程序的核心功能实现等,都会写在这里。
- 作用:封装业务逻辑,确保业务规则和流程的一致性。这一层不应该直接处理数据访问(那是仓储层的职责),而是通过依赖注入使用仓储层提供的数据访问功能。
3. Furion.Core:核心层
- 功能:这一层通常包含应用程序的核心基础设施,如实体定义、仓储接口、领域模型等。核心层应该是轻量级的,并且不依赖于其他实现细节(例如数据库访问层)。
- 作用:定义核心业务对象和基础设施代码,供应用层和数据访问层使用。这一层关注于领域模型和接口定义,确保应用的核心业务逻辑可以独立于具体的技术实现进行开发和测试。
4. Furion.Database.Migrations:EF Core 架构迁移文件层
- 功能:这一层专门用于存放 EF Core 的数据库迁移文件。这些文件包含了数据库架构的变更记录,EF Core 通过这些迁移文件来保持数据库和应用程序模型之间的一致性。
- 作用:管理数据库架构的变更和迁移,是数据库与应用程序之间的一座桥梁。开发人员可以通过迁移来应用或回滚数据库的变更。
5. Furion.EntityFramework.Core:EF Core 配置层
- 功能:这一层负责配置和**管理 EF Core,**通常包括 DbContext 的配置、模型创建规则、数据库上下文的注入和数据访问的具体实现等。
- 作用:集中管理 EF Core 的配置和数据访问逻辑,为业务层提供数据操作的基础设施。这个层次将数据访问与业务逻辑分离,遵循依赖倒置原则。
6. Furion.Web.Core:Web 核心层
- 功能:这一层包含了与 Web 相关的公共代码,如过滤器、中间件、Web Helpers 等。通常是跨多个控制器或模块共享的通用代码,确保 Web 请求处理的通用逻辑集中管理。
- 作用:为 Web 层提供通用功能支持,如请求过滤、授权认证、跨域配置、异常处理等。通过这一层,Web 层的代码可以更加简洁且专注于业务功能的实现。
7. Furion.Web.Entry:Web 入口层/启动层
- 功能:这是 Web 应用程序的入口点,通常包含程序启动类(如
Program.cs
)和Startup.cs
,用于配置应用程序启动时所需的所有服务和中间件。 - 作用:配置应用程序的启动流程,包括依赖注入的初始化、路由配置、应用中间件管道的设置等。这一层负责将整个应用程序整合起来,并将其运行在 Web 服务器上。
三、初级后端工程师开发特别要注意的具体结构
1. Application 项目
1.1 项目作用
Application 项目主要负责服务类的实现、数据传输对象(DTO)的定义,以及接口的定义。它是应用程序的业务逻辑层,通过定义和实现服务来处理业务规则,并通过 DTO 进行数据传输。
1.2 书写方式
- 项目名称:
Test.Admin.Application
- 文件夹结构:
- 接口定义:放置用于定义服务接口的文件夹。
- Dtos:包含具体的数据传输对象(DTOs)。
- 服务类:包含业务逻辑的实现类。
- 接口定义:放置用于定义服务接口的文件夹。
- 基础服务类:
BaseService.cs
,用于封装公共的业务逻辑或服务功能。 - 全局引用文件:
GlobalUsings.cs
,用于定义常用的using
指令,以避免在每个文件中重复引用。
- 文件夹结构:
1.3 例子
接口定义:File 上传
具体的数据对象:
namespace Easy.Admin.Application.File.Dtos
{
public class UploadFileOutput
{
/// <summary>
/// 文件名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 附件链接
/// </summary>
public string Url { get; set; }
}
}
服务类:
using Easy.Admin.Application.File.Dtos;
using Easy.Admin.Core.Options;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using OnceMi.AspNetCore.OSS;
namespace Easy.Admin.Application.File
{
public class FileService : IDynamicApiController, ITransient
{
private readonly IOSSService _ossService;
private readonly IOptionsMonitor<OssConnectionOptions> _ossOptionsMonitor;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IIdGenerator _idGenerator;
public FileService(IOSSService ossService,
IOptionsMonitor<OssConnectionOptions> ossOptionsMonitor,
IHttpContextAccessor httpContextAccessor,
IWebHostEnvironment webHostEnvironment,
IIdGenerator idGenerator)
{
_ossService = ossService;
_ossOptionsMonitor = ossOptionsMonitor;
_httpContextAccessor = httpContextAccessor;
_webHostEnvironment = webHostEnvironment;
_idGenerator = idGenerator;
}
/// <summary>
/// 上传附件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[NonUnify]
public async Task<List<UploadFileOutput>> Upload([Required] IFormFile file)
{
if (file is null or { Length: 0 })
{
throw Oops.Oh("请上传文件");
}
var options = _ossOptionsMonitor.CurrentValue;
var now = DateTime.Today;
string name = _idGenerator.Encode(_idGenerator.NewLong());
string extension = Path.GetExtension(file.FileName);
if (string.IsNullOrWhiteSpace(extension))
{
throw Oops.Bah("无效文件");
}
// 文件路径
string filePath = $"/{now.Year}/{now.Month:D2}/{now.Day:D2}/";
// 本地存储处理
if (!options.Enable)
{
filePath = string.Concat(options.Bucket.TrimEnd('/'), filePath);
string s = Path.Combine(_webHostEnvironment.WebRootPath, filePath);
if (!Directory.Exists(s))
{
Directory.CreateDirectory(s);
}
var stream = System.IO.File.Create($"{s}{name}{extension}");
await file.CopyToAsync(stream);
await stream.DisposeAsync();
var request = _httpContextAccessor.HttpContext!.Request;
string url = $"{request.Scheme}://{request.Host.Value}/{filePath}{name}{extension}";
return new List<UploadFileOutput>()
{
new()
{
Name = $"{name}{extension}",
Url = url
}
};
}
// 云存储处理
string fileName = $"{filePath}{name}{extension}";
await _ossService.PutObjectAsync(options.Bucket, fileName, file.OpenReadStream());
string bucket = options.Provider == OSSProvider.Minio ? $"/{options.Bucket}" : string.Empty;
return new List<UploadFileOutput>()
{
new()
{
Name = $"{name}{extension}",
Url = $"{options.Domain.TrimEnd('/')}{bucket}{fileName}"
}
};
}
}
}
2.Core 项目
1. 项目作用
Core 项目是应用程序的基础层,提供应用的基础服务和公共资源,支持其他项目模块(如 Web 应用层、业务逻辑层等)的开发和运行。它通常包含基础设施、工具类、核心业务逻辑、数据库操作等。
2. 书写方式
- 项目名称:
Test.Admin.Core
- 公共资源文件夹:包含各类共享资源和基础服务。
- 接口文件夹:放置接口定义的文件夹。
- 接口1:具体的接口文件。
- 接口2:具体的接口文件。
- 抽象类文件夹:放置抽象类的文件夹。
- 抽象类1:具体的抽象类文件。
- 抽象类2:具体的抽象类文件。
- 资源类1:公共资源类。
- 资源类2:公共资源类。
- 接口文件夹:放置接口定义的文件夹。
- SqlSugar ORM:集成了 SqlSugar ORM,用于处理数据库操作。
- Pager 分页:处理数据库查询结果的分页。
- Repositories 仓库类:提供数据查询和持久化的方法。
- 缓存机制类:用于优化数据库查询,减少数据库访问次数,提高性能。
- 扩展方法类:定义自定义的查询扩展或其他实用工具方法。
- 工作单元类:用于管理数据库事务,确保数据操作的一致性和完整性。
- 过滤器类:用于添加特定的过滤器或配置查询选项。
- 公共资源文件夹:包含各类共享资源和基础服务。