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、上面提供的yourAccessKeyId
和yourAccessKeySecret
是无效的