gorm/gin框架实战

gorm/gin框架实战

项目简介

学习源视频:【最新Go Web开发教程】基于gin框架和gorm的web开发实战 (七米出品)_哔哩哔哩_bilibili

本博客为我的学习笔记。

项目目标:实现一个备忘录工具(当然不支持alert),仅仅是可以记录待办事项。

实现了:添加待办项、删除待办项、完成待办项、查询待办项

项目主页展示:

image-20240603161443744

添加、查询待办项展示:

image-20240603161731924

删除待办项展示:

image-20240603163615841

项目框架

可以看看之前同专栏的博客,这是一个很基本的框架

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"net/http"
)

type Todo struct {
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Status bool   `json:"status"`
}

var (
	DB *gorm.DB
)

func initMySQL() (err error) {
	
}

func main() {
	//连接数据库
	err := initMySQL()
	if err != nil {
		panic(err)
	}
	defer DB.Close() //关闭数据库连接
	//模型绑定
	DB.AutoMigrate(&Todo{})
	r := gin.Default()
	//设置静态资源文件
	r.Static("/static", "static")
	// 设置gin框架模版文件
	r.LoadHTMLGlob("templates/*")

	//设置路由
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	//设置路由组
	v1Group := r.Group("/v1")
	{
		//添加一个事项
		v1Group.POST("/todo", func(c *gin.Context) {
			
		})
		//查看一个事项
		v1Group.GET("/todo/:id", func(c *gin.Context) {

		})
		//查看所有事项
		v1Group.GET("/todo/", func(c *gin.Context) {
			
		})
		//修改一个事项
		v1Group.PUT("/todo/:id", func(c *gin.Context) {

		})
		//删除一个事项
		v1Group.DELETE("/todo/:id", func(c *gin.Context) {

		})
	}
	r.Run()
}

接口填充

数据库连接

DB, err = gorm.Open("mysql", "usr1:12345@tcp(***:3306)/db1?charset=utf8&parseTime=True&loc=Local")
if err != nil {
    panic(err)
}
return DB.DB().Ping()

添加一个事项

v1Group.POST("/todo", func(c *gin.Context) {
    //前端页面填写待办事项,点击提交,会发送请求到这
    //1.从请求中把数据拿出来
    var todo Todo
    c.BindJSON(&todo)
    fmt.Println(todo)
    //2.存入数据库 + 3.返回响应
    if err = DB.Create(&todo).Error; err != nil {
        c.JSON(http.StatusOK, gin.H{
            "error": err.Error(),
        })
    } else {
        c.JSON(http.StatusOK, todo)
    }
})

查看所有事项

//查看一个事项
v1Group.GET("/todo/:id", func(c *gin.Context) {
    //...一般用不到
})
//查看所有事项
v1Group.GET("/todo/", func(c *gin.Context) {
    var todoList []Todo

    if err = DB.Find(&todoList).Error; err != nil {
        c.JSON(http.StatusOK, gin.H{
            "error": err.Error(),
        })
    } else {
        fmt.Println(todoList)
        c.JSON(http.StatusOK, todoList)
    }
})

修改一个事项

//修改一个事项
v1Group.PUT("/todo/:id", func(c *gin.Context) {
    id, ok := c.Params.Get("id")
    if !ok {
        c.JSON(http.StatusOK, gin.H{
            "error": "无效的id",
        })
        return
    }
    var todo Todo
    if err = DB.Where("id=?", id).First(&todo).Error; err != nil {
        c.JSON(http.StatusOK, gin.H{
            "error": err.Error(),
        })
    } else {
        c.BindJSON(&todo)
        if err = DB.Save(&todo).Error; err != nil {
            c.JSON(http.StatusOK, gin.H{
                "error": err.Error(),
            })
        } else {
            c.JSON(http.StatusOK, todo)
        }
    }
})

删除一个事项

//删除一个事项
v1Group.DELETE("/todo/:id", func(c *gin.Context) {
    id, ok := c.Params.Get("id")
    if !ok {
        c.JSON(http.StatusOK, gin.H{
            "error": "无效的id",
        })
        return
    }
    if err = DB.Where("id=?", id).Delete(Todo{}).Error; err != nil {
        c.JSON(http.StatusOK, gin.H{
            "error": err.Error(),
        })
    } else {
        c.JSON(http.StatusOK, gin.H{
            id: "delete",
        })
    }
})

