Gin+Gorm练手小项目bubble清单企业级结构剖析

news2024/11/25 11:52:11

概述

本项目来源于Qimi老师的小清单项目——基于gin+gorm开发的练手小项目,通过该项目可初识go web开发该有的姿势。笔者对代码有些许修改,以下是项目成功运行的截图,主要功能有添加,删除,确认,查看待办事项等(所以是小项目啦~)
在这里插入图片描述

项目结构树

这个项目虽然比较小,但是还是可以用企业级代码结构去划分,以下是项目结构树:

├─controllers
├─dao
├─models
├─routers
├─static
│  ├─css
│  ├─fonts
│  └─js
└─template

在这里插入图片描述
划分项目结构,利于代码组织和可维护,也有利于团队协作。

后端源码

main.go

package main

import (
	"bubble/dao"
	"bubble/models"
	"bubble/routers"
)

func main() {

	err := dao.InitMySQL()
	if err != nil {
		panic(err)
	}

	err = dao.DB.AutoMigrate(&models.Todo{})
	if err != nil {
		panic(err)
	}
	r := routers.SetupRouter()
	err = r.Run()
	if err != nil {
		panic(err)
	}
}

controller.go

package controllers

import (
	"bubble/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 CreateTodo(c *gin.Context) {
	var todo models.Todo
	err := c.BindJSON(&todo)
	if err != nil {
		panic(err)
	}
	if err := models.CTodo(&todo); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
	} else {
		c.JSON(http.StatusOK, gin.H{
			"code": 200,
			"msg":  "success",
			"data": todo,
		})
	}
}

func GetTodo(c *gin.Context) {

	if todoList, err := models.GTodo(); err != nil {
		c.JSON(http.StatusBadRequest, err.Error())
	} else {
		c.JSON(http.StatusOK, todoList)
	}
}

func UpdateTodo(c *gin.Context) {
	id, ok := c.Params.Get("id")
	if !ok {
		c.JSON(http.StatusBadRequest, gin.H{"error": "无效的id"})
		return
	}
	todo, err := models.UTodo(id)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	err = c.BindJSON(&todo)
	if err != nil {
		panic(err)
	}
	if err = models.STodo(todo); err != nil {
		c.JSON(http.StatusOK, gin.H{"error": err.Error()})
	} else {
		c.JSON(http.StatusOK, todo)
	}
}

func DeleteTodo(c *gin.Context) {
	id, ok := c.Params.Get("id")
	if !ok {
		c.JSON(http.StatusOK, gin.H{"error": "无效的id"})
		return
	}
	if err := models.DTodo(id); err != nil {
		c.JSON(http.StatusOK, gin.H{"error": err.Error()})
	} else {
		c.JSON(http.StatusOK, gin.H{id: "deleted"})
	}
}

mysql.go

package dao

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

var DB *gorm.DB

func InitMySQL() (err error) {
	dsn := "root:@tcp(127.0.0.1:3306)/bubble?charset=utf8mb4&parseTime=True&loc=Local"
	DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	return err
}

todo.go

package models

import (
	"bubble/dao"
)

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

//Todo 增删改查

// CTodo 创建todo
func CTodo(todo *Todo) (err error) {
	if err = dao.DB.Create(&todo).Error; err != nil {
		return err
	}
	return
}

// GTodo 查询todo
func GTodo() (todoList []*Todo, err error) {
	err = dao.DB.Find(&todoList).Error
	return
}

func UTodo(id string) (todo *Todo, err error) {
	if err := dao.DB.Where("id=?", id).First(&todo).Error; err != nil {
		return nil, err
	}
	return
}

func STodo(todo *Todo) (err error) {
	err = dao.DB.Save(&todo).Error
	return
}

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

routers.go

package routers

import (
	"bubble/controllers"
	"github.com/gin-gonic/gin"
)

