【go语言开发】gorm库连接和操作mysql,实现一个简单的用户注册和登录

本文主要介绍使用gorm库连接和操作mysql,首先安装gorm和mysql依赖库;然后初始化mysql,配置连接池等基本信息;然后建表、完成dao、controller开发;最后在swagger中测试

文章目录

  • 前言
  • 安装依赖库
  • 数据库初始化
  • 账号注册和登录
    • 创建实体类User
    • dao
    • controller
    • router配置
  • 测试

欢迎大家访问个人博客网址:https://www.maogeshuo.com,博主努力更新中…

参考文档:

  • 【go语言开发】yaml文件配置和解析
  • 【go语言开发】loglus日志框架的使用
  • 【go语言开发】swagger安装和使用

前言

GORM 是一个强大的 ORM(对象关系映射)库,可以简化数据库操作并提供方便的查询方法。它提供了一种简单而强大的方式来处理数据库操作,包括连接到数据库、定义数据模型、执行查询、插入、更新和删除数据等功能。

以下是 GORM 库的一些主要特点和优点:

  • 支持多种数据库引擎:GORM 支持多种主流的数据库引擎,如 MySQL、PostgreSQL、SQLite、SQL Server 等。

  • 自动迁移:通过 GORM,你可以使用简单的代码就能自动创建、更新数据库表结构,而无需手动编写 SQL。

  • 链式方法:GORM 提供了丰富的链式方法,用于构建复杂的查询条件,并支持预加载相关数据,实现数据的懒加载。

  • 事务支持:GORM 提供了事务支持,确保在数据操作时的原子性和一致性。

  • 回调函数:你可以注册各种回调函数,以在特定事件发生时执行自定义逻辑,如在保存数据之前或之后执行某些操作。

  • 软删除:GORM 支持软删除功能,即标记删除数据而非真正从数据库中删除,方便数据恢复和数据保留。

  • 关系映射:GORM 可以轻松地定义模型之间的关系,如一对一、一对多、多对多等,并提供方便的方法来处理这些关系。

  • 性能优化:GORM 对数据库操作进行了优化,提供了缓存、批量插入等功能,以提高性能。

安装依赖库

当使用 GORM 时,首先需要安装 GORM 包和相应的数据库驱动。

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

数据库初始化

初始化mysql,我这里只配置了两张表,设置连接池相关参数

package coreimport ("code-go/model/do""fmt""gorm.io/driver/mysql""gorm.io/gorm""log""time"
)var DB *gorm.DB// InitMysql 初始化mysql
func InitMysql() (*gorm.DB, error) {mysqlConfig := Config.Database.Mysqldsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",mysqlConfig.UserName,mysqlConfig.Password,mysqlConfig.Host,mysqlConfig.Port,mysqlConfig.Database)LOG.Println("dsn: ", dsn)dbMysql, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {log.Println("open db_mysql error ", err)return nil, err}DB = dbMysql//迁移表autoMigrateTable()// 是否打开日志if mysqlConfig.LogMode {dbMysql.Debug()}db, _ := dbMysql.DB()//设置连接池的最大闲置连接数db.SetMaxIdleConns(10)//设置连接池中的最大连接数量db.SetMaxOpenConns(100)//设置连接的最大复用时间db.SetConnMaxLifetime(10 * time.Second)return dbMysql, nil
}// 自动迁移表
func autoMigrateTable() {err := DB.AutoMigrate(&do.User{}, &do.OperationLog{})if err != nil {LOG.Error("迁移表结构失败:", err)}
}

SetMaxIdleConns:设置最大空闲连接数,目前默认值为2,0<= n<=MaxIdleConns
SetMaxOpenConns: 设置最大连接数,默认为0
SetConnMaxLifetime:设置连接的最大存活时间,当d<=0,connections are not closed due to a connection’s age
至于其他的配置,查看源码和官方文档https://gorm.io/docs/

账号注册和登录

创建实体类User

package doimport ("gorm.io/gorm"
)type User struct {gorm.ModelUsername     string  `gorm:"type:varchar(20);not null;unique;index:idx_username" json:"username"`Password     string  `gorm:"size:255;not null" json:"password,omitempty"`Mobile       string  `gorm:"type:varchar(11);not null;unique" json:"mobile"`Avatar       string  `gorm:"type:varchar(255)" json:"avatar"`Nickname     *string `gorm:"type:varchar(20)" json:"nickname"`Introduction *string `gorm:"type:varchar(255)" json:"introduction"`Status       uint    `gorm:"type:tinyint(1);default:1;comment:'1正常, 2禁用'" json:"status"`Creator      string  `gorm:"type:varchar(20);" json:"creator"`Roles        []*Role `gorm:"many2many:user_roles" json:"roles"`
}