ApiPost接口测试

添加接口

image-20240603165318647

image-20240603165544890

查看接口

image-20240603165337290

修改接口

image-20240603165451043

删除接口

image-20240603165524808

image-20240603165617457

企业级项目划分

1.controller

控制器:控制路由进来后执行的函数

package controller

import (
	"fmt"
	"gin_demo_BubbleList/models"
	"github.com/gin-gonic/gin"
	"net/http"
)

/*
url -> controller -> logic -> model
请求 -> 控制器 -> 业务逻辑 -> 模型层的增删改查
*/
func IndexHandler(c *gin.Context) {
	c.HTML(http.StatusOK, "index.html", nil)
}

func Create(c *gin.Context) {
	//前端页面填写待办事项,点击提交,会发送请求到这
	//1.从请求中把数据拿出来
	var todo models.Todo
	c.BindJSON(&todo)
	fmt.Println(todo)
	//2.存入数据库 + 3.返回响应
	err := models.CreateTodo(&todo)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
	} else {
		c.JSON(http.StatusOK, todo)
	}
	//if err = DB.Create(&todo).Error; err != nil {
	//	c.JSON(http.StatusOK, gin.H{
	//		"error": err.Error(),
	//	})
	//} else {
	//	c.JSON(http.StatusOK, todo)
	//}
}

func GetTodoList(c *gin.Context) {
	todoList, err := models.GetTodoList()
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
	} else {
		fmt.Println(todoList)
		c.JSON(http.StatusOK, todoList)
	}
	//if err = DB.Find(&todoList).Error; err != nil {
	//	c.JSON(http.StatusOK, gin.H{
	//		"error": err.Error(),
	//	})
	//} else {
	//	fmt.Println(todoList)
	//	c.JSON(http.StatusOK, todoList)
	//}
}

func UpdateById(c *gin.Context) {
	id, ok := c.Params.Get("id")
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": "无效的id",
		})
		return
	}
	todo, err := models.GetTodoById(id)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
		return
	}
	//var todo Todo
	//if err = DB.Where("id=?", id).First(&todo).Error; err != nil {
	//	c.JSON(http.StatusOK, gin.H{
	//		"error": err.Error(),
	//	})
	//	return
	//}
	c.BindJSON(&todo)
	if err = models.UpdateTodoById(todo); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
	} else {
		c.JSON(http.StatusOK, todo)
	}
}

func DeleteById(c *gin.Context) {
	id, ok := c.Params.Get("id")
	if !ok {
		c.JSON(http.StatusOK, gin.H{
			"error": "无效的id",
		})
		return
	}
	err := models.DeleteTodo(id)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"error": err.Error(),
		})
	} else {
		c.JSON(http.StatusOK, gin.H{
			id: "delete",
		})
	}
	//if err = DB.Where("id=?", id).Delete(Todo{}).Error; err != nil {
	//	c.JSON(http.StatusOK, gin.H{
	//		"error": err.Error(),
	//	})
	//} else {
	//	c.JSON(http.StatusOK, gin.H{
	//		id: "delete",
	//	})
	//}
}

2.models

模具:模型+业务逻辑(ps:可以分开)

package models

import (
	"gin_demo_BubbleList/dao"
)

type Todo struct {
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Status bool   `json:"status"`
}

// Todo 增删改查
// CreateTodo 创建一个Todo
func CreateTodo(todo *Todo) (err error) {
	err = dao.DB.Create(&todo).Error
	return
}

// GetTodoList 获取全部的Todo
func GetTodoList() (todoList []*Todo, err error) {
	if err = dao.DB.Find(&todoList).Error; err != nil {
		return nil, err
	}
	return
}

// GetTodoById 通过id获取一个Todo对象
func GetTodoById(id string) (todo *Todo, err error) {
	todo = new(Todo)
	if err = dao.DB.Where("id=?", id).First(&todo).Error; err != nil {
		return nil, err
	}
	return
}

// UpdateTodoById 更新一个Todo对象
func UpdateTodoById(todo *Todo) (err error) {
	err = dao.DB.Save(todo).Error
	return
}

// DeleteTodo
func DeleteTodo(id string) (err error) {
	err = dao.DB.Where("id=?", id).Delete(&Todo{}).Error
	return
}

3.dao

dao:存放关于数据库的相关操作

