说明

基于 gin + gorm

源项目仓库地址:Q1mi - bubble

仓库地址:xxcheng - todo

目录结构

|-- conf 配置文件
|   |-- config.go
|   |-- config.ini
|   `-- config.ini.example
|-- controller 控制
|   `-- controller.go
|-- dao 接口
|   `-- mysql.go
|-- go.mod
|-- go.sum
|-- main.go 入口
|-- models 模型
|   `-- todo.go
|-- readme.md
|-- routers 路由
|   `-- routers.go
|-- static 静态资源
|   |-- css
|   |-- fonts
|   `-- js
`-- templates HTML模板
    |-- favicon.ico
    `-- index.html

准备工作

创建数据库

CREATE DATABASE go_todo;

安装依赖

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
go get -u gopkg.in/ini.v1

步骤拆分

持久化处理

dao/mysql.go

package dao

// ...

var (
    DB *gorm.DB
)

func InitMySQL(cfg *conf.MySQLConfig) (err error) {
    dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
        cfg.User,
        cfg.Password,
        cfg.Host,
        cfg.Port,
        cfg.DatabaseName,
    )
    DB, err = gorm.Open(mysql.Open(dsn))
    if err == nil {
        return
    }

    return err

}

实体封装

ORM 模型

models/todo.go

type Todo struct {
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt gorm.DeletedAt `gorm:"index"`
    ID        uint           `json:"id" gorm:"primarykey"`
    Title     string         `json:"title"`
    Status    bool           `json:"status"`
}

操作

models/todo.go

package models

// 添加
func AddTodo(todo *Todo) (err error) {
    return dao.DB.Create(&todo).Error
}
// 修改
func ModifyTodo(todo *Todo) (err error) {
    return dao.DB.Save(&todo).Error
}
// 删除
func DeleteTodo(ID string) (err error) {
    return dao.DB.Delete(&Todo{}, ID).Error
}
// 查询所有
func GetAllTodos() (todos []*Todo, err error) {
    err = dao.DB.Find(&todos).Error
    return todos, err
}
// 查询
func GetTodo(ID string) (todo *Todo, err error) {
    todo = new(Todo)
    err = dao.DB.First(&todo, ID).Error
    return todo, err
}

控制交互

controller/controller.go

package controller

type Todo = models.Todo

// 首页请求
func IndexHandle(ctx *gin.Context) {
    ctx.HTML(200, "index.html", nil)
}
// 增加 请求
func AddTodo(ctx *gin.Context) {
    var todo Todo
    ctx.BindJSON(&todo)
    if err := models.AddTodo(&todo); err != nil {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": err,
        })
    } else {
        ctx.JSON(200, gin.H{
            "code":    0,
            "message": "success",
            "data":    &todo,
        })
    }
}
//更新 请求
func UpdateTodo(ctx *gin.Context) {
    ID, isExist := ctx.Params.Get("id")
    if !isExist {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": "id字段未提供~",
        })
        return
    }
    todo, err := models.GetTodo(ID)
    if err != nil {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": err,
        })
        return
    }
    ctx.BindJSON(&todo)
    err = models.ModifyTodo(todo)
    if err != nil {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": err,
        })
        return
    }
    ctx.JSON(200, gin.H{
        "code": 0,
        "data": todo,
    })
}
// 删除 请求
func DeleteTodo(ctx *gin.Context) {
    ID, isExist := ctx.Params.Get("id")
    if !isExist {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": "id字段未提供~",
        })
        return
    }
    err := models.DeleteTodo(ID)
    if err != nil {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": err,
        })
        return
    }
    ctx.JSON(200, gin.H{
        "code": 0,
    })
}
// 获取所有记录 请求
func GetAllTodos(ctx *gin.Context) {
    if todos, err := models.GetAllTodos(); err != nil {
        ctx.JSON(200, gin.H{
            "code":    1,
            "message": err,
        })
    } else {
        ctx.JSON(200, todos)
    }
}

路由处理

加载模板、加载静态资源、路由注册

routers/routers.go

package routers

func SetupRputer() *gin.Engine {
    r := gin.Default()
    //加载模板
    r.LoadHTMLGlob("templates/*")
    //加载静态资源
    r.Static("/static", "static")
    r.GET("/", controller.IndexHandle)

    v1Group := r.Group("/v1")
    {
        //提交新的
        v1Group.POST("/todo", controller.AddTodo)
        //获取全部
        v1Group.GET("/todo", controller.GetAllTodos)
        //更新
        v1Group.PUT("/todo/:id", controller.UpdateTodo)
        //删除
        v1Group.DELETE("/todo/:id", controller.DeleteTodo)
    }
    return r
}

其他

配置模板

conf/config.go

package conf


var Conf = new(ApplicationConfig)

type ApplicationConfig struct {
    Port         uint16 `ini:"port"`
    *MySQLConfig `ini:"mysql"`
}

type MySQLConfig struct {
    User         string `ini:"user"`
    Password     string `ini:"password"`
    Host         string `ini:"host"`
    Port         uint16 `ini:"port"`
    DatabaseName string `ini:"dbName"`
}

func Init(file string) error {
    return ini.MapTo(Conf, file)
}

配置文件

config/config.ini

port=19999

[mysql]
user=root
password=jpc0519Qcloud
host=host
port=port
dbName=dbName

入口 & 启动

main.go

const defaultConfFile = "./conf/config.ini"

func main() {
    conf.Init(defaultConfFile)
    //连接数据库
    dao.InitMySQL(conf.Conf.MySQLConfig)
    //绑定模型
    r := routers.SetupRputer()
    dao.DB.AutoMigrate(&models.Todo{})
    r.Run(fmt.Sprintf(":%d", conf.Conf.Port))
}

运行效果

首次访问

image-20230731175901036

添加数据

image-20230731175944434

更新状态

image-20230731180019955

删除

image-20230731180035366

文章目录