Files
2025-11-17 13:32:54 +08:00

207 lines
5.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}