【Gin】文件上传下载(单文件 + 多文件)

文件上传页面

🚀 一、单文件上传

核心逻辑

  1. 获取单个上传文件
  2. 校验文件是否存在
  3. 生成唯一文件名(纳秒时间戳)
  4. 保存文件到本地目录
  5. 返回标准化响应

Handler 代码

Go 复制代码
// SingleFileUpload 单文件上传
// 前端form表单key:file
func SingleFileUpload(c *gin.Context) {
	// 1. 获取单个文件
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "获取上传文件失败",
			"err":  err.Error(),
		})
		return
	}

	// 2. 生成唯一文件名,防止重名覆盖
	ext := filepath.Ext(file.Filename) // 获取文件后缀
	fileName := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
	savePath := "./upload/" + fileName // 保存路径

	// 3. 保存文件到服务器
	err = c.SaveUploadedFile(file, savePath)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "文件保存失败",
			"err":  err.Error(),
		})
		return
	}

	// 4. 返回成功结果
	c.JSON(http.StatusOK, gin.H{
		"code":     200,
		"msg":      "单文件上传成功",
		"file_name": fileName,
		"file_size": file.Size,
	})
}

文件信息保存数据库

Go 复制代码
	fileInfo := model.File{}
	fileInfo.Name = file.Filename
	fileInfo.Size = fmt.Sprintf("%.2f MB", float64(file.Size)/1024/1024)
	fileInfo.Type = strings.TrimLeft(ext, ".")
	fileInfo.Time = time.Now().Format(time.DateOnly)
	fileInfo.Url = filename
	err = service.SaveFile(fileInfo)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "文件信息保存失败",
		})
		return
	}

📂 二、多文件上传

核心逻辑

  1. 解析多文件表单
  2. 获取文件列表并校验
  3. 遍历文件批量保存
  4. 统计上传结果
  5. 返回完整响应数据

Handler 代码

Go 复制代码
// MultiFileUpload 多文件上传
// 前端form表单key:file(支持多选)
func MultiFileUpload(c *gin.Context) {
	// 1. 解析multipart表单
	form, err := c.MultipartForm()
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "解析上传表单失败",
			"err":  err.Error(),
		})
		return
	}

	// 2. 获取所有上传文件
	files := form.File["file"]
	if len(files) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": 400,
			"msg":  "未选择任何上传文件",
		})
		return
	}

	// 存储成功的文件名
	var successFiles []string

	// 3. 遍历保存所有文件
	for _, file := range files {
		ext := filepath.Ext(file.Filename)
		fileName := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext)
		savePath := "./upload/" + fileName

		// 保存单个文件
		if err := c.SaveUploadedFile(file, savePath); err == nil {
			successFiles = append(successFiles, fileName)
		}
	}

	// 4. 返回上传结果
	c.JSON(http.StatusOK, gin.H{
		"code":          200,
		"msg":           "多文件上传完成",
		"total_count":   len(files),       // 总文件数
		"success_count": len(successFiles), // 成功上传数
		"files":         successFiles,      // 成功文件名列表
	})
}

✅ 三、核心知识点总结

  1. 单文件c.FormFile("file") 获取文件 + c.SaveUploadedFile() 保存
  2. 多文件c.MultipartForm() 解析表单 + 遍历批量保存
  3. 唯一命名time.Now().UnixNano() 生成纳秒时间戳,彻底避免文件覆盖

四、文件下载

HTML关键代码

html 复制代码
<a href="/download/${file.url}" download >
    <i class="fas fa-download"></i>
</a>

Handler 代码

Go 复制代码
func GetDownloadFile(c *gin.Context) {
	url := c.Param("url")
	c.FileAttachment("C:/Users/87417/Desktop/2/"+url, url)
}
相关推荐
念何架构之路2 天前
Gin辅助模块与学习路径
学习·gin
念何架构之路3 天前
Gin内置中间件详解
中间件·gin
灯澜忆梦4 天前
【基于GO的Web开发15】gin路由和路由组
前端·后端·golang·gin
灯澜忆梦4 天前
【基于GO的Web开发14】gin请求重定向
前端·后端·golang·gin
远游客07135 天前
为什么用「年×100+月」做比较
算法·gin
灯澜忆梦5 天前
【基于GO的Web开发11】gin获取URL‑Path 路径参数
前端·后端·golang·html·gin
灯澜忆梦5 天前
【基于GO的Web开发10】gin获取HTML-Form表单提交参数
前端·后端·golang·html·gin
圣殿骑士-Khtangc6 天前
Gin优雅关停与平滑重启从零停机到热更新
golang·gin
念何架构之路6 天前
Gin响应渲染
前端·javascript·gin
灯澜忆梦7 天前
【基于GO的Web开发9】gin框架返回json
前端·后端·golang·gin