go语言web开发系列之一:gin+gorm开发一个简单的热榜接口站

一,热榜的例子:

以抽屉新热榜为例,只存储资讯的链接和提示,

用户点击时会跳转到外部的网站阅读

我们在这里只实现了显示单条内容和多条内容的功能,

主要是把它做为后续功能集成演示的一个基础

后续的集成包括:

  1.  
    统一报错信息
  2.  
     
  3.  
    统一rest输出
  4.  
     
  5.  
    validator
  6.  
     
  7.  
    日志功能
  8.  
     
  9.  
    安全
  10.  
     
  11.  
    接口文档
  12.  
     
  13.  
    统一读取配置文件
  14.  
     
  15.  
    ...
  16.  
     
  17.  
    其他想到再补充吧

说明:刘宏缔的go森林是一个专注golang的博客,
          地址:https://blog.csdn.net/weixin_43881017

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,演示项目的相关信息

1,项目地址:

https://github.com/liuhongdi/digv01

2,项目功能:输出一条资讯的信息、输出多条资讯的信息

3,项目结构:

    

4,  项目各文件夹的说明:

    controller:  控制器,负责接收参数、验证参数,调用service,统一输出

    dao:          到数据库的访问

    doc:          文档

    global:      全局用到的变量,主要是配置、数据库连接、日志功能等

    model:    数据模型

    router:   路由

   service:   主要的业务逻辑

