13. 用户注册功能实现

文章目录

  • 一 、增加路由
  • 二、书写流程控制(controller)逻辑
  • 三、书写业务逻辑
  • 四、与DB交互
  • 五、测试

代码地址:https://gitee.com/lymgoforIT/bluebell

一 、增加路由

添加路由,使用分组管理

v1 := r.Group("/api/v1")// 注册
v1.POST("/signup", controller.SignUpHandler)

由于我们的项目是非常简单的上入门项目,所以并不会用到DDD等复杂的目录设计和管理,而是用了最基本的MVC三层结构。

  • controller目录用于接收路由,进行基本的参数校验,不做业务逻辑处理。
  • logic目录用于处理业务逻辑。
  • dao目录用于用数据源交互。

绿色即为本次注册功能需要新增的代码文件

在这里插入图片描述

二、书写流程控制(controller)逻辑

controller/user.go user.go文件主要负责用户的注册和登录。 这里首先写注册逻辑,后续的登录逻辑也会在这个文件中实现。

package controllerimport ("bluebell/models""github.com/gin-gonic/gin""github.com/go-playground/validator/v10""go.uber.org/zap"
)// SignUpHandler 处理注册请求的函数
func SignUpHandler(c *gin.Context) {// 1. 获取参数和参数校验p := new(models.ParamSignUp)if err := c.ShouldBindJSON(p); err != nil {// 请求参数有误,直接返回响应zap.L().Error("SignUp with invalid param", zap.Error(err))// 判断err是不是validator.ValidationErrors 类型errs, ok := err.(validator.ValidationErrors)if !ok {ResponseError(c, CodeInvalidParam)return}ResponseErrorWithMsg(c, CodeInvalidParam, removeTopStruct(errs.Translate(trans)))return}// 2. 业务处理if err := logic.SignUp(p); err != nil {zap.L().Error("logic.SignUp failed", zap.Error(err))if errors.Is(err, mysql.ErrorUserExist) {ResponseError(c, CodeUserExist)return}ResponseError(c, CodeServerBusy)return}// 3. 返回响应ResponseSuccess(c, nil)
}

代码说明:

  1. controller层不做业务逻辑,主要就是组织整体流程的,如参数校验,业务处理,返回响应。
  2. 返回结果比较通用,所以封装工具函数更为简介、易读。
  3. 适当的定义一些错误码是不错的选择。

定义状态码并封装响应方法

controller/code.go

package controllertype ResCode int64const (CodeSuccess ResCode = 1000 + iotaCodeInvalidParamCodeUserExistCodeUserNotExistCodeInvalidPasswordCodeServerBusyCodeNeedLoginCodeInvalidToken
)var codeMsgMap = map[ResCode]string{CodeSuccess:         "success",CodeInvalidParam:    "请求参数错误",CodeUserExist:       "用户名已存在",CodeUserNotExist:    "用户名不存在",CodeInvalidPassword: "用户名或密码错误",CodeServerBusy:      "服务繁忙",CodeNeedLogin:    "需要登录",CodeInvalidToken: "无效的token",
}func (c ResCode) Msg() string {msg, ok := codeMsgMap[c]if !ok {msg = codeMsgMap[CodeServerBusy]}return msg
}

controller/response.go

package controllerimport ("net/http""github.com/gin-gonic/gin"
)/*
{"code": 10000, // 程序中的错误码"msg": xx,     // 提示信息"data": {},    // 数据
}*/type ResponseData struct {Code ResCode     `json:"code"`Msg  interface{} `json:"msg"`Data interface{} `json:"data,omitempty"`
}func ResponseError(c *gin.Context, code ResCode) {c.JSON(http.StatusOK, &ResponseData{Code: code,Msg:  code.Msg(),Data: nil,})
}func ResponseErrorWithMsg(c *gin.Context, code ResCode, msg interface{}) {c.JSON(http.StatusOK, &ResponseData{Code: code,Msg:  msg,Data: nil,})
}func ResponseSuccess(c *gin.Context, data interface{}) {c.JSON(http.StatusOK, &ResponseData{Code: CodeSuccess,Msg:  CodeSuccess.Msg(),Data: data,})
}

三、书写业务逻辑

首先,我们需要查询DB中要注册的用户名是否已经存在,所以需要先提供一个可以和DB交互的model,user

models/user.go

提示:可以直接SQL转对应的结构体

在这里插入图片描述

package modelsimport "time"type User struct {ID         int64     `gorm:"column:id" db:"id" json:"id" form:"id"`UserId     int64     `gorm:"column:user_id" db:"user_id" json:"user_id" form:"user_id"`Username   string    `gorm:"column:username" db:"username" json:"username" form:"username"`Password   string    `gorm:"column:password" db:"password" json:"password" form:"password"`Email      string    `gorm:"column:email" db:"email" json:"email" form:"email"`Gender     int64     `gorm:"column:gender" db:"gender" json:"gender" form:"gender"`CreateTime time.Time `gorm:"column:create_time" db:"create_time" json:"create_time" form:"create_time"`UpdateTime time.Time `gorm:"column:update_time" db:"update_time" json:"update_time" form:"update_time"`
}func (User) TableName() string {return "user"
}

