init
This commit is contained in:
207
server/internal/handler/upload.go
Normal file
207
server/internal/handler/upload.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user