func SetupRouter() *gin.Engine {
	r := gin.Default()
	r.Static("/static", "static")
	r.LoadHTMLGlob("template/*")
	r.GET("/", controllers.IndexHandler)

	v1Group := r.Group("/v1")
	{
		v1Group.POST("/todo", controllers.CreateTodo)

		v1Group.GET("todo/", controllers.GetTodo)

		v1Group.PUT("todo/:id", controllers.UpdateTodo)

		v1Group.DELETE("todo/:id", controllers.DeleteTodo)
	}

	return r
}

学习使用

前后端所有源码都已经上传至我的资源里:https://download.csdn.net/download/m0_63230155/88064315?spm=1001.2014.3001.5503,供其他小伙伴学习使用,这个是免费下载的!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

APP测试学习之Android模拟器Genymotion安装配置不上解决方法以及adb基本使用

Android模拟器Genymotion安装配置不上解决方法以及adb基本使用 Genymotion下载安装配置遇见的问题解决方法adb基本使用 Genymotion下载 1.首先进入官网 https://www.genymotion.com/ 2.在官网注册一个账号 https://www-v1.genymotion.com/account/login/ 3.下载 https://www.g…

Linux之设备树解耦架构解读-V1.0

术语和缩略语 本文档使用了以下术语和缩略语 Dts:DTS即Device Tree Source,是一个文本形式的文件,用于描述硬件信息。一般都是固定信息,无法变更,无法overlay。 Dtsi:可以理解为dts的公共部分&#xff0…

【编程技巧--函数指针回调函数】

1.什么是函数指针 在C语言中,一个函数在编译时被分配一个入口地址(第一条指令的地址),我们可以将地址赋给一个指针,这样,指针变量持有函数入口地址,它就指向了该函数,所以称这种指针为指向函数的指针,简称函数指针。 我们在编写代码的时候可以用函数名…

教你快速安装Bootstrap

目录 Bootstrap简介Bootstrap的下载Bootstrap的使用 Bootstrap简介 Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作,基于HTML、CSS、JavaScript开发的简洁、直观、强悍的前端开发框架,它会使Web开发更加快捷Bootstrap框架的优点 开发…

【电路原理学习笔记】第4章:能量与功率:4.3 电阻的额定功率

第4章:能量与功率 4.3 电阻的额定功率 额定功率是一个电阻器可以消耗的最大功率,且保证其不会被过多的热量损坏或改变其阻值。额定功率与电阻值无关,主要由电阻的材料成分、物理尺寸和形状决定。在其他条件相同的情况下,电阻的表…

Redis分布式锁的演变历程

什么时候用分布式锁 当并发去读写一个【共享资源】的时候,我们为了保证数据的正确,需要控制同一时刻只有一个线程访问。 分布式锁就是用来控制同一时刻,只有一个 JVM 进程中的一个线程可以访问被保护的资源。 分布式锁入门 分布式锁应该满足…

MySQL数据库之高级SQL语句

目录 一.MySQL语句前言 1.1 按关键字排序 1.2 环境准备 1.3单字段排序 1.3.1升序 1.3.2降序 1.3.3 order by还可以结合where进行条件过滤 ​编辑 1.4多字段排序 1.4.1查询学生信息先按兴趣id升序排列,相同分数的,id按照降序排列 1.4.2查询学生信息先…

Win10环境下Android Studio中运行Flutter HelloWorld项目

一、引言 Android Studio是Android的官方IDE(Integrated Development Environment)。它专为Android而打造,可以加快开发速度,为Android设备构建最高品质的应用。 Flutter是Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开…

Linux--stdin、stdout、stderr的文件描述符fd

stdin的文件描述符是 &#xff1a;0 stdout的文件描述符是 &#xff1a;1 stderr的文件描述符是 &#xff1a;2 证明&#xff1a; #include <stdio.h>int main() {printf("stdin: %d\n",stdin->_fileno);printf("stdout: %d\n",stdout->…

instsrv 注册 windows 系统服务

