fix: 增加基于mongodb的图片模型

增加基于mongodb的图片模型
This commit is contained in:
yaoyilin
2022-11-06 23:35:20 +08:00
parent 4b51f0734a
commit 772cc9ff7e
11 changed files with 355 additions and 31 deletions

44
app/controller/img.go Normal file
View File

@@ -0,0 +1,44 @@
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"gitlab.52pay.top/go/easygoadmin/app/model"
"gitlab.52pay.top/go/easygoadmin/utils/common"
"net/http"
)
var Img = new(img)
type img struct{}
func (c *img) Image(ctx *gin.Context) {
mode := ctx.Param("mode")
if mode == "" {
ctx.JSON(http.StatusOK, common.JsonResult{
Code: -1,
Msg: "业务类型不能为空",
})
return
}
filename := ctx.Param("filename")
if filename == "" {
ctx.JSON(http.StatusOK, common.JsonResult{
Code: -1,
Msg: "业务类型不能为空",
})
return
}
image := &model.UserImage{}
err := image.GetByPath(fmt.Sprintf("%s/%s", mode, filename))
if err != nil {
ctx.JSON(http.StatusOK, common.JsonResult{
Code: -1,
Msg: "图片不存在",
})
return
}
contentType := http.DetectContentType(image.Image)
ctx.Data(200, contentType, image.Image)
}

View File

@@ -19,7 +19,7 @@ var Upload = new(uploadCtl)
type uploadCtl struct{} type uploadCtl struct{}
func (c *uploadCtl) UploadImage(ctx *gin.Context) { func (u *uploadCtl) UploadImage(ctx *gin.Context) {
// 调用上传方法 // 调用上传方法
result, err := service.Upload.UploadImage(ctx) result, err := service.Upload.UploadImage(ctx)
if err != nil { if err != nil {
@@ -40,3 +40,33 @@ func (c *uploadCtl) UploadImage(ctx *gin.Context) {
Data: result, Data: result,
}) })
} }
func (u *uploadCtl) UploadImage2Db(ctx *gin.Context) {
typ := ctx.Param("typ")
if typ == "" {
ctx.JSON(http.StatusOK, common.JsonResult{
Code: -1,
Msg: "业务类型不能为空",
})
return
}
// 调用上传方法
result, err := service.Upload.UploadImage2Db(ctx, typ)
if err != nil {
ctx.JSON(http.StatusOK, common.JsonResult{
Code: -1,
Msg: err.Error(),
})
return
}
// 拼接图片地址
result.FileUrl = utils.GetImageUrl(result.FileUrl)
// 返回结果
ctx.JSON(http.StatusOK, common.JsonResult{
Code: 0,
Msg: "上传成功",
Data: result,
})
}

95
app/model/user_image.go Normal file
View File

@@ -0,0 +1,95 @@
package model
import (
"context"
"fmt"
"gitlab.52pay.top/go/easygoadmin/library/cfg"
"gitlab.52pay.top/go/easygoadmin/utils"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"strings"
"time"
)
var userImageTable *mongo.Collection
var ctx context.Context
func init() {
config := cfg.Instance()
tableName := fmt.Sprintf("%suser_images", config.Mongodb.Prev)
userImageTable = utils.Mongodb.Collection(tableName)
ctx = context.Background()
}
type UserImage struct {
_id primitive.ObjectID
Image []byte
Model string
MId string
FileType string
Attr string
Created time.Time
}
func (u *UserImage) Insert() (string, error) {
result, err := userImageTable.InsertOne(ctx, u)
if err != nil {
return "", err
}
u._id = result.InsertedID.(primitive.ObjectID)
return u.Id(), nil
}
func (u *UserImage) Get(id string) error {
objectId, err := primitive.ObjectIDFromHex(id)
if err != nil {
return fmt.Errorf("输入ID非法err: %s", err.Error())
}
result := userImageTable.FindOne(ctx, bson.D{{"_id", objectId}})
if result == nil {
return fmt.Errorf("查询失败")
}
if result.Err() != nil {
return fmt.Errorf("查询失败, err: %s", result.Err())
}
if err := result.Decode(u); err != nil {
return fmt.Errorf("解析失败err: %s", err.Error())
}
return nil
}
func (u *UserImage) Id() string {
return u._id.Hex()
}
func (u *UserImage) FileName() string {
return fmt.Sprintf("%s%s", u.Id(), u.FileType)
}
func (u *UserImage) Url() string {
return fmt.Sprintf("/img/%s/%s", u.Model, u.FileName())
}
func (u *UserImage) GetByPath(path string) error {
parts := strings.Split(path, "/")
if len(parts) != 2 {
return fmt.Errorf("路径非法%s", path)
}
mode := parts[0]
subPars := strings.Split(parts[1], ".")
if len(subPars) != 2 {
return fmt.Errorf("文件格式非法%s", path)
}
id := subPars[0]
fileExt := "." + subPars[1]
err := u.Get(id)
if err != nil {
return fmt.Errorf("图片读取错误err: %s", err.Error())
}
if fileExt != u.FileType || mode != u.Model {
return fmt.Errorf("图片不存在")
}
return nil
}