logic/user.go
负责校验用户名是否已经存在,若不存在,则生成唯一的用户ID,注册用户

import ("bluebell/models""bluebell/pkg/snowflake"
)func SignUp(p *models.ParamSignUp) (err error) {// 1.判断用户存不存在if err := mysql.CheckUserExist(p.Username); err != nil {return err}// 2.生成UIDuserID := snowflake.GenID()// 构造一个User实例user := &models.User{UserID:   userID,Username: p.Username,Password: p.Password,}// 3.保存进数据库return mysql.InsertUser(user)
}

四、与DB交互

定义与DB交互时可能出现的相关错误码

dao/mysql/error_code.go

package mysqlimport "errors"var (ErrorUserExist       = errors.New("用户已存在")ErrorUserNotExist    = errors.New("用户不存在")ErrorInvalidPassword = errors.New("用户名或密码错误")ErrorInvalidID       = errors.New("无效的ID")
)

校验用户名是否已经存在、对密码加密、保存新注册的用户

dao/mysql/user.go

package mysqlimport ("bluebell/models""crypto/md5""encoding/hex"
)// 把每一步数据库操作封装成函数
// 待logic层根据业务需求调用const secret = "lym.com"// CheckUserExist 检查指定用户名的用户是否存在
func CheckUserExist(username string) (err error) {var count int64if err := db.Model(models.User{}).Where("username = ?", username).Count(&count).Error; err != nil {return err}if count > 0 {return ErrorUserExist}return
}// InsertUser 想数据库中插入一条新的用户记录
func InsertUser(user *models.User) (err error) {// 对密码进行加密user.Password = encryptPassword(user.Password)// 执行SQL语句入库u := &models.User{UserId:   user.UserId,Username: user.Username,Password: user.Password,}err = db.Create(&u).Errorreturn
}// encryptPassword 密码加密
func encryptPassword(oPassword string) string {h := md5.New()h.Write([]byte(secret))return hex.EncodeToString(h.Sum([]byte(oPassword)))
}

五、测试

编译

go build

运行

 ./bluebell.exe ./config/config.yaml

注册,因为lym已经存在,所以会返回用户名已存在
在这里插入图片描述
注册一个不存在的名字试试,成功!
在这里插入图片描述

查询DB,注册成功,且密码是经过MD5加密过的(实际就是123)
在这里插入图片描述

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

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

相关文章

Python JSON 数据解析

文章目录 JSON将Python数据结构转换为JSON字符串将JSON字符串解析为Python数据结构处理JSON数组处理JSON对象和字段名称json.dumps 与 json.loads 实例使用json.dumps将Python字典转换为JSON字符串使用json.loads将JSON字符串解析为Python字典完整代码示例 JSON json模块提供了…

【java】22:throws 异常处理

基本介绍 1)如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。 2)在方法声明中用throw…

Linux - 进程信号

1、信号入门 1.1、生活角度的信号 你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时, 你该怎么处理快递。也就是你能“识别快递”;当快递员到了你楼下,你也收到快递到来的通…

Pytest+Selenium UI自动化测试实战实例(全)

🍅 视频学习:文末有免费的配套视频可观看 🍅 关注公众号【互联网杂货铺】,回复 1 ,免费获取软件测试全套资料,资料在手,涨薪更快 今天来说说pytest吧,经过几周的时间学习&#xff0c…

Redis实现用户活跃排行榜

在这里用户活跃度排行榜,主要是基于redis的zset数据结构来实现的,下面来看一下实例。 方案设计 来看一下业务场景先 1.场景说明 在技术派中,提供了一个用户的活跃排行榜,当然作为一个博客社区,更应该实现的是作者排…

连号区间数 刷题笔记

1.单个元素算一个连续区间 2.题意为 单独截取数组中的一段元素 例如 a数组假设为 3 1 2 5 4 6 7 假设取 a[3]-a[5] 则取出 5 4 6 重新排序后为 4 5 6 连续了 则ans; 假设 取a[i]-a[j]这一段元素 设该段元素的最大值为max,最小值为min 如果该段元素重新排序后…

docker本地搭建spark yarn hive环境

docker本地搭建spark yarn hive环境 前言软件版本准备工作使用说明构建基础镜像spark on yarn模式构建on-yarn镜像启动on-yarn集群手动方式自动方式 spark on yarn with hive(derby server)模式构建on-yarn-hive镜像启动on-yarn-hive集群手动方式自动方式 常用示例spark执行sh脚…

