191 lines
6.1 KiB
C#
191 lines
6.1 KiB
C#
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;
|
|
} |