dao

package daoimport ("code-go/core""code-go/model/do"
)func InsertUser(user do.User) error {tx := core.DB.Create(&user)if tx.Error != nil {core.LOG.Println("insert user in do fail")return tx.Error}return nil
}func GetUserByUsername(userName string) *do.User {var user *do.Usertx := core.DB.Model(&do.User{}).Where("username=?", userName).Find(&user)if tx.Error != nil {core.LOG.Println("Query user by username fail")}return user
}

controller

package apiimport ("code-go/app/admin/dao""code-go/common""code-go/core""code-go/global""code-go/model/do""code-go/model/vo""code-go/util""fmt""github.com/gin-gonic/gin""net/http""strconv""time"
)// Register 用户注册
//
//	@Summary	用户注册
//	@Produce	json
//	@Router		/api/user/register [post]
//	@Param		username	query	string	true	"用户名"
//	@Param		password	query	string	true	"密码"
//	@Param		mobile		query	string	true	"电话"
func Register(c *gin.Context) {userName := c.Query("username")password := c.Query("password")mobile := c.Query("mobile")if userName == "" || password == "" {core.LOG.Println("输入的用户名和密码为空")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.VALILD_FAIL, "输入的用户名或密码为空"))return}// 查询用户daoUser := dao.GetUserByUsername(userName)if daoUser.Username == userName {core.LOG.Printf("用户: %s 已存在\n", userName)c.JSON(http.StatusOK, common.OkWithData("输入的用户已存在"))return}// 生成用户genPasswd := util.GenPasswd(password)var user do.Useruser.Mobile = mobileuser.Username = userNameuser.Password = genPasswduser.Status = core.User_status_OKerr := dao.InsertUser(user)if err != nil {core.LOG.Println("插入用户失败 ", err)c.JSON(http.StatusOK, common.FailWithCodeMsg(common.INSERT_DB_FAIL, "插入用户失败"))return}c.JSON(http.StatusOK, common.Ok())}// Login 用户登录
//
//	@Summary	用户登录
//	@Produce	json
//	@Router		/api/user/login [post]
//	@Param		username	query	string	true	"用户名"
//	@Param		password	query	string	true	"密码"
func Login(c *gin.Context) {userLogin := vo.UserLoginReqVo{}err := c.ShouldBindQuery(&userLogin)if err != nil {core.LOG.Println("用户登录:参数绑定失败")c.JSON(http.StatusOK, common.FailWithMsg("参数绑定失败"))return}userName := userLogin.Usernamepassword := userLogin.Passwordif userName == "" || password == "" {core.LOG.Println("用户登录:输入的用户名和密码为空")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.VALILD_FAIL, "输入的用户名和密码为空"))return}// 校验格式isMatched := util.ValidateUserName(userName)if !isMatched {core.LOG.Println("用户登录:用户名格式校验失败")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.VALILD_FAIL, "用户名格式校验失败"))return}//isMatched = util.ValidatePassword(password)//if !isMatched {//	global.Log.Println("用户登录:密码格式校验失败")//	c.JSON(http.StatusOK, common.FailWithCodeMsg(common.VALILD_FAIL, "密码格式校验失败"))//	return//}// TODO: 生成验证码// 数据库查询user := dao.GetUserByUsername(userName)if user.Username == "" {core.LOG.Println("用户登录:未查询到用户")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.USER_NOT_EXIST, common.GetMapInfo(common.USER_NOT_EXIST)))return}//校验登录密码是否和数据库一致isPasswordMatch := util.ComparePasswd(user.Password, password)if !isPasswordMatch {core.LOG.Println("用户登录:用户密码输入错误")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.USER_PASSWORD_NOT_MATCHED,common.GetMapInfo(common.USER_PASSWORD_NOT_MATCHED)))return}// TODO:生成tokentoken, err := util.GenerateToken(strconv.Itoa(int(user.ID)), user.Username)if err != nil {core.LOG.Println("用户登录:生成token失败")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.AUTHORIZATION_FAIL, "生成token失败"))return}c.Header(global.Authorization, token)// 写入redisredisToken := fmt.Sprintf("user-token-%s", userName)isOk := core.Redis.SetEX(redisToken, token, 7*24*time.Hour)if isOk == false {core.LOG.Println("用户登录:设置值到redis")c.JSON(http.StatusOK, common.FailWithCodeMsg(common.REDIS_SET_FAIL, "设置值到Redis失败"))return}userVo := vo.ConvertToUserResVo(user)c.Header(global.Authorization, token)c.JSON(http.StatusOK, gin.H{"token": token,"user":  userVo,})}// GetUserByUsername 根据用户名查询用户
//
//	@Summary	用户登录
//	@Produce	json
//	@Router		/api/user/getUserByName [get]
//	@Param		username	query	string	true	"用户名"	maxlength(20)
func GetUserByUsername(c *gin.Context) {userName := c.Query("username")user := dao.GetUserByUsername(userName)if user.Username == "" {c.JSON(http.StatusOK, common.FailWithMsg("未查询到该用户"))return}userVo := vo.ConvertToUserResVo(user)c.JSON(http.StatusOK, common.OkWithData(userVo))
}// GetAllUser 查询所有的用户
//
//	@Summary	查询所有的用户
//	@Produce	json
//	@Router		/api/user/getAllUser [get]
//	@Param		pagenum		query	int	true	"页数"
//	@Param		pagesize	query	int	true	"页面大小"
func GetAllUser(c *gin.Context) {pageNum, _ := strconv.Atoi(c.Query("pagenum"))pageSize, _ := strconv.Atoi(c.Query("pagesize"))core.LOG.Printf("pagenum: %d, pagesize: %d\n", pageNum, pageSize)if pageNum <= 0 {pageNum = 0}if pageSize <= 0 {pageSize = 1}users, total := dao.GetUser(pageNum, pageSize)c.JSON(http.StatusOK, common.OkWithData(common.NewPageRes(users, total)))
}

