- 程序入口是
Program.cs - 控制器在
SouthernMoneyBackend/Controllers目录下 - 数据库的服务层位于
Database/xxxService.cs
依赖通过依赖注入实现,无需手动管理依赖。
- 安装dotnet-ef 工具:
dotnet tool install --global dotnet-ef - 生成迁移(在仓库根目录执行:
dotnet ef migrations add AddPostsAndLikes \
--project Database/Database.csproj \
--startup-project SouthernMoneyBackend/SouthernMoneyBackend.csproj \
--output-dir Migrations- 应用迁移到数据库:
dotnet ef database update \
--project Database/Database.csproj \
--startup-project SouthernMoneyBackend/SouthernMoneyBackend.csprojdotnet run --project SouthernMoneyBackend/SouthernMoneyBackend.csproj访问/swagger即可查看API可视化文档
为了简化模型,需要数据就用GET,执行动作就用POST
通用准则:所有接口均返回ApiResponse<T>对象,其中T是具体的响应数据类型。
格式如下:
{
"Success": bool,
"Message": "错误信息", //optional
"Data": { },//optional
"Timestamp": "2023-10-01T12:00:00Z"
}下文提到的响应返回对象指的是"Data"字段对应的内容。例如/login/loginByPassword的完整响应如下:
{
"Success": true,
"Data": {
"Token": "登录令牌",
"RefreshToken": "刷新令牌"
},
"Timestamp": "2023-10-01T12:00:00Z"
}分页:所有分页接口都返回ApiResponse<PagedResult<T>>对象,其中T是具体的响应数据类型。
格式如下:
{
"Success": bool,
"Message": "错误信息", //optional
"Data": {
"Items": [ ],//optional
"TotalCount": 0,
"PageSize": 0,
"CurrentPage": 0
},
"Timestamp": "2023-10-01T12:00:00Z"
}- 路径:
/test - 方法:
GET - 成功响应:
{
"message": "Server is running"
}- 路径:
/login/register - 方法:
POST - 参数:
{
"Name": "用户名",
"Password": "密码"
}- 路径:
/login/loginByPassword - 方法:
POST - 参数:
{
"Name": "用户名",
"Password": "密码"
}- 成功响应:
{
"Token": "登录令牌",
"RefreshToken": "刷新令牌"
}- 路径:
/login/refreshToken - 方法:
POST - 参数:
{
"RefreshToken": "刷新令牌"
}- 成功响应:
{
"Token": "登录令牌",
"RefreshToken": "刷新令牌"
}- 路径:
/images/upload - 方法:
POST - 参数(form):
file: 图片文件(必填,最大2MB)imageType: 图片类型(必填)description: 图片描述(可选)
- 成功响应:
200 OK: 返回{ "ImageId": "图片ID" }
- 错误响应:
400 Bad Request: 包含错误信息(如文件为空、文件大小超过限制)401 Unauthorized: 认证失败
- 路径:
/images/get?id={imageId} - 方法:
GET - 参数:
imageId: 图片ID(必填,Guid格式)
- 成功响应:
200 OK: 返回Image对象,包含图片数据和元信息
- 错误响应:
404 Not Found: 图片不存在401 Unauthorized: 认证失败
- 路径:
/posts/create - 方法:
POST - 参数:
{
"Title": "帖子标题",
"Content": "帖子内容",
"Tags": [
"标签1",
"标签2"
],
"ImageIds": [
"图片ID1",
"图片ID2"
]
}- 路径:
/posts/get?id={postId} - 方法:
GET - 参数:
postId: 帖子ID(必填,Guid格式)
- 成功响应:
{
"Title": "帖子标题",
"Content": "帖子内容",
"CreateTime": "2023-01-01T00:00:00Z", //datetime
"ReportCount": 0, //int
"ViewCount": 0, //int
"LikeCount": 0, //int
"IsBlocked": false, //bool
"IsLiked": false, //bool
"Tags": [
"标签1",
"标签2"
],
"ImageIds": [
"图片ID1",
"图片ID2"
],
"Uploader":{
"Id":123123,
"Name":"用户名",
"Avatar":"图片ID"
}
}- 路径:
/posts/page?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页帖子数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 10,
"CurrentPage": 1,
"PageSize": 10,
"Posts": [
{
...
},
]
}- 路径:
/posts/search?query={query} - 方法:
GET - 参数:
query: 搜索关键词(必填)
- 成功响应:
{
"TotalCount": 10,
"CurrentPage": 1,
"PageSize": 10,
"Posts": [
{
...
},
]
}- 路径:
/posts/report - 方法:
POST - 参数:
{
"PostId": "帖子ID",
"Reason": "举报原因"
}- 成功响应:
200 OK
- 路径:
/posts/like?id={postId} - 方法:
POST - 参数:
postId: 帖子ID(必填,Guid格式)
- 成功响应:
{
"LikeCount": 1, //int
}- 路径:
/posts/delete - 方法:
POST - 参数:
{
"PostId": "帖子ID"
}- 成功响应:
200 OK
- 错误响应:
404 Not Found: 帖子不存在403 Forbidden: 无权限删除(非帖子作者或管理员)
- 路径:
/posts/edit - 方法:
POST - 参数:
{
"PostId": "帖子ID",
"Title": "新标题",
"Content": "新内容",
"Tags": [
"新标签1",
"新标签2"
],
"ImageIds": [
"新图片ID1",
"新图片ID2"
]
}- 成功响应:
200 OK
- 路径:
/posts/myPosts?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页帖子数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 10,
"CurrentPage": 1,
"PageSize": 10,
"Posts": [
{
...
},
]
}- 路径:
/user/profile - 方法:
GET - 成功响应:
{
"Id": 123123,
"Name": "用户名",
"Email": "用户邮箱",
"Avatar": "图片ID",
"IsBlocked": false, //bool
"CreateTime": "2023-01-01T00:00:00Z", //datetime
"IsAdmin": false, //bool
"Asset": {
"Total":10000,
"TodayEarn":100,
"AccumulatedEarn":1000000,
"EarnRate":0.01,
"Balance":10000
}
}- 路径:
/user/update - 方法:
POST - 参数:
{
"Name": "用户名",
"Email": "用户邮箱"
}- 成功响应:
200 OK
- 路径:
/user/changePassword - 方法:
POST - 参数:
{
"CurrentPassword": "当前密码",
"NewPassword": "新密码"
}- 成功响应:
200 OK
- 路径:
/user/uploadAvatar - 方法:
POST - 参数(form):
file: 图片文件(必填,最大2MB)
- 成功响应:
200 OK: 返回{ "AvatarId": "头像图片ID" }
- 错误响应:
400 Bad Request: 包含错误信息(如文件为空、文件大小超过限制)401 Unauthorized: 认证失败
- 路径:
/user/topup - 方法:
POST - 参数:
{
"Amount": 100.00 //decimal
}- 成功响应:
200 OK
- 路径:
/user/openAccount - 方法:
POST - 参数: 无
- 成功响应:
200 OK
- 路径:
/store/myProducts?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页商品数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 100,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": "商品ID",
"Name": "商品名称",
"Price": 100.00,
"Description": "商品描述",
"CategoryId": "分类ID",
"CategoryName": "分类名称",
"UploaderUserId": 123,
"UploaderName": "用户名",
"CreateTime": "创建时间"
},
]
}- 路径:
/store/products?page={page}&pageSize={pageSize}&categoryId={categoryId}&search={search} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页商品数量(必填,整数,默认值为10)categoryId: 分类ID(可选,Guid格式)search: 搜索关键词(可选)
- 成功响应:
{
"TotalCount": 100,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": "商品ID",
"Name": "商品名称",
"Price": 100.00,
"Description": "商品描述",
"CategoryId": "分类ID",
"CategoryName": "分类名称",
"UploaderUserId": 123,
"UploaderName": "用户名",
"CreateTime": "创建时间"
},
]
}- 路径:
/store/categories/{id}/products?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
id: 分类ID(必填,Guid格式)page: 页码(必填,整数,默认值为1)pageSize: 每页商品数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 100,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": "商品ID",
"Name": "商品名称",
"Price": 100.00,
"Description": "商品描述",
"CategoryId": "分类ID",
"CategoryName": "分类名称",
"UploaderUserId": 123,
"UploaderName": "用户名",
"CreateTime": "创建时间"
},
]
}- 路径:
/store/search?q={query}&page={page}&pageSize={pageSize} - 方法:
GET - 参数:
q: 搜索关键词(必填)page: 页码(必填,整数,默认值为1)pageSize: 每页商品数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 100,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": "商品ID",
"Name": "商品名称",
"Price": 100.00,
"Description": "商品描述",
"CategoryId": "分类ID",
"CategoryName": "分类名称",
"UploaderUserId": 123,
"UploaderName": "用户名",
"CreateTime": "创建时间"
},
]
}- post:
/store/publish - parameter
{
"Name": "商品名称",
"Price": 100.00, //decimal
"Description": "商品描述",
"CategoryId": "分类ID", //Guid格式
}- 路径:
/store/delete - 方法:
POST - 参数:
{
"ProductId": "商品ID"
}- 成功响应:
200 OK
- 路径:
/store/detail?id={productId} - 方法:
GET - 参数:
productId: 商品ID(必填,Guid格式)
- 成功响应:
{
"Id": "qweqwe",//guid
"Price": 100.00, //decimal
"Description": "商品描述",
"CategoryId": "分类ID", //Guid格式
"CategoryName": "商品分类名称",
"Uploader":{
"Id":123123,
"Name":"用户名",
"Avatar":"图片ID"
}
}- 路径:
/store/products/{id} - 方法:
GET - 参数:
id: 商品ID(必填,Guid格式)
- 成功响应:
{
"Id": "qweqwe",//guid
"Price": 100.00, //decimal
"Description": "商品描述",
"CategoryId": "分类ID", //Guid格式
"CategoryName": "商品分类名称",
"UploaderUserId": 123123,
"UploaderName": "用户名",
"CreateTime": "创建时间"
}- 路径:
/store/avgPrice?categoryId={categoryId} - 方法:
GET - 参数:
categoryId: 商品分类ID(必填,Guid格式)
- 成功响应:
{
"AvgPrice": 100.00 //decimal
}- 路径:
/store/categories - 方法:
GET - 成功响应:
{
"Success": true,
"Message": null,
"Data": [
{
"Id": "分类ID",
"Name": "分类名称",
"CoverImageId": "封面图片ID",
"CreateTime": "创建时间"
},
...
],
"Timestamp": "时间戳"
}- 路径:
/store/categories/{id} - 方法:
GET - 参数:
id: 分类ID(必填,Guid格式)
- 成功响应:
{
"Success": true,
"Message": null,
"Data": {
"Id": "分类ID",
"Name": "分类名称",
"CoverImageId": "封面图片ID",
"CreateTime": "创建时间"
},
"Timestamp": "时间戳"
}- 路径:
/store/category/search?name={name} - 方法:
GET - 成功响应:
{
"Categories": [
"商品分类1",
"商品分类2"
]//最多10个分类
}- Post:
/store/category/create - parameter
{
"Category": "商品分类",
"Cover": "图片ID"
}- 路径:
/store/categories/{categoryId}/favorite - 方法:
POST - 参数:
categoryId: 分类ID(必填,Guid格式)
- 成功响应:
200 OK
- 路径:
/store/categories/{categoryId}/unfavorite - 方法:
POST - 参数:
categoryId: 分类ID(必填,Guid格式)
- 成功响应:
200 OK
- 路径:
/store/favoriteCategories - 方法:
GET - 成功响应:
{
"Success": true,
"Data": [
{
"Id": "分类ID", //Guid格式
"Name": "分类名称",
"CoverImageId": "封面图片ID", //Guid格式
"CreateTime": "创建时间"
}
]
}- 路径:
/store/categories/{categoryId}/isFavorited - 方法:
GET - 参数:
categoryId: 分类ID(必填,Guid格式)
- 成功响应:
{
"Success": true,
"Data": {
"IsFavorited": true
}
}- 路径:
/transaction/buy - 方法:
POST - 参数:
{
"ProductId": "商品ID",
}- 成功响应:
200 OK
- 路径:
/transaction/myRecords?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页记录数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 10,
"CurrentPage": 1,
"PageSize": 10,
"Records": [
{
"Id": "qweqwe",//guid
"ProductId": "商品ID",//guid
"Quantity": 1, //int
"Price": 100.00, //decimal
"TotalPrice": 100.00, //decimal
"PurchaseTime": "2023-01-01T00:00:00Z" //datetime
},
]
}- 路径: GET
/notification/my?page={page}&pageSize={pageSize} - 参数:
page: 当前页码,默认1pageSize: 每页数量,默认10
- 成功响应
{
"code": 200,
"message": "success",
"data": {
"total": 100,
"page": 1,
"pageSize": 10,
"list": [
{
"Id": "guid",
"Content": "string",
"Type": "system", // 通知类型:system/activity/message
"CreateTime": "2023-01-01T00:00:00Z",
"IsRead": false
}
]
}
}- 路径: GET
/notification/unread-count - 成功响应
{
"code": 200,
"message": "success",
"data": 5
}- 路径: POST
/notification/read - 参数
{
"NotificationIds": ["通知ID1", "通知ID2"] // 支持单个或多个通知ID
}- 成功响应
{
"code": 200,
"message": "success"
}- 路径: POST
/notification/read-all - 成功响应
{
"code": 200,
"message": "success"
}- 路径:
/admin/handleUser - 方法:
POST - 参数:
{
"UserId": 123, //int
"IsBlocked": true, //bool
"HandleReason": "处理原因"
}- 成功响应:
200 OK
- 路径:
/admin/setAdmin - 方法:
POST - 参数:
{
"UserId": 123 //int
}- 成功响应:
200 OK
- 路径:
/admin/users?page={page}&pageSize={pageSize}&isBlocked={isBlocked}&isAdmin={isAdmin}&search={search} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页记录数量(必填,整数,默认值为10)isBlocked: 是否被封禁(可选,bool)isAdmin: 是否是管理员(可选,bool)search: 搜索关键词(可选,用于搜索用户名或邮箱)
- 成功响应:
{
"TotalCount": 100,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": 123123,
"Name": "用户名",
"Avatar": "图片ID",
"Email": "用户邮箱",
"IsBlocked": false, //bool
"IsAdmin": false //bool
},
]
}- 路径:
/admin/users/{userId} - 方法:
GET - 参数:
userId: 用户ID(必填,整数)
- 成功响应:
{
"Id": 123123,
"Name": "用户名",
"Avatar": "图片ID",
"Email": "用户邮箱",
"IsBlocked": false, //bool
"IsAdmin": false //bool
}- 路径:
/admin/statistics - 方法:
GET - 成功响应:
{
"TotalUsers": 1000,
"TotalProducts": 500,
"TotalTransactions": 2000,
"RecentTransactions": 150,
"BannedUsers": 10
}- 路径:
/admin/reportedPosts?page={page}&pageSize={pageSize} - 方法:
GET - 参数:
page: 页码(必填,整数,默认值为1)pageSize: 每页记录数量(必填,整数,默认值为10)
- 成功响应:
{
"TotalCount": 10,
"CurrentPage": 1,
"PageSize": 10,
"Items": [
{
"Id": "帖子ID",
"Title": "帖子标题",
"Content": "帖子内容",
"CreateTime": "2023-01-01T00:00:00Z",
"ReportCount": 3,
"ViewCount": 100,
"LikeCount": 10,
"IsBlocked": false,
"IsLiked": false,
"Tags": ["标签1", "标签2"],
"ImageIds": ["图片ID1", "图片ID2"],
"Uploader": {
"Id": 123123,
"Name": "用户名"
}
},
]
}- 路径:
/admin/handleReport - 方法:
POST - 参数:
{
"PostId": "帖子ID",
"IsBlocked": true, //bool
"HandleReason": "处理原因"
}- 成功响应:
200 OK
*:在development环境下,禁用了JWT认证
所有非登录相关的API(即非/login/*,/test路径)都需要在请求头中提供以下认证信息:
Authorization: Bearer <jwt_token>
其中<jwt_token>是通过登录接口(/login/loginByPassword)获取的JWT令牌。
- 认证失败时,API将返回
401 Unauthorized状态码 - 响应将包含标准化的错误信息,格式为:
{ "success": false, "message": "认证失败原因", "timestamp": "时间戳" }
- 可以通过
/login/refreshToken端点使用refresh token刷新过期的令牌(一般来说,refresh token的过期时间要比jwt token长)