View File

@@ -8,12 +8,14 @@ package service
import ( import (
"errors" "errors"
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gitlab.52pay.top/go/easygoadmin/app/model"
"gitlab.52pay.top/go/easygoadmin/utils" "gitlab.52pay.top/go/easygoadmin/utils"
"gitlab.52pay.top/go/easygoadmin/utils/gconv" "gitlab.52pay.top/go/easygoadmin/utils/gconv"
"gitlab.52pay.top/go/easygoadmin/utils/gregex" "gitlab.52pay.top/go/easygoadmin/utils/gregex"
"gitlab.52pay.top/go/easygoadmin/utils/gstr" "gitlab.52pay.top/go/easygoadmin/utils/gstr"
"io"
"mime/multipart"
"path" "path"
"path/filepath" "path/filepath"
"strconv" "strconv"
@@ -33,39 +35,42 @@ type FileInfo struct {
FileType string `json:"fileType"` FileType string `json:"fileType"`
} }
func (s *uploadService) UploadImage(ctx *gin.Context) (FileInfo, error) { func (s *uploadService) UploadImage2Db(ctx *gin.Context, typ string) (result FileInfo, err error) {
if utils.AppDebug() { ginFile, fileExt, err := getFile(ctx)
return FileInfo{}, errors.New("演示环境,暂无权限操作")
}
// 获取文件(注意这个地方的file要和html模板中的name一致)
file, err := ctx.FormFile("file")
if err != nil { if err != nil {
return FileInfo{}, errors.New("上传文件不能为空") return
} }
//获取文件名称 file, err := ginFile.Open()
fmt.Println(file.Filename) if err != nil {
//文件大小 return
fmt.Println(file.Size) }
//获取文件的后缀名 body, err := io.ReadAll(file)
fileExt := path.Ext(file.Filename) if err != nil {
fmt.Println(fileExt) return
}
image := model.UserImage{
Image: body,
Model: typ,
FileType: fileExt,
Created: time.Now(),
}
_, err = image.Insert()
if err != nil {
return result, err
}
return FileInfo{
FileName: image.FileName(),
FileSize: int64(len(image.Image)),
FileUrl: image.Url(),
FileType: image.FileType,
}, nil
}
// 允许上传文件后缀 func (s *uploadService) UploadImage(ctx *gin.Context) (FileInfo, error) {
allowExt := "jpg,gif,png,bmp,jpeg,JPG" file, fileExt, err := getFile(ctx)
// 检查上传文件后缀
if !checkFileExt(fileExt, allowExt) {
return FileInfo{}, errors.New("上传文件格式不正确,文件后缀只允许为:" + allowExt + "的文件")
}
// 允许文件上传最大值
allowSize := "1M"
// 检查上传文件大小
isvalid, err := checkFileSize(file.Size, allowSize)
if err != nil { if err != nil {
return FileInfo{}, err return FileInfo{}, err
} }
if !isvalid {
return FileInfo{}, errors.New("上传文件大小不得超过:" + allowSize)
}
// 临时存储目录 // 临时存储目录
savePath := utils.TempPath() + "/" + time.Now().Format("20060102") savePath := utils.TempPath() + "/" + time.Now().Format("20060102")
@@ -139,3 +144,39 @@ func checkFileSize(fileSize int64, maxSize string) (bool, error) {
} }
return cfSize >= fileSize, nil return cfSize >= fileSize, nil
} }
func getFile(ctx *gin.Context) (*multipart.FileHeader, string, error) {
if utils.AppDebug() {
return nil, "", errors.New("演示环境,暂无权限操作")
}
// 获取文件(注意这个地方的file要和html模板中的name一致)
file, err := ctx.FormFile("file")
if err != nil {
return nil, "", errors.New("上传文件不能为空")
}
//获取文件名称
//fmt.Println(file.Filename)
//文件大小
//fmt.Println(file.Size)
//获取文件的后缀名
fileExt := path.Ext(file.Filename)
//fmt.Println(fileExt)
// 允许上传文件后缀
allowExt := "jpg,gif,png,bmp,jpeg,JPG"
// 检查上传文件后缀
if !checkFileExt(fileExt, allowExt) {
return nil, "", errors.New("上传文件格式不正确,文件后缀只允许为:" + allowExt + "的文件")
}
// 允许文件上传最大值
allowSize := "1M"
// 检查上传文件大小
isvalid, err := checkFileSize(file.Size, allowSize)
if err != nil {
return nil, "", err
}
if !isvalid {
return nil, "", errors.New("上传文件大小不得超过:" + allowSize)
}
return file, fileExt, nil
}

View File

