Gin框架开发GoFly快速开发框架集成了本地、阿里云、腾讯云、七牛云文件存储方式,并留有继续拓展其他云存储能力,本文介绍多种文件存储使用和继续集成其他云存储方法指导
GoFly框架v3.01版本更新重点集成了多种文件存储方式,解决了之前单一存储插件切换不便的问题。新版本提供统一的API接口(UploadFile/DelFile),支持本地存储和阿里云、腾讯云等多种云存储,可通过后台配置灵活切换存储位置。框架还详细说明了如何扩展新的存储方式(如华为云),开发者只需按照规范创建对应实现类并进行配置即可。这一改进使文件管理更便捷,为业务开发节省了大量时间。
前言
基于gin-web框架开发GoFly快速开发框架v3.01版本已更新,本次更新最大亮点是把多种文件存储方式集成在框架中,放弃之前单一种方式做成独立插件安装,单个插件虽然有代码少的优点,但是在实际业务开发时,当切换其他存储位置时,之前存储位置文件无法访问,且代码结构相对零散。所以从实现业务需求出发,我们决定把多种存储方式集成在一起,统一代码结构,统一调用,后台统一管理,切换方便。
在软件开发中文件上传存储、访问文件是一个必不可少的功能,好用文件存储管理可让开发省去很多的时间,这也是GoFly框架本次更新重视文件文件存储管理的原因。
如下图GoFly后台的文件存储配置,开发时可以直接通过后台配置不同存储位置参数,点“文件存储方式”切换并提交“保存”即可完成不同文件存储位置变更。

