package handler import ( "fmt" "net/http" "os" "path/filepath" "strings" "time" "github.com/gin-gonic/gin" ) // ImageHandler 图片上传处理器 type ImageHandler struct { uploadDir string } // NewImageHandler 创建图片处理器 func NewImageHandler(uploadDir string) *ImageHandler { return &ImageHandler{uploadDir: uploadDir} } // Init 初始化上传目录 func (h *ImageHandler) Init() error { return os.MkdirAll(h.uploadDir, 0755) } // Upload 上传图片 func (h *ImageHandler) Upload(c *gin.Context) { file, err := c.FormFile("image") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "请选择图片文件"}) return } // 验证文件类型 ext := strings.ToLower(filepath.Ext(file.Filename)) allowedExts := map[string]bool{ ".jpg": true, ".jpeg": true, ".png": true, ".gif": true, ".webp": true, ".bmp": true, } if !allowedExts[ext] { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "不支持的图片格式,仅支持 jpg、png、gif、webp"}) return } // 验证文件大小 (最大 5MB) if file.Size > 5*1024*1024 { c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "图片大小不能超过 5MB"}) return } // 生成唯一文件名 filename := fmt.Sprintf("%d_%s%s", time.Now().UnixNano(), randomString(8), ext) filepath := filepath.Join(h.uploadDir, filename) // 保存文件 if err := c.SaveUploadedFile(file, filepath); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "message": "保存图片失败"}) return } // 返回访问 URL url := "/uploads/" + filename c.JSON(http.StatusOK, gin.H{ "code": 0, "message": "上传成功", "data": gin.H{ "url": url, }, }) } // randomString 生成随机字符串 func randomString(length int) string { const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" result := make([]byte, length) for i := range result { result[i] = chars[time.Now().UnixNano()%int64(len(chars))] time.Sleep(time.Nanosecond) } return string(result) }