likes
comments
collection
share

要毕业了,小学一下 Gin + Gorm

作者站长头像
站长
· 阅读数 13

长期认识并不会日积月累地成为恋爱,好比冬季每天的气候罢,你没法把今天的温度加在昨天的上面,好等明天积累成个和暖的春日。 —— 《围城》

前言

PS:为方便阅读,文末会附上最终代码,代码实现过程会在文章中体现。

2023.05.16 厚厚的云层挂在天上,挡住太阳,微风吹拂,悠然漂浮。令人悠闲、陶醉,在此情景,不学习点东西,岂不是愧对自己。

在迫切学习的心情中,开启浏览器,看了无数篇 Gin + Gorm 的文章,再无法抑制心里的冲动,于是开始落笔。

希望这篇能带给你学习的快乐,哈哈哈!

What is Gin?

  • Gin 是一种使用Go编程语言编写的Web框架,它基于HTTP/2协议设计,具有高效、快速、轻量级等特点。

  • Gin提供了路由、中间件、模板渲染、错误处理等基本功能,同时还支持插件机制,可以方便地扩展和定制。

  • Gin的设计目标是提供一个高性能的Web框架,它通过使用Go语言的高并发和协程特性,以及HTTP/2协议的优化,使得它可以处理高并发和大规模请求,并且响应速度快、资源占用少,适合用于构建高性能、可伸缩的Web应用程序。

因此,在Go语言社区中,Gin是一个非常受欢迎的Web框架之一。

Hello Gin

安装

在使用前,先要下载 Gin 包,然后在项目中导入

go get -u github.com/gin-gonic/gin

创建一个 main.go 文件,在文件中引入 Gin import "github.com/gin-gonic/gin"

基本路由

每一个接口,或者每一个页面都是一段 url 访问,要让对应的路由访问对应的方法或者页面,这里需要我们自己写逻辑代码,以常用的 POSTGET 为例:

func main() {
   ginServer := gin.Default()
   // GET方法
   ginServer.GET("/getGin", func(c *gin.Context) {
      c.JSON(200, gin.H{
         "message": "Hello Gin!",
      })
   })

   // POST方法
   ginServer.POST("/postGin", func(c *gin.Context) {
      c.JSON(200, gin.H{
         "message": "Hello Gin!",
      })
   })

   _ = ginServer.Run("127.0.0.1:8080") // 监听并在 0.0.0.0:8080 上启动服务
}

编码完成后,使用 go run main.go 执行代码,然后使用curl工具模拟请求:

要毕业了,小学一下 Gin + Gorm

可以看到结果,返回了对应的数据。但是往往在使用到接口的时候,都是一个交互性,所以需要有数据的交互,也就是接受数据,返回数据(这里返回的数据是定时的数据,暂时不考虑数据库,后面说到 gorm 会完善)。

接下来就是如何接受POST,GET上带的参数了。

解析url上的参数

Gin 官网中提供了内置方法 QueryPostForm,分别用来解析 url 上拼接的数据与 POST 请求的数据体。将 POST 方法内容修改为:

ginServer.POST("/postGin", func(c *gin.Context) {
   id := c.Query("id")
   page := c.DefaultQuery("page", "0")
   name := c.PostForm("name")
   message := c.PostForm("message")

   result := map[string]interface{}{
      "id":      id,
      "page":    page,
      "name":    name,
      "message": message,
   }

   c.JSON(200, gin.H{
      "data": result,
   })
})

接下来使用 curl -X POST --data-urlencode "name=陪我去看海吧" --data-urlencode "message=Hello Gin" "http://127.0.0.1:8080/postGin?id=1" 模拟请求,有url拼接的数据 id,也有请求体中的数据 name 和 message。

要毕业了,小学一下 Gin + Gorm

可以看到,我们传递过去的参数都成功的被解析了。

到这里,基本的用法已经掌握了,现在就像一首美妙的乐曲,音符跳跃,旋律优美,但总觉得缺少了一段高潮,那一段令人心悸的瞬间。那就是少了交互,而不是自己写这些死数据,我们要赋予数据活力,让他成为真正的数据,所以需要使用数据库,将数据存入数据库。

Q:如何连接数据库呢?

Gorm:有我呢!

What is Gorm?

