Golang实现小型CMS内容管理功能(一):Gin框架搭配Gorm实现增删查改功能
创始人
2024-02-02 05:07:53

我自己开发了一款在线客服系统,最近一直琢磨把客服系统官网做好。因为访客来的人不少,大部分人可能就是看看官网界面就走了,怎样把这些访客留存下来,去测试试用客服系统,是我一直琢磨的问题。

官网是一个企业的门面,也是一个系统的门面,还是需要把门面的内容整理总结一下,让大家能清楚看到系统的功能。网站的内容少,那么搜索引擎收录的就少,这样会导致网站的权重不高,搜索排名比较低。

因此要简单的加上一个小型的内容管理功能。

大家感兴趣也可以去看看唯一客服系统

设计数据库

很简单的两张表,分类表和内容表

DROP TABLE IF EXISTS `cms_cate`;
CREATE TABLE `cms_cate` (`id` int(11) NOT NULL AUTO_INCREMENT,`cat_name` varchar(50) NOT NULL DEFAULT '' COMMENT '分类名称',`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '创建时间',PRIMARY KEY (`id`) COMMENT '自增主键索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'CMS分类表';
DROP TABLE IF EXISTS `cms_news`;
CREATE TABLE `cms_news` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(500) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标题',`content` text COLLATE utf8mb4_general_ci COMMENT '内容',`cat_id` int(11) NOT NULL DEFAULT '0' COMMENT '分类ID',`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP  COMMENT '创建时间',PRIMARY KEY (`id`) COMMENT '自增主键索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'CMS内容表';

编写数据库操作gorm Model部分

设计两个结构体

type CmsCate struct {Id        uint       `json:"id"`CatName   string     `json:"cat_name"`CreatedAt types.Time `json:"created_at"`
}
type CmsNews struct {Id        uint       `json:"id"`Title     string     `json:"title"`Content   string     `json:"content"`CreatedAt types.Time `json:"created_at"`
}

types.Time类型是我对time.Time类型的包装,用于在序列化为json的时候,可以格式化时间。

默认的Time类型,JSON序列化出来后是UTC格式,不符合观看习惯

package typesimport ("database/sql/driver""fmt""time"
)type Time struct {time.Time
}func (t Time) MarshalJSON() ([]byte, error) {localTime := t.Format("2006-01-02 15:04:05")return []byte(fmt.Sprintf(`"%s"`, localTime)), nil
}
func (t Time) Value() (driver.Value, error) {var zeroTime time.Timeif t.Time.UnixNano() == zeroTime.UnixNano() {return nil, nil}return t.Time, nil
}
func (t *Time) Scan(v interface{}) error {value, ok := v.(time.Time)if ok {*t = Time{Time: value}return nil}return fmt.Errorf("can not convert %v to timestamp", v)
}

分类表和内容表的增删查改

DB就是*gorm.DB类型,这是在链接数据库的时候,已经赋值好的全局变量

/*内容表*/
//根据条件查询条数
func CountCmsNews(query interface{}, args ...interface{}) uint {var v uintDB.Table("cms_news").Where(query, args...).Count(&v)return v
}//根据条件更新
func (this *CmsNews) SaveCmsNews(query interface{}, args ...interface{}) error {db := DB.Table("cms_news").Where(query, args...).Update(this)return db.Error
}//增加数据
func (this *CmsNews) AddCmsNews() error {return DB.Create(this).Error
}//根据条件查询分页列表
func FindCmsNews(page, pagesize int, query interface{}, args ...interface{}) []CmsNews {offset := (page - 1) * pagesizevar res []CmsNewsDB.Table("cms_news").Where(query, args...).Order("id desc").Offset(offset).Limit(pagesize).Find(&res)return res
}//根据条件删除
func DelCmsNews(query interface{}, args ...interface{}) error {return DB.Where(query, args...).Delete(&CmsNews{}).Error
}/*分类表*/
//根据条件分类
func (this *CmsCate) SaveCmsCate(query interface{}, args ...interface{}) error {db := DB.Table("cms_cate").Where(query, args...).Update(this)return db.Error
}//增加分类
func (this *CmsCate) AddCmsCate() error {return DB.Create(this).Error
}//根据条件查询分类列表
func FindCmsCate(page, pagesize int, query interface{}, args ...interface{}) []CmsCate {offset := (page - 1) * pagesizevar res []CmsCateDB.Table("cms_cate").Where(query, args...).Order("id desc").Offset(offset).Limit(pagesize).Find(&res)return res
}//根据条件删除分类
func DelCmsCate(query interface{}, args ...interface{}) error {return DB.Where(query, args...).Delete(&CmsCate{}).Error
}

编写gin路由处理部分

gin路由入口

 //系统相关systemGroup := engine.Group("/system")systemGroup.Use(){//分类列表systemGroup.GET("/cmsCate", controller.GetCmsCate)//删除分类systemGroup.GET("/delCmsCate", controller.DelCmsCate)//增加或编辑分类systemGroup.POST("/cmsCate", controller.PostCmsCate)//CMS内容列表systemGroup.GET("/cmsNews", controller.GetCmsNews)//增加或编辑内容systemGroup.POST("/cmsNews", controller.PostCmsNews)//删除内容systemGroup.GET("/delCmsNews", controller.DelCmsNews)}

gin框架路由处理逻辑

返回参数部分,我进行了小的封装,可以参考去掉。

只看调用model部分的处理逻辑

package controllerimport ("github.com/gin-gonic/gin""kefu/models""kefu/types""strconv"
)type CmsCateForm struct {Id       uint   `form:"id" json:"id" uri:"id" xml:"id"`CateName string `form:"cate_name" json:"cate_name" uri:"cate_name" xml:"cate_name" binding:"required"`
}//分类列表(暂不分页)
func GetCmsCate(c *gin.Context) {list := models.FindCmsCate(1, 1000, "")c.JSON(200, gin.H{"code":   types.ApiCode.SUCCESS,"msg":    types.ApiCode.GetMessage(types.ApiCode.SUCCESS),"result": list,})
}//编辑CMS分类
func PostCmsCate(c *gin.Context) {var form CmsCateFormerr := c.Bind(&form)if err != nil {c.JSON(200, gin.H{"code":   types.ApiCode.FAILED,"msg":    types.ApiCode.GetMessage(types.ApiCode.INVALID),"result": err.Error(),})return}modelCms := &models.CmsCate{Id:      form.Id,CatName: form.CateName,}//添加分类if form.Id == 0 {err := modelCms.AddCmsCate()if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}} else {//修改分类err := modelCms.SaveCmsCate("id = ?", form.Id)if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}}c.JSON(200, gin.H{"code": types.ApiCode.SUCCESS,"msg":  types.ApiCode.GetMessage(types.ApiCode.SUCCESS),})
}type CmsNewsForm struct {Id      uint   `form:"id" json:"id" uri:"id" xml:"id"`CateId  string `form:"cate_id" json:"cate_id" uri:"cate_id" xml:"cate_id" binding:"required"`Content string `form:"content" json:"content" uri:"content" xml:"content" binding:"required"`Title   string `form:"title" json:"title" uri:"title" xml:"title" binding:"required"`
}//CMS内容列表
func GetCmsNews(c *gin.Context) {//分页处理page, _ := strconv.Atoi(c.Query("page"))if page <= 0 {page = 1}pagesize, _ := strconv.Atoi(c.Query("pagesize"))if pagesize <= 0 || pagesize > 50 {pagesize = 10}//判断分类ID条件catId := c.Query("cat_id")query := "1=1 "args := make([]interface{}, 0)if catId != "" {query += "and cat_id = ? "args = append(args, catId)}//分页查询count := models.CountCmsNews(query, args...)list := models.FindCmsNews(page, pagesize, query, args...)c.JSON(200, gin.H{"code": types.ApiCode.SUCCESS,"msg":  types.ApiCode.GetMessage(types.ApiCode.SUCCESS),"result": gin.H{"list":     list,"count":    count,"pagesize": pagesize,"page":     page,},})
}//编辑CMS内容
func PostCmsNews(c *gin.Context) {var form CmsNewsFormerr := c.Bind(&form)if err != nil {c.JSON(200, gin.H{"code":   types.ApiCode.FAILED,"msg":    types.ApiCode.GetMessage(types.ApiCode.INVALID),"result": err.Error(),})return}modelCms := &models.CmsNews{Id:    form.Id,CatId: form.CateId,Title: form.Title,}//添加if form.Id == 0 {err := modelCms.AddCmsNews()if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}} else {//修改err := modelCms.SaveCmsNews("id = ?", form.Id)if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}}c.JSON(200, gin.H{"code": types.ApiCode.SUCCESS,"msg":  types.ApiCode.GetMessage(types.ApiCode.SUCCESS),})
}//删除分类
func DelCmsCate(c *gin.Context) {id := c.Query("id")err := models.DelCmsCate("id = ?", id)if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}c.JSON(200, gin.H{"code": types.ApiCode.SUCCESS,"msg":  types.ApiCode.GetMessage(types.ApiCode.SUCCESS),})
}//删除内容
func DelCmsNews(c *gin.Context) {id := c.Query("id")err := models.DelCmsNews("id = ?", id)if err != nil {c.JSON(200, gin.H{"code": types.ApiCode.FAILED,"msg":  err.Error(),})return}c.JSON(200, gin.H{"code": types.ApiCode.SUCCESS,"msg":  types.ApiCode.GetMessage(types.ApiCode.SUCCESS),})
}

可以使用接口测试工具,对接口进行测试

相关内容

热门资讯

应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...