This commit is contained in:
sjk
2025-11-17 14:11:46 +08:00
commit ad4a600af9
1659 changed files with 171560 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
package handler
import (
"fmt"
"mime/multipart"
"dianshang/internal/config"
"dianshang/pkg/logger"
"dianshang/pkg/response"
"dianshang/pkg/storage"
"github.com/gin-gonic/gin"
)
type UploadHandler struct {
config *config.Config
localStorage *storage.LocalStorage
ossStorage *storage.OSSStorage
}
func NewUploadHandler(cfg *config.Config) *UploadHandler {
handler := &UploadHandler{
config: cfg,
localStorage: storage.NewLocalStorage(&cfg.Upload),
}
// 如果配置了OSS初始化OSS存储
if cfg.Upload.StorageType == "oss" {
ossStorage, err := storage.NewOSSStorage(&cfg.Upload.OSS)
if err != nil {
logger.Errorf("初始化OSS存储失败: %v", err)
logger.Warn("将使用本地存储作为后备")
} else {
handler.ossStorage = ossStorage
logger.Info("OSS存储初始化成功")
}
}
return handler
}
// UploadImage 上传图片
func (h *UploadHandler) UploadImage(c *gin.Context) {
file, header, err := c.Request.FormFile("file")
if err != nil {
response.BadRequest(c, "获取上传文件失败: "+err.Error())
return
}
defer file.Close()
// 验证文件类型
if !storage.IsValidImageType(header.Filename) {
response.BadRequest(c, "不支持的图片格式,仅支持 jpg, jpeg, png, gif, webp, svg 格式")
return
}
// 验证文件大小 (5MB)
if header.Size > 5*1024*1024 {
response.BadRequest(c, "文件过大图片大小不能超过5MB")
return
}
// 生成文件名
filename := storage.GenerateFilename(header.Filename)
// 上传文件
fileURL, err := h.uploadFile(file, filename, "static/images")
if err != nil {
response.InternalServerError(c, "上传文件失败: "+err.Error())
return
}
response.Success(c, gin.H{
"url": fileURL,
"filename": filename,
"size": header.Size,
})
}
// UploadFile 上传通用文件
func (h *UploadHandler) UploadFile(c *gin.Context) {
file, header, err := c.Request.FormFile("file")
if err != nil {
response.BadRequest(c, "获取上传文件失败: "+err.Error())
return
}
defer file.Close()
// 验证文件大小 (10MB)
if header.Size > 10*1024*1024 {
response.BadRequest(c, "文件过大文件大小不能超过10MB")
return
}
// 生成文件名
filename := storage.GenerateFilename(header.Filename)
// 上传文件
fileURL, err := h.uploadFile(file, filename, "static/uploads")
if err != nil {
response.InternalServerError(c, "上传文件失败: "+err.Error())
return
}
response.Success(c, gin.H{
"url": fileURL,
"filename": filename,
"size": header.Size,
})
}
// BatchUploadImages 批量上传图片
func (h *UploadHandler) BatchUploadImages(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
response.BadRequest(c, "获取上传文件失败: "+err.Error())
return
}
files := form.File["files"]
if len(files) == 0 {
response.BadRequest(c, "没有选择文件,请选择要上传的图片")
return
}
// 限制批量上传数量
if len(files) > 10 {
response.BadRequest(c, "文件数量过多一次最多上传10个文件")
return
}
var results []gin.H
var errors []string
for _, header := range files {
file, err := header.Open()
if err != nil {
errors = append(errors, fmt.Sprintf("%s: 打开文件失败", header.Filename))
continue
}
// 验证文件类型
if !storage.IsValidImageType(header.Filename) {
errors = append(errors, fmt.Sprintf("%s: 不支持的图片格式", header.Filename))
file.Close()
continue
}
// 验证文件大小
if header.Size > 5*1024*1024 {
errors = append(errors, fmt.Sprintf("%s: 文件过大", header.Filename))
file.Close()
continue
}
// 生成文件名
filename := storage.GenerateFilename(header.Filename)
// 上传文件
fileURL, err := h.uploadFile(file, filename, "static/images")
file.Close()
if err != nil {
errors = append(errors, fmt.Sprintf("%s: 上传失败", header.Filename))
continue
}
// 添加成功结果
results = append(results, gin.H{
"url": fileURL,
"filename": filename,
"originalName": header.Filename,
"size": header.Size,
})
}
response.Success(c, gin.H{
"files": results,
"errors": errors,
"total": len(files),
"success": len(results),
"failed": len(errors),
})
}
// uploadFile 核心上传方法根据配置选择OSS或本地存储
func (h *UploadHandler) uploadFile(file multipart.File, filename string, objectPath string) (string, error) {
// 如果配置为OSS且OSS存储已初始化使用OSS
if h.config.Upload.StorageType == "oss" && h.ossStorage != nil {
fileURL, err := h.ossStorage.UploadFile(file, filename, objectPath)
if err != nil {
logger.Errorf("OSS上传失败: %v, 切换到本地存储", err)
// OSS上传失败降级到本地存储
return h.localStorage.UploadFile(file, filename, objectPath)
}
logger.Infof("文件上传到OSS成功: %s", fileURL)
return fileURL, nil
}
// 使用本地存储
fileURL, err := h.localStorage.UploadFile(file, filename, objectPath)
if err != nil {
return "", err
}
logger.Infof("文件上传到本地成功: %s", fileURL)
return fileURL, nil
}