Gin框架实现多文件上传

959 阅读3分钟

Gin是一款轻量级的Web框架,它基于Golang语言,提供高效的路由处理和中间件,使得构建Web应用程序更加容易。

在这篇文章中,我们将使用Gin框架来实现文件上传功能,具体步骤如下:

1. 创建项目

我们首先需要创建一个Gin项目,可以使用如下命令:

go mod init example.com/uploads
go get -u github.com/gin-gonic/gin

然后在项目根目录下,创建一个main.go文件,用于编写Gin的路由处理和中间件。

2. 编写路由处理

Gin框架的路由处理非常简单,我们可以通过以下代码实现文件上传的路由:

func main() {
    r := gin.Default()

    r.POST("/uploads", func(c *gin.Context) {
        // TODO: 实现文件上传代码
    })

    r.Run() // listen and serve on 0.0.0.0:8080
}

该代码创建了一个POST方法的/uploads路由,我们需要在其中实现文件上传逻辑。

3. 实现文件上传逻辑

我们可以通过Gin的Context对象获取上传的文件,实现文件上传如下:

func main() {
    r := gin.Default()

    r.POST("/uploads", func(c *gin.Context) {
        // 解析请求体
        form, err := c.MultipartForm()
        if err != nil {
           c.String(http.StatusBadRequest, fmt.Sprintf("解析请求体失败: %s", err.Error()))
           return
        }
        // 处理文件
        files := form.File["files"]
        for _, file := range files {
           err = c.SaveUploadedFile(file, "<你的文件存储路径>")
           if err != nil {
              c.String(http.StatusBadRequest, fmt.Sprintf("上传文件失败: %s", err.Error()))
              return
           }
        }
    })

    r.Run() // listen and serve on 0.0.0.0:8080
}

在这里,我们使用了form.File方法来获取上传的文件。然后,我们对每个文件调用SaveUploadedFile()方法来保存它。这个方法包括两个参数:文件和路径。一旦文件保存成功,我们就可以返回一个成功信息。

可以发现, 这种方法是不够优雅的, 我们可以参考Gin框架文件上传里面的写法

  1. 定义一个MyFiles结构体
// "mime/multipart" 使用的包
type MyFiles struct {
   Files []*multipart.FileHeader `form:"files" binding:"required"`
}
  1. 增加BindFiles方法
func BindFiles(c *gin.Context, obj *MyFiles) error {
   if err := c.ShouldBind(obj); err != nil {
      return err
   }

   // 文件校验逻辑, 例如文件大小, 文件类型等
   // ...

   return nil
}
  1. 修改/uploads路由函数
// 多文件上传
r.POST("/uploads", func(c *gin.Context) {
   var myFiles MyFiles
   if err := BindFiles(c, &myFiles); err != nil {
      c.JSON(500, gin.H{
         "message": err.Error(),
      })
      return
   }
   c.JSON(200, gin.H{
      "message": "ok",
   })

   // 保存文件
   for _, file := range myFiles.Files {
      c.SaveUploadedFile(file, file.Filename)
   }
})

这种方式把获取参数的逻辑从路由函数中抽离出来, 使得程序解偶, 同时我们可以在BindFiles中增加文件校验的逻辑, 是的我们程序更加健壮, 提高服务的可用性

完整代码

package main

import (
   "github.com/gin-gonic/gin"
   "mime/multipart"
)

type MyFiles struct {
   Files []*multipart.FileHeader `form:"files" binding:"required"`
}

func BindFiles(c *gin.Context, obj *MyFiles) error {
   if err := c.ShouldBind(obj); err != nil {
      return err
   }

   // 文件校验逻辑, 例如文件大小, 文件类型等
   // ...

   return nil
}

func main() {
   r := gin.Default()
   r.GET("/ping", func(c *gin.Context) {
      c.JSON(200, gin.H{
         "message": "pong",
      })
   })

   // 多文件上传
   r.POST("/uploads", func(c *gin.Context) {
      var myFiles MyFiles
      if err := BindFiles(c, &myFiles); err != nil {
         c.JSON(500, gin.H{
            "message": err.Error(),
         })
         return
      }
      c.JSON(200, gin.H{
         "message": "ok",
      })

      // 保存文件
      for _, file := range myFiles.Files {
         c.SaveUploadedFile(file, file.Filename)
      }
   })

   r.Run() // listen and serve on
}

写在后面

这篇文章介绍了如何使用Gin框架来实现多文件上传。我们使用MultipartForm()方法来解析请求体,使用SaveUploadedFile()方法来保存上传的文件。除此之外, 我们还可以通过ShouldBind方式来自定绑定参数, 减少了我们自己去完成参数的绑定的逻辑, 代码的可读性也更高了.