From 46f1b488a5738a2246303e794ea803af931af894 Mon Sep 17 00:00:00 2001 From: wilgx0 <396861557@qq.com> Date: Wed, 18 May 2022 14:30:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/common/upload.go | 38 +++ go.mod | 1 + go.sum | 15 ++ internal/app/common/consts/upload.go | 19 ++ internal/app/common/controller/upload.go | 87 ++++++ internal/app/common/router/router.go | 7 + internal/app/common/service/sys_config.go | 35 +++ internal/app/common/service/upload.go | 306 ++++++++++++++++++++++ library/libUtils/utils.go | 47 ++++ manifest/config/config.yaml.bak | 9 +- 10 files changed, 563 insertions(+), 1 deletion(-) create mode 100644 api/v1/common/upload.go create mode 100644 internal/app/common/consts/upload.go create mode 100644 internal/app/common/controller/upload.go create mode 100644 internal/app/common/service/upload.go diff --git a/api/v1/common/upload.go b/api/v1/common/upload.go new file mode 100644 index 0000000..9925364 --- /dev/null +++ b/api/v1/common/upload.go @@ -0,0 +1,38 @@ +package common + +import "github.com/gogf/gf/v2/frame/g" + +// 单图上传 +type UploadSingleImgReq struct { + g.Meta `path:"/singleImg" tags:"上传图片" method:"post" summary:"上传图片"` +} + +// 单文件上传 +type UploadSingleFileReq struct { + g.Meta `path:"/singleFile" tags:"上传文件" method:"post" summary:"上传文件"` +} + +type UploadSingleRes struct { + g.Meta `mime:"application/json"` + UploadResponse +} + +// 多图上传 +type UploadMultipleImgReq struct { + g.Meta `path:"/multipleImg" tags:"上传多图片" method:"post" summary:"上传多图片"` +} + +// 多文件上传 +type UploadMultipleFileReq struct { + g.Meta `path:"/multipleFile" tags:"上传多文件" method:"post" summary:"上传多文件"` +} + +type UploadMultipleRes []*UploadResponse + +type UploadResponse struct { + Size int64 `json:"size"` + Path string `json:"path"` + FullPath string `json:"full_path"` + Name string `json:"name"` + Type string `json:"type"` +} diff --git a/go.mod b/go.mod index 59928e0..00543ab 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/mojocn/base64Captcha v1.3.5 github.com/mssola/user_agent v0.5.3 github.com/shirou/gopsutil v3.21.11+incompatible + github.com/tencentyun/cos-go-sdk-v5 v0.7.34 // indirect github.com/tiger1103/gfast-cache v0.0.7 github.com/tiger1103/gfast-token v0.1.0 github.com/tklauser/go-sysconf v0.3.10 // indirect diff --git a/go.sum b/go.sum index b71e17f..69d06a1 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/casbin/casbin/v2 v2.42.0 h1:EA0aE5PZnFSYY6WulzTScOo4YO6xrGAAZkXRLs8p2ME= github.com/casbin/casbin/v2 v2.42.0/go.mod h1:sEL80qBYTbd+BPeL4iyvwYzFT3qwLaESq5aFKVLbLfA= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -10,6 +11,8 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -65,7 +68,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -83,8 +89,12 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0= github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mssola/user_agent v0.5.3 h1:lBRPML9mdFuIZgI2cmlQ+atbpJdLdeVl2IDodjBR578= github.com/mssola/user_agent v0.5.3/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -110,10 +120,15 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= +github.com/tencentyun/cos-go-sdk-v5 v0.7.34 h1:xm+Pg+6m486y4eugRI7/E4WasbVmpY1hp9QBSRErgp8= +github.com/tencentyun/cos-go-sdk-v5 v0.7.34/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= github.com/tiger1103/gfast-cache v0.0.7 h1:YRuSFxFdvNlIsHAndS7XjYRLd4tmXGWhvHt9rK0LVT0= github.com/tiger1103/gfast-cache v0.0.7/go.mod h1:s6cRWyr87wz6IJNGKRV6Ahq9hcuVz8h2PAtGrO66JO8= github.com/tiger1103/gfast-token v0.1.0 h1:C41f0lZ5nLizHtgfRNvE3nf7hVQ+IO0dCCgg3a9/Oa4= diff --git a/internal/app/common/consts/upload.go b/internal/app/common/consts/upload.go new file mode 100644 index 0000000..af4f580 --- /dev/null +++ b/internal/app/common/consts/upload.go @@ -0,0 +1,19 @@ +package consts + +const ( + UploadPath = "upload_file" + ImgTypeKey = "sys.uploadFile.imageType" + ImgSizeKey = "sys.uploadFile.imageSize" + FileTypeKey = "sys.uploadFile.fileType" + FileSizeKey = "sys.uploadFile.fileSize" + CheckFileTypeImg = "img" // 文件类型(图片) + CheckFileTypeFile = "file" // 文件类型(任意) +) + +const ( + SourceLocal = iota // 上传到本地 + SourceTencent // 上传至腾讯云 + SourceAli // 上传到阿里云 + SourceQiniu // 上传到七牛云 + //................... +) diff --git a/internal/app/common/controller/upload.go b/internal/app/common/controller/upload.go new file mode 100644 index 0000000..a897c27 --- /dev/null +++ b/internal/app/common/controller/upload.go @@ -0,0 +1,87 @@ +package controller + +import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/tiger1103/gfast/v3/api/v1/common" + "github.com/tiger1103/gfast/v3/internal/app/common/consts" + "github.com/tiger1103/gfast/v3/internal/app/common/service" +) + +var Upload = new(uploadController) + +type uploadController struct{} + +// 上传单图 +func (c *uploadController) SingleImg(ctx context.Context, req *common.UploadSingleImgReq) (res *common.UploadSingleRes, err error) { + r := g.RequestFromCtx(ctx) + file := r.GetUploadFile("file") + if file == nil { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeImg, v.Int()) + if err != nil { + return + } + res = &common.UploadSingleRes{ + UploadResponse: response, + } + // 上传第三方 + return +} + +// 上传多图 +func (c *uploadController) MultipleImg(ctx context.Context, req *common.UploadMultipleImgReq) (res *common.UploadMultipleRes, err error) { + r := g.RequestFromCtx(ctx) + files := r.GetUploadFiles("file") + if len(files) == 0 { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeImg, v.Int()) + if err != nil { + return + } + res = &mf + return +} + +// 上传单文件 +func (c *uploadController) SingleFile(ctx context.Context, req *common.UploadSingleFileReq) (res *common.UploadSingleRes, err error) { + r := g.RequestFromCtx(ctx) + file := r.GetUploadFile("file") + if file == nil { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeFile, v.Int()) + if err != nil { + return + } + res = &common.UploadSingleRes{ + UploadResponse: response, + } + return +} + +// 上传多文件 +func (c *uploadController) MultipleFile(ctx context.Context, req *common.UploadMultipleFileReq) (res *common.UploadMultipleRes, err error) { + r := g.RequestFromCtx(ctx) + files := r.GetUploadFiles("file") + if len(files) == 0 { + err = gerror.New("上传文件必须") + return + } + v, _ := g.Cfg().Get(ctx, "upload.default") + mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeFile, v.Int()) + if err != nil { + return + } + res = &mf + return +} diff --git a/internal/app/common/router/router.go b/internal/app/common/router/router.go index 8f07559..ea5ce56 100644 --- a/internal/app/common/router/router.go +++ b/internal/app/common/router/router.go @@ -21,5 +21,12 @@ func BindController(group *ghttp.RouterGroup) { controller.Captcha, ) }) + + // 文件上传 + group.Group("/upload", func(group *ghttp.RouterGroup) { + group.Bind( + controller.Upload, + ) + }) }) } diff --git a/internal/app/common/service/sys_config.go b/internal/app/common/service/sys_config.go index 057f161..10cc59b 100644 --- a/internal/app/common/service/sys_config.go +++ b/internal/app/common/service/sys_config.go @@ -10,6 +10,7 @@ package service import ( "context" "errors" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" "github.com/tiger1103/gfast/v3/api/v1/system" @@ -27,6 +28,8 @@ type IConfig interface { Get(ctx context.Context, id int) (res *system.ConfigGetRes, err error) Edit(ctx context.Context, req *system.ConfigEditReq, userId uint64) (err error) Delete(ctx context.Context, ids []int) (err error) + GetConfigByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) + GetByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) } type configTmpl struct { @@ -148,3 +151,35 @@ func (s *configTmpl) Delete(ctx context.Context, ids []int) (err error) { }) return } + +// GetConfigByKey 通过key获取参数(从缓存获取) +func (s *configTmpl) GetConfigByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) { + if key == "" { + err = gerror.New("参数key不能为空") + return + } + cache := Cache() + cf := cache.Get(ctx, consts.CacheSysConfigTag+key) + if cf != nil && !cf.IsEmpty() { + err = gconv.Struct(cf, &config) + return + } + config, err = s.GetByKey(ctx, key) + if err != nil { + return + } + if config != nil { + cache.Set(ctx, consts.CacheSysConfigTag+key, config, 0, consts.CacheSysConfigTag) + } + return +} + +// GetByKey 通过key获取参数(从数据库获取) +func (s *configTmpl) GetByKey(ctx context.Context, key string) (config *entity.SysConfig, err error) { + err = dao.SysConfig.Ctx(ctx).Where("config_key", key).Scan(&config) + if err != nil { + g.Log().Error(ctx, err) + err = gerror.New("获取配置失败") + } + return +} diff --git a/internal/app/common/service/upload.go b/internal/app/common/service/upload.go new file mode 100644 index 0000000..7e710bc --- /dev/null +++ b/internal/app/common/service/upload.go @@ -0,0 +1,306 @@ +package service + +import ( + "context" + "errors" + "fmt" + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/net/ghttp" + "github.com/gogf/gf/v2/os/gfile" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/text/gregex" + "github.com/gogf/gf/v2/text/gstr" + "github.com/gogf/gf/v2/util/gconv" + "github.com/gogf/gf/v2/util/grand" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" + "github.com/tiger1103/gfast/v3/api/v1/common" + "github.com/tiger1103/gfast/v3/internal/app/common/consts" + "github.com/tiger1103/gfast/v3/internal/app/common/model/entity" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + +type IUpload interface { + UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result common.UploadResponse, err error) + UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result common.UploadMultipleRes, err error) +} + +type uploadTmpl struct{} + +func Upload() IUpload { + return &uploadTmpl{} +} + +// 上传多文件 +func (s *uploadTmpl) UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result common.UploadMultipleRes, err error) { + for _, item := range files { + f, e := s.UploadFile(ctx, item, checkFileType, source) + if e != nil { + return + } + result = append(result, &f) + } + return +} + +// 上传单文件 +func (s *uploadTmpl) UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result common.UploadResponse, err error) { + + // 检查文件类型 + err = s.CheckType(ctx, checkFileType, file) + if err != nil { + return + } + + // 检查文件大小 + err = s.CheckSize(ctx, checkFileType, file) + if err != nil { + return + } + + // 非图片文件只能上传至本地 + if checkFileType == consts.CheckFileTypeFile { + source = consts.SourceLocal + } + + switch source { + // 上传至本地 + case consts.SourceLocal: + result, err = s.UploadLocal(ctx, file) + // 上传至腾讯云 + case consts.SourceTencent: + result, err = s.UploadTencent(ctx, file) + default: + err = errors.New("source参数错误!") + } + + if err != nil { + return + } + return +} + +// 上传至腾讯云 +func (s *uploadTmpl) UploadTencent(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) { + v, err := g.Cfg().Get(ctx, "upload.tencentCOS") + if err != nil { + return + } + m := v.MapStrVar() + var ( + upPath = m["upPath"].String() + rawUrl = m["rawUrl"].String() + secretID = m["secretID"].String() + secretKey = m["secretKey"].String() + ) + name := gfile.Basename(file.Filename) + name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6)) + name = name + gfile.Ext(file.Filename) + + path := upPath + name + + url, _ := url.Parse(rawUrl) + b := &cos.BaseURL{BucketURL: url} + client := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: secretID, + SecretKey: secretKey, + Transport: &debug.DebugRequestTransport{ + RequestHeader: false, + RequestBody: false, + ResponseHeader: false, + ResponseBody: false, + }, + }, + }) + opt := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentLength: int64(file.Size), + }, + } + var f io.ReadCloser + f, err = file.Open() + if err != nil { + return + } + defer f.Close() + _, err = client.Object.Put(context.Background(), path, f, opt) + result = common.UploadResponse{ + Size: file.Size, + Path: rawUrl + path, + FullPath: rawUrl + path, + Name: file.Filename, + Type: file.Header.Get("Content-type"), + } + return +} + +// 上传本地 +func (s *uploadTmpl) UploadLocal(ctx context.Context, file *ghttp.UploadFile) (result common.UploadResponse, err error) { + if file == nil { + err = errors.New("文件必须!") + return + } + r := g.RequestFromCtx(ctx) + urlPerfix := fmt.Sprintf("http://%s/", r.Host) + p := strings.Trim(consts.UploadPath, "/") + sp := s.getStaticPath(ctx) + if sp != "" { + sp = strings.Trim(sp, "/") + } + nowData := time.Now().Format("2006-01-02") + // 包含静态文件夹的路径 + fullDirPath := sp + "/" + p + "/" + nowData + fileName, err := file.Save(fullDirPath, true) + if err != nil { + return + } + // 不含静态文件夹的路径 + fullPath := p + "/" + nowData + "/" + fileName + + result = common.UploadResponse{ + Size: file.Size, + Path: fullPath, + FullPath: urlPerfix + fullPath, + Name: file.Filename, + Type: file.Header.Get("Content-type"), + } + return +} + +// 检查上传文件大小 +func (s *uploadTmpl) CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) { + + var ( + configSize *entity.SysConfig + ) + + if checkFileType == consts.CheckFileTypeFile { + + //获取上传大小配置 + configSize, err = s.getUpConfig(ctx, consts.FileSizeKey) + if err != nil { + return + } + } else if checkFileType == consts.CheckFileTypeImg { + + //获取上传大小配置 + configSize, err = s.getUpConfig(ctx, consts.ImgSizeKey) + if err != nil { + return + } + } else { + return errors.New(fmt.Sprintf("文件检查类型错误:%s|%s", consts.CheckFileTypeFile, consts.CheckFileTypeImg)) + } + + var rightSize bool + rightSize, err = s.checkSize(configSize.ConfigValue, file.Size) + if err != nil { + return + } + if !rightSize { + err = gerror.New("上传文件超过最大尺寸:" + configSize.ConfigValue) + return + } + return +} + +// 检查上传文件类型 +func (s *uploadTmpl) CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) { + + var ( + configType *entity.SysConfig + ) + + if checkFileType == consts.CheckFileTypeFile { + //获取上传类型配置 + configType, err = s.getUpConfig(ctx, consts.FileTypeKey) + if err != nil { + return + } + + } else if checkFileType == consts.CheckFileTypeImg { + //获取上传类型配置 + configType, err = s.getUpConfig(ctx, consts.ImgTypeKey) + if err != nil { + return + } + } else { + return errors.New(fmt.Sprintf("文件检查类型错误:%s|%s", consts.CheckFileTypeFile, consts.CheckFileTypeImg)) + } + + rightType := s.checkFileType(file.Filename, configType.ConfigValue) + if !rightType { + err = gerror.New("上传文件类型错误,只能包含后缀为:" + configType.ConfigValue + "的文件。") + return + } + return +} + +//获取上传配置 +func (s *uploadTmpl) getUpConfig(ctx context.Context, key string) (config *entity.SysConfig, err error) { + config, err = Config().GetConfigByKey(ctx, key) + if err != nil { + return + } + if config == nil { + err = gerror.New("上传文件类型未设置,请在后台配置") + return + } + return +} + +//判断上传文件类型是否合法 +func (s *uploadTmpl) checkFileType(fileName, typeString string) bool { + suffix := gstr.SubStrRune(fileName, gstr.PosRRune(fileName, ".")+1, gstr.LenRune(fileName)-1) + imageType := gstr.Split(typeString, ",") + rightType := false + for _, v := range imageType { + if gstr.Equal(suffix, v) { + rightType = true + break + } + } + return rightType +} + +//检查文件大小是否合法 +func (s *uploadTmpl) checkSize(configSize string, fileSize int64) (bool, error) { + match, err := gregex.MatchString(`^([0-9]+)(?i:([a-z]*))$`, configSize) + if err != nil { + return false, err + } + if len(match) == 0 { + err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB)") + return false, err + } + var cfSize int64 + switch gstr.ToUpper(match[2]) { + case "MB", "M": + cfSize = gconv.Int64(match[1]) * 1024 * 1024 + case "KB", "K": + cfSize = gconv.Int64(match[1]) * 1024 + case "": + cfSize = gconv.Int64(match[1]) + } + if cfSize == 0 { + err = gerror.New("上传文件大小未设置,请在后台配置,格式为(30M,30k,30MB),最大单位为MB") + return false, err + } + return cfSize >= fileSize, nil +} + +// 静态文件夹目录 +func (s *uploadTmpl) getStaticPath(ctx context.Context) string { + value, _ := g.Cfg().Get(ctx, "server.serverRoot") + if !value.IsEmpty() { + return value.String() + } + return "" +} diff --git a/library/libUtils/utils.go b/library/libUtils/utils.go index 20b8280..9d65377 100644 --- a/library/libUtils/utils.go +++ b/library/libUtils/utils.go @@ -17,6 +17,7 @@ import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "net" + "net/http" "os" "path" "strings" @@ -124,3 +125,49 @@ func ParseFilePath(pathStr string) (fileName string, fileType string) { fileName = strings.TrimSuffix(fileNameWithSuffix, fileType) return } + +// IsNotExistMkDir 检查文件夹是否存在 +// 如果不存在则新建文件夹 +func IsNotExistMkDir(src string) error { + if exist := !FileIsExisted(src); exist == false { + if err := MkDir(src); err != nil { + return err + } + } + + return nil +} + +// MkDir 新建文件夹 +func MkDir(src string) error { + err := os.MkdirAll(src, os.ModePerm) + if err != nil { + return err + } + + return nil +} + +//获取文件后缀 +func GetExt(fileName string) string { + return path.Ext(fileName) +} + +// GetType 获取文件类型 +func GetType(p string) (result string, err error) { + file, err := os.Open(p) + if err != nil { + g.Log().Error(context.TODO(), err) + return + } + buff := make([]byte, 512) + + _, err = file.Read(buff) + + if err != nil { + g.Log().Error(context.TODO(), err) + return + } + filetype := http.DetectContentType(buff) + return filetype, nil +} diff --git a/manifest/config/config.yaml.bak b/manifest/config/config.yaml.bak index 67876a7..aace541 100644 --- a/manifest/config/config.yaml.bak +++ b/manifest/config/config.yaml.bak @@ -83,4 +83,11 @@ gfcli: noModelComment: true path: "./internal/app/system" - +# 上传配置 +upload: + default: 0 # 默认上传至本地 + tencentCOS: + upPath : "/gfast/" + rawUrl : "https://yxh-1301841944.cos.ap-chongqing.myqcloud.com" + secretID : "AKIDsKckd83HTh0795wlKcyreyCfvDHYZmbk" + secretKey : "2tc6Lj6LODppZ3aWCeqElBLcqzwz06zg"