gin+gorm增删改查目录框架

从网上找资料,发现,很多都是直接的结构

路由,后端的controller层,还有model层,都是放在了同一个main.go文件中,如果写项目的话,还得自己去拆文件,拆代码,经过查询和自己总结,下面放一个目录框架

总体目录结构

按照业务流程顺序,解释说明

1、加载自定义封装函数文件、数据库、redis

package main

import (
	"ginchat/router"
	"ginchat/utils"
)

func main() {
	utils.InitConfig()
	utils.InitMysql()
	utils.InitRedis()
	r := router.Router()

	r.Run(":8081")
}

依次的三个函数

system_init.go文件里面

package utils

import (
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"os"
	"time"
)

var (
	DB  *gorm.DB
	err error
	Red *redis.Client
)

func InitRedis() {
	fmt.Print("随便打印点什么,标记一下")
	Red = redis.NewClient(&redis.Options{
		Addr:         viper.GetString("redis.addr"),
		Password:     viper.GetString("redis.password"),
		DB:           viper.GetInt("redis.DB"),
		PoolSize:     viper.GetInt("redis.poolSize"),
		MinIdleConns: viper.GetInt("redis.minIdleConn"),
	})

}

func InitConfig() {
	viper.SetConfigName("app")
	viper.AddConfigPath("config")
	err := viper.ReadInConfig()
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println("config app", viper.Get("app"))
	fmt.Println("config mysql", viper.Get("mysql"))
}

func InitMysql() {
	newLogger := logger.New(
		//自定义日志模版 打印SQL语句
		log.New(os.Stdout, "\r\n", log.LstdFlags),
		logger.Config{
			SlowThreshold: time.Second, //慢SQL阈值
			LogLevel:      logger.Info, //级别
			Colorful:      true,        //彩色
		},
	)
	fmt.Print(newLogger)
	DB, err = gorm.Open(mysql.Open(viper.GetString("mysql.dns")), &gorm.Config{})
	if err != nil {
		fmt.Println("连接数据库失败", err)
	} else {
		fmt.Printf("数据库连接成功: %v", DB)
	}

}

2、加载路由文件

package router

import (
	"fmt"
	"ginchat/service"
	"github.com/gin-gonic/gin"
)

func Router() *gin.Engine {
	fmt.Print("进入路由了")
	r := gin.Default()
	//用户模块
	r.GET("/user/getUserList", service.GetUserList)
	r.POST("/user/createUser", service.CreateUser)
	r.DELETE("/user/deleteUser", service.DeleteUser)
	r.PUT("/user/updateUser", service.UpdateUser)

	return r
}

3、这里面的MySQL和Redis配置,可以直接写死在这个文件里面,也可以单独摘出来,放在配置文件中,这里是放在了配置文件中

app.yml中

mysql:
  dns: admin3:123456@tcp(127.0.0.1:3306)/ginchat?charset=utf8mb4&parseTime=True&loc=Local
redis:
  addr:"127.0.0.1:6379"
  password:""
  DB:0
  poolSize:30
  minIdleConn:30

说明一下,dns里面的参数

账号:密码@tcp(ip:端口号)/数据库名字?xxxxxxxx

4、然后,预备的工作就完成了。另外,有一个sql文件下面的testGorm.go文件

package main

