一文搞懂gin中各种上传文件方式
一、先封装一个根据年月日时间方式来创建目录
- 1、创建一个
utils
的文件夹并且创建folder.go
的文件package utils import ( "os" "path/filepath" "time" ) //定义一个创建文件目录的方法 func Mkdir(basePath string) string { // 1.获取当前时间,并且格式化时间 folderName := time.Now().Format("2006/01/02") folderPath := filepath.Join(basePath,folderName) //使用mkdirall会创建多层级目录 os.MkdirAll(folderPath, os.ModePerm) return folderPath } 复制代码
- 2、测试创建文件目录
- 3、测试结果
└── 2020 └── 11 └── 10 复制代码
二、使用form
表单上传单个文件
- 1、简单的使用
gin
中的模板创建一个文件{{define "chapter01/form_upload.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/" method="post" enctype="multipart/form-data"> <div> 用户名:<input type="text" name="name" /> </div> <div> <input type="file" name="file" /> </div> <div> <input type="submit" value="提交"/> </div> </form> </body> </html> {{end}} 复制代码
- 2、
gin
后端实现文件上传package main import ( "demo01/utils" "fmt" "github.com/gin-gonic/gin" "net/http" "path" "path/filepath" "strconv" "time" ) func main() { router := gin.Default() // 配置加载模板路径 router.LoadHTMLGlob("templates/**/*") // 渲染模板 router.GET("/", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "chapter01/form_upload.html", nil) }) router.POST("/", func(ctx *gin.Context) { //获取普通文本 name := ctx.PostForm("name") // 获取文件(注意这个地方的file要和html模板中的name一致) file, err := ctx.FormFile("file") if err != nil { fmt.Println("获取数据失败") ctx.JSON(http.StatusOK, gin.H{ "code": 1, "message": "获取数据失败", }) } else { fmt.Println("接收的数据", name, file.Filename) //获取文件名称 fmt.Println(file.Filename) //文件大小 fmt.Println(file.Size) //获取文件的后缀名 extstring := path.Ext(file.Filename) fmt.Println(extstring) //根据当前时间鹾生成一个新的文件名 fileNameInt := time.Now().Unix() fileNameStr := strconv.FormatInt(fileNameInt,10) //新的文件名 fileName := fileNameStr + extstring //保存上传文件 filePath := filepath.Join(utils.Mkdir("upload"), "/", fileName) ctx.SaveUploadedFile(file, filePath) ctx.JSON(http.StatusOK, gin.H{ "code": 0, "message": "success", }) } }) router.Run() } 复制代码
- 3、如果要对文件格式化及文件大小判断,可以进一步加判断。我这就省去了
三、使用表单上传多个文件
- 1、上传多个文件其实就是在
html
中加上multiple
属性(前提是后端支持){{define "chapter01/form_upload2.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/" method="post" enctype="multipart/form-data"> <input type="file" name="file" multiple/> <input type="submit" value="提交"/> </form> </body> </html> {{end}} 复制代码
- 2、后端代码
package main import ( "demo01/utils" "fmt" "github.com/gin-gonic/gin" "net/http" "path/filepath" "strconv" "time" ) func main() { router := gin.Default() router.LoadHTMLGlob("templates/**/*") router.GET("/", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "chapter01/form_upload2.html", nil) }) router.POST("/", func(ctx *gin.Context) { if form, err := ctx.MultipartForm(); err == nil { //1.获取文件 files := form.File["file"] //2.循环全部的文件 for _, file := range files { // 3.根据时间鹾生成文件名 fileNameInt := time.Now().Unix() fileNameStr := strconv.FormatInt(fileNameInt,10) //4.新的文件名(如果是同时上传多张图片的时候就会同名,因此这里使用时间鹾加文件名方式) fileName := fileNameStr + file.Filename //5.保存上传文件 filePath := filepath.Join(utils.Mkdir("upload"), "/", fileName) ctx.SaveUploadedFile(file, filePath) } ctx.JSON(http.StatusOK, gin.H{ "code": 0, "message": "上传成功", }) } else { ctx.JSON(http.StatusOK, gin.H{ "code": 0, "message": "获取数据失败", }) } }) router.Run() } 复制代码
四、使用ajax
上传文件
这里就演示上传多张图片及普通内容的方式
- 1、前端使用
ajax
上传文件{{define "chapter01/ajax_upload.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> </head> <body> <input type="text" id="username"> <input type="file" id="file" multiple> <button id="btn">提交</button> </body> <script> $(function () { $('#btn').on('click', function () { let formData = new FormData(); const fileList = $("#file")[0].files; const username = $('#username').val(); console.log(fileList) //上传文件的 for (const item of fileList) { formData.append("file", item); } // 普通值 formData.append("username", username) $.ajax({ type: 'post', url: '/', data:formData, contentType:false, processData:false, success: function (response) { console.log(response) } }) }) }) </script> </html> {{end}} 复制代码
- 2、后端的代码实现和之前表单上传的一样的
五、使用ajax
上传文件到阿里云oss
上
- 1、阿里oss文档地址
// 安装依赖包 go get github.com/aliyun/aliyun-oss-go-sdk/oss 复制代码
- 2、前端页面和上面的一样的
{{define "chapter01/ajax_upload1.html"}} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script> </head> <body> <input type="file" id="file"> <button id="btn">提交</button> </body> <script> $(function () { $('#btn').on('click', function () { let formData = new FormData(); const fileList = $("#file")[0].files; console.log(fileList) //上传文件的 for (const item of fileList) { formData.append("file", item); } $.ajax({ type: 'post', url: '/', data:formData, contentType:false, processData:false, success: function (response) { console.log(response) } }) }) }) </script> </html> {{end}} 复制代码
- 3、在
gin
中上传到阿里oss
中package main import ( "bytes" "demo01/utils" "fmt" "github.com/aliyun/aliyun-oss-go-sdk/oss" "github.com/gin-gonic/gin" "io/ioutil" "net/http" "os" "path" "path/filepath" "strconv" "time" ) func main() { router := gin.Default() router.LoadHTMLGlob("templates/**/*") router.GET("/", func(ctx *gin.Context) { ctx.HTML(http.StatusOK, "chapter01/ajax_upload1.html", nil) }) router.POST("/", func(ctx *gin.Context) { if file, err := ctx.FormFile("file"); err == nil { //获取文件的后缀名 extString := path.Ext(file.Filename) fmt.Println("111", extString) //允许上传文件的格式 allowExtMap := map[string]bool { ".jpg": true, ".png": true, ".gif": true, ".jpeg": true, } if _, ok := allowExtMap[extString]; !ok { ctx.JSON(http.StatusBadRequest, gin.H{ "code": 0, "message": "上传文件格式不支持", }) } // 根据时间鹾生成文件名 fileNameInt := time.Now().Unix() fileNameStr := strconv.FormatInt(fileNameInt, 10) fileName := fileNameStr + extString filePath := filepath.Join(utils.Mkdir("static/upload"), "/", fileName) fmt.Println("22",filePath) //client, err := oss.New("Endpoint", "yourAccessKeyId", "yourAccessKeySecret") client, err := oss.New("http://oss-cn-shenzhen.aliyuncs.com", "LTAI4Ff9jV7DfiPrJT36a", "zZOpRqGtKNQl30Su6Ytj12b3IEF") if err != nil { fmt.Println("阿里云上传错误", err) return } //指定存储空间 //bucket, err := client.Bucket("yourBucketName") bucket, err := client.Bucket("shuiping-code") if err != nil { fmt.Println("存储空间错误") os.Exit(-1) } //打开文件 fileHandle, err := file.Open() if err != nil { ctx.JSON(http.StatusOK, gin.H{ "code": 1, "message": "打开文件错误", }) return } defer fileHandle.Close() fileByte,_:= ioutil.ReadAll(fileHandle) //上传到oss上 err = bucket.PutObject(filePath, bytes.NewReader(fileByte)) if err != nil { fmt.Println(err) ctx.JSON(http.StatusOK, gin.H{ "code":0, "message": "解析错误", }) return } ctx.JSON(http.StatusOK, gin.H{ "code":0, "message": "上传成功", }) } else { ctx.JSON(http.StatusOK, gin.H{ "code":0, "message": "上传失败", }) } }) router.Run() } 复制代码
- 4、后端的代码有点多,全部写在一起,仅仅是方便新手学习查阅看的,如果你项目中使用可以将业务拆分到几个函数中
- 5、上面提供的
yourAccessKeyId
和yourAccessKeySecret
是无效的