179 lines
5.3 KiB
C#
179 lines
5.3 KiB
C#
using HoneyBox.Core.Interfaces;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
|
||
namespace HoneyBox.Admin.Controllers;
|
||
|
||
/// <summary>
|
||
/// 文件上传控制器
|
||
/// </summary>
|
||
[ApiController]
|
||
[Route("api/admin/upload")]
|
||
[Authorize]
|
||
public class UploadController : ControllerBase
|
||
{
|
||
private readonly IImageUploadService _uploadService;
|
||
private readonly ILogger<UploadController> _logger;
|
||
|
||
private static readonly HashSet<string> AllowedImageExtensions = new(StringComparer.OrdinalIgnoreCase)
|
||
{
|
||
".jpg", ".jpeg", ".png", ".gif", ".webp", ".avif"
|
||
};
|
||
|
||
private const long MaxFileSize = 20 * 1024 * 1024; // 20MB
|
||
|
||
public UploadController(IImageUploadService uploadService, ILogger<UploadController> logger)
|
||
{
|
||
_uploadService = uploadService;
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取预签名上传URL(当前不支持直传,返回标识让前端降级)
|
||
/// </summary>
|
||
[HttpPost("presigned-url")]
|
||
public IActionResult GetPresignedUrl([FromBody] PresignedUrlRequest request)
|
||
{
|
||
// 当前不支持直传,返回标识让前端降级到服务端上传
|
||
return Ok(new
|
||
{
|
||
code = 0,
|
||
message = "success",
|
||
data = new { supportsDirectUpload = false }
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上传图片(服务端上传)
|
||
/// </summary>
|
||
[HttpPost("image")]
|
||
[RequestSizeLimit(MaxFileSize)]
|
||
public async Task<IActionResult> UploadImage(IFormFile file)
|
||
{
|
||
if (file == null || file.Length == 0)
|
||
{
|
||
return Ok(new { code = 1, message = "请选择要上传的图片" });
|
||
}
|
||
|
||
if (file.Length > MaxFileSize)
|
||
{
|
||
return Ok(new { code = 1, message = "图片大小不能超过20MB" });
|
||
}
|
||
|
||
var extension = Path.GetExtension(file.FileName);
|
||
if (!AllowedImageExtensions.Contains(extension))
|
||
{
|
||
return Ok(new { code = 1, message = "不支持的图片格式,仅支持 jpg/jpeg/png/gif/webp/avif" });
|
||
}
|
||
|
||
try
|
||
{
|
||
using var stream = file.OpenReadStream();
|
||
var url = await _uploadService.UploadStreamAsync(stream, file.FileName, file.ContentType, "uploads");
|
||
|
||
if (!string.IsNullOrEmpty(url))
|
||
{
|
||
return Ok(new
|
||
{
|
||
code = 0,
|
||
message = "上传成功",
|
||
data = new
|
||
{
|
||
url,
|
||
fileName = file.FileName,
|
||
fileSize = file.Length
|
||
}
|
||
});
|
||
}
|
||
else
|
||
{
|
||
return Ok(new { code = 1, message = "上传失败" });
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "图片上传异常: {FileName}", file.FileName);
|
||
return Ok(new { code = 1, message = "上传失败,请稍后重试" });
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量上传图片
|
||
/// </summary>
|
||
[HttpPost("images")]
|
||
[RequestSizeLimit(MaxFileSize * 10)]
|
||
public async Task<IActionResult> UploadImages(List<IFormFile> files)
|
||
{
|
||
if (files == null || files.Count == 0)
|
||
{
|
||
return Ok(new { code = 1, message = "请选择要上传的图片" });
|
||
}
|
||
|
||
var results = new List<object>();
|
||
var errors = new List<string>();
|
||
|
||
foreach (var file in files)
|
||
{
|
||
if (file.Length > MaxFileSize)
|
||
{
|
||
errors.Add($"{file.FileName}: 文件大小超过限制");
|
||
continue;
|
||
}
|
||
|
||
var extension = Path.GetExtension(file.FileName);
|
||
if (!AllowedImageExtensions.Contains(extension))
|
||
{
|
||
errors.Add($"{file.FileName}: 不支持的图片格式");
|
||
continue;
|
||
}
|
||
|
||
try
|
||
{
|
||
using var stream = file.OpenReadStream();
|
||
var url = await _uploadService.UploadStreamAsync(stream, file.FileName, file.ContentType, "uploads");
|
||
|
||
if (!string.IsNullOrEmpty(url))
|
||
{
|
||
results.Add(new
|
||
{
|
||
url,
|
||
fileName = file.FileName,
|
||
fileSize = file.Length
|
||
});
|
||
}
|
||
else
|
||
{
|
||
errors.Add($"{file.FileName}: 上传失败");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "图片上传异常: {FileName}", file.FileName);
|
||
errors.Add($"{file.FileName}: 上传异常");
|
||
}
|
||
}
|
||
|
||
if (results.Count == 0)
|
||
{
|
||
return Ok(new { code = 1, message = string.Join("; ", errors) });
|
||
}
|
||
|
||
return Ok(new
|
||
{
|
||
code = 0,
|
||
message = errors.Count > 0 ? $"部分上传成功,失败: {string.Join("; ", errors)}" : "上传成功",
|
||
data = results
|
||
});
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 预签名URL请求
|
||
/// </summary>
|
||
public class PresignedUrlRequest
|
||
{
|
||
public string FileName { get; set; } = string.Empty;
|
||
public string ContentType { get; set; } = string.Empty;
|
||
public long FileSize { get; set; }
|
||
}
|