注册步骤 Win r 打开 cmd 窗口执行 instsrv.exe myserver C:\Windows\System32\srvany.exe 示例&#xff1a; instsrv.exe nginx C:\Windows\System32\srvany.exe win r 运行 regedit 进入注册表&#xff0c;依次找到以下路径 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\S…

如何应用MySQL高阶语句(子查询)

目录 一、SQL高阶语句 常用查询 关键字排序 升序降序 按区域进行查找 分组统计 limit限制显示结果条目 As别名设置 使用场景 嵌套克隆复制表结构 二、通配符 三、子查询 insert子查询 update子查询 delete子查询 Exists检测 一、SQL高阶语句 常用查询 对于MyS…

非50欧系统阻抗的S参数测试

1. S参数依赖于系统阻抗 S参数的定义需要约定一个系统阻抗。同一个微波电路&#xff0c;在不同系统阻抗下的S参数是不同的。例如&#xff0c;50欧电阻在50欧系统阻抗下的S11为零&#xff0c;是没有反射的匹配状态&#xff1b;但50欧电阻在75欧系统阻抗下的S11不为零&#xff0…

Puppeteer 使用教程-实战篇(爬取图片、视频、音频,页面数据)

目录 前言 一、 获取实体店铺信息 二、 获取全国各省市县地图json数据 三、 cookies 四、 获取网络图片、视频资源 五、 自动化测试 总结 前言 续上篇&#xff0c;我们简单讲述一下puppeteer常见的应用场景&#xff0c;包括静态页面数据获取&#xff0c;网络请求获取截取…

详解CPU的态

目录 1.CPU的工作过程 2.寄存器 3.CPU的上下文 4.系统调用 5.CPU的态 1.CPU的工作过程 CPU要执行的指令的地址存在寄存器中&#xff0c;指令存放在内存中&#xff0c;而CPU本质上就是一个去内存中根据地址取指令&#xff0c;然后执行指令的硬件。 举一个例子&#xff1a…

【雕爷学编程】Arduino动手做(22)——8X8 LED点阵MAX7219屏4

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#xff0c;这…

vscode使用技巧

在使用vscode编辑代码时&#xff0c;在settings.json中增加配置项可以配置回车换行缩进补齐方式&#xff1a; 第一种&#xff1a;使用空格补齐&#xff1a; "editor.insertSpaces":true 按下回车换行后&#xff1a; 第二种&#xff1a;使用tab键补齐&#xff1a; …

【java】对ArrayList中的元素进行排序的几种方式

对ArrayList中的元素进行排序的几种方式 一、使用Collections工具类 1、对基本类型排序 通过Collections.sort()对基本类型排序默认是以升序排序 // 1.Collections.sort()默认按照升序排序 List<Integer> integerList new ArrayList<>(); Collections.addAll(…

每日一刷——替换空格

题目描述&#xff1a; 请实现一个函数&#xff0c;将一个字符串中的每个空格替换成“%20”。例如&#xff0c;当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 我的思路&#xff1a;从左向右循环遍历字符串&#xff0c;定义一个空串。如果遇到空格&#xf…

Ubuntu18.04 拯救者R9-7945HX 4060 配置ZED 2i代双目相机驱动+ORBSLAM2

AMD的拯救者网卡很拉&#xff0c;研究了很久除了换网卡可以解决网络问题&#xff0c;其它没找到合适的办法&#xff0c;这里我用手机USB共享网络的方式勉强上网&#xff0c;这里不得不说华为的信号桥很好用。 之前在1050ti的电脑上布置过&#xff0c;很顺利&#xff0c;这个新…

SDUT 2023 summer team contest(for 22) - 1-Gym - 102220

B - Balanced Diet 题意&#xff1a;这题题意有点难搞啊&#xff0c;就是有n个物品&#xff0c;一个有m种&#xff0c;对于第 i 种物品如果你要买它就至少买 l[i]个&#xff0c;然后就是给你n行&#xff0c;每行两个数&#xff0c;ai,bi,表示这个糖果类型为bi&#xff0c;价值为…