router配置

package middlewareimport ("code-go/app/admin/api"_ "code-go/docs""github.com/gin-gonic/gin"swaggerFiles "github.com/swaggo/files"     // swagger embed filesginSwagger "github.com/swaggo/gin-swagger" // gin-swagger middleware
)// InitRouter 初始化Router
func InitRouter() *gin.Engine {g := gin.New()g.Use(gin.Recovery())g.Use(Logger())g.Use(Cors())// 需授权auth := g.Group("/api"){auth.GET("/user/getAllUser", api.GetAllUser)auth.POST("/user/register", api.Register)auth.POST("/user/login", api.Login)auth.GET("/user/getUserByName", api.GetUserByUsername)}// 无需授权norm := g.Group("/"){norm.GET("/getIp", api.GetIp)norm.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))norm.GET("/captcha", api.GetCaptcha)norm.POST("/checkCaptcha", api.CheckCaptcha)}return g
}

测试

使用swagger测试如下,可以确认登录成功,且有token生成
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

springBoot整合Redis(三、整合Spring Cache)

缓存的框架太多了&#xff0c;各有各的优势&#xff0c;比如Redis、Memcached、Guava、Caffeine等等。 如果我们的程序想要使用缓存&#xff0c;就要与这些框架耦合。聪明的架构师已经在利用接口来降低耦合了&#xff0c;利用面向对象的抽象和多态的特性&#xff0c;做到业务代…

上市公司财务报表精讲系列一:黄山旅游

上市公司财务报表精讲系列一&#xff1a;黄山旅游 一、主营业务分行业、分产品、分地区情况二、董事会报告三、净利润现金流四、净资产收益率五、权益乘数和总资产周转率六、负债结构图七、行业分析八、案例总结九、2023年度业绩 一、主营业务分行业、分产品、分地区情况 二、董…

为国产信创服务器提供LDAP统一身份认证方案

金融信创作为 8 大行业信创之首&#xff0c;早已成为其他行业信创建设的参考。金融行业有着极为复杂的业务场景&#xff0c;对系统有着极高的稳定可靠需求&#xff0c;因此&#xff0c;在寻找微软 AD 国产化替代方案时&#xff0c;常会涉及到更深层次的场景。例如&#xff0c;最…

unity学习(45)——选择角色菜单——客户端处理服务器的数据

1.已知客户端ReceiveCallBack中已经收到来自服务器返回的数据包。 2.问题是客户端MessageManager中的Update并没有拆解该数据包 &#xff0c;因该是因为脚本没有挂载。 挂在SelectMenu场景中的Camera上即可。 挂载后成功达到目地 其中Update中的List是一个起到全局效果的static…

CVPR 2024 | Modular Blind Video Quality Assessment:模块化无参视频质量评估

