为什么要搭建web服务
通俗来说,web服务可以为用户提供服务,最简单的例子,当你使用百度搜索数据,这个过程其实就是你把你的信息发送到百度的服务器,百度服务器接收并分析你的数据,并且给你返回你需要的数据,显示在你的页面上,这个过程就是web服务运行的过程。要实现的功能可基本总结为增删改查,我们接下来便以为校园搭建一个问答平台系统为例。
什么是Gin
Gin是一个用Go语言编写的Web框架,以其高性能、优雅和功能丰富而著称。它提供了一个极简的API来创建Web应用和API服务,同时支持中间件、路由、模板渲染、日志记录等功能。Gin的设计目标是创建一个快速且易于使用的Web框架,它特别适合用于开发RESTful API。
Gin 只是一个框架,框架就是一个工具
快速开始
- 创建一个 go 项目
- 创建
main.go并检测项目是否可以运行
- 下载并安装 Gin
$ go get -u
使用github.com/gin-gonic/gin - 启动并测试
启动:
Go run main.go
测试(在gitbash命令行中输入 curl 127.0.0.1:8080/ping ):
到这里为止,就完成了一个基础的web服务的搭建。
基础:
什么是GORM
GORM是一个快速操作数据库的Go语言工具,可以让你通过调用方法(函数)的方式对数据库进行各种操作,以代替相对复杂的sql语句。
Quick Start
- 直接下载数据库或者用docker创建一个容器
- 导入GORM库
go get -u gorm.io/gorm
go get -u gorm.io/driver/{sqlName} // {}中需要替换成你当前的sql类型
3. 连接数据库(一般使用Mysql或pgsql)
我个人使用的是Mysql数据库
func main() {
//dsn是数据库链接语句,其中包含了数据库的各种信息
dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := GORM.Open(mysql.Open(dsn), &GORM.Config{})
}
4. 声明模型
结构体的各个字段对应着数据库的各个字段,可以理解为一个结构体就相当于是一条数据库的数据。 比如我们要构建一个User结构体并存于数据库中
// 就是一个结构体
type User struct {
ID uint32 `json:"id" gorm:"primarykey"`
Username string `json:"username" gorm:"unique"`
Name string `json:"name" gorm:"unique"`
Password string `json:"password"`
Email string `json:"email"`
Hobbies *string `json:"hobbies"`
IsAdmin bool `json:"isAdmin"`
}
- 自动迁移
_ = db.AutoMigrate(&Model{}) 这行代码通常用于自动迁移数据库,确保数据库中的表结构与给定的 Go 结构体 Model 相匹配。
_ = db.AutoMigrate(&Model{})
6. 结构体查询
我们可以使用结构体作为查询条件,比如下面的一个进行用户查询的代码块,使用Where进行查询,我们对每一个块都进行类似的查询的话,可以在错误的时候快速判断错误处(如果返回了nil值便会输出错误信息)
var user User
//用户查找
if err := db.Where("username = ?", input.Username).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户无法找到!"})
return
}
7.基本的增删改查
// 创建问题API
r.POST("/questions", CreateQuestion)
// 获取问题列表API
r.GET("/questions", GetQuestion)
// 查看单个问题API
r.GET("/questions/:question_id", SingelQuestion)
// 更新问题API
r.PUT("/questions/:question_id", PutQuestion)
// 删除问题API
r.DELETE("/questions/:question_id", DeleteQuestion)
在以上的代码块中,我们对于用户的提问编写了增删改查四个区块,在Question中进行编写并引用,以下是Question中的详细内容
// Question 建立提问平台结构
type Question struct {
ID uint `json:"question_id" gorm:"primarykey"`
Title string `json:"title"`
Content string `json:"content"`
UserID uint `json:"user_id"`
CreatedAt time.Time `json:"created_at"`
}
// CreateQuestion 创建问题
func CreateQuestion(c *gin.Context) {
var question Question
if err := c.ShouldBind(&question); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "输入错误!"})
return
}
question.CreatedAt = time.Now()
//问题保存至数据库
result := db.Create(&question)
if result.Error != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "问题创建失败!"})
return
}
c.JSON(http.StatusOK, response)
}
// GetQuestion 获取问题列表
func GetQuestion(c *gin.Context) {
//创立问题列表
var question []Question
if err := db.Find(&question).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "问题获取失败!"})
return
}
c.JSON(http.StatusOK, gin.H{"questions": question})
}
// SingelQuestion 获取单个问题
func SingelQuestion(c *gin.Context) {
var question Question
id := c.Param("id")
if err := db.First(&question, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "问题未找到!"})
return
}
c.JSON(http.StatusOK, question)
}
// PutQuestion 更新问题
func PutQuestion(c *gin.Context) {
var question Question
id := c.Param("id")
if err := db.First(&question, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "问题未找到!"})
return
}
if err := c.ShouldBindJSON(&question); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "错误输入!"})
return
}
db.Save(&question)
c.JSON(http.StatusOK, gin.H{"message": "问题更新成功!"})
}
// DeleteQuestion 删除问题
func DeleteQuestion(c *gin.Context) {
var question Question
id := c.Param("id")
if err := db.Delete(&question, id).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "问题未找到"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "问题删除成功!"})
}
随意创建一条:
上文使用的物理删除,也就是彻底删除数据,在视频中我们还学到了一类Go软删除的方法,我们可以在User结构体中定义Deleted gorm.DeletedAt,这样在调用支持的Model时记录不会从数据库中真正删除。