likes
comments
collection
share

Golang-Todolist

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

前言

作为一名前端工程师,我个人觉得有必要去学一门后端语言,目前的行情越来越差,可能对全栈工程师更加友好一点,毕竟老板可以用一个人的钱,招来两个人,当然了前后端都自己包揽的话确实压力有点大,所以学习后端可以使我们在前端招聘中与竞争对手拉开差距,废话不多说,开搞!

我也是初学者勿喷,有什么问题可以在评论区探讨,谢谢

所需

  1. 首先必须安装GO GO下载链接
  2. Goland编译器 Goland下载链接
  3. MysqlMysql下载链接
  4. 最好有一点nodejs写接口的经验 这样学起来还是很轻松的

需求

做一个增删改查的 Todolist 不要小看一个 Todolist 这里涵盖着业务中最常见的 crud 通过这一个简单的例子来上手Go语言

分析

首先我们需要把整体架构设计出来,也就是把文件目录先创建好,然后在对应文件夹下书写我们的业务代码,我们可以把整体项目拆分成四个模块

  1. 数据库模块
  2. 数据库表结构模块
  3. Controller模块 (接收客户端发送的请求并执行对应的回调函数,暂时可以这么理解)
  4. Service模块 (与数据库进行交互)
todolist/ 
  └── server/ 
    └── db/ 
      └── mysql.go
    └── model/ 
      └── todolist.go
    └── controller/ 
      └── todolist.go
    └── service/ 
      └── todolist.go
    main.go // 入口文件

这个就是我们最终的文件结构

开发

我们把模块已经拆分好了,在各自文件夹开发就好了

基础配置

在核心功能开发前,我们还需要把基础服务搭建起来

安装开启本地服务的依赖

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

开启本地服务

// 设置响应头允许跨域
func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
       c.Header("Access-Control-Allow-Origin", "*")
       c.Header("Access-Control-Allow-Headers", "Content-Type")
       c.Header("Access-Control-Allow-Methods", "GET,POST")

       if c.Request.Method == "OPTIONS" {
          c.JSON(http.StatusOK, "")
          c.Abort()
          return
       }

       c.Next()
    }
}

func main() {
    r := gin.Default()
    r.Use(Cors())

    if err := r.Run(":8080"); err != nil {
       fmt.Printf("Server is failed running at 8080")
    }
}

定义数据库表结构

model/todolist.go 中编写

package model

import (
    "database/sql"
    "time"
)
// gorm给我们提供的默认字段
type GormModel struct {
    ID        uint         `json:"id" gorm:"primarykey"`
    CreatedAt time.Time    `json:"created_at"`
    UpdatedAt time.Time    `json:"updated_at"`
    DeletedAt sql.NullTime `json:"deleted_at" gorm:"index"`
}

// todolist的表结构
type Todolist struct {
    GormModel
    Content     string `json:"content"`
    IsCompleted bool   `json:"is_completed"`
}

json:"XXX"代表这个字段在JSON格式中字段名,因为平时的习惯都是以小写开头,但是因为go语言的原因, 包与包之间,只能调用以大写开头的,否则无法使用外部成员

连接mysql

db/mysql.go 中编写,这次使用的是gorm进行数据库的连接 官方文档

首先安装依赖

go get -u gorm.io/gorm

Golang-Todolist

package db

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

func Connect(dbName string) *gorm.DB {
    // refer https://github.com/go-sql-driver/mysql#dsn-data-source-name for details
    // user pass 填入你mysql的账号密码
    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{})

    if err != nil { // 处理错误
       panic(err.Error())
    }

    return db
}

这样我们就得到了数据库的实例对象,可以开始操作数据库啦,不过在操作数据库前,还需要在入口文件进行配置噢~

在 main.go 中编写

db.AutoMigrate把我们先前定义的表结构传递进去model/todolist.go中的Todolist,那么我们启动服务后,数据库就会创建一张表出来了

// 设置响应头允许跨域
func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
       c.Header("Access-Control-Allow-Origin", "*")
       c.Header("Access-Control-Allow-Headers", "Content-Type")
       c.Header("Access-Control-Allow-Methods", "GET,POST")

       if c.Request.Method == "OPTIONS" {
          c.JSON(http.StatusOK, "")
          c.Abort()
          return
       }

       c.Next()
    }
}

func main() {

    r := gin.Default()
    // 连接表名为study的数据库
    db := db.Connect("study")
    // 建立数据库映射表
    db.AutoMigrate(&model.Todolist{})
    // 使用中间件
    r.Use(Cors())

    if err := r.Run(":8080"); err != nil {
       fmt.Printf("Server is failed running at 8080")
    }
}

我们可以通过运行main函数来调试我们的代码是否成功

Golang-Todolist