Learn OpenGL 04 纹理

纹理环绕方式 纹理坐标的范围通常是从(0, 0)到(1, 1),那如果我们把纹理坐标设置在范围之外会发生什么?OpenGL默认的行为是重复这个纹理图像(我们基本上忽略浮点纹理坐标的整数部分),但OpenGL提供了更多的选择&#xf…

LCR 131. 砍竹子 I

解题思路:(与砍竹子II的区别是,这里的竹子长度数量级较小) 数学推导或贪心 切分规则: 等长,且尽量为3 b0时,pow(3,a) b1时,pow(3,a-1)*4 少一段3,并入b生成一…

Java进阶-实现一个基本的消息队列

消息队列是一种用于在应用程序之间传递消息的关键组件,它能够提高系统的可伸缩性和可靠性。在这篇文章中,我们将探讨如何实现一个基本的消息队列,了解其核心概念和基本原理。 一、消息队列的概念 消息队列是一种通信方式,它允许…

洛谷 1019.单词接龙

这道题用的搜索,也就是DFS,但是有一点难度,虽然说是对于搜索的知识点的考察,但是对于编程者的编程模拟能力和分析能力会有比较大的要求。 思路:首先我们审题,会注意到以下几点: 1.单词后面相同…

【pytorch学习】交叉熵损失函数 nn.CrossEntropyLoss() = nn.LogSoftmax(dim=1) + nn.NLLLoss()

结论: Pytorch中CrossEntropyLoss()函数的主要是将softmax-log-NLLLoss合并到一块得到的结果。 from: https://zhuanlan.zhihu.com/p/98785902 import torch import torch.nn as nn x_inputtorch.randn(3,3)#随机生成输入 print(x_input:\n,x_input)…

YUNBEE云贝:3月9日-PostgreSQL中级工程师PGCE认证培训

课程介绍 根据学员建议和市场需求,规划和设计了《PostgreSQL CE 认证课程》,本课程以内部原理、实践实战为主,理论与实践相结合。课程包含PG 简介、安装使用、服务管理、体系结构等基础知识。同时结合一线实战案例, 面向 PG 数据库的日常维护管理、服务和…

Vue | 基于 vue-admin-template 项目的跨域问题解决方法

目录 一、现存问题 二、解决方法 2.1 修改的第一个地方 2.2 修改的第二个地方 2.3 修改的第三个地方 自存 一、现存问题 报错截图如下: 二、解决方法 2.1 修改的第一个地方 在 .env.development 文件中: # base api # VUE_APP_BASE_API /d…

springboot整合shiro的实战教程(一)

文章目录 1.权限的管理1.1 什么是权限管理1.2 什么是身份认证1.3 什么是授权 2.什么是shiro3.shiro的核心架构3.1 Subject3.2 SecurityManager3.3 Authenticator3.4 Authorizer3.5 Realm3.6 SessionManager3.7 SessionDAO3.8 CacheManager3.9 Cryptography 4. shiro中的认证4.1…

我的 4096 创作纪念日

作者:明明如月学长, CSDN 博客专家,大厂高级 Java 工程师,《性能优化方法论》作者、《解锁大厂思维:剖析《阿里巴巴Java开发手册》》、《再学经典:《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

header组件编写和Vuex store创建

src\components\Header\index.vue <template><header class"header"><h1><slot></slot></h1></header> </template><script> export default {name: Header } </script> src\main.js 引入全局样式 imp…

YOLOv8+DeepSort/ByteTrack-PyQt-GUI / yolov5 deepsort 行人/车辆(检测 +计数+跟踪+测距+测速)

YoloV8结合可视化界面和GUI&#xff0c;实现了交互式目标检测与跟踪&#xff0c;为用户提供了一体化的视觉分析解决方案。通过YoloV8算法&#xff0c;该系统能够高效准确地检测各类目标&#xff0c;并实时跟踪它们的运动轨迹。 用户可以通过直观的可视化界面进行操作&#xff…

Unity性能优化篇(七) UI优化注意事项以及使用Sprite Atlas打包精灵图集

UI优化注意事项 1.尽量避免使用IMGUI(OnGUI)来做游戏时的UI&#xff0c;因为IMGUI的开销比较大。 2.如果一个UGUI的控件不需要进行射线检测&#xff0c;则可以取消勾选Raycast Target 3.尽量避免使用完全透明的图片和UI控件。因为即使完全透明&#xff0c;我们看不见它&#xf…

常见BUG如何在测试过程中分析定位

前言 在测试的日常工作中&#xff0c;相信经常有测试的小伙伴遇到类似的情况&#xff1a;在项目上线时&#xff0c;只要出现问题&#xff08;bug&#xff09;&#xff0c;就很容易成为“背锅侠”。 软件测试人员在工作中是无法避免的要和开发人员和产品经理打交道的&#xff…