GORM 是一个用于Go语言的 ORM库,它提供了一种简单且强大的方式来与数据库进行交互。通过使用GORM,您可以在Go应用程序中使用结构体(structs)来表示数据库表,并使用方法和查询语法来执行各种数据库操作。这样,您可以通过简洁的代码完成与数据库的交互,而无需手动编写大量的SQL语句。

—— 来自ChatGPT

安装

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

初始化连接

package main

import (
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
   "gorm.io/gorm/schema"
)

func main() {
   dsn := "user:password@tcp(127.0.0.1:3306)/dbName?charset=utf8mb4&parseTime=True&loc=Local"
   db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
      NamingStrategy: schema.NamingStrategy{
         SingularTable: true,
      },
   })

   if err != nil {
      panic("failed to connect database")
   }
}

在将 userpassworddbName 都替换成你自己的之后,执行main.go文件,即可连接成功。

先说说这里面配置项的作用。

各配置项作用

  • charset=utf8mb4: 这个选项指定了数据库连接的字符集。utf8mb4 是一种字符编码,支持存储和处理 Unicode 字符,包括一些特殊的表情符号和符号。

  • parseTime=True: 这个选项告诉 GORM 将数据库中的时间类型字段解析为 Go 的 time.Time 类型。默认情况下,MySQL 将时间字段作为字符串返回,而设置 parseTime=True 可以让 GORM 自动将其转换为 Go 的时间类型,便于在应用程序中进行处理和操作。

  • loc=Local: 这个选项指定了时区。在数据库操作中,时区的设置对于正确地处理时间非常重要。通过将时区设置为 Local,GORM 将使用本地系统时间,就不会出现8小时时差的问题。

  • SingularTable: true: 告诉 GORM 使用单数形式的表名。如果我们有一个名为 User 的模型,GORM 将使用表名 user 来进行数据库查询,而不是默认的 users。如果不设置,他每次查表的时候,这个名字会变成复数也就是会改变查询表名,可能会查不到表而报错。

CRUD 实现

CRUDCreate(创建)、Retrieve(读取)、Update(更新)和 Delete(删除)的缩写,它是用于描述对于持久化存储系统(如数据库)执行基本操作的常见术语。

Create(增)

接口实现:

// 新增
ginServer.POST("/label/add", func(c *gin.Context) {
   var label Label
   err := c.ShouldBindJSON(&label)
   fmt.Printf("参数:%v \n", label)
   if err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
         "message": "添加失败",
         "code":    "400",
         "data":    gin.H{},
      })
   } else {
      db.Create(&label)
      c.JSON(http.StatusOK, gin.H{
         "message": "添加成功",
         "code":    "200",
         "data":    label,
      })
   }
})

curl命令测试接口:

要毕业了,小学一下 Gin + Gorm

这里可以在你对应的数据库表里看见数据已经被添加进去了,在这里多添加几条,方便后面的测试。

Retrieve(查)

接口实现:

// 查询
ginServer.GET("/label/getAll", func(c *gin.Context) {
   var labels []Label
   result := db.Find(&labels)
   fmt.Printf("数据:%v \n", labels)
   // 查询条数,如果为0,则说明表为空
   if result.Error == nil {
      c.JSON(http.StatusOK, gin.H{
         "message": "查询成功",
         "code":    200,
         "data":    labels,
      })
   } else {
      c.JSON(http.StatusBadGateway, gin.H{
         "message": "查询报错",
         "code":    500,
         "data":    gin.H{},
      })
   }
})

curl接口测试:

要毕业了,小学一下 Gin + Gorm

Update(改)

接口实现:

// 修改
ginServer.PUT("/label/update/:id", func(c *gin.Context) {
   var label Label
   id := c.Param("id")

   findResult := db.First(&label, id)
   if findResult.RowsAffected > 0 {
      err := c.ShouldBindJSON(&label)
      if err != nil {
         c.JSON(http.StatusBadRequest, gin.H{
            "message": "修改失败",
            "code":    400,
            "data":    gin.H{},
         })
      } else {
         db.Where("id = ?", id).Updates(&label)
         c.JSON(http.StatusOK, gin.H{
            "message": "修改成功",
            "code":    200,
            "data":    label,
         })
      }
   } else {
      c.JSON(http.StatusBadRequest, gin.H{
         "message": "没有匹配的id",
         "code":    400,
         "data":    gin.H{},
      })
   }
})

curl测试接口:

要毕业了,小学一下 Gin + Gorm

