GO框架三件套 (后端实践)| 豆包MarsCode AI刷题

154 阅读4分钟

为什么要搭建web服务

通俗来说,web服务可以为用户提供服务,最简单的例子,当你使用百度搜索数据,这个过程其实就是你把你的信息发送到百度的服务器,百度服务器接收并分析你的数据,并且给你返回你需要的数据,显示在你的页面上,这个过程就是web服务运行的过程。要实现的功能可基本总结为增删改查,我们接下来便以为校园搭建一个问答平台系统为例。

什么是Gin

Gin是一个用Go语言编写的Web框架,以其高性能、优雅和功能丰富而著称。它提供了一个极简的API来创建Web应用和API服务,同时支持中间件、路由、模板渲染、日志记录等功能。Gin的设计目标是创建一个快速且易于使用的Web框架,它特别适合用于开发RESTful API。

Gin 只是一个框架,框架就是一个工具

快速开始

  1. 创建一个 go 项目

  1. 创建 main.go 并检测项目是否可以运行

  1. 下载并安装 Gin $ go get -u
    使用github.com/gin-gonic/gin
  2. 启动并测试

启动:

Go run main.go

测试(在gitbash命令行中输入 curl 127.0.0.1:8080/ping ):

到这里为止,就完成了一个基础的web服务的搭建。

基础:

什么是GORM

GORM是一个快速操作数据库的Go语言工具,可以让你通过调用方法(函数)的方式对数据库进行各种操作,以代替相对复杂的sql语句。

Quick Start

  1. 直接下载数据库或者用docker创建一个容器
  2. 导入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"`
}

  1. 自动迁移

_ = 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": "问题删除成功!"})
}

随意创建一条:

image.png

上文使用的物理删除,也就是彻底删除数据,在视频中我们还学到了一类Go软删除的方法,我们可以在User结构体中定义Deleted gorm.DeletedAt,这样在调用支持的Model时记录不会从数据库中真正删除。