成功的示例: (这里我使用的是navicat)

Golang-Todolist

数据库中会多了一张todolist表,里面的字段跟我们写的表结构是一一对应的,如果你们的情况跟我一样证明已经成功了!恭喜!!!

编写sql

service/mysql.go 中编写,这里我们把增删改查的方法写好供外面使用

这里就不一一赘述了,可能会有点啰嗦,大概解释一下数据库实例的方法,详情可以到gorm官方文档查看

  1. Order 排序
  2. Find 把我们创建的属性引用传递进去,我们就可以得到查询出来的数据
  3. Create 添加
  4. Model 传递定义的表结构 指定表查询
  5. Where 根据关键词查询
  6. Update 修改/更新
  7. Select 选择属性
  8. Scan 将搜索到的值 赋值到我们传递进去的属性 与Find类似
  9. ...
package service

import (
    "gorm.io/gorm"
    "server/server/model"
)

type Todolist struct {
    *gorm.DB
}

func (list *Todolist) GetList() []model.Todolist {
    var todos []model.Todolist
    list.Order("id desc").Find(&todos)

    return todos
}

func (list *Todolist) AddTodo(content string) model.Todolist {
    var todo = model.Todolist{
       Content:     content,
       IsCompleted: false,
    }

    list.Create(&todo)
    return todo
}

func (list *Todolist) ToggleTodo(id uint) uint {
    var completed bool
    list.Model(&model.Todolist{}).Where("id = ?", id).Select("is_completed").Scan(&completed)
    list.Model(&model.Todolist{}).Where("id = ?", id).Update("is_completed", !completed)

    return id
}

func (list *Todolist) DeleteTodo(id uint) uint {
    list.Delete(&model.Todolist{}, id)

    return id
}

编写controller

  1. Todolist 里面包含了所有增删改查的数据库操作
  2. PostBody 是Post请求体的类型,后面用于获取请求体数据
  3. ShouldBindJSON 是一个函数我们把定义好的结构传入,即可获得请求体的数据
type Todolist struct {
    service.Todolist
}

type PostBody struct {
    Id      uint
    Content string
}

func (list *Todolist) List(c *gin.Context) {
    todos := list.GetList()
    c.JSON(http.StatusOK, gin.H{
       "code": 200,
       "msg":  "ok",
       "data": todos,
    })
}

func (list *Todolist) Add(c *gin.Context) {
    var body PostBody
    c.ShouldBindJSON(&body)
    todo := list.AddTodo(body.Content)
    fmt.Println("body", body)
    fmt.Println("todo", todo)

    c.JSON(http.StatusOK, gin.H{
       "code": 200,
       "msg":  "ok",
       "data": todo,
    })

}

func (list *Todolist) Toggle(c *gin.Context) {
    var body PostBody
    c.ShouldBindJSON(&body)

    id := list.ToggleTodo(body.Id)
    c.JSON(http.StatusOK, gin.H{
       "code": 200,
       "msg":  "ok",
       "data": id,
    })
}

func (list *Todolist) Delete(c *gin.Context) {
    var body PostBody
    c.ShouldBindJSON(&body)

    id := list.DeleteTodo(body.Id)
    c.JSON(http.StatusOK, gin.H{
       "code": 200,
       "msg":  "ok",
       "data": id,
    })
}

处理请求

回到我们的 main.go 入口文件,把增删改查的接口定义好

这里我们做的就是依赖注入

  • service是操作数据库的所以依赖数据库实例,我们只需要把db传入即可
  • controller就是依赖service中的方法,所以传入todolistService
// main.go

...
// service
todolistService := service.Todolist{
    DB: db,
}

// controller
todolistController := controller.Todolist{
    Todolist: todolistService,
}

// 获取列表
r.GET("/list", todolistController.List)
// 添加
r.POST("/add", todolistController.Add)
// 切换完成状态
r.POST("/toggle", todolistController.Toggle)
// 删除
r.POST("/delete", todolistController.Delete)

...

测试

这里我使用的是postman进行接口的测试

  1. list 通过访问 localhost:8080/list 得到我们所有的结果,目前为空

Golang-Todolist

  1. add 通过访问 localhost:8080/add 记得选择POST请求

Golang-Todolist

数据库中就多了一条记录 Golang-Todolist

  1. toggle 通过访问 localhost:8080/toggle 记得选择POST请求

Golang-Todolist

  1. delete 通过访问 localhost:8080/delete 记得选择POST请求

Golang-Todolist

如果结果跟我一样的话,证明你已经掌握了简单的 crud 啦

结尾

如果有以下问题或其他问题可以在评论区询问我哦~!

  1. Goland编译器无法运行代码
  2. Goland无法安装依赖
  3. Go安装失败
  4. ......