@@ -118,7 +118,7 @@ layui.use(['upload','croppers'],function(){
,saveH:` + cropArr[1] + ` ,saveH:` + cropArr[1] + `
,mark:` + cropRateStr + ` //选取比例 ,mark:` + cropRateStr + ` //选取比例
,area:['750px','500px'] //弹窗宽度 ,area:['750px','500px'] //弹窗宽度
,url: "/upload/uploadImage" ,url: "/upload/uploadImage2Db/` + name + `"
,done: function(url){ ,done: function(url){
//上传完毕回调 //上传完毕回调
$('#` + name + `').val(url); $('#` + name + `').val(url);

2
go.mod
View File

@@ -31,8 +31,8 @@ require (
github.com/tebeka/strftime v0.1.5 // indirect github.com/tebeka/strftime v0.1.5 // indirect
github.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07 github.com/toolkits/file v0.0.0-20160325033739-a5b3c5147e07
github.com/x-cray/logrus-prefixed-formatter v0.5.2 github.com/x-cray/logrus-prefixed-formatter v0.5.2
go.mongodb.org/mongo-driver v1.11.0 // indirect
go.opentelemetry.io/otel v1.8.0 // indirect go.opentelemetry.io/otel v1.8.0 // indirect
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
xorm.io/builder v0.3.9 // indirect xorm.io/builder v0.3.9 // indirect

View File

@@ -17,6 +17,15 @@ var (
once sync.Once once sync.Once
) )
func InstanceByPath(filePath string) *config {
var conf config
if _, err := toml.DecodeFile(filePath, &conf); err != nil {
return nil
}
instance = &conf
return instance
}
// 获取配置文档实例 // 获取配置文档实例
func Instance() *config { func Instance() *config {
once.Do(func() { once.Do(func() {
@@ -34,6 +43,7 @@ func Instance() *config {
type config struct { type config struct {
Database database Database database
Mongodb mongodb
Logger logger Logger logger
EasyGoAdmin easygoadmin EasyGoAdmin easygoadmin
RedisCfg redisCfg RedisCfg redisCfg
@@ -47,6 +57,15 @@ type database struct {
Prev string Prev string
} }
type mongodb struct {
Host string
Port int
User string
Password string
Database string
Prev string
}
type redisCfg struct { type redisCfg struct {
Addr string Addr string
Port int64 Port int64

View File

@@ -56,6 +56,14 @@ func init() {
{ {
// 上传图片 // 上传图片
upload.POST("/uploadImage", controller.Upload.UploadImage) upload.POST("/uploadImage", controller.Upload.UploadImage)
// 上传图片存到mongoDb
upload.POST("/uploadImage2Db/:typ", controller.Upload.UploadImage2Db)
}
/* mongodb图片 */
img := router.Group("img")
{
img.GET("/:mode/:filename", controller.Img.Image)
} }
/* 登录注册 */ /* 登录注册 */

42
user_image_test.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
"fmt"
"gitlab.52pay.top/go/easygoadmin/app/model"
"testing"
"time"
)
func TestUserImage_Insert(t *testing.T) {
image := &model.UserImage{
Image: []byte("test image"),
Created: time.Now(),
}
_, err := image.Insert()
if err != nil {
t.Error(err)
t.Fail()
}
t.Log("insert ok, id is", image.Id())
}
func TestUserImage_Get(t *testing.T) {
image := &model.UserImage{
Image: []byte("test image"),
Model: "test",
MId: "123",
Created: time.Now(),
}
_, err := image.Insert()
if err != nil {
t.Error(err)
t.Fail()
}
image2 := new(model.UserImage)
err = image2.Get(image.Id())
if err != nil {
t.Error(err)
t.Fail()
}
fmt.Println(image2.Model)
}

View File

@@ -22,6 +22,9 @@ func init() {
// 获取配置实例 // 获取配置实例
config := cfg.Instance() config := cfg.Instance()
if config == nil {
return
}
var err error var err error
XormDb, err = xorm.NewEngine("mysql", config.Database.Master) XormDb, err = xorm.NewEngine("mysql", config.Database.Master)
if err != nil { if err != nil {

42
utils/mongodb.go Normal file
View File

@@ -0,0 +1,42 @@
package utils
import (
"context"
"fmt"
"github.com/sirupsen/logrus"
"gitlab.52pay.top/go/easygoadmin/library/cfg"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var Mongodb *mongo.Database
func init() {
logrus.Info("初始化并连接mongodb")
config := cfg.Instance()
uri := fmt.Sprintf("mongodb://%s:%s@%s:%d",
config.Mongodb.User,
config.Mongodb.Password,
config.Mongodb.Host,
config.Mongodb.Port)
clientOpt := options.Client().
ApplyURI(uri)
cli, err := mongo.Connect(context.Background(), clientOpt)
if err != nil {
logrus.Errorf("mongo数据库连接错误:%v", err.Error())
return
}
// 通过engine.Ping()来进行数据库的连接测试是否可以连接到数据库。
err = cli.Ping(context.Background(), nil)
if err == nil {
logrus.Info("mongo数据库连接成功")
//关闭连接
//defer XormDb.Close()
} else {
logrus.Errorf("mongo数据库连接错误:%v", err.Error())
return
}
Mongodb = cli.Database(config.Mongodb.Database)
}