参考了www.bilibili.com/video/BV1aB…
1.项目目标
我们的目标是通过gin+gorm实现数据库的增删改查,也就是CRUD(create,read,update,delete),并使用postman去检测我们端口的设计成功与否。 该文档的目的旨在将项目构建的方式及其思考方式全程搭建起来。 tips:随时查看gin和gorm的文档,有清晰且完整的中文教程。
2.项目思路
1.该项目是在goland本地运行,故必须先满足依赖需求,如mysql以及数据库操作软件,我这里使用的是DBeaver去检查和操作数据库情况。 2.该项目是由gin+gorm编写的,建议提前下好库以及gorm关于mysql的依赖。且记得提前创建数据库表。 3.创建web服务器,再进行绑定数据库db。 4.使用RESTful模式去编写端口,设置post,delete,put,get几个方法,并一步一步的去实现他。
3.项目过程
1.创建webapp
所有的事情都从这里开始,我们首先创建web服务器,使用gin.Default()我们可以直接定义web服务器,再通过r.Run()进行运行。
package main
import (
"fmt"
"net/http"
"strconv"
"time"
"gorm.io/gorm/schema"
"github.com/gin-gonic/gin"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
r := gin.Default()
port := "3113"
r.Run(":" + port) // 运行webapp
}
2.连接数据库
在进行数据库的连接前,我们得进行Model的创建。一般推荐先进行Model的创建,这样使用起来更方便。其中Model里设置传入json的key。
type List struct {
gorm.Model //id,created_at,updated_at
Name string `json:"Name"`
Status string `json:"Status"`
Phone string `json:"Phone"`
Email string `json:"Email"`
Address string `json:"Address"`
}
接下来在main函数里进行数据库的连接
// Connect DateBase
dsn := "root:Csd123456,@tcp(127.0.0.1:3306)/crud_sample?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{ // 把单数表创建开启,即表创建出来是list而不是lists
SingularTable: true,
},
})
fmt.Println(db)
fmt.Println(err)
// 以下代码复制于https://gorm.io/zh_CN/docs/connecting_to_the_database.html
sqlDB, err := db.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)
// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(10 * time.Second) // 十秒钟
// 绑定数据库
db.AutoMigrate(&List{})
以下是重中之重,其中password是你数据库的密码,而crud_sample是你刚创建的数据库。
dsn := "root:password@tcp(127.0.0.1:3306)/crud_sample?charset=utf8mb4&parseTime=True&loc=Local"
此时我们运行程序,打开数据库软件,会发现出现表已经创建。 接下来我们在main函数进行测试
// no route will run
r.NoRoute(func(c *gin.Context) {
// 实现内部重定向
c.HTML(http.StatusOK, "404.html", gin.H{
"title": "404",
})
})
// test
r.GET("/test", func(c *gin.Context) {
c.JSON(200, "success")
})
接下来我们使用postman发送get请求到127.0.0.1:3113/test 显示success,证明我们的路由也没问题。 ####
3.进行GET方式的实现
实现get方法的思路:
1.使用ShouldBindJSON函数将传来的参数传入data之中。 2.写好错误解释方式 ,当返回无错误时,使用db.Create()去创建data数据。 3.返回json数据用以显示成功。
// add
r.POST("/usr/add", func(c *gin.Context) {
var data List
err := c.ShouldBindJSON(&data)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"message": err.Error(),
"data": gin.H{},
"code": "400",
})
} else {
db.Create(&data) //create a line in the database
c.JSON(200, gin.H{
"message": "success",
"data": data,
"code": http.StatusOK,
})
}
})
在postman进行检测,使用post访问127.0.0.1:3113/usr/add。 进行body的编写,用以传入数据。 此时我们能在我们数据库软件中查看到我们新增的数据。
4.进行DELETE方式的实现
实现delete的思路
1.在delete中我们通过对id的访问去删除数据,所以我们先要使用c.Param获取url所给的id,即是:id。 2.使用db.Where("id=?", id).Find(&data)去访问数据库中所符合的id。 3.再排除无该id的索引后,我们使用Delete方法去实现该条data的删除。,并使用c.JSON返回成功信息。
// delete
r.DELETE("/usr/delete/:id", func(c *gin.Context) {
var data []List
// accept id
id := c.Param("id")
db.Where("id=?", id).Find(&data)
if len(data) == 0 { // if not found id
c.JSON(200, gin.H{
"message": "delete failed,not found id",
"code": "400",
})
} else {
db.Where("id=?", id).Delete(&data)
c.JSON(200, gin.H{
"message": "delete succeeded",
"code": "200",
})
}
})
打开postman,找到delete方法,在url输入127.0.0.1:3113/usr/delete/1,我们就删除刚创建的数据。 但由于我们orm使用的是软删除,其可能仍能在数据库中显示,但其列表中显示了删除时间。
5.进行PUT方式的实现
我们先使用POST请求多创建几条数据方便我们PUT和GET。
实现put的思路
1.我们延续我们DELETE中的思路通过c.Param去接收id号。 2.在排除错误情况后,我们使用ShouldBindJSON将接受的body传入data中。 3.我们通过db.where方法查询id所在数据,并使用Update方法去将传入的数据体中。 4.返回显示成功的json
// put
r.PUT("/usr/update/:id", func(c *gin.Context) {
var data List
// accept id
id := c.Param("id")
db.Select("id").Where("id=?", id).Find(&data)
if data.ID == 0 { // if not found id
c.JSON(200, gin.H{
"message": "Put failed,not found id",
"code": "400",
})
} else { // ID is already
err := c.ShouldBindJSON(&data)
if err != nil {
// put failed
c.JSON(200, gin.H{
"message": "put failed",
"code": "400",
})
} else {
db.Where("id = ?", "id").Updates(&data)
c.JSON(http.StatusOK, gin.H{
"message": "put succeeded",
"code": "200",
})
}
}
})
让我们打开postman来检测一下。创建新的request,设置method为PUT,url为127.0.0.1:3113/usr/update/2 输入自己手写的body,打开数据库我们会发现我们第二条数据已被修改。
5.进行GET方式的实现-1
为什么要将GET方式分两种讨论,因为这就涉及我们会有请求单条数据或查看很多数据的两种方式。我们首先实现的是请求单条数据。
实现get的思路-1
1.我们首先想到的是使用name来请求数据的显示,也就是zhangsan,lisi,wangwu这种。延续之前的思路使用c.Param去接收数据。 2.我们也和之前一样使用db.Where("name=?", name).Find(&data)去寻找数据,并用Find绑定到data上。 3.排除错误,并返回查询的数据。
// get
// use name to get conditions
r.GET("/usr/list/:name", func(c *gin.Context) {
name := c.Param("name")
var data []List // find datalists
db.Where("name=?", name).Find(&data)
if len(data) == 0 {
c.JSON(200, gin.H{
"message": "not found",
"code": "400",
"data": gin.H{},
})
} else {
c.JSON(200, gin.H{
"message": "get successfully",
"code": "200",
"data": data,
})
}
})
接下来我们仍然打开post进行测试。找到GET方法,输入127.0.0.1:3113/usr/list/wangwu,来查询我们在之前输入的数据。
6.进行GET方式的实现-2
接下来我们实现按页查询或查询所有数据.
实现get的思路-2
1.我们首先实现是将所有的数据进行展示db.Model(datalist).Count(&total).Limit(-1).Offset(-1).Find(&datalist),通过将Limit和Offset设置为-1,我们访问了数据库中所有的数据并传入在datalist中。 2.随后我们就像第一个get请求一样进行数据的表出。 3.我们此时又想到我们得进行分页管理,便设置了pageSize为页面大小,显示几条数据,pageNum是第几个页面。 4.将Limit参数和Offset参数进行更改,得到如下的代码。 5.由于pageSize和pageNum默认为0,设置pageSize和pageNum为0时为-1,这将展示所有的数据。
// get all or get by page
r.GET("/usr/list", func(c *gin.Context) {
var datalist []List
pageSize, _ := strconv.Atoi(c.Query("pageSize")) //use strconv.Atoi here to make string to int
pageNum, _ := strconv.Atoi(c.Query("pageNum"))
if pageSize == 0 { // if no pageSize or pageNum, show all page
pageSize = -1
}
if pageNum == 0 {
pageNum = -1
}
// get all data
var total int64
db.Model(datalist).Count(&total).Limit(pageSize).Offset(pageNum).Find(&datalist)
if len(datalist) == 0 {
c.JSON(200, gin.H{
"message": "get failed,no data",
"code": "400",
"data": gin.H{},
})
} else {
c.JSON(200, gin.H{ //return datalist json response
"message": "get succeed",
"code": "200",
"data": gin.H{
"list": datalist,
"total": total,
"pageNum": pageNum,
"pageSize": pageSize,
},
})
}
})
打开postman,url输入127.0.0.1:3113/usr/list进行检测。 我们可以在postman的Params中设置参数,传入pageNum和pageSize,其会自动修改请求来达到你的要求。 当我们send后会在下面显示你所想展示的数据。
以上,所有的功能实现完成。