# Server 项目
Base on netcore3.x,建议开发IDE Visual Studio 2019
# 目录结构
解决方案目录结构如下:
TenantSite.Server
├── 1-Presentation
│ ├── AlonsoAdmin.HttpApi // TenantSite.UI 的后台API项目
│ └── AlonsoAdmin.HttpApi.Init // TenantSite.Developer.Tools 的后台API项目。
├── 2-Application
│ ├── AlonsoAdmin.Services // 服务层
├── 3-Domain
│ └── AlonsoAdmin.Domain // 领域层,用于编写针对领域的逻辑函数(如事务处理等)
└── 4-Infrastructure
├── AlonsoAdmin.Common // Common 常用工具、用户、配置、前后端规约实体等核心类库项目
├── AlonsoAdmin.Entities // 数据库实体类库项目
├── AlonsoAdmin.MultiTenant // 多租户类库项目
└── AlonsoAdmin.Repository // 数据仓储类库项目
2
3
4
5
6
7
8
9
10
11
12
13
14
# 配置说明
建议刚上手时使用开发人员工具进行配置。
HttpApi项目配置文件及说明如下:
{
// 启动参数配置,更改后需重启程序生效
"Startup": {
// 缓存
"Cache": {
"Type": 0, // 0:内存 1:Redis
"Redis": {
"ConnectionString": "127.0.0.1:6379,password=,defaultDatabase=2"
}
},
// 日志
"Log": {
"Operation": true // API访问日志开关
},
"TenantRouteStrategy": 0 // 租户策略,0:Route模式 1:Host模式
},
// 系统配置,支持热更新,修改后立即生效,无需重新启动程序
"System": {
// 监控CURD动作得SQL语句,开启将在日志窗口中显示执行的SQL语句
"WatchCurd": true,
// 用于雪花算法,数据中心ID
"DataCenterId": 5,
// 用于雪花算法,工作站ID
"WorkId": 20,
// 是否启用API权限验证,如果启用API需与资源绑定,否则将不允许访问API
"EnableApiAccessControl": true,
// 头像上次参数
"uploadAvatar": {
"uploadPath": "D:/upload/avatar", // 上传根路径
"requestPath": "/upload/avatar", // 相对根路径
"maxSize": 1048576,
"contentType": [
"image/jpg",
"image/png",
"image/jpeg",
"image/gif"
]
}
},
// 租户配置,目前采样配置方式,应该改为从总控平台获取
"Tenants": [
{
"Id": "1", // 租户唯一标识
"Code": "Tenant1",// 租户Code(唯一标识),如果为Host模式将作为租户的二级域名
"Name": "租户1", // 租户名称
// 当前租户的数据库参数配置,支持多数据库,不同应用可指向不同的数据库
"DbOptions": [
{
// 应用数据库key
"Key": "system",
// 数据库类型 MySql = 0, SqlServer = 1, PostgreSQL = 2, Oracle = 3, Sqlite = 4
// 更多支持:https://github.com/dotnetcore/FreeSql/wiki/入门
"DbType": "0",
"ConnectionStrings": [
{
// 连接字符
"ConnectionString": "Server=localhost; Port=3306; Database=tenant1db; Uid=root; Pwd=000000; Charset=utf8mb4;",
// 0主库 1为从库
"UseType": 0
},
{
"ConnectionString": "Server=localhost; Port=3306; Database=Tenant1db; Uid=root; Pwd=000000; Charset=utf8mb4;",
"UseType": 1
}
]
},
// 多数据库支持,blog为第二个应用库配置示例,与system配置结构一致
{
"Key": "blog",
"DbType": "0",
"ConnectionStrings": [
{
"ConnectionString": "Server=localhost; Port=3306; Database=Tenant1db; Uid=root; Pwd=000000; Charset=utf8mb4;",
"UseType": 0
},
{
"ConnectionString": "Server=localhost; Port=3306; Database=Tenant1db; Uid=root; Pwd=000000; Charset=utf8mb4;",
"UseType": 1
}
]
}
],
// 当前租户 JWT Token 配置参数
"Items": {
"Audience": "https://www.xxxx.com/",
"ExpirationMinutes": "1000",
"Issuer": "https://www.xxxx.com/",
"Secret": "2qtiOLpT7mJQx239e2kgMheAH7B9lGQJnoxYRCb7KX3x1ogDEd55I7dJ1ziYptiTF"
}
},
// 复制租户1可进行租户2的配置
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# 新增模块应用
首先保证初始化工作完成,系统可正常运行。
为了更准确描述步骤,下方以字典管理模块为例介绍步骤
模块名:Dictionary
模块涉及两张数据表,字典主表:Dictionary, 字典明细表:DictionaryEntry
# 第一步:创建实体
# 目录文件结构
在数据库实体项目(AlonsoAdmin.Entities)中创建目录结构
AlonsoAdmin.Entities
└── Dictionary // 模块文件夹,需使用英文名称命名
├── DictionaryEntryEntity.cs // 表 DictionaryEntry 映射实体
└── DictionaryHeaderEntity.cs // 表 Dictionary 映射实体
2
3
4
示例:
# 第二步:创建仓储
仓储接口类命名规范:I + [表名/业务名] + Repository
仓储实现类命名规范:[表名/业务名] + Repository
系统将自动注入到容器
# 目录文件结构
在仓储项目(AlonsoAdmin.Repository)中创建目录结构
AlonsoAdmin.Repository
└── Dictionary // 模块文件夹,需使用英文名称命名
├── Implement // 实现
│ ├── DictionaryHeaderRepository.cs
│ └── DictionaryEntryRepository.cs
└── Interface // 接口
├── IDictionaryHeaderRepository.cs
└── IDictionaryEntryRepository.cs
2
3
4
5
6
7
8
示例:
# 第三步:创建服务
服务接口类命名规范:I + [表名/业务名] + Service
服务实现类命名规范:[表名/业务名] + Service
服务将自动注入到容器
前端请求后台实体(DTO)命名规范: [表名/业务名] + Request
后台响应前端实体(DTO)命名规范: [表名/业务名] + Response
# 目录文件结构
在服务项目中创建目录结构(推荐如下目录结构,也可按自己习惯)
AlonsoAdmin.Services
└── Dictionary // 模块文件夹,需使用英文名称命名
├── Mapper.cs // autoMapper 实体映射类并继承 AutoMapper.Profile
├── Request // DTO文件夹:前端请求后台实体对象
│ ├── DictionaryHeaderRequest.cs
│ └── DictionaryEntryRequest.cs
├── Response // DTO文件夹:后台响应前台实体对象
│ ├── DictionaryHeaderResponse.cs
│ └── DictionaryEntryResponse.cs
├── Interface // 服务接口
│ ├── IDictionaryHeaderService.cs
│ └── IDictionaryEntryService.cs
└── Implement // 服务实现
├── DictionaryHeaderService.cs
└── DictionaryEntryService.cs
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果实现服务逻辑复杂,或用到多表事务处理的时候,可在领域项目中创建领域进行抽离聚合业务应用。
以上文件的创建顺序推荐:DTO(Request/Response) > Mapper.cs > Interface > Implement
示例:
# 第四步:创建接口
# 目录文件结构
在API项目中创建目录结构
AlonsoAdmin.HttpApi
└── Controllers
└── V1
└── Dictionary // 模块文件夹,需使用英文名称命名
├── _ModuleBaseController.cs // 模块接口控制器基础类
├── DictionaryHeaderController.cs // 字典API
└── DictionaryEntryController.cs // 字典明细API
2
3
4
5
6
7
接口与前端约定好通用API方法,如下:
- Create 创建
- Update 更新
- Delete 物理删除-单条
- DeleteBatch 物理删除-批量
- SoftDelete 逻辑删除-单条
- SoftDeleteBatch 逻辑删除-批量
- GetItem 得到实体
- GetList 取得条件下分页列表数据
- GetAll 取得条件下所有的数据(不分页)
示例:
# 第五步:生成API
完成上面4步,启动程序 用管理员身份进入API管理进行API生成
此操作将通过路由自动生成Api接口
如果存在相同Api将更新,不存在将自动新增Api
注:为了安全起见,系统不会自动删除在HttpApi中找不到的API
# 示例代码
# 鉴权用户使用
构造函数依赖注入IAuthUser即可使用。
public class DemoService
{
private readonly IAuthUser _authUser;
public DemoService(IAuthUser authUser)
{
_authUser = authUser;
}
public async Task<IResponseEntity> Test()
{
// 通过 _authUser 可获取到当前用户包括所属租户在内的信息
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 缓存使用
构造函数依赖注入ICache即可使用。
public class DemoService
{
private readonly ICache _cache;
public DemoService(ICache cache)
{
_cache = cache;
}
public async Task<IResponseEntity> Test()
{
// 通过 _cache 可对缓存操作
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 数据库实体类示例
数据库实体命名规范:[表名/业务名]+Entity
创建实体类并继承已定义好公共属性的 BaseEntity 实体类
如果提前建立了数据库及表字段,实体类可通过工具生成(DbFirst), 实体生成 (opens new window)
推荐使用创建实体类,系统将自动同步到数据库(CodeFirst), 实体特性 (opens new window)
示例文件:DictionaryHeaderEntity.cs
namespace AlonsoAdmin.Entities.Dictionary
{
/// <summary>
/// 数据字典分类
/// </summary>
[Table(Name = "sys_dictionary")]
public class DictionaryHeaderEntity : BaseEntity
{
/// <summary>
/// 编码
/// </summary>
[Column(Name = "CODE", Position = 2)]
public string Code { get; set; } = string.Empty;
/// <summary>
/// 名称
/// </summary>
[Column(Name = "TITLE", Position = 3)]
public string Title { get; set; } = string.Empty;
/// <summary>
/// 描述
/// </summary>
[Column(Name = "DESCRIPTION", Position = 4)]
public string Description { get; set; } = string.Empty;
/// <summary>
/// 排序
/// </summary>
[Column(Name = "ORDER_INDEX", Position = 5)]
[MaxValue]
public int? OrderIndex { get; set; }
#region 导航属性
public virtual ICollection<DictionaryEntryEntity> DictionaryItems { get; set; }
#endregion
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 仓储接口类示例
仓储接口类命名规范:I + [表名/业务名] + Repository
示例文件:IDictionaryHeaderRepository.cs
namespace AlonsoAdmin.Repository.Dictionary.Interface
{
// IRepositoryBase<T> T 为第一步创建的实体类
public interface IDictionaryHeaderRepository: IRepositoryBase<DictionaryHeaderEntity>
{
}
}
2
3
4
5
6
7
8
# 仓储实现类示例
仓储实现类命名规范:[表名/业务名] + Repository
示例文件:DictionaryHeaderRepository.cs
继承仓储基类RepositoryBase和接口IDictionaryHeaderRepository
在构造函数注入IMultiTenantDbFactory(数据工厂类)和IAuthUser(授权用户类)
namespace AlonsoAdmin.Repository.Dictionary.Implement
{
public class DictionaryHeaderRepository
: RepositoryBase<DictionaryHeaderEntity>, // RepositoryBase<T> T为前面创建的数据库实体
IDictionaryHeaderRepository // 前面创建的接口类
{
public DictionaryHeaderRepository(IMultiTenantDbFactory dbFactory, IAuthUser user)
: base(dbFactory.Db(Constants.SystemDbKey), user)
// Constants.SystemDbKey 为模块的数据库连接Key,不同实现支持不同数据库连接
{
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# DTO实体类示例
- Request DTO
前端请求实体对象,通常有三种类型的实体对象场景
- 新增对象 (命名规范:[业务名] + Add + Request)
- 编辑对象 (命名规范:[业务名] + Edit + Request)
- 查询对象 (命名规范:[业务名] + Filter + Request)
示例中的三种场景的实体对象均放在了同一文件中(DictionaryHeaderRequest.cs,当然也可以拆分开单独文件)
- Response DTO
后台响应实体对象,通常有两种类型的实体对象场景
- 用于列表展示的实体对象 (命名规范:[业务名] + ForList + Response)
- 用于详情展示的实体对象 (命名规范:[业务名] + ForItem + Response)
示例中的两种场景的实体对象均放在了同一文件中(DictionaryHeaderResponse.cs,当然也可以拆分开单独文件)
DictionaryHeaderRequest.cs 内容结构如下
namespace AlonsoAdmin.Services.Dictionary.Request
{
/// <summary>
/// 前端添加对象实体类
/// 命名规范:[业务名] + Add + Request
/// </summary>
public class DictionaryHeaderAddRequest
{
// 在这定义接收前端的属性
// 属性名尽量保持与数据库实体属性名一致,以减少编写Mapper.cs中的映射代码量
// ...省略属性代码,明细见源码
}
/// <summary>
/// 前端编辑对象实体类
/// 命名规范:[业务名] + Edit + Request
/// 继承 '前端添加对象实体类'
/// </summary>
public class DictionaryHeaderEditRequest : DictionaryHeaderAddRequest
{
/// <summary>
/// 主键ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 排序
/// </summary>
public int? OrderIndex { get; set; }
/// <summary>
/// 记录版本(乐观锁,用于限制脏写)
/// </summary>
public int Revision { get; set; }
}
/// <summary>
/// 前端查询对象实体类
/// 命名规范:[业务名] + Filter + Request
/// </summary>
public class DictionaryHeaderFilterRequest
{
/// <summary>
/// 查询关键字
/// </summary>
public string Key { get; set; } = string.Empty;
/// <summary>
/// 是否包含禁用的数据
/// </summary>
public bool WithDisable { get; set; } = false;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
DictionaryHeaderResponse.cs 内容结构如下
namespace AlonsoAdmin.Services.Dictionary.Response
{
/// <summary>
/// 响应前端列表展示的实体对象
/// 命名规范:[业务名] + ForList + Response
/// 可直接继承数据库实体
/// 自定义属性的两种场景:
/// 1.对于字段比较多,无需全部展示时,可以不继承(取名也尽量保持一致)
/// 2.专用于前端的字段展示,和数据库属性不一致(需在Mapper.cs中做映射逻辑)
/// </summary>
public class DictionaryHeaderForListResponse : DictionaryHeaderEntity
{
}
/// <summary>
/// 响应前端详情展示的实体对象
/// 命名规范:[业务名] + ForItem + Response
/// 可直接继承数据库实体(示例为直接继承)
/// 自定义属性的两种场景:
/// 1.对于字段比较多,无需全部展示时,可以不继承(取名也尽量保持一致)
/// 2.专用于前端的字段展示,和数据库属性不一致(需在Mapper.cs中做映射逻辑)
/// </summary>
public class DictionaryHeaderForItemResponse : DictionaryHeaderEntity
{
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Mapper.cs实体映射示例
Mapper.cs 主要作用就是解决 数据库实体对象(DO)、前后端交互的实体对象(DTO)间的映射问题
Mapper.cs 继承 AutoMapper.Profile 类,系统将自动注入到容器
关于AutoMapper更多知识见: AutoMapper (opens new window)
namespace AlonsoAdmin.Services.Dictionary
{
public class Mapper : Profile
{
public Mapper()
{
#region Dictionary
// 创建 用到的映射 (DTO -> DO)
CreateMap<DictionaryHeaderAddRequest, DictionaryHeaderEntity>();
// 更新 用到的映射 (DTO -> DO)
CreateMap<DictionaryHeaderEditRequest, DictionaryHeaderEntity>();
// 查询列表 用到的映射 (DO -> DTO)
CreateMap<DictionaryHeaderEntity, DictionaryHeaderForListResponse>();
// 查询单条明细 用到的映射 (DO -> DTO)
CreateMap<DictionaryHeaderEntity, DictionaryHeaderForItemResponse>();
#endregion
#region DictionaryEntry
// 类似 Dictionary 节点代码
#endregion
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Interface服务接口示例
服务接口类命名规范:I + [表名/业务名] + Service
服务实现类命名规范:[表名/业务名] + Service
namespace AlonsoAdmin.Services.Dictionary.Interface
{
/// <summary>
/// 字典主表服务接口类
/// </summary>
public interface IDictionaryHeaderService
: IBaseService<
DictionaryHeaderFilterRequest, // 查询对象实体 DTO
DictionaryHeaderAddRequest, // 新增对象实体 DTO
DictionaryHeaderEditRequest // 编辑对象实体 DTO
>
{
#region 特殊接口 (通用接口在IBaseService中已定义)
// 定义特殊接口
#endregion
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Implement服务实现示例
服务接口类命名规范:I + [表名/业务名] + Service
服务实现类命名规范:[表名/业务名] + Service
using AlonsoAdmin.Common.Auth;
using AlonsoAdmin.Common.Cache;
using AlonsoAdmin.Common.Extensions;
using AlonsoAdmin.Common.RequestEntity;
using AlonsoAdmin.Common.ResponseEntity;
using AlonsoAdmin.Entities.Dictionary;
using AlonsoAdmin.Repository.Dictionary.Interface;
using AlonsoAdmin.Services.Dictionary.Interface;
using AlonsoAdmin.Services.Dictionary.Request;
using AlonsoAdmin.Services.Dictionary.Response;
using AutoMapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AlonsoAdmin.Services.Dictionary.Implement
{
public class DictionaryHeaderService: IDictionaryHeaderService
{
private readonly IMapper _mapper;
private readonly ICache _cache;
private readonly IAuthUser _authUser;
private readonly IDictionaryHeaderRepository _dictionaryHeaderRepository;
/// <summary>
/// 构造函数 参数对象系统自动注入
/// </summary>
/// <param name="mapper">autoMapper 映射工具对象</param>
/// <param name="cache">缓存对象</param>
/// <param name="authUser">授权用户对象</param>
/// <param name="dictionaryHeaderRepository">仓储对象</param>
public DictionaryHeaderService(
IMapper mapper,
ICache cache,
IAuthUser authUser,
IDictionaryHeaderRepository dictionaryHeaderRepository
)
{
_mapper = mapper;
_cache = cache;
_authUser = authUser;
_dictionaryHeaderRepository = dictionaryHeaderRepository;
}
#region 通用接口服务实现(实现IBaseService.CS中定义的接口)
/// <summary>
/// 创建
/// </summary>
/// <param name="req">DTO:新增实体</param>
/// <returns></returns>
public async Task<IResponseEntity> CreateAsync(DictionaryHeaderAddRequest req)
{
var item = _mapper.Map<DictionaryHeaderEntity>(req);
var result = await _dictionaryHeaderRepository.InsertAsync(item);
return ResponseEntity.Result(result != null && result?.Id != "");
}
/// <summary>
/// 更新
/// </summary>
/// <param name="req">DTO:编辑实体</param>
/// <returns></returns>
public async Task<IResponseEntity> UpdateAsync(DictionaryHeaderEditRequest req)
{
if (req == null || req?.Id == "")
{
return ResponseEntity.Error("更新的实体主键丢失");
}
var entity = _mapper.Map<DictionaryHeaderEntity>(req);
await _dictionaryHeaderRepository.UpdateAsync(entity);
return ResponseEntity.Ok("更新成功");
}
/// <summary>
/// 删除 - 单条物理删除
/// </summary>
/// <param name="id">主键ID</param>
/// <returns></returns>
public async Task<IResponseEntity> DeleteAsync(string id)
{
if (id == null || id == "")
{
return ResponseEntity.Error("删除对象的主键获取失败");
}
var result = await _dictionaryHeaderRepository.DeleteAsync(id);
return ResponseEntity.Result(result > 0);
}
/// <summary>
/// 删除 - 批量物理删除
/// </summary>
/// <param name="ids">待删除的ID集合</param>
/// <returns></returns>
public async Task<IResponseEntity> DeleteBatchAsync(string[] ids)
{
if (ids == null || ids.Length == 0)
{
return ResponseEntity.Error("删除对象的主键获取失败");
}
var result = await _dictionaryHeaderRepository.Where(m => ids.Contains(m.Id)).ToDelete().ExecuteAffrowsAsync();
return ResponseEntity.Result(result > 0);
}
/// <summary>
/// 删除 - 单条逻辑删除(软删除)
/// </summary>
/// <param name="id">待删除的ID</param>
/// <returns></returns>
public async Task<IResponseEntity> SoftDeleteAsync(string id)
{
if (id == null || id == "")
{
return ResponseEntity.Error("删除对象的主键获取失败");
}
var result = await _dictionaryHeaderRepository.SoftDeleteAsync(id);
return ResponseEntity.Result(result);
}
/// <summary>
/// 删除 - 批量逻辑删除(软删除)
/// </summary>
/// <param name="ids">待删除的ID集合</param>
/// <returns></returns>
public async Task<IResponseEntity> SoftDeleteBatchAsync(string[] ids)
{
if (ids == null || ids.Length == 0)
{
return ResponseEntity.Error("删除对象的主键获取失败");
}
var result = await _dictionaryHeaderRepository.SoftDeleteAsync(ids);
return ResponseEntity.Result(result);
}
/// <summary>
/// 得到实体
/// </summary>
/// <param name="id">主键ID</param>
/// <returns></returns>
public async Task<IResponseEntity> GetItemAsync(string id)
{
var result = await _dictionaryHeaderRepository.GetAsync(id);
var data = _mapper.Map<DictionaryHeaderForItemResponse>(result);
return ResponseEntity.Ok(data);
}
/// <summary>
/// 得到查询条件的分页列表数据
/// </summary>
/// <param name="req">带分页属性的DTO查询对象</param>
/// <returns></returns>
public async Task<IResponseEntity> GetListAsync(RequestEntity<DictionaryHeaderFilterRequest> req)
{
var key = req.Filter?.Key;
var withDisable = req.Filter != null ? req.Filter.WithDisable : false;
var list = await _dictionaryHeaderRepository.Select
.WhereIf(key.IsNotNull(), a => (a.Title.Contains(key) || a.Code.Contains(key) || a.Description.Contains(key)))
.WhereIf(!withDisable, a => a.IsDisabled == false)
.Count(out var total)
.OrderBy(true, a => a.OrderIndex)
.Page(req.CurrentPage, req.PageSize)
.ToListAsync();
var data = new ResponsePageEntity<DictionaryHeaderForListResponse>()
{
List = _mapper.Map<List<DictionaryHeaderForListResponse>>(list),
Total = total
};
return ResponseEntity.Ok(data);
}
/// <summary>
/// 得到查询条件的所有数据
/// </summary>
/// <param name="req">DTO查询对象</param>
/// <returns></returns>
public async Task<IResponseEntity> GetAllAsync(DictionaryHeaderFilterRequest req)
{
var key = req?.Key;
var withDisable = req != null ? req.WithDisable : false;
var list = await _dictionaryHeaderRepository.Select
.WhereIf(key.IsNotNull(), a => (a.Title.Contains(key) || a.Code.Contains(key) || a.Description.Contains(key)))
.WhereIf(!withDisable, a => a.IsDisabled == false)
.OrderBy(true, a => a.OrderIndex)
.ToListAsync();
var result = _mapper.Map<List<DictionaryHeaderForListResponse>>(list);
return ResponseEntity.Ok(result);
}
#endregion
#region 特殊接口服务实现
#endregion
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# 模块基类代码展示
模块基类主要用于统一路由地址、统一权限策略、统一版本
示例文件:_ModuleBaseController.cs
using AlonsoAdmin.HttpApi.SwaggerHelper;
using static AlonsoAdmin.HttpApi.SwaggerHelper.CustomApiVersion;
namespace AlonsoAdmin.HttpApi.Controllers.V1.Dictionary
{
/// <summary>
/// 模块控制器基类,用于统一模块的路由地址(版本+模块名称)
/// 继承 BaseController,在BaseController已定义了权限策略
/// </summary>
[CustomRoute(ApiVersions.v1, "Dictionary")]
public abstract class ModuleBaseController : BaseController
{
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# API示例
API类命名规范:[业务名/表名] + Controller
主要用来调用对应的服务
示例文件:DictionaryHeaderController.cs
using System.ComponentModel;
using System.Threading.Tasks;
using AlonsoAdmin.Common.RequestEntity;
using AlonsoAdmin.Common.ResponseEntity;
using AlonsoAdmin.Services.Dictionary.Interface;
using AlonsoAdmin.Services.Dictionary.Request;
using Microsoft.AspNetCore.Mvc;
namespace AlonsoAdmin.HttpApi.Controllers.V1.Dictionary
{
[Description("字典管理")] // 如果使用API管理中生成API功能,将以这个描述填充相应标题内容
public class DictionaryHeaderController : ModuleBaseController
{
private readonly IDictionaryHeaderService _dictionaryService;
public DictionaryHeaderController(IDictionaryHeaderService dictionaryService)
{
_dictionaryService = dictionaryService;
}
#region 通用API方法
/// <summary>
/// 创建记录
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseEntity> Create(DictionaryHeaderAddRequest req)
{
return await _dictionaryService.CreateAsync(req);
}
/// <summary>
/// 更新记录
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPut]
public async Task<IResponseEntity> Update(DictionaryHeaderEditRequest req)
{
return await _dictionaryService.UpdateAsync(req);
}
/// <summary>
/// 物理删除 - 单条
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete]
public async Task<IResponseEntity> Delete(string id)
{
return await _dictionaryService.DeleteAsync(id);
}
/// <summary>
/// 物理删除 - 批量
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPut]
public async Task<IResponseEntity> DeleteBatch(string[] ids)
{
return await _dictionaryService.DeleteBatchAsync(ids);
}
/// <summary>
/// 软删除 - 单条
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete]
public async Task<IResponseEntity> SoftDelete(string id)
{
return await _dictionaryService.SoftDeleteAsync(id);
}
/// <summary>
/// 软删除 - 批量
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPut]
public async Task<IResponseEntity> SoftDeleteBatch(string[] ids)
{
return await _dictionaryService.SoftDeleteBatchAsync(ids);
}
/// <summary>
/// 得到实体
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
public async Task<IResponseEntity> GetItem(string id)
{
return await _dictionaryService.GetItemAsync(id);
}
/// <summary>
/// 取得条件下分页列表数据
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseEntity> GetList(RequestEntity<DictionaryHeaderFilterRequest> req)
{
return await _dictionaryService.GetListAsync(req);
}
/// <summary>
/// 取得条件下所有的数据(不分页)
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseEntity> GetAll(DictionaryHeaderFilterRequest req)
{
return await _dictionaryService.GetAllAsync(req);
}
#endregion
#region 特殊API方法
// 特殊API方法需定义特性Description,以方便程序自动生成API记录的描述,通用方法无需定义特性Description,如果定义将覆盖默认
#endregion
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
← UI 项目