无参视频质量评估 (Blind Video Quality Assessment&#xff0c;BVQA) 在评估和改善各种视频平台并服务用户的观看体验方面发挥着关键作用。当前基于深度学习的模型主要以下采样/局部块采样的形式分析视频内容&#xff0c;而忽视了实际空域分辨率和时域帧率对视频质量的影响&am…

学习 考证 帆软 FCP-FineBI V6.0 心得

学习背景&#xff1a; 自2024年1月起&#xff0c;大部分时间就在家里度过了&#xff0c;想着还是需要充实一下自己&#xff0c;我是一个充满热情的个体。由于之前公司也和帆软结缘&#xff0c;无论是 Fine-Report 和 Fine-BI 都有接触3年之久&#xff0c;但是主要做为管理者并…

MyBatis复杂映射开发之多对多查询

多对多查询的模型 用户表和角色表的关系为&#xff0c;一个用户有多个角色&#xff0c;一个角色被多个用户使用。 多对多查询的需求&#xff1a;查询所有用户的同时查询出该用户对应的所有角色。 startuml !theme plain top to bottom direction skinparam linetype ortho cl…

阿里云服务器使用教程_搭建网站教程_2024建站教程

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…

XUbuntu22.04之显示实时网速(二百一十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

智能网联各地市政策盘点

本文旨在对2023年及2024年初各地市所出台的智能网联相关政策进行全面的梳理与总结。通过与此前发布的关于2023年和2024年初各部委、省、直辖市智能网联相关政策的盘点相互呼应&#xff0c;力求为读者呈现一个全面、系统的政策概览。 文 | 吴冬升 全文6000字&#xff0c;预计阅读…

html--3D爱心

文章目录 代码效果 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>爱心</title><style type"text/css">*{margin: 0px;border: 0px;}body{overflow: hidden;background-…

Docker-部署若依项目

文章目录 后端一、搭建局域网二、redis安装测试 三、MySQL安装四、后端项目放入位置及使用Dockerfile自定义镜像后端项目放入位置 前端配置检查各个端口是否启动nginx部署 首先得先把内部的文件给删除清空 docker images–查看有哪些文件 docker rmi -f ID–删除ID 后端 一、…

腾讯QQ推出AI聊天搭子;零一万物01AI宣布开源Yi-9B模型

&#x1f989; AI新闻 &#x1f680; 腾讯QQ推出AI聊天搭子&#xff0c;进军AI对话领域 摘要&#xff1a;腾讯QQ合作筑梦岛和混元助手&#xff0c;推出了AI对话功能“AI聊天搭子”&#xff0c;提供多种虚拟角色与用户实时互动&#xff0c;目前已开启测试。此外&#xff0c;抖…

STM32/GD32——I2C通信协议

芯片选型 Ciga Device — GD32F470系列 通讯规则 I2C协议&#xff08;或称IIC&#xff09;是由飞利浦&#xff08;现在的恩智浦半导体&#xff09;公司开发的一种通用的总线协议。它使用两根线&#xff08;时钟线和数据线&#xff09;来传输数据&#xff0c;支持多个设备共享…

智能设备 app 设计 —— 蓝蓝 UI 设计公司

今天给大家推荐是智能设备app设计&#xff0c;随着智能设备的逐渐普及随之操作app也越来越多&#xff0c;希望能给大家带来灵感 #日常灵感 #创意设计#UI提升#ui设计#app #设计案例分享|#设计 #产品设计#产品设计#设计灵感 #B端产品经理 #ui #产品 #美工 #交互 #产品经理 #开发 …

乐优商城(九)数据同步

1. 项目问题分析 现在项目中有三个独立的微服务&#xff1a; 商品微服务&#xff1a;原始数据保存在 MySQL 中&#xff0c;从 MySQL 中增删改查商品数据。搜索微服务&#xff1a;原始数据保存在 ES 的索引库中&#xff0c;从 ES 中查询商品数据。商品详情微服务&#xff1a;做…

怎么在图片上直接编辑文字?3个方法教你轻松编辑

怎么在图片上直接编辑文字&#xff1f;随着技术的飞速发展&#xff0c;图片编辑已经成为我们日常生活和工作中不可或缺的一部分。在图片上直接编辑文字&#xff0c;不仅能够添加说明和标注&#xff0c;提高信息的传达效率&#xff0c;还能够增强图片的美观和设计感&#xff0c;…

qt练习案例

记录一下qt练习案例&#xff0c;方便学习qt知识点 基本部件 案例1 需求&#xff0c;做一个标签&#xff0c;显示"你好"知识点&#xff0c;QLabel画面 4. 参考&#xff0c;Qt 之 QLabel 案例2 需求&#xff0c;做一个标签&#xff0c;显示图片 知识点&#xff0c;…

c++初阶------类和对象(六大默认构造函数的揭破)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

1.JavaWebJava基础加强[万字长文]-Junit、反射、注解核心知识点梳理

导语&#xff1a; 一、Junit单元测试 1.Junit测试概述 2.Junit使用步骤 3.Junit_Before&After 二、反射 1.反射概述 2.反射获取字节码Class对象的三种方式 3.Class对象功能概述 4.Class对象功能_获取Field 5.Class对象功能_获取Constructor 6.Class对象功能_获取…