A:初版
This commit is contained in:
1 parent
237cbd8788
commit
ab3721912d
102 files changed
+7929
-20
No files matched your search
@@ -0,0 +1,193 @@
|
||||
using Sharp.NetServer.Attributes;
|
||||
using Sharp.NetServer.Controllers;
|
||||
using Sharp.NetServer.Models;
|
||||
|
||||
namespace NetServer.Test.Examples.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 产品管理控制器示例
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/products")]
|
||||
public class ProductController : BaseController
|
||||
{
|
||||
private static readonly List<Product> Products = new()
|
||||
{
|
||||
new Product { Id = 1, Name = "笔记本电脑", Price = 5999.00m, Stock = 50, Category = "电子产品" },
|
||||
new Product { Id = 2, Name = "无线鼠标", Price = 99.00m, Stock = 200, Category = "电子产品" },
|
||||
new Product { Id = 3, Name = "机械键盘", Price = 399.00m, Stock = 100, Category = "电子产品" },
|
||||
new Product { Id = 4, Name = "显示器", Price = 1299.00m, Stock = 30, Category = "电子产品" },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有产品(公开接口,带缓存和限流)
|
||||
/// GET /api/products
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[RateLimit(200, RateLimitScope.Ip)]
|
||||
[ResponseCache(60, VaryByQueryKeys = true)]
|
||||
[HttpGet]
|
||||
public async Task GetAllProductsAsync(HttpContext context)
|
||||
{
|
||||
var category = GetQueryParam(context, "category", "");
|
||||
var products = string.IsNullOrEmpty(category)
|
||||
? Products
|
||||
: Products.Where(p => p.Category.Equals(category, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
await WriteSuccessResponseAsync(context, products);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取产品详情
|
||||
/// GET /api/products/1
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[ResponseCache(30)]
|
||||
[HttpGet("{id}")]
|
||||
public async Task GetProductByIdAsync(HttpContext context)
|
||||
{
|
||||
var idStr = context.Request.Url.Segments.LastOrDefault()?.TrimEnd('/');
|
||||
if (int.TryParse(idStr, out var id))
|
||||
{
|
||||
var product = Products.FirstOrDefault(p => p.Id == id);
|
||||
if (product != null)
|
||||
{
|
||||
await WriteSuccessResponseAsync(context, product);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await NotFoundAsync(context, "产品未找到");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建产品(需要认证)
|
||||
/// POST /api/products
|
||||
/// Body: { "name": "新产品", "price": 199.00, "stock": 100, "category": "类别" }
|
||||
/// </summary>
|
||||
[Authorize(Roles = "Admin")]
|
||||
[RateLimit(20, RateLimitScope.User)]
|
||||
[HttpPost]
|
||||
public async Task CreateProductAsync(HttpContext context)
|
||||
{
|
||||
var productData = await ReadJsonBodyAsync<Product>(context);
|
||||
|
||||
if (productData == null || string.IsNullOrEmpty(productData.Name) || productData.Price <= 0)
|
||||
{
|
||||
await BadRequestAsync(context, "无效的产品数据");
|
||||
return;
|
||||
}
|
||||
|
||||
productData.Id = Products.Max(p => p.Id) + 1;
|
||||
Products.Add(productData);
|
||||
|
||||
await WriteSuccessResponseAsync(context, productData, "产品创建成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新库存
|
||||
/// PATCH /api/products/1/stock
|
||||
/// Body: { "quantity": 10 }
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
[HttpPatch("{id}/stock")]
|
||||
public async Task UpdateStockAsync(HttpContext context)
|
||||
{
|
||||
var idStr = context.Request.Url.Segments[^2].TrimEnd('/');
|
||||
if (!int.TryParse(idStr, out var id))
|
||||
{
|
||||
await BadRequestAsync(context, "无效的产品ID");
|
||||
return;
|
||||
}
|
||||
|
||||
var product = Products.FirstOrDefault(p => p.Id == id);
|
||||
if (product == null)
|
||||
{
|
||||
await NotFoundAsync(context, "产品未找到");
|
||||
return;
|
||||
}
|
||||
|
||||
var stockUpdate = await ReadJsonBodyAsync<Dictionary<string, object>>(context);
|
||||
if (stockUpdate != null && stockUpdate.TryGetValue("quantity", out var quantityObj))
|
||||
{
|
||||
if (int.TryParse(quantityObj.ToString(), out var quantity))
|
||||
{
|
||||
product.Stock = quantity;
|
||||
await WriteSuccessResponseAsync(context, product, "库存更新成功");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await BadRequestAsync(context, "无效的库存数量");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除产品
|
||||
/// DELETE /api/products/1
|
||||
/// </summary>
|
||||
[Authorize(Roles = "Admin")]
|
||||
[HttpDelete("{id}")]
|
||||
public async Task DeleteProductAsync(HttpContext context)
|
||||
{
|
||||
var idStr = context.Request.Url.Segments.LastOrDefault()?.TrimEnd('/');
|
||||
if (!int.TryParse(idStr, out var id))
|
||||
{
|
||||
await BadRequestAsync(context, "无效的产品ID");
|
||||
return;
|
||||
}
|
||||
|
||||
var product = Products.FirstOrDefault(p => p.Id == id);
|
||||
if (product == null)
|
||||
{
|
||||
await NotFoundAsync(context, "产品未找到");
|
||||
return;
|
||||
}
|
||||
|
||||
Products.Remove(product);
|
||||
await WriteSuccessResponseAsync(context, new { id }, "产品删除成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索产品
|
||||
/// GET /api/products/search?q=键盘&minPrice=100&maxPrice=500
|
||||
/// </summary>
|
||||
[AllowAnonymous]
|
||||
[RateLimit(150, RateLimitScope.Ip)]
|
||||
[HttpGet("search")]
|
||||
public async Task SearchProductsAsync(HttpContext context)
|
||||
{
|
||||
var query = GetQueryParam(context, "q", "");
|
||||
var minPriceStr = GetQueryParam(context, "minPrice", "0");
|
||||
var maxPriceStr = GetQueryParam(context, "maxPrice", decimal.MaxValue.ToString());
|
||||
|
||||
decimal.TryParse(minPriceStr, out var minPrice);
|
||||
decimal.TryParse(maxPriceStr, out var maxPrice);
|
||||
|
||||
var results = Products.Where(p =>
|
||||
(string.IsNullOrEmpty(query) || p.Name.Contains(query, StringComparison.OrdinalIgnoreCase)) &&
|
||||
p.Price >= minPrice &&
|
||||
p.Price <= maxPrice
|
||||
).ToList();
|
||||
|
||||
await WriteSuccessResponseAsync(context, new
|
||||
{
|
||||
query,
|
||||
minPrice,
|
||||
maxPrice,
|
||||
count = results.Count,
|
||||
products = results
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 产品数据模型
|
||||
/// </summary>
|
||||
public class Product
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public decimal Price { get; set; }
|
||||
public int Stock { get; set; }
|
||||
public string Category { get; set; } = string.Empty;
|
||||
}
|
||||
Reference in new issue
Block a user