From bbb15376cb5421600b03b40716e6233a2a9d63a5 Mon Sep 17 00:00:00 2001 From: yxh Date: Mon, 16 Mar 2020 23:51:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- app/controller/admin/cms_news.go | 4 +- app/controller/admin/config_params.go | 4 + app/controller/admin/upload.go | 22 ++++ app/model/admin/cms_news/cms_news.go | 22 ++-- app/model/admin/cms_news/cms_news_entity.go | 5 - app/model/admin/cms_news/cms_news_model.go | 126 ++++++++++-------- app/model/admin/sys_config/sys_config.go | 10 ++ app/service/admin/cms_service/news.go | 4 +- app/service/admin/params_service/params.go | 17 +++ app/service/admin/upload_service/upload.go | 134 ++++++++++++++++++++ app/service/cache_service/cache_values.go | 1 + router/router.go | 10 +- test/demo2_test.go | 4 +- 14 files changed, 285 insertions(+), 81 deletions(-) create mode 100644 app/controller/admin/upload.go create mode 100644 app/service/admin/upload_service/upload.go diff --git a/.gitignore b/.gitignore index 8fa530b..a3bf133 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ cbuild main .vscode *.exe -tmp \ No newline at end of file +tmp +resource/pub_upload/ \ No newline at end of file diff --git a/app/controller/admin/cms_news.go b/app/controller/admin/cms_news.go index 7e26e4d..2dfc51b 100644 --- a/app/controller/admin/cms_news.go +++ b/app/controller/admin/cms_news.go @@ -25,9 +25,9 @@ func (c *CmsNews) Add(r *ghttp.Request) { if err := r.Parse(&req); err != nil { response.FailJson(true, r, err.(*gvalid.Error).FirstString()) } - menuIds := r.GetInts("menuIds") + cateIds := r.GetInts("cateIds") userId := user_service.GetLoginID(r) - ids, err := cms_service.AddNews(req, menuIds, userId) + ids, err := cms_service.AddNews(req, cateIds, userId) if err != nil { response.FailJson(true, r, err.Error()) } diff --git a/app/controller/admin/config_params.go b/app/controller/admin/config_params.go index 841eef6..c6cad83 100644 --- a/app/controller/admin/config_params.go +++ b/app/controller/admin/config_params.go @@ -4,6 +4,7 @@ import ( "gfast/app/model/admin/sys_config" "gfast/app/service/admin/params_service" "gfast/app/service/admin/user_service" + "gfast/app/service/cache_service" "gfast/library/response" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" @@ -49,6 +50,7 @@ func (c *Params) Add(r *ghttp.Request) { if err != nil { response.FailJson(true, r, err.Error()) } + cache_service.New().Remove(req.ConfigKey) response.SusJson(true, r, "添加参数成功") } } @@ -70,6 +72,7 @@ func (c *Params) Edit(r *ghttp.Request) { if err != nil { response.FailJson(true, r, err.Error()) } + cache_service.New().Remove(req.ConfigKey) response.SusJson(true, r, "修改参数成功") } id := r.GetInt("id") @@ -90,5 +93,6 @@ func (c *Params) Delete(r *ghttp.Request) { if err != nil { response.FailJson(true, r, "删除失败") } + cache_service.New().RemoveByTag(cache_service.AdminSysConfigTag) response.SusJson(true, r, "删除成功") } diff --git a/app/controller/admin/upload.go b/app/controller/admin/upload.go new file mode 100644 index 0000000..a4e9358 --- /dev/null +++ b/app/controller/admin/upload.go @@ -0,0 +1,22 @@ +package admin + +import ( + "gfast/app/service/admin/upload_service" + "gfast/library/response" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/net/ghttp" +) + +type Upload struct{} + +func (c *Upload) UpImg(r *ghttp.Request) { + upFile := r.GetUploadFile("file") + info, err := upload_service.UpImg(upFile) + if err != nil { + response.FailJson(true, r, "上传失败,"+err.Error()) + } + res := g.Map{ + "fileInfo": info, + } + response.SusJson(true, r, "上传成功", res) +} diff --git a/app/model/admin/cms_news/cms_news.go b/app/model/admin/cms_news/cms_news.go index 972d949..d467b94 100644 --- a/app/model/admin/cms_news/cms_news.go +++ b/app/model/admin/cms_news/cms_news.go @@ -31,20 +31,20 @@ type ReqAddParams struct { } //添加文章操作 -func AddNews(req *ReqAddParams, menuIds []int, userId int) (insId []int64, err error) { - if len(menuIds) == 0 { +func AddNews(req *ReqAddParams, cateIds []int, userId int) (insId []int64, err error) { + if len(cateIds) == 0 { err = gerror.New("栏目不能为空") return } tx, err := g.DB().Begin() if err != nil { g.Log().Error(err) - err = gerror.New("保存失败") + err = gerror.New("添加失败") return } - for _, menuId := range menuIds { + for _, cateId := range cateIds { entity := &Entity{ - CateId: gconv.Uint(menuId), + CateId: gconv.Uint(cateId), UserId: gconv.Uint64(userId), NewsStatus: req.NewsStatus, IsTop: req.IsTop, @@ -60,16 +60,16 @@ func AddNews(req *ReqAddParams, menuIds []int, userId int) (insId []int64, err e IsJump: req.IsJump, JumpUrl: req.JumpUrl, } - res, err := entity.Save() - if err != nil { - g.Log().Error(err) + res, e := entity.Save() + if e != nil { + g.Log().Error(e) err = gerror.New("添加文章失败") tx.Rollback() return } - id, err := res.LastInsertId() - if err != nil { - g.Log().Error(err) + id, e := res.LastInsertId() + if e != nil { + g.Log().Error(e) err = gerror.New("添加文章失败") tx.Rollback() return diff --git a/app/model/admin/cms_news/cms_news_entity.go b/app/model/admin/cms_news/cms_news_entity.go index 475bad3..ae539b5 100644 --- a/app/model/admin/cms_news/cms_news_entity.go +++ b/app/model/admin/cms_news/cms_news_entity.go @@ -46,11 +46,6 @@ func (r *Entity) Insert() (result sql.Result, err error) { return Model.Data(r).Insert() } -// InsertIgnore does "INSERT IGNORE INTO ..." statement for inserting current object into table. -func (r *Entity) InsertIgnore() (result sql.Result, err error) { - return Model.Data(r).InsertIgnore() -} - // Replace does "REPLACE...INTO..." statement for inserting current object into table. // If there's already another same record in the table (it checks using primary key or unique index), // it deletes it and insert this one. diff --git a/app/model/admin/cms_news/cms_news_model.go b/app/model/admin/cms_news/cms_news_model.go index 4838d93..977a1a9 100644 --- a/app/model/admin/cms_news/cms_news_model.go +++ b/app/model/admin/cms_news/cms_news_model.go @@ -8,13 +8,12 @@ import ( "database/sql" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" - "github.com/gogf/gf/frame/gmvc" "time" ) // arModel is a active record design model for table cms_news operations. type arModel struct { - gmvc.M + M *gdb.Model } var ( @@ -22,54 +21,6 @@ var ( Table = "cms_news" // Model is the model object of cms_news. Model = &arModel{g.DB("default").Table(Table).Safe()} - // Columns defines and stores column names for table cms_news. - Columns = struct { - Id string // - CateId string // 栏目id - NewsFormat string // 内容格式;1:html;2:md - UserId string // 发表者用户id - NewsStatus string // 状态;1:已发布;0:未发布; - IsTop string // 是否置顶;1:置顶;0:不置顶 - Recommended string // 是否推荐;1:推荐;0:不推荐 - NewsHits string // 查看数 - NewsLike string // 点赞数 - CreateTime string // 创建时间 - UpdateTime string // 更新时间 - PublishedTime string // 发布时间 - DeleteTime string // 删除时间 - NewsTitle string // post标题 - NewsKeywords string // seo keywords - NewsExcerpt string // post摘要 - NewsSource string // 转载文章的来源 - NewsContent string // 文章内容 - Thumbnail string // 缩略图 - IsJump string // 是否跳转地址 - JumpUrl string // 跳转地址 - IsPushed string // 是否已推送 - }{ - Id: "id", - CateId: "cate_id", - NewsFormat: "news_format", - UserId: "user_id", - NewsStatus: "news_status", - IsTop: "is_top", - Recommended: "recommended", - NewsHits: "news_hits", - NewsLike: "news_like", - CreateTime: "create_time", - UpdateTime: "update_time", - PublishedTime: "published_time", - DeleteTime: "delete_time", - NewsTitle: "news_title", - NewsKeywords: "news_keywords", - NewsExcerpt: "news_excerpt", - NewsSource: "news_source", - NewsContent: "news_content", - Thumbnail: "thumbnail", - IsJump: "is_jump", - JumpUrl: "jump_url", - IsPushed: "is_pushed", - } ) // FindOne is a convenience method for Model.FindOne. @@ -90,12 +41,6 @@ func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) { return Model.FindValue(fieldsAndWhere...) } -// FindArray is a convenience method for Model.FindArray. -// See Model.FindArray. -func FindArray(fieldsAndWhere ...interface{}) ([]gdb.Value, error) { - return Model.FindArray(fieldsAndWhere...) -} - // FindCount is a convenience method for Model.FindCount. // See Model.FindCount. func FindCount(where ...interface{}) (int, error) { @@ -277,6 +222,53 @@ func (m *arModel) Data(data ...interface{}) *arModel { return &arModel{m.M.Data(data...)} } +// Insert does "INSERT INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Insert(data ...interface{}) (result sql.Result, err error) { + return m.M.Insert(data...) +} + +// Replace does "REPLACE INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Replace(data ...interface{}) (result sql.Result, err error) { + return m.M.Replace(data...) +} + +// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. +// It updates the record if there's primary or unique index in the saving data, +// or else it inserts a new record into the table. +// +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Save(data ...interface{}) (result sql.Result, err error) { + return m.M.Save(data...) +} + +// Update does "UPDATE ... " statement for the model. +// +// If the optional parameter is given, the dataAndWhere[0] is the updated +// data field, and dataAndWhere[1:] is treated as where condition fields. +// Also see Model.Data and Model.Where functions. +func (m *arModel) Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + return m.M.Update(dataAndWhere...) +} + +// Delete does "DELETE FROM ... " statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Delete(where ...interface{}) (result sql.Result, err error) { + return m.M.Delete(where...) +} + +// Count does "SELECT COUNT(x) FROM ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Count(where ...interface{}) (int, error) { + return m.M.Count(where...) +} + // All does "SELECT FROM ..." statement for the model. // It retrieves the records from table and returns the result as []*Entity. // It returns nil if there's no record retrieved with the given conditions from table. @@ -312,6 +304,16 @@ func (m *arModel) One(where ...interface{}) (*Entity, error) { return entity, nil } +// Value retrieves a specified record value from table and returns the result as interface type. +// It returns nil if there's no record found with the given conditions from table. +// +// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields +// and fieldsAndWhere[1:] is treated as where condition fields. +// Also see Model.Fields and Model.Where functions. +func (m *arModel) Value(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return m.M.Value(fieldsAndWhere...) +} + // FindOne retrieves and returns a single Record by Model.WherePri and Model.One. // Also see Model.WherePri and Model.One. func (m *arModel) FindOne(where ...interface{}) (*Entity, error) { @@ -340,6 +342,18 @@ func (m *arModel) FindAll(where ...interface{}) ([]*Entity, error) { return entities, nil } +// FindValue retrieves and returns single field value by Model.WherePri and Model.Value. +// Also see Model.WherePri and Model.Value. +func (m *arModel) FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return m.M.FindValue(fieldsAndWhere...) +} + +// FindCount retrieves and returns the record number by Model.WherePri and Model.Count. +// Also see Model.WherePri and Model.Count. +func (m *arModel) FindCount(where ...interface{}) (int, error) { + return m.M.FindCount(where...) +} + // Chunk iterates the table with given size and callback function. func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) { m.M.Chunk(limit, func(result gdb.Result, err error) bool { diff --git a/app/model/admin/sys_config/sys_config.go b/app/model/admin/sys_config/sys_config.go index 0c10836..882d185 100644 --- a/app/model/admin/sys_config/sys_config.go +++ b/app/model/admin/sys_config/sys_config.go @@ -176,3 +176,13 @@ func DeleteByIds(ids []int) error { } return nil } + +//通过key获取配置信息 +func GetByKey(key string) (config *Entity, err error) { + config, err = Model.FindOne("config_key", key) + if err != nil { + g.Log().Error(err) + err = gerror.New("获取配置失败") + } + return +} diff --git a/app/service/admin/cms_service/news.go b/app/service/admin/cms_service/news.go index f71b141..bcb6e14 100644 --- a/app/service/admin/cms_service/news.go +++ b/app/service/admin/cms_service/news.go @@ -5,6 +5,6 @@ import ( ) //添加文章操作 -func AddNews(req *cms_news.ReqAddParams, menuIds []int, userId int) (insId []int64, err error) { - return cms_news.AddNews(req, menuIds, userId) +func AddNews(req *cms_news.ReqAddParams, cateIds []int, userId int) (insId []int64, err error) { + return cms_news.AddNews(req, cateIds, userId) } diff --git a/app/service/admin/params_service/params.go b/app/service/admin/params_service/params.go index 01c50f1..8daf1a6 100644 --- a/app/service/admin/params_service/params.go +++ b/app/service/admin/params_service/params.go @@ -2,6 +2,7 @@ package params_service import ( "gfast/app/model/admin/sys_config" + "gfast/app/service/cache_service" ) //保存参数 @@ -38,3 +39,19 @@ func CheckConfigKeyUnique(configKey string, configId int64) error { func DeleteByIds(ids []int) error { return sys_config.DeleteByIds(ids) } + +//通过key获取参数 +func GetConfigByKey(key string) (config *sys_config.Entity, err error) { + cache := cache_service.New() + cf := cache.Get(key) + if cf != nil { + config = cf.(*sys_config.Entity) + return + } + config, err = sys_config.GetByKey(key) + if err != nil { + return + } + cache.Set(key, config, 0, cache_service.AdminSysConfigTag) + return +} diff --git a/app/service/admin/upload_service/upload.go b/app/service/admin/upload_service/upload.go new file mode 100644 index 0000000..6717d7f --- /dev/null +++ b/app/service/admin/upload_service/upload.go @@ -0,0 +1,134 @@ +package upload_service + +import ( + "gfast/app/model/admin/sys_config" + "gfast/app/service/admin/params_service" + "github.com/gogf/gf/errors/gerror" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/os/gtime" + "github.com/gogf/gf/text/gregex" + "github.com/gogf/gf/text/gstr" + "github.com/gogf/gf/util/gconv" +) + +var uploadPath string + +//上传得文件信息 +type FileInfo struct { + FileName string + FileSize int64 + FileUrl string + fileType string +} + +func init() { + uploadPath = g.Cfg().GetString("server.ServerRoot") + "/pub_upload/" +} + +//上传图片 +func UpImg(file *ghttp.UploadFile) (fileInfo *FileInfo, err error) { + if file == nil { + err = gerror.New("未上传任何文件") + return + } + //获取上传类型配置 + config, err := getUpConfig("sys.uploadFile.imageType") + if err != nil { + return + } + //检测文件类型 + rightType := checkFileType(file.Filename, config.ConfigValue) + if !rightType { + err = gerror.New("上传文件类型错误,只能包含后缀为:" + config.ConfigValue + "的文件。") + return + } + //获取上传大小配置 + config, err = getUpConfig("sys.uploadFile.imageSize") + if err != nil { + return + } + rightSize, err := checkSize(config.ConfigValue, file.Size) + if err != nil { + return + } + if !rightSize { + gerror.New("上传文件超过最大尺寸:" + config.ConfigValue) + return + } + path := getUpPath() + fileName, err := file.Save(path, true) + if err != nil { + return + } + fileInfo = &FileInfo{ + FileName: file.Filename, + FileSize: file.Size, + FileUrl: getUrl(path, fileName), + fileType: file.Header.Get("Content-type"), + } + return +} + +//检查文件大小是否合法 +func 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 getUpConfig(key string) (config *sys_config.Entity, err error) { + config, err = params_service.GetConfigByKey(key) + if err != nil { + return + } + if config == nil { + err = gerror.New("上传文件类型未设置,请在后台配置") + return + } + return +} + +//判断上传文件类型是否合法 +func checkFileType(fileName, typeString string) bool { + suffix := gstr.SubStr(fileName, gstr.Pos(fileName, ".")+1) + imageType := gstr.Split(typeString, ",") + rightType := false + for _, v := range imageType { + if gstr.Equal(suffix, v) { + rightType = true + break + } + } + return rightType +} + +func getUpPath() (upPath string) { + upPath = uploadPath + gtime.Date() + "/" + return +} + +func getUrl(path, fileName string) string { + url := gstr.SubStr(path, gstr.Pos(path, "/pub_upload/")+1) + fileName + return url +} diff --git a/app/service/cache_service/cache_values.go b/app/service/cache_service/cache_values.go index 99f733f..a397834 100644 --- a/app/service/cache_service/cache_values.go +++ b/app/service/cache_service/cache_values.go @@ -11,4 +11,5 @@ const ( const ( AdminAuthTag = iota AdminCmsTag + AdminSysConfigTag ) diff --git a/router/router.go b/router/router.go index 70da1cf..443c945 100644 --- a/router/router.go +++ b/router/router.go @@ -21,20 +21,24 @@ func init() { //后台操作日志记录 group.Hook("/*", ghttp.HOOK_AFTER_OUTPUT, hook.OperationLog) + //文件上传 + group.POST("/upload", new(admin.Upload)) + //后台首页 group.ALL("/index", new(admin.Index)) + //权限管理 group.ALL("/auth", new(admin.Auth)) - + //cms管理 group.Group("/cms", func(group *ghttp.RouterGroup) { group.ALL("/menu", new(admin.CmsMenu)) group.ALL("/news", new(admin.CmsNews)) group.ALL("/model", new(admin.CmsModel)) }) - + //配置管理 group.Group("/config", func(group *ghttp.RouterGroup) { group.ALL("/dict", new(admin.Dict)) group.ALL("/params", new(admin.Params)) }) - + //系统监控 group.Group("/monitor", func(group *ghttp.RouterGroup) { group.ALL("/online", new(admin.MonitorOnline)) group.ALL("/job", new(admin.MonitorJob)) diff --git a/test/demo2_test.go b/test/demo2_test.go index d2ad02d..326f20a 100644 --- a/test/demo2_test.go +++ b/test/demo2_test.go @@ -1,6 +1,8 @@ package test import ( + "fmt" + "github.com/gogf/gf/os/gtime" "testing" ) @@ -9,5 +11,5 @@ func TestDemo2(t *testing.T) { } func test21(t *testing.T) { - + fmt.Println(gtime.Date()) }