Delete(删)

接口实现:

// 删除
ginServer.DELETE("/label/delete/:id", func(c *gin.Context) {
   var label Label
   id := c.Param("id")
   deleteResult := db.Delete(&label, id)

   if deleteResult.RowsAffected > 0 {
      c.JSON(http.StatusOK, gin.H{
         "message": "删除成功",
         "code":    200,
         "data":    gin.H{},
      })
   } else {
      c.JSON(http.StatusBadRequest, gin.H{
         "message": "无该条数据,删除失败",
         "code":    400,
         "data":    gin.H{},
      })
   }
})

curl 测试接口:

要毕业了,小学一下 Gin + Gorm

整体代码

// main.go
package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
   "gorm.io/gorm/schema"
   "net/http"
)

func main() {
   dsn := "root:123456@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
   db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
      NamingStrategy: schema.NamingStrategy{
         SingularTable: true,
      },
   })

   if err != nil {
      panic("failed to connect database")
   }

   type Label struct {
      ID    uint   `gorm:"primaryKey"`
      Label string `gorm:"column:label_title"`
   }

   // 接口
   ginServer := gin.Default()
   // 新增
   ginServer.POST("/label/add", func(c *gin.Context) {
      var label Label
      err := c.ShouldBindJSON(&label)
      fmt.Printf("参数:%v \n", label)
      if err != nil {
         c.JSON(http.StatusBadRequest, gin.H{
            "message": "添加失败",
            "code":    "400",
            "data":    gin.H{},
         })
      } else {
         db.Create(&label)
         c.JSON(http.StatusOK, gin.H{
            "message": "添加成功",
            "code":    "200",
            "data":    label,
         })
      }
   })

   // 删除
   ginServer.DELETE("/label/delete/:id", func(c *gin.Context) {
      var label Label
      id := c.Param("id")
      deleteResult := db.Delete(&label, id)

      if deleteResult.RowsAffected > 0 {
         c.JSON(http.StatusOK, gin.H{
            "message": "删除成功",
            "code":    200,
            "data":    gin.H{},
         })
      } else {
         c.JSON(http.StatusBadRequest, gin.H{
            "message": "无该条数据,删除失败",
            "code":    400,
            "data":    gin.H{},
         })
      }
   })

   // 修改
   ginServer.PUT("/label/update/:id", func(c *gin.Context) {
      var label Label
      id := c.Param("id")

      findResult := db.First(&label, id)
      if findResult.RowsAffected > 0 {
         err := c.ShouldBindJSON(&label)
         if err != nil {
            c.JSON(http.StatusBadRequest, gin.H{
               "message": "修改失败",
               "code":    400,
               "data":    gin.H{},
            })
         } else {
            db.Where("id = ?", id).Updates(&label)
            c.JSON(http.StatusOK, gin.H{
               "message": "修改成功",
               "code":    200,
               "data":    label,
            })
         }
      } else {
         c.JSON(http.StatusBadRequest, gin.H{
            "message": "没有匹配的id",
            "code":    400,
            "data":    gin.H{},
         })
      }
   })

   // 查询
   ginServer.GET("/label/getAll", func(c *gin.Context) {
      var labels []Label
      result := db.Find(&labels)
      fmt.Printf("数据:%v \n", labels)
      // 查询条数,如果为0,则说明表为空
      if result.Error == nil {
         c.JSON(http.StatusOK, gin.H{
            "message": "查询成功",
            "code":    200,
            "data":    labels,
         })
      } else {
         c.JSON(http.StatusBadGateway, gin.H{
            "message": "查询报错",
            "code":    500,
            "data":    gin.H{},
         })
      }
   })

   _ = ginServer.Run("127.0.0.1:8080") // 监听并在 0.0.0.0:8080 上启动服务
}

为了方便,所有的代码都放在了 main.go 中。

总结

  • gin 写接口非常简洁,内置了POST、GET、PUT、DELETE等方法
  • gorm 中可以使用封装的方法简化 sql 语句,也可以使用原生 sql 语句来执行
  • gorm 中每一个结构体都可以表示一张表结构
  • curl可以用来请求web服务器,功能很强大,使用熟练,在一些小地方调试更快,更方便

结束语

交谈终至,以文字相遇,也以文字结束。感谢相遇,文字对面的独一无二的你!

转载自:https://juejin.cn/post/7233720373236645948
评论
请登录