package dao

import "github.com/jinzhu/gorm"

var (
	DB *gorm.DB
)

func InitMySQL() (err error) {
	DB, err = gorm.Open("mysql", "usr1:12345@tcp(***:3306)/db1?charset=utf8&parseTime=True&loc=Local")
	if err != nil {
		panic(err)
	}
	return DB.DB().Ping()
}

4.router

router:一般用于设置路由

package router

import (
	"gin_demo_BubbleList/controller"
	"github.com/gin-gonic/gin"
)

func SetRouter() *gin.Engine {
	r := gin.Default()
	//设置静态资源文件
	r.Static("/static", "static")
	// 设置gin框架模版文件
	r.LoadHTMLGlob("templates/*")

	//设置路由
	r.GET("/", controller.IndexHandler)
	//设置路由组
	v1Group := r.Group("/v1")
	{
		//添加一个事项
		v1Group.POST("/todo", controller.Create)
		//查看所有事项
		v1Group.GET("/todo/", controller.GetTodoList)
		//修改一个事项
		v1Group.PUT("/todo/:id", controller.UpdateById)
		//删除一个事项
		v1Group.DELETE("/todo/:id", controller.DeleteById)
	}
	return r
}

4.整体架构

image-20240603175629138

我的源码:6月/gin_demo_BubbleList · 沉着冷静/2023 - 码云 - 开源中国 (gitee.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/675332.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux基础1-基本指令3

上篇文章我们说到了文件,pwd,touch,mkdir等知识。 Linux基础1-基本指令2(你真的了解文件吗?)-CSDN博客 本文继续梳理其他基础命令 1.本章重点 1.删除一个空目录命令rmdir 2.删除一个文件指令rm(重要!) 3.man命令&am…

Gradle下载慢的问题解决

把gradle地址前面的部分改一下就行,下载就快多了 改成这个地址: https://mirrors.aliyun.com/macports/distfiles/gradle/ 这个是gradle的阿里云镜像下载地址,在国内下载起来很快 如何改地址: 找到路径 项目/app/gradle/wrappe…

养老产业能否成为国家经济的新支柱?

养老产业,随着人口老龄化的加剧,逐渐成为国家经济的新支柱。在中国,老年人口的快速增长已经引起了社会的广泛关注,这也带动了对养老服务和健康医疗需求的持续增加。 政府也在积极应对这一挑战,出台了一系列政策来支持…

理解与应用排序算法(快速排序C实现)

目录 一、排序的定义 二、内排序方法 三、插入排序 3.1 直接插入排序 3.1 折半插入排序 3.1 链表插入排序 四、交换排序 五、起泡排序 六、快速排序 一、排序的定义 稳定排序和非稳定排序 设文件f(R1......Ri......Rj......Rn)中记录Ri、Rj(i≠j&#xff0…

TMS320F280049 ECAP模块--应用(2)

例1-上升沿触发 如下图所示,evt1-4设置为上升沿触发,在每个上升沿ctr值依次加载到cap1-4. 例2-上升下降沿触发 每个边沿都可选为事件,每次事件到来,依次把ctr加载到cap1-4。 例3-差异模式下上升沿触发 差异模式下每次事件到来时…

varchar 字段扩展问题

背景 近期接到一个产品需求,由于上游业务字段扩大了字段,下游的字段也得跟着调整扩大,这就涉及几十张大表,十几亿行数据的变更。 如果按照传统方式 onlie-ddl 借用第三方工具也得三四天分批跑,看了看MySQL官网&#…

ctfshow-web入门-爆破(web25)及php_mt_seed工具的安装与使用

爆个🔨,不爆了 hexdec() 函数用于将十六进制字符串转换为十进制数; 注意: 我最开始做这道题时看错了,误以为随机数的种子直接来自于 flag 的前八位,以为就是 ctfshow{ 这八个字符然后 md5 加密再截取&a…

使用jquery.mousewheel-3.0.6.pack.js时报错

基于1.12.4版本的jquery.min.js,在使用jquery.mousewheel-3.0.6.pack.js时报错了: 可以如下解决: addEventListener事件里要加上{ passive: false },这样就可以在使用鼠标滚轮放大缩小图片时,就不会报上述的错误了。 …

VsQt单元测试目录的管理方式

正常项目的文件管理方式 正常项目的目录,是由文件系统中实际的文件夹进行分类管理的。 但是如果单元测试用实际文件夹管理的话,会出现问题,就是被测类太多了,用文件系统管理的话,不太方面查看,如下图所示。…

7EPhone云手机各功能详解

上篇文章详细介绍了7EPhone云手机的注册和购买(没看到的同学可以自主去翻看一下哈~),这篇文章主要给大家讲解7EPhone作为专业海外社媒营销工具,界面上显示什么信息,云机到底有什么功能,这些功能具体怎么来使…

招聘兼职发布客服的骗局大揭秘

在现今的互联网社会中,线上兼职成为许多人追求额外收入或灵活就业的方式。然而,这其中也隐藏着不少骗局,在各大招聘网站或者招聘软件上的今日头条兼职客服招聘就是其中之一。本文将详细揭露这种骗局的运作方式,以帮助大家识别和防…

对比WPF和Avalonia的边框渲染差异

众所周知&#xff0c;诸如Border、Rectangle等元素&#xff0c;是具有边框的。但在WPF和Avalonia中&#xff0c;边框的渲染机制有所不同。 如下代码&#xff0c;Border的边框和背景色均为黑色&#xff0c;并且将透明度设为0.5&#xff1a; <Border Width"100" H…

知了汇智携手数字经济商会,共促物联网鸿蒙产教融合新篇章

5月31日&#xff0c;由成都市数字经济商会主办&#xff0c;华为技术有限公司协办&#xff0c;成都知了汇智科技有限公司及成都市数字经济商会人才专委会共同承办的“产教融合物联网鸿蒙人才交流”大会在成都天府软件园产教融合基地隆重举办。 会议旨在加速四川省鸿蒙技术产业的…

Transformer详解(3-1)-attention为什么要除以根号d

attention的计算公式&#xff0c;为什么要除以根号d? 参考 NLP面试官&#xff1a;“Attention为什么要除以根号d” 算法女生这么回答当场想发 offer

【轻触按键】终篇 -- 纯硬 VS 复合

1、选型 2、开关机电路–填坑1 3、开关机电路–填坑1.a 4、开关机电路–复合芯片解决方案 填坑2 总结 上述几篇&#xff0c;基本上都是比较靠谱的硬件方案&#xff1b; ①所有开关均关闭&#xff1b; X1灯亮&#xff1b;P-MOS 管Q1关断&#xff1b; 特别注意&#xff0c;…

每日两题 / 34. 在排序数组中查找元素的第一个和最后一个位置 33. 搜索旋转排序数组(LeetCode热题100)

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 根据二分函数&#xff0c;得到>target和<target的两个&#xff0c;分别是答案的l和r class Solution { public:vector<int> searchRange(vector<int>& nums,…

简单聊下服务器防病毒

在当今数字化时代&#xff0c;服务器作为数据存储、处理与传输的核心设备&#xff0c;其安全性显得尤为关键。服务器防病毒工作&#xff0c;不仅是保障企业信息安全的重要一环&#xff0c;更是维护用户数据隐私的关键举措。以下&#xff0c;我们将从多个方面&#xff0c;简单探…

spring boot +Scheduled 动态定时任务配置

通常情况下我们设定的定时任务都是固定的,有时候需要我们动态的配置定时任务,下面看代码 import com.mybatisflex.core.query.QueryWrapper; import com.yzsec.dsg.web.modules.exportpwd.entity.ExportPwd; import com.yzsec.dsg.web.modules.exportpwd.entity.table.Export…

04C编译过程/32位,64位区别/断言/位域...

C零碎语法 目录 文章目录 C零碎语法1.编译过程1.2 编译1.3 汇编1.4 链接 2.不同位机器&#xff0c;各数据类型所占位数3.assert() 断言&#xff08;宏&#xff09;3.1缺点3.2解决办法3.3使用举例3.3.1函数开始处检验传入参数的合法性 4.位域4.1举例4.2补充 5.typedef/define(…

Android11 AudioTrack和Track建立联系

应用程序创建AudioTrack时&#xff0c;导致AudioFlinger在播放线程中&#xff0c;创建Track和其对应。那它们之间是通过什么来建立联系传递数据的&#xff1f;答案是共享内存。 创建Track时&#xff0c;导致其父类TrackBase的构造函数被调用 //frameworks/av/services/audiofl…