import (
	"fmt"
	"ginchat/models"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func main() {
	db, err := gorm.Open(mysql.Open("admin3:123456@tcp(127.0.0.1:3306)/ginchat?charset=utf8mb4&parseTime=True&loc=Local"), &gorm.Config{})
	if err != nil {
		fmt.Println("连接数据库失败", err)
	} else {
		fmt.Printf("数据库连接成功: %v", db)
	}
	err2 := db.AutoMigrate(&models.UserBasic{})
	if err2 != nil {
		return
	} else {
		fmt.Printf("创建表成功: %v", db)
	}
}

用于临时生成数据表的一个文件,可以去直接执行此函数,生成数据表,或者也可以自己手动去利用navicat去创建表格

这里用到了models包下面的UserBasic{}

package models

import (
	"fmt"
	"ginchat/utils"
	"gorm.io/gorm"
)

type UserBasic struct {
	gorm.Model
	Name          string
	Password      string
	Phone         string `valid:"matches(^1[3-9]{1}\\d{9}$)"`
	Email         string `valid:"email"`
	Avatar        string //头像
	Identity      string
	ClientIp      string
	Salt          string
	ClientPort    string
	LoginTime     uint64
	HeartbeatTime uint64
	LoginOutTime  uint64
	IsLogout      bool
	DeviceInfo    string
}

func (table *UserBasic) TableName() string {
	return "user_basic"
}

func GetUserList() []*UserBasic {
	data := make([]*UserBasic, 10)
	//fmt.Printf("data的内容为: %v\n", &data)
	utils.DB.Find(&data)
	for _, v := range data {
		fmt.Println(v)
	}
	return data

}

func CreateUser(user UserBasic) *gorm.DB {
	return utils.DB.Create(&user)
}

func DeleteUser(user UserBasic) *gorm.DB {
	return utils.DB.Delete(&user)
}

func UpdateUser(user UserBasic) *gorm.DB {
	return utils.DB.Model(&user).Updates(UserBasic{Name: user.Name, Phone: user.Phone, Email: user.Email, Password: user.Password, Avatar: user.Avatar})
}

func FindUserByName(name string) UserBasic {
	user := UserBasic{}
	utils.DB.Where("name=?", name).First(&user)
	return user
}

func FindUserByPhone(phone string) UserBasic {
	user := UserBasic{}
	utils.DB.Where("phone=?", phone).First(&user)
	return user
}

func FindUserByEmail(email string) UserBasic {
	user := UserBasic{}
	utils.DB.Where("email=?", email).First(&user)
	return user
}

UserBasic里面需要定义好数据表的字段

5、gorm.Model是gorm包已经先给预先设置好的4个字段

同时,前面是用驼峰式写法,如果不做特殊说明的话,基本上就会转变为下划线方式去设置字段,这个是gorm默认的对应关系

字段名可以控制,字段类型和大小,如果在创建之后不符合自己要求,可以自己额外修改

6、接下来就是后面的调取引用函数了

controller层

package service

import (
	"fmt"
	"ginchat/models"
	"ginchat/utils"
	"github.com/asaskevich/govalidator"
	"github.com/gin-gonic/gin"
	"math/rand"
	"strconv"
)

func GetUserList(c *gin.Context) {
	data := make([]*models.UserBasic, 10)
	data = models.GetUserList()
	c.JSON(200, gin.H{
		"code":    200,
		"message": data,
	})
}

func CreateUser(c *gin.Context) {
	user := models.UserBasic{}
	user.Name = c.PostForm("name")
	user.Phone = c.PostForm("phone")
	user.Email = c.PostForm("email")
	password := c.PostForm("password")
	rePassword := c.PostForm("repassword")

	salt := fmt.Sprintf("%06d", rand.Int31())

	if password != rePassword {
		c.JSON(200, gin.H{
			"code":    -1,
			"message": "两次密码不一样!",
		})
		return

	}
	data1 := models.FindUserByName(user.Name)
	fmt.Print(data1)
	if data1.Name != "" {
		c.JSON(200, gin.H{
			"code":    -1,
			"message": "用户名不能重复!",
		})
		return
	}
	data2 := models.FindUserByPhone(user.Phone)
	fmt.Print(data2)
	if data2.Phone != "" {
		c.JSON(200, gin.H{
			"code":    -1,
			"message": "手机号不能重复!",
		})
		return
	}
	data3 := models.FindUserByEmail(user.Email)
	fmt.Print(data3)
	if data3.Email != "" {
		c.JSON(200, gin.H{
			"code":    -1,
			"message": "邮箱不能重复!",
		})
		return
	}
	user.Password = utils.MakePassword(password, salt)
	user.Salt = salt
	models.CreateUser(user)
	c.JSON(200, gin.H{
		"code":    0,
		"message": "新增用户成功!",
	})

}

func DeleteUser(c *gin.Context) {
	user := models.UserBasic{}
	id, _ := strconv.Atoi(c.Query("id"))
	user.ID = uint(id)
	models.DeleteUser(user)
	c.JSON(200, gin.H{
		"code":    0,
		"message": "删除用户成功!",
	})
}

func UpdateUser(c *gin.Context) {
	user := models.UserBasic{}
	id, _ := strconv.Atoi(c.PostForm("id"))
	user.ID = uint(id)
	user.Name = c.PostForm("name")
	user.Password = c.PostForm("password")
	user.Phone = c.PostForm("phone")
	user.Email = c.PostForm("email")
	_, err := govalidator.ValidateStruct(user)
	if err != nil {
		fmt.Print(err)
		c.JSON(200, gin.H{
			"code":    -1,
			"message": "修改参数不匹配!",
		})
		return
	} else {
		fmt.Print(user)
		models.UpdateUser(user)
		c.JSON(200, gin.H{
			"code":    0,
			"message": "修改用户成功!",
		})
	}

}

这里举例的是,用户信息表的相关增删改查

另外两个自己封装函数文件,暂时上面几个函数未用到

先贴在这里md5.go和resp.go

package utils

import (
	"crypto/md5"
	"encoding/hex"
	"strings"
)

// Md5Encode 小写
func Md5Encode(data string) string {
	h := md5.New()
	h.Write([]byte(data))
	tempStr := h.Sum(nil)

	return hex.EncodeToString(tempStr)
}

// MD5Encode 大写
func MD5Encode(data string) string {
	return strings.ToUpper(Md5Encode(data))
}

// MakePassword 加密
func MakePassword(plainpwd, salt string) string {
	return Md5Encode(plainpwd + salt)
}

// ValidPassword 解密
func ValidPassword(plainpwd, salt, password string) bool {
	return Md5Encode(plainpwd+salt) == password
}
package utils

import (
	"encoding/json"
	"net/http"
)

type H struct {
	Code  int
	Msg   string
	Data  interface{}
	Rows  interface{}
	Total interface{}
}

func Resp(w http.ResponseWriter, code int, data interface{}, msg string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	h := H{
		Code: code,
		Data: data,
		Msg:  msg,
	}
	ret, err := json.Marshal(h)
	if err != nil {
		panic(err)
	}
	w.Write(ret)
}

func RespFail(w http.ResponseWriter, msg string) {
	Resp(w, -1, nil, msg)
}

func RespOK(w http.ResponseWriter, data interface{}, msg string) {
	Resp(w, 0, data, msg)
}

func RespOKList(w http.ResponseWriter, data interface{}, total interface{}) {
	RespList(w, 0, data, total)
}

func RespList(w http.ResponseWriter, code int, data interface{}, total interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	h := H{
		Code:  code,
		Rows:  data,
		Total: total,
	}
	ret, err := json.Marshal(h)
	if err != nil {
		panic(err)
	}
	w.Write(ret)
}

此部分代码是看了B站up主之后总结出来的,感兴趣的可以去搜索看一下

000_项目背景能获得什么技术栈_哔哩哔哩_bilibili

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

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

相关文章

计算机网络——数据链路层(1)

一、概述 在计算机网络中,数据链路层承担着点对点通信的任务,用于跨物理层在网段节点之间参数数据。它在网络分层中处于物理层之上,网路层之下。 在链路层的讨论中,我们将看到两种截然不同类型的链路层信道。第一种类型是广播信道…

数字身份所有权:Web3时代用户数据的掌控权

随着Web3时代的来临,数字身份的概念正焕发出崭新的光芒。在这个数字化的时代,用户的个人数据变得愈加珍贵,而Web3则为用户带来了数字身份所有权的概念,重新定义了用户与个人数据之间的关系。本文将深入探讨Web3时代用户数据的掌控…

【竞技宝】DOTA2:世一C遇到瓶颈? yatoro直言一号位上分太难了

北京时间2024年1月18日,spirit在去年再次拿到了TI国际邀请赛的冠军,成为了OG之后第二支两次在世界赛夺冠的战队,在夺冠之后,spirit直接给选手们放了假。此前AR夺冠的ESL吉隆坡站的比赛,spirit战队就并未参加&#xff0…

视频转码实例:把MP4转为MKV视频,一键批量转换的操作方法

在数字媒体时代,视频格式的多样性是不可避免的。经常把MP4格式的视频转换为MKV格式。MKV格式有较高的音频和视频质量,能在其他设备或软件上播放视频。以下是云炫AI智剪如何把MP4视频转为MKV格式的一键批量转换操作方法。 已转码的mkv视频效果缩略图展示…

kubernetes pod 高级

一、pod资源限制 1、什么是pod的资源限制 在Kubernetes集群中,为了使系统能够稳定的运行,通常会对Pod的资源使用量进行限制。 在Kubernetes集群中,如果有一个程序出现异常,并占用大量的系统资源。如果未对该Pod进行资源限制的话…

Git学习笔记(第4章):Git分支

目录 4.1 分支的概述 4.1.1 什么是分支 4.1.2 分支的好处 4.2 查看分支(查) 4.3 创建分支(增) 4.4 切换分支 4.5 修改分支(改) 4.6 合并分支(正常合并) 4.7 合并分支&#…

CGAL最小生成树、可视化

CGAL 5.4.5 - Surface Mesh: User Manual 1、Kruskal计算最小生成树 #include <CGAL/Simple_cartesian.h> #include <CGAL/Surface_mesh.h> #include <boost/graph/kruskal_min_spanning_tree.hpp> #include <iostream> #include <fstream> #inc…

贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现

目录 参考链接 定义 直观理解 公式推导 一次贝塞尔曲线&#xff08;线性公式&#xff09; 二次贝塞尔曲线&#xff08;二次方公式&#xff09; 三次贝塞尔曲线&#xff08;三次方公式&#xff09; n次贝塞尔曲线&#xff08;一般参数公式&#xff09; 代码实现 参考链接…

群晖NAS搭建WebDav结合内网穿透实现公网访问本地影视资源

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

2024华数杯国际数学建模B题思路+代码+模型+论文

2024华数杯国际数学建模B题思路代码模型论文&#xff1a;1.17上午第一时间更新&#xff0c;详细内容见文末名片 问题B&#xff1a;光伏电 背景 中国的电力构成包括传统的能源发电&#xff08;如煤炭、石油和天然气&#xff09;、可再生能源发电 &#xff08;如水力发电、风能…

OpenGL:关于纹理映射时任意四边形中的插值问题(二)

OpenGL&#xff1a;关于纹理映射时任意四边形中的插值问题-CSDN博客 上次是使用逆双线性插值的方法解决四边形纹理映射时产生的折痕问题。 其实也有点问题&#xff0c;就是双线性插值会使得纹理产生一点扭曲。 不是投影的效果。 想达到纹理投影的效果&#xff0c;可以使用透…

AndroidStudio下载安装教程

下载链接&#xff1a;官方下载 https://developer.android.google.cn/studio?hlzh-cn点击后弹出条款及条件页面&#xff0c;往下滑&#xff0c;勾选同意&#xff0c;然后就点击下载&#xff0c;等待下载完成 下载完成后双击打开&#xff0c;Next 继续Next 选择安装路径&am…

行列转化【附加面试题】

在MySQL中&#xff0c;行列转换是一种常见的操作。它包括行转列和列转行两种情况。 行转列&#xff1a;行转列是将表中的某些行转换成列&#xff0c;以提供更为清晰、易读的数据视图。例如&#xff0c;假设我们有一个包含科目和分数的表&#xff0c;我们可以使用SUM和CASE语句…

C++(13)——string

上篇文章中介绍了中部分函数的用法&#xff0c;本篇文章将继续对其他的函数进行介绍&#xff1a; 1. substr: string substr (size_t pos 0, size_t len npos) const; 函数的两个参数如上述代码所示&#xff0c;此函数的主要作用是根据一个已有的的对象的起始坐标开始&a…

基于python集成学习算法XGBoost农业数据可视化分析预测系统

文章目录 基于python集成学习算法XGBoost农业数据可视化分析预测系统一、项目简介二、开发环境三、项目技术四、功能结构五、功能实现模型构建封装类用于网格调参训练模型系统可视化数据请求接口模型评分 0.5*mse 六、系统实现七、总结 基于python集成学习算法XGBoost农业数据可…

我终于学会的前端技能——代码调试、打断点

在技术的世界里&#xff0c;要用魔法来打败魔法 说来惭愧我做前端已近三年了竟然还没有学会如何调试代码&#xff0c;也就是给自己的代码打上断点一步步看它的运行状态以达到理清代码运行逻辑、排查问题提升开发效率的目的。直到最近我才学会了这一技能&#xff0c;在这之前我…

JSP简单学习

jsp是在html中嵌入java代码 jsp也是在j2ee服务端中的java组件 第一次运行 在第一次运行jsp代码时会经历以下步骤&#xff0c;将jsp转为java代码&#xff0c;将java代码转为class文件。 所以通常会比较慢&#xff0c;编译后就好多了。 四大作用域 requestsessionpageapplica…

CUDA Toolkit 下载,安装,验证

CUDA Toolkit 下载 进cuda官网下载 CUDA Toolkit链接&#xff1a; https://developer.nvidia.com/cuda-downloads 官网默认显示当前的最新版本&#xff0c;这里以安装CUDA Toolkit 12.2 为示例 下载CUDA Toolkit 完成 CUDA Toolkit 安装 开始安装&#xff1a; 点同意&#…

Linux第30步_通过USB OTG将固件烧写到eMMC中

学习目的&#xff1a;在Win11中&#xff0c;使用STM32CubeProgrammer工具&#xff0c;通过USB OTG将固件烧写到eMMC中。 安装软件检查&#xff1a; 1、是否安装了JAVA; 2、是否安装了STM32CubeProgrammer工具; 3、是否安装 了DFU驱动程序; 4、是否安装了“Notepad”软件; …

关于SpringBoot项目整合Log4j2实现自定义日志打印失效原因

主要的原因是因为&#xff0c;SpringBoot的logback包的存在&#xff0c;会导致Spring Boot项目优先实现logback的日志设置&#xff0c;所以导致我们用Log4j2实现自定义日志失效。 先找l哪个包引用了logback包 进入之后查询logback 然后双击包 发现是spring-boot-starter-loggin…