三,sql相关说明:     

  1.  
    CREATE TABLE `article` (
  2.  
    `articleId` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  3.  
    `type` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '类型',
  4.  
    `subject` varchar(500) NOT NULL DEFAULT '' COMMENT '标题',
  5.  
    `addTime` datetime NOT NULL DEFAULT '2020-11-19 00:00:00' COMMENT '添加时间',
  6.  
    `isHot` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否热榜,0:非热,1,热',
  7.  
    `url` varchar(500) NOT NULL DEFAULT '' COMMENT '链接地址',
  8.  
    `domain` varchar(100) NOT NULL DEFAULT '' COMMENT '域',
  9.  
    `userId` bigint unsigned NOT NULL DEFAULT '0' COMMENT '推荐用户',
  10.  
    `approvalStaffId` int unsigned NOT NULL DEFAULT '0' COMMENT '批准员工',
  11.  
    `digSum` int unsigned NOT NULL DEFAULT '0' COMMENT '被顶的次数',
  12.  
    `commentSum` int unsigned NOT NULL DEFAULT '0' COMMENT '被评论的次数',
  13.  
    `isPublish` tinyint NOT NULL DEFAULT '0' COMMENT '0,未发布,1,已发布',
  14.  
    PRIMARY KEY (`articleId`),
  15.  
    KEY `isPublish` (`isPublish`)
  16.  
    ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文章表'

   插入6条演示数据:

  1.  
    INSERT INTO `article` (`articleId`, `type`, `subject`, `addTime`, `isHot`, `url`, `domain`, `userId`, `approvalStaffId`, `digSum`, `commentSum`, `isPublish`) VALUES
  2.  
    (1, 0, '【最近,南非发现一座大油田】石油和天然气两种重要资源是南非储量的最短板,“贫油”的帽子也一直扣在南非的头上摘不下来。可就在最近,在南非海域进行油气勘探已久的道达尔透露了其新的勘探成果:在距离南非南部海岸约175公里的奥特尼夸盆地的11B/12B地区,再次发现了重要的凝析气,可能蕴藏着大量天然气及原油。', '2020-11-19 00:00:00', 1, 'https://mp.weixin.qq.com/s/1btbmouH-2KuIHUMoucq2w', '', 1, 1, 0, 0, 1),
  3.  
    (2, 1, '让喵喵来开启周五的早晨吧!', '2020-11-19 00:00:00', 0, 'https://m.weibo.cn/status/4573112073720433?', 'm.weibo.cn', 0, 0, 0, 0, 1),
  4.  
    (3, 0, '汤姆·赫兰德、黛茜·雷德利、麦斯·米科尔森、尼克·乔纳斯主演的《混沌漫步》公开预告。影片由《明日边缘》导演道格·里曼执导,暂时定档明年1月22日上映。', '2020-11-19 00:00:00', 1, 'http://news.mtime.com/2020/11/19/1604795.html', 'news.mtime.com', 0, 0, 0, 0, 1),
  5.  
    (4, 1, '扫地机器人这个东西确实方便,大多数时候把房间扫的比较干净,但还有很多边边角角清扫不上,希望厂家能够在app上显示出机器人的路线图,明确告知哪些路段没有照顾到,要不然就再开发一个项目经理机器人,跟在扫地机器人屁股后面监督。//@大窑儿:可以弄个步数排行榜,让机器人们互相点赞,揣摩,攀比,内卷,无意义竞争。', '2020-11-19 00:00:00', 0, '', '', 0, 0, 0, 0, 1),
  6.  
    (5, 0, '【世卫组织建议医生不要使用瑞德西韦治疗新冠】世卫组织指导小组表示,证据显示,瑞德西韦对提高新冠肺炎患者的存活率没有显著影响。这项建议发表在上周五的《英国医学杂志》中。', '2020-11-19 00:00:00', 0, 'https://www.thepaper.cn/newsDetail_forward_10067542', 'thepaper.cn', 0, 0, 0, 0, 1),
  7.  
    (6, 0, '11月19日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例17例,均为境外输入病例(福建6例,上海4例,陕西3例,广东2例,北京1例,四川1例);无新增死亡病例;新增疑似病例1例,为本土病例(在天津)。', '2020-11-19 00:00:00', 0, 'http://m.news.cctv.com/2020/11/20/ARTIIR9o72TuDF80s6hY2IvD201120.shtml', 'm.news.cctv.com', 0, 0, 0, 0, 1);

四,go代码说明

1,main.go

  1.  
    package main
  2.  
     
  3.  
    import (
  4.  
    _ "github.com/jinzhu/gorm/dialects/mysql"
  5.  
    "github.com/liuhongdi/digv01/global"
  6.  
    "github.com/liuhongdi/digv01/router"
  7.  
    "log"
  8.  
    )
  9.  
     
  10.  
    func init() {
  11.  
    err := global.SetupDBLink()
  12.  
    if err != nil {
  13.  
    log.Fatalf("init.setupDBEngine err: %v", err)
  14.  
    }
  15.  
    }
  16.  
     
  17.  
    func main() {
  18.  
    //引入路由
  19.  
    r := router.Router()
  20.  
    //run
  21.  
    r.Run(":8080")
  22.  
    }

2,router/router.go

  1.  
    package router
  2.  
     
  3.  
    import (
  4.  
    "github.com/gin-gonic/gin"
  5.  
    "github.com/liuhongdi/digv01/controller"
  6.  
    )
  7.  
     
  8.  
    func Router() *gin.Engine {
  9.  
    router := gin.Default()
  10.  
    // 路径映射
  11.  
    router.GET("/article/getone/:id", controller.NewArticleController().GetOne);
  12.  
    router.GET("/article/list", controller.NewArticleController().GetList);
  13.  
    return router
  14.  
    }

3,controller/articleController.go

  1.  
    package controller
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/gin-gonic/gin"
  6.  
    "github.com/liuhongdi/digv01/service"
  7.  
    "net/http"
  8.  
    "strconv"
  9.  
    )
  10.  
     
  11.  
    type ArticleController struct{}
  12.  
     
  13.  
    func NewArticleController() ArticleController {
  14.  
    return ArticleController{}
  15.  
    }
  16.  
    //得到一篇文章的详情
  17.  
    func (a ArticleController) GetOne(c *gin.Context) {
  18.  
     
  19.  
    id := c.Params.ByName("id")
  20.  
    fmt.Println("id:"+id);
  21.  
     
  22.  
    articleId,err := strconv.ParseInt(id, 10, 64);
  23.  
    if (err != nil) {
  24.  
    c.AbortWithStatus(400)
  25.  
    fmt.Println(err.Error())
  26.  
    }
  27.  
     
  28.  
    articleOne,err := service.GetOneArticle(articleId);
  29.  
    if err != nil {
  30.  
    c.AbortWithStatus(404)
  31.  
    fmt.Println(err.Error())
  32.  
    } else {
  33.  
    c.JSON(http.StatusOK, &articleOne)
  34.  
    }
  35.  
    return
  36.  
    }
  37.  
     
  38.  
    //得到多篇文章,按分页返回
  39.  
    func (a ArticleController) GetList(c *gin.Context) {
  40.  
     
  41.  
    page := c.DefaultQuery("page", "0")
  42.  
    pageInt, err := strconv.Atoi(page)
  43.  
    if (err != nil) {
  44.  
    c.AbortWithStatus(400)
  45.  
    fmt.Println(err.Error())
  46.  
    }
  47.  
    pageSize := 2;
  48.  
    pageOffset := pageInt * pageSize
  49.  
     
  50.  
    articles,err := service.GetArticleList(pageOffset,pageSize)
  51.  
    if err != nil {
  52.  
    c.AbortWithStatus(404)
  53.  
    fmt.Println(err.Error())
  54.  
    } else {
  55.  
    c.JSON(http.StatusOK, &articles)
  56.  
    }
  57.  
    return
  58.  
    }

