一文搞懂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"}}
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    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"}}
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    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"}}
    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
        <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、上面提供的yourAccessKeyIdyourAccessKeySecret是无效的

你可能感兴趣的:(go,golang)