在线体验地址:https://spl.goflys.cn/webbusiness/ ,账号:gofly 密码:gofly123
开发使用方法
框架把多种文件存储位置集成后,提供给业务开发统一调用函数,只需在后台选择存储位置和配置相关参数即可,代码部分就不用单独处理。
统一文件处理模块引入:
import (
"gofly/utils/extend/uploads"
)
1.统一上传文件函数
函数名:UploadFile
参数:c请求上下文,file上传文件流
返回:url是返回文件路径
//处理文件上传,bin返回地址
url, cover_url, err := uploads.New().UploadFile(c, file)
注意:如果在选择文件上传云服务器,但某个功能文件需要单独本地存储,则New()添加参数如下:
//处理文件上传,bin返回地址
url, cover_url, err := uploads.New("local").UploadFile(c, file)
if err != nil {
gf.Failed().SetMsg("上传文件失败").SetData(err).Regin(c)
return
}
其中New("local")参数local可以改为:alioss、tencentcos、qiniuoss等其他云存储名。
2.统一删除文件函数
函数名:DelFile
参数:url是删除文件路径,不包含域名的路径。
err:=uploads.DelFile(url)
3.示例代码
实际调用上传函数实例代码:
// 上传文件
func (api *Upfile) LocalFile(c *gf.GinCtx) {
//file文件流
file, err := c.FormFile("file")
if err != nil {
gf.Failed().SetMsg("获取数据失败").SetData(err).Regin(c)
return
}
//判断文件是否已经传过
fileContent, _ := file.Open()
defer fileContent.Close()
var byteContainer []byte = make([]byte, 1000000)
fileContent.Read(byteContainer)
m_d5 := md5.New()
m_d5.Write(byteContainer)
sha1_str := hex.EncodeToString(m_d5.Sum(nil))
//查找该用户是否传过
attachment, _ := gf.Model("business_attachment").Where("business_id", businessID).
Where("sha1", sha1_str).Fields("id,pid,name,title,type,url,filesize,mimetype,cover_url as cover").Find()
if attachment != nil { //文件是否已经存在
//更新到最前面
maxId, _ := gf.Model("business_attachment").Where("business_id", businessID).Order("weigh desc").Value("id")
if maxId != nil {
gf.Model("business_attachment").Data(map[string]interface{}{"weigh": maxId.Int() + 1, "pid": 1}).Where("id", attachment["id"]).Update()
}
gf.Success().SetMsg("文件已上传").SetData(attachment).Regin(c)
} else {
//这里处理文件上传 并返回地址, uploads.New().UploadFile就是把文件上传到配置设定位置
url, cover_url, err := uploads.New().UploadFile(c, file)
if err != nil {
gf.Failed().SetMsg("上传文件失败").SetData(err).Regin(c)
return
}
filename_arr := strings.Split(file.Filename, ".")
//文件类型
fileData := gf.Map{
"type": 0, //图片
"pid": 1, //存储在默认文件夹
"sha1": sha1_str,
"title": filename_arr[0],
"name": file.Filename,
"url": url, //附件路径
"cover_url": cover_url, //封面
"storage": "local",
"createtime": time.Now().Unix(),
"filesize": file.Size,
"mimetype": file.Header["Content-Type"][0],
}
//保存数据
file_id, _ := gf.Model("business_attachment").Data(fileData).InsertAndGetId()
//更新排序
gf.Model("business_attachment").Data(map[string]interface{}{"weigh": file_id}).Where("id", file_id).Update()
//处理预览url地址
gf.Success().SetMsg("文件上传成功").SetData(gf.GetFullUrl(url)).Regin(c)
}
}
如果某个功能需单独存储在指定位置,和系统设置的全局存储位置不同,比如把使用频率或者访问速度要求较低的,我们可以把他存储在本地,那么把uploads.New("local").UploadFile(c, file)的New函数中添加存储位置名,本地存储名为:local 则上传本地调用的代码如下:
//处理文件上传,并返回地址
url, cover_url, err := uploads.New("local").UploadFile(c, file)
if err != nil {
gf.Failed().SetMsg("上传文件失败").SetData(err).Regin(c)
return
}
4.框架封装好的上传文件接口
框架已经为各端客户端封装好了,可以直接调用上传文件接口,使用GoFly框架开发时没有特殊要求就不需要写上传文件接口代码,直接调用现成就实现上传。
4.1管理后后台(admin端)
接口:域名+admin/datacenter/upfile/upload
4.2管理后后台(business端)
接口:域名+business/datacenter/upfile/upload
4.3 非管理后台客户端(微信小程序、app、h5应用)
接口:域名+common/upload/upfile
继续扩展其他存储指导
如果框架已经集成的存储方式没有你需要的,可以参考现有的存储代码继续拓展。集成上传文件的代码位置在:utils\extend\uploads,在uploads目录下有个index.go是统一调用函数入口及配置存储代码。目录下的local.go为本地上传功能代码、aliOSS.go为阿里云存储功能代码、tencentCOS.go为腾讯云存储功能代码、qiniuOSS.go为七牛云存储功能代码,开发新的存储方式时可以参考他们。
下面介绍集成新的上传方式步骤,这里以华为云存储为例演示:
1.创建存储代码文件
在utils\extend\uploads创建一个名为:huaweiobs.go 代码框架如下:
package uploads
import (
"errors"
"fmt"
"gofly/utils/gf"
"mime/multipart"
"path"
"path/filepath"
"time"
obs "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs"
)
// 华为对象存储服务 OBS
type HuaweiObs struct {
Client *obs.Client//具体更加华为提供SKD为准
Ready bool
Config Config
Bucket *obs.Bucket//具体更加华为提供SKD为准
}
func (m *HuaweiObs ) InitClient(config Config) {
m.Ready = false
m.Config = config
client, err := oss.New(config.Endpoint, config.KeyId, config.Secret)
if err != nil {
return
}
m.Client = client
m.Bucket, err = client.Bucket(config.BucketName)
if err != nil {
return
}
m.Ready = true
}
// 上传文件
func (m *HuaweiObs ) UploadFile(c *gf.GinCtx, file *multipart.FileHeader) (url, cover_url string, err error) {
if !m.Ready {
err = errors.New("not ready")
return
}
fd, err := file.Open()
if err != nil {
return
}
defer fd.Close()
//注意:文件名称必须以alioss开头,MakeFileName函数就是生成以huaweiobs 开头的文件名称
path_name := fmt.Sprintf("%v/%v/%v", m.Config.DirPath, time.Now().Format("20060102"), MakeFileName(file, "huaweiobs"))
url = path_name
err = m.Bucket.PutObject(path_name, fd)
return
}
// 删除文件(单个)
func (m *HuaweiObs ) RemoveFile(fileUrl string) error {
if !m.Ready {
return errors.New("not ready")
}
return m.Bucket.DeleteObject(fileUrl)
}
// 下载文件
func (m *HuaweiObs ) DownloadFile(fileUrl string) error {
fileUrl, cloudFileUrl := InitFileUrl(fileUrl, m.Config)
if !m.Ready {
return errors.New("not ready")
}
// 检查对象是否存在
_, err := m.Bucket.GetObjectMeta(cloudFileUrl)
if err != nil {
return err
}
// 下载文件
return m.Bucket.GetObjectToFile(cloudFileUrl, fileUrl)
}
// 移动文件
func (m *HuaweiObs ) MoveFile(fileUrl string, targerDir string) (string, error) {
// 01. 拷贝
_, fileUrl = InitFileUrl(fileUrl, m.Config)
_, targerUrl = InitFileUrl(targerUrl, m.Config)
_, err := m.Bucket.CopyObject(fileUrl, targerUrl)
if err != nil {
return "", err
}
// 02. 删除
err = m.Bucket.DeleteObject(fileUrl)
if err != nil {
return "", err
}
return targerUrl, nil
}
2.在index.go引入华为云存储功能
写好上传、删除等相关接口后,需要把huaweiobs.go在统一调用index.go文件注册,具体如下
2.1在New初始配置函数中添加
func New(uptype ...string) StaticCloud {
var staticCloud StaticCloud
var upTypeStr string = ""
var config = Config{}
if len(uptype) > 0 && uptype[0] != "" {
upTypeStr = uptype[0]
} else {
confType, _ := gcfg.Instance("upload").Get(ctx, "Type")
upTypeStr = confType.String()
}
switch upTypeStr {
case "alioss":
alioss, _ := gcfg.Instance("upload").Get(ctx, "alioss")
mapConf := alioss.Map()
config = Config{
BaseUrl: gf.String(mapConf["ABaseUrl"]),
Endpoint: gf.String(mapConf["AEndpoint"]),
KeyId: gf.String(mapConf["AKeyId"]),
Secret: gf.String(mapConf["ASecret"]),
BucketName: gf.String(mapConf["ABucketName"]),
DirPath: gf.String(mapConf["ADirPath"]),
}
staticCloud = &AliOSS{}
case "tencentcos":
tencentcos, _ := gcfg.Instance("upload").Get(ctx, "tencentcos")
mapConf := tencentcos.Map()
config = Config{
BaseUrl: gf.String(mapConf["TBaseUrl"]),
Endpoint: gf.String(mapConf["TEndpoint"]),
KeyId: gf.String(mapConf["TKeyId"]),
Secret: gf.String(mapConf["TSecret"]),
BucketName: gf.String(mapConf["TBucketName"]),
Region: gf.String(mapConf["TRegion"]),
DirPath: gf.String(mapConf["TDirPath"]),
}
staticCloud = &TencentCOS{}
case "qiniuoss":
qiniuoss, _ := gcfg.Instance("upload").Get(ctx, "qiniuoss")
mapConf := qiniuoss.Map()
config = Config{
BaseUrl: gf.String(mapConf["QBaseUrl"]),
Endpoint: gf.String(mapConf["QEndpoint"]),
KeyId: gf.String(mapConf["QKeyId"]),
Secret: gf.String(mapConf["QSecret"]),
BucketName: gf.String(mapConf["QBucketName"]),
DirPath: gf.String(mapConf["QDirPath"]),
UseHTTPS: gf.Bool(mapConf["QUseHTTPS"]),
Zone: gf.Int(mapConf["QZone"]),
}
staticCloud = &QiniuOSS{}
case "huaweiobs":
huaweiobs, _ := gcfg.Instance("upload").Get(ctx, "huaweiobs")
mapConf := huaweiobs.Map()
config = Config{
BaseUrl: gf.String(mapConf["HBaseUrl"]),
Endpoint: gf.String(mapConf["HEndpoint"]),
KeyId: gf.String(mapConf["HKeyId"]),
Secret: gf.String(mapConf["HSecret"]),
BucketName: gf.String(mapConf["HBucketName"]),
DirPath: gf.String(mapConf["HDirPath"]),
}
staticCloud = &HuaweiObs{}
default:
local, _ := gcfg.Instance("upload").Get(ctx, "local")
mapConf := local.Map()
config = Config{
BaseUrl: gf.String(mapConf["LBaseUrl"]),
DirPath: gf.String(mapConf["LDirPath"]),
}
staticCloud = &Local{}
}
staticCloud.InitClient(config)
return staticCloud
}
2.2配置统一删除
// 删除附件统一入口,结果返回:bool
func DelFile(fileUrl string) error {
//处理地址
filseName := gfile.Name(fileUrl)
uptype := ""
if strings.HasPrefix(filseName, "local") { //本地存储
uptype = "local"
} else if strings.HasPrefix(filseName, "alioss") { //阿里云
uptype = "alioss"
} else if strings.HasPrefix(filseName, "tencentcos") { //腾讯云
uptype = "tencentcos"
} else if strings.HasPrefix(filseName, "qiniuoss") { //七牛云
uptype = "qiniuoss"
}else if strings.HasPrefix(filseName, "huaweiobs") { //华为云
uptype = "huaweiobs"
} else { //默认返回设置上传方式的地址
UpType, _ := gcfg.Instance("upload").Get(ctx, "Type")
uptype = UpType.String()
}
return New(uptype).RemoveFile(fileUrl)
}
3.添加配置文件
在后端资源目录:resource\config\upload.yaml添加华为云存储配置参数:
# 存储方式
Type: local
# 配置传输文件最大值,如上传文件最大上限,单位为MB
MaxBodySize: 600
# 允许上传的文件类型
AllowedExt: .jpg,.jpeg,.png,.pdf,.ico
# 本地存储配置
local:
LBaseUrl: http://localhost:8200
LDirPath: /resource/uploads/
# 阿里云静态云存储配置
alioss:
ABaseUrl: https://hcoder.oss-cn-beijing.aliyuncs.com/
AEndpoint: oss-cn-beijing.aliyuncs.com
AKeyId:
ASecret:
ABucketName:
ADirPath:
# 腾讯云静态云存储配置
tencentcos:
TBaseUrl: https://gofly-1257246782.cos.ap-nanjing.myqcloud.com
TEndpoint:
TKeyId: AKIDGUYaP1TmtpY4NSJxlWK0eAbzEKEvRkw0
TSecret:
TBucketName: gofly-1257246782
TRegion: ap-nanjing
TDirPath: /goflys
# 七牛云存储配置
qiniuoss:
QBaseUrl: http://t3wcppubp.hn-bkt.clouddn.com/
QEndpoint:
QKeyId: dtxSwoGm1hwkn5FvhEI8QBvIKxn08_5iYypjC4u8
QSecret:
QBucketName: goflys
QDirPath: image
QDestBucketName: <nil>
QUseHTTPS: false
QZone: 4
# 华为云存储配置(具体参数根据华为云调整)
huaweiobs:
HBaseUrl: https://obs.cn-north-4.myhuaweicloud.com
HEndpoint: obs.cn-north-4.myhuaweicloud.com
HKeyId:
HSecret:
HBucketName:
HDirPath:
4.把新增存储方式添加管理后台
后端添加好后,需要把新增加存储方式添加到管理后台,方便配置和管理。在管理后台前端代码位置:src\views\datacenter\configuration\components\UploadConfig.vue添加代码:
在js代码中handleChangeType函数条件华为云的数据配置,代码如下
//切换上传方式
const handleChangeType=(value:any)=>{
if(value=="local"){
formData.value=Object.assign({},formData.value,{BaseUrl:baseData.local.LBaseUrl,DirPath:baseData.local.LDirPath})
}else if(value=="tencentcos"){
formData.value=Object.assign({},formData.value,{BaseUrl:baseData.tencentcos.TBaseUrl,Endpoint:baseData.tencentcos.TEndpoint,
KeyId:baseData.tencentcos.TKeyId,Secret:baseData.tencentcos.TSecret,BucketName:baseData.tencentcos.TBucketName,
Region:baseData.tencentcos.TRegion,DirPath:baseData.tencentcos.TDirPath})
}else if(value=="alioss"){
formData.value=Object.assign({},formData.value,{BaseUrl:baseData.alioss.ABaseUrl,Endpoint:baseData.alioss.AEndpoint,
KeyId:baseData.alioss.AKeyId,Secret:baseData.alioss.ASecret,BucketName:baseData.alioss.ABucketName,
DirPath:baseData.alioss.ADirPath})
}else if(value=="qiniuoss"){
formData.value=Object.assign({},formData.value,{BaseUrl:baseData.qiniuoss.QBaseUrl,Endpoint:baseData.qiniuoss.QEndpoint,
KeyId:baseData.qiniuoss.QKeyId,Secret:baseData.qiniuoss.QSecret,BucketName:baseData.qiniuoss.QBucketName,
DestBucketName:baseData.qiniuoss.QDestBucketName,UseHTTPS:baseData.qiniuoss.QUseHTTPS,Zone:baseData.qiniuoss.QZone,
DirPath:baseData.qiniuoss.QDirPath})
}else if(value=="huaweiobs"){//新增的华为云
formData.value=Object.assign({},formData.value,{BaseUrl:baseData.huaweiobs.HBaseUrl,Endpoint:baseData.huaweiobs.HEndpoint,
KeyId:baseData.huaweiobs.HKeyId,Secret:baseData.huaweiobs.ASecret,BucketName:baseData.huaweiobs.HBucketName,
DirPath:baseData.huaweiobs.HDirPath})
}
console.log(formData.value)
}
到此我们就把扩展新存储介绍完了,大家可以通过本文介绍了解,Gin集成的GoFly框架文件存储使用和继续扩展新存储方式的方法。
更多推荐
所有评论(0)