提示:简单实现两个小功能,如有需要可以自行扩展
前言
如何使用Gin框架实现文件上传功能?这里我们使用地鼠文档的内容作为示例
这里我们将文件上传分为两类:
- 一类是单文件上传,实现此功能使用的是Context包下的
FormFile()
方法 - 另一类是多文件上传,实现此功能使用Context包下的
MultipartForm()
方法
一、单文件上传
单文件上传是指前端请求时给后端一次性发送一个文件,通过Gin框架的处理,我们可以将前端传给的文件保存到我们的工程目录中,其保存路径是可以自定义的
1.前端实现
这里我们使用示例代码,前端界面是一个最简易的上传。
这里不需要创建vue项目再单独启动了,创建一个html文件,使用浏览器打开本地文件即可
已经在表单中填写了提交方式为Post以及请求的路径为http://localhost:8080/upload
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
上传文件:<input type="file" name="file" >
<input type="submit" value="提交">
</form>
</body>
</html>
2.后端实现
后端的代码其实非常简单,我们来梳理一下逻辑
- 首先得创建Gin框架的基本路由,然后调用其POST方法进行传输文件
- Context包下的FormFile()方法需要传什么参数?返回什么东西?这里我们可以看到,需要传递一个string类型的name参数,这里的name需要和前端
<input>
标签中定义的name保持一致。返回一个FileHeader类型的结构体以及一个error - 我们看到返回的FileHeader中定义了什么?文件的名字,大小,协议头部信息等。我们这个案例中在页面显示下文件名
- 如果传输成功在界面上显示文件名称,如果传输失败返回错误信息,逻辑梳理结束
代码实现:
func main() {
r := gin.Default()
r.MaxMultipartMemory = 8 << 20 // 可以限制文件上传大小
r.POST("/upload", func(c *gin.Context) {
file, err := c.FormFile("file")// 这里的file需要和前端<input>标签中的file对应
if err != nil {
c.String(500, "上传文件出错")
}
c.SaveUploadedFile(file, "./gin/gin-singleFile/static/"+file.Filename)
c.String(http.StatusOK, file.Filename)
})
r.Run(":8080")
}
注意:
SaveUploadedFile()方法中需要传递得到的file文件以及定义保存路径
- 如果我们只填写
c.SaveUploadedFile(file, file.Filename)
,这个时候文件就会保存在工程文件根目录下,也就是和go.mod文件同级中,并且文件名就是file.Filename。这样其实默认是保存在./
下 - 如果我们需要保存在其他目录下,就可以根据实际情况调整,
./xxx/xxx/xxx
- 可以自己输入不同的文件目录,测试一下效果
效果测试:
浏览器上传文件
这时候选择文件上传即可,注意不要忘记运行后端
后端将文件保存在指定路径中
这时候就完成了单文件上传的功能
二、多文件上传
多文件上传也是相同的逻辑,只不过Gin框架处理的时候需要使用MultipartForm()
方法,前端上传多个文件让Gin框架处理,我们拿到的是一个文件map
该方法不需要传递任何参数,并且返回的是个Form结构体,这个Form中又有什么东西呢?原来是将File封装到了map中并且类型是FileHeader,那么这个FileHeader在上边我们已经介绍过了,定义的是文件相关的字段,这样将其封装到map中,可以传递多个file
1.前端实现
代码如下(示例):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">
上传文件:<input type="file" name="files" multiple>
<input type="submit" value="提交">
</form>
</body>
</html>
2.后端实现
代码实现
func main() {
r := gin.Default()
r.POST("/upload", func(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("err is %v", err.Error()))
}
files := form.File["files"]
for _, file := range files {
if err2 := c.SaveUploadedFile(file, "./gin/gin-multiFile/static/"+file.Filename); err2 != nil {
c.String(http.StatusBadRequest, fmt.Sprintf("upload err %v", err2.Error()))
return
}
}
c.String(200, fmt.Sprintf("upload is ok %d files", len(files)))
})
r.Run(":8080")
}
我们使用for range来遍历这个文件map,将文件一一取出并保存在指定文件目录下
注意:
- form.File(“files”)中的"files"需要和前端
<input>
标签中保持一致,这是前后端进行交互的一个重要名称 - 在上传完成后,对获得的文件map进行计算长度,这里使用的是len()进行长度计算,得到的是files中的文件个数
效果测试:
浏览器上传两个文件
提交后显示文件个数
后端文件保存在指定路径
此时多文件上传功能也已经实现
总结
Gin框架处理单文件和多文件上传有各自的方法,单文件上传使用的是Context包下的FormFile()
,多文件上传使用的是Context包下的MultipartForm()
,可以自行测试效果