4,service/article.go

  1.  
    package service
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/liuhongdi/digv01/dao"
  6.  
    "github.com/liuhongdi/digv01/model"
  7.  
    )
  8.  
    //得到一篇文章的详情
  9.  
    func GetOneArticle(articleId int64) (*model.Article, error) {
  10.  
    return dao.SelectOneArticle(articleId)
  11.  
    }
  12.  
     
  13.  
    //得到多篇文章,按分页返回
  14.  
    func GetArticleList(page int ,pageSize int) ([]*model.Article,error) {
  15.  
    articles, err := dao.SelectAllArticle(page,pageSize)
  16.  
    if err != nil {
  17.  
    fmt.Println("is error")
  18.  
    return nil,err
  19.  
    } else {
  20.  
    fmt.Println("not is error")
  21.  
    return articles,nil
  22.  
    }
  23.  
    }

5,dao/article.go

  1.  
    package dao
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "github.com/liuhongdi/digv01/global"
  6.  
    "github.com/liuhongdi/digv01/model"
  7.  
    )
  8.  
    //查询一条数据
  9.  
    func SelectOneArticle(articleId int64) (*model.Article, error) {
  10.  
    fields := []string{"articleId", "subject", "url"}
  11.  
    articleOne:=&model.Article{}
  12.  
    err := global.DBLink.Select(fields).Where("articleId=?",articleId).First(&articleOne).Error
  13.  
    if (err != nil) {
  14.  
    return nil,err
  15.  
    } else {
  16.  
    return articleOne,nil
  17.  
    }
  18.  
    }
  19.  
    //查询总数
  20.  
    func SelectcountAll() (int, error) {
  21.  
    var count int
  22.  
    err := global.DBLink.Where("isPublish=?",1).Count(&count).Error
  23.  
    if err != nil {
  24.  
    return 0, err
  25.  
    }
  26.  
    return count, nil
  27.  
    }
  28.  
    //查询多条数据
  29.  
    func SelectAllArticle(pageOffset int,pageSize int) ([]*model.Article, error) {
  30.  
    fields := []string{"articleId", "subject", "url"}
  31.  
    rows,err := global.DBLink.Select(fields).Table(model.Article{}.TableName()).Where("isPublish=?",1).Offset(pageOffset).Limit(pageSize).Rows()
  32.  
     
  33.  
    if err != nil {
  34.  
    fmt.Println("sql is error:")
  35.  
    fmt.Println(err)
  36.  
    return nil, err
  37.  
    }
  38.  
     
  39.  
    defer rows.Close()
  40.  
    var articles []*model.Article
  41.  
    for rows.Next() {
  42.  
    fmt.Println("rows.next:")
  43.  
    r := &model.Article{}
  44.  
    if err := rows.Scan(&r.ArticleId, &r.Subject, &r.Url); err != nil {
  45.  
    fmt.Println("rows.next:")
  46.  
    fmt.Println(err)
  47.  
    return nil, err
  48.  
    }
  49.  
    articles = append(articles, r)
  50.  
    }
  51.  
    return articles, nil
  52.  
    }

6,model/article.go

  1.  
    package model
  2.  
     
  3.  
    type Article struct {
  4.  
    ArticleId int64 `gorm:"column:articleId",json:"articleId"` // 自增
  5.  
    Subject string `gorm:"column:subject",json:"title"` //
  6.  
    Url string `gorm:"column:url",json:"url"`
  7.  
    ImgUrl string `json:"imgurl"`
  8.  
    HeadUrl string `json:"headurl"`
  9.  
    }
  10.  
    //返回表名
  11.  
    func (Article) TableName() string {
  12.  
    return "article"
  13.  
    }

7,global/db.go

  1.  
    package global
  2.  
     
  3.  
    import "github.com/jinzhu/gorm"
  4.  
     
  5.  
    var (
  6.  
    DBLink *gorm.DB
  7.  
    )
  8.  
    //连接到数据库
  9.  
    func SetupDBLink() error {
  10.  
    var err error
  11.  
    DBLink, err = gorm.Open("mysql", "root:password@tcp(127.0.0.1:3306)/dig?charset=utf8&parseTime=True&loc=Local")
  12.  
    if err == nil {
  13.  
    // 全局禁用表名复数
  14.  
    DBLink.SingularTable(true)
  15.  
    //打开sql日志
  16.  
    DBLink.LogMode(true)
  17.  
    return nil
  18.  
    } else {
  19.  
    return err
  20.  
    }
  21.  
    }

五,测试效果

1,一条数据:访问:

http://127.0.0.1:8080/article/getone/1

返回:

2,多条数据:访问:

http://127.0.0.1:8080/article/list?page=2

返回:

六,查看库的版本:

  1.  
    module github.com/liuhongdi/digv01
  2.  
     
  3.  
    go 1.15
  4.  
     
  5.  
    require (
  6.  
    github.com/gin-gonic/gin v1.6.3
  7.  
    github.com/jinzhu/gorm v1.9.16
  8.  
    )
原文地址:https://www.cnblogs.com/ExMan/p/14312130.html