首先下载腾讯云cos sdk:
go get -u github.com/tencentyun/cos-go-sdk-v5
所需要的包:
import (
"context"
"project/app/global/my_errors" // 错误处理 可自行配置
"project/app/global/variable" // 公共变量 可自行配置
"project/app/utils/md5_encrypt" // md5加密 可自行配置
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/tencentyun/cos-go-sdk-v5"
"mime/multipart"
"net/http"
"net/url"
"path"
"time"
)
配置使用cos保存文件:
// 保存文件
func saveUploadedFile(file *multipart.FileHeader, newSavePath string) (r bool, saveFilePath string) {
//COS客户端连接
cosUrl, _ := url.Parse(variable.ConfigYml.GetString("TencentCos.CosUrl"))
secretId := variable.ConfigYml.GetString("TencentCos.SecretID")
secretKey := variable.ConfigYml.GetString("TencentCos.SecretKey")
b := &cos.BaseURL{BucketURL: cosUrl}
client := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: secretId,
SecretKey: secretKey,
},
})
// 保存文件,原始文件名进行全局唯一编码加密、md5 加密,保证在后台存储不重复
var saveErr error
if sequence := variable.SnowFlake.GetId(); sequence > 0 {
saveFileName := fmt.Sprintf("%d%s", sequence, file.Filename)
saveFileName = md5_encrypt.MD5(saveFileName) + path.Ext(saveFileName)
saveFilePath := newSavePath + saveFileName
// 3.通过文件流上传对象
fd, err := file.Open()
if err != nil {
return false, ""
}
defer fd.Close()
_, saveErr = client.Object.Put(context.Background(), saveFilePath, fd, nil)
if saveErr == nil {
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
return true, saveFilePath
}
} else {
saveErr = errors.New(my_errors.ErrorsSnowflakeGetIdFail)
variable.ZapLog.Error("文件保存出错:" + saveErr.Error())
}
return false, ""
}
文件上传可以设置按照 [savePathPre]/xxx年/xx月/xxx.jpg 格式存储为对象键(Key):
func generateYearMonthPath(savePathPre string) string {
curYearMonth := time.Now().Format("2006/01")
newSavePathPre := savePathPre + curYearMonth
return newSavePathPre + "/"
}
开始上传:
//上传多文件
ctx.MultipartForm
//上传单文件
ctx.FormFile(“file”) //file 是文件名
单文件上传:
// 单文件上传
func Upload(ctx *gin.Context, savePath string) (r bool, finnalSavePath interface{}) {
// 对象键(Key)是对象在存储桶中的唯一标识。
newSavePath := generateYearMonthPath(savePath)
// 1.获取上传的文件名(参数验证器已经验证完成了第一步错误,这里简化)
file, _ := ctx.FormFile(variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")) // file 是一个文件结构体(文件对象)
if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
finnalSavePath = gin.H{
"path": saveFilePath,
}
return true, finnalSavePath
}
return false, nil
}
多文件上传:
// 多文件上传
func MultUpload(ctx *gin.Context, savePath string) (r bool, multFinnalSavePath interface{}) {
// 对象键(Key)是对象在存储桶中的唯一标识。
newSavePath := generateYearMonthPath(savePath)
//获取到所有的文件
form, _ := ctx.MultipartForm()
//获取到所有的文件数组
files := form.File[variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")]
var saveFilePaths []string
//遍历数组进行处理
for _, file := range files {
//进行文件保存
if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {
saveFilePaths = append(saveFilePaths, saveFilePath)
}
}
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
multFinnalSavePath = gin.H{
"paths": saveFilePaths,
}
return true, multFinnalSavePath
}
创建一个Upload控制器:
// 开始上传动态Picture 目录+年份+月份
func (u *CosUpload) StartUploadPic(context *gin.Context) {
savePath := variable.ConfigYml.GetString("FileUploadSetting.CosPictureSavePath")
if r, finnalSavePath := upload_cos.MultUpload(context, savePath); r == true {
response.Success(context, consts.CurdStatusOkMsg, finnalSavePath)
} else {
response.Fail(context, consts.FilesUploadFailCode, consts.FilesUploadFailMsg, "")
}
}
接口示例:
service/upload_cos/upload_cos.go 完整代码:
package upload_cos
import (
"context"
"project/app/global/my_errors"
"project/app/global/variable"
"project/app/utils/md5_encrypt"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/tencentyun/cos-go-sdk-v5"
"mime/multipart"
"net/http"
"net/url"
"path"
"time"
)
// 单文件上传
func Upload(ctx *gin.Context, savePath string) (r bool, finnalSavePath interface{}) {
// 对象键(Key)是对象在存储桶中的唯一标识。
newSavePath := generateYearMonthPath(savePath)
// 1.获取上传的文件名(参数验证器已经验证完成了第一步错误,这里简化)
file, _ := ctx.FormFile(variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")) // file 是一个文件结构体(文件对象)
if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
finnalSavePath = gin.H{
"path": saveFilePath,
}
return true, finnalSavePath
}
return false, nil
}
// 多文件上传
func MultUpload(ctx *gin.Context, savePath string) (r bool, multFinnalSavePath interface{}) {
// 对象键(Key)是对象在存储桶中的唯一标识。
newSavePath := generateYearMonthPath(savePath)
//获取到所有的文件
form, _ := ctx.MultipartForm()
//获取到所有的文件数组
files := form.File[variable.ConfigYml.GetString("FileUploadSetting.UploadFileField")]
var saveFilePaths []string
//遍历数组进行处理
for _, file := range files {
//进行文件保存
if r, saveFilePath := saveUploadedFile(file, newSavePath); r == true {
saveFilePaths = append(saveFilePaths, saveFilePath)
}
}
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
multFinnalSavePath = gin.H{
"paths": saveFilePaths,
}
return true, multFinnalSavePath
}
// 保存文件
func saveUploadedFile(file *multipart.FileHeader, newSavePath string) (r bool, saveFilePath string) {
//COS客户端连接
cosUrl, _ := url.Parse(variable.ConfigYml.GetString("TencentCos.CosUrl"))
secretId := variable.ConfigYml.GetString("TencentCos.SecretID")
secretKey := variable.ConfigYml.GetString("TencentCos.SecretKey")
b := &cos.BaseURL{BucketURL: cosUrl}
client := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: secretId,
SecretKey: secretKey,
},
})
// 保存文件,原始文件名进行全局唯一编码加密、md5 加密,保证在后台存储不重复
var saveErr error
if sequence := variable.SnowFlake.GetId(); sequence > 0 {
saveFileName := fmt.Sprintf("%d%s", sequence, file.Filename)
saveFileName = md5_encrypt.MD5(saveFileName) + path.Ext(saveFileName)
saveFilePath := newSavePath + saveFileName
// 3.通过文件流上传对象
fd, err := file.Open()
if err != nil {
return false, ""
}
defer fd.Close()
_, saveErr = client.Object.Put(context.Background(), saveFilePath, fd, nil)
if saveErr == nil {
// 上传成功,返回资源的相对路径,这里请根据实际返回绝对路径或者相对路径
return true, saveFilePath
}
} else {
saveErr = errors.New(my_errors.ErrorsSnowflakeGetIdFail)
variable.ZapLog.Error("文件保存出错:" + saveErr.Error())
}
return false, ""
}
// 文件上传可以设置按照 xxx年/xx月 格式存储 对象键(Key)
func generateYearMonthPath(savePathPre string) string {
curYearMonth := time.Now().Format("2006/01")
newSavePathPre := savePathPre + curYearMonth
return newSavePathPre + "/"
}