自学内容网 自学内容网

Gin框架简易搭建(4)--项目开发

项目信息

项目四个初始功能所在处,很快将对投票验证信息以及录入活动和参赛者的功能将在后续实现

需求分析

这个项目需要如下的功能:

  1. 参赛人员列表及详情(前端)
  2. 排行榜
  3. 投票功能
  4. 用户的注册和登陆
  5. 活动规则(前端)

数据库

表名称参数一(主键)参数二参数三参数四参数五参数六参数七参数八
activity(活动表)id(主键)name(活动名称)add_time(添加时间)
player(参赛选手表)id(主键)nickname(选手名称)aid(参与活动)ref(编号)avatar(头像int)score(得分)declaration(个性签名)update_time(更新时间)
user(群众评委)id(主键)username(用户名)password(密码)add_time(添加时间)update_time(更新时间)
vote(用户给选手点赞记录表)id(主键)user_id(投票者id)player_id(参赛选手id)add_time(添加时间)

补充

  1. gin.Context,这个结构体方便我们通过它访问http请求的各种信息。简而言之,就是通过修改它的内容,在返回的报文显示。
  2. module文件夹中的结构体Json后缀是什么意思?在json中,后缀里的名字就是这个结构体成员变量的名称;而程序中该成员变量的名称是前面声明的名称
  3. where查询:查到的话——Error返回nil;没查到返回错误信息,这一点还是挺容易写错的
  4. c.DefaultPostForm获取方式:(参数1,参数2)返回值——参数1是键名,参数2是设置的“若没有查询到的返回默认值”。("username",""),这种用法,就是说如果查询到就返回查询到的用户名,查不到就返回空字符串。

数据库注意事项的

这个项目的主要问题来源于数据库

  1. 传输类型:注意结构体声明的时候,类型和数据库的类型是否一致

  2. 字段名:字段名在gormmysql之间存在转化关系,建议程序里面使用驼峰命名,数据库中使用下划线隔开

    1. 数据库字段名与结构体字段名的转换
    • 默认转换规则GORM默认会将结构体字段的驼峰命名转换为数据库字段的下划线命名。例如,Go 结构体中的字段 UserName 将自动映射到数据库中的字段 user_name

    • 自定义转换:如果需要自定义字段名的转换规则,可以通过标签(tag)来指定。例如:

      type User struct {
          UserName string `gorm:"column:username"`
      }
      

      在这种情况下,即使结构体字段名为UserName,GORM 也会将其映射到数据库中的username字段。

    1. 标签的使用
    • column 标签:通过 gorm:"column:xxx" 标签可以显式指定数据库中的字段名。
    • type 标签:可以指定数据库字段的数据类型。
    • size 标签:可以指定字段的大小(例如字符串长度)。
    • primaryKey 标签:指定字段为数据库表的主键。
    1. 自动迁移
    • 当使用 GORM的自动迁移功能(AutoMigrate)时,GORM会根据结构体字段名自动生成数据库表结构。这种情况下,GORM会自动应用上述的字段名转换规则。
    1. 忽略字段
    • 如果某些字段不需要映射到数据库表中,可以使用 gorm:"-" 标签将其忽略。
  3. sql语句查错:在sql语句使用时,建议直接在Gorm中文文档中复制,在报错信息出现时,建议直接将error打印在json文件中,在测试的插件中以报文形式返回。

代码解释

这个项目的代码可以参考项目地址里面的完整代码,下面的部分是对于开发的四个简单功能进行详细的解释

首先,我们的设计模式依旧是路由-->类controller-->模块func,对于核心的设计,选择的方法是获取信息-->验证-->录入数据库并返回json

注册

首先,注册我们使用用户名、密码、确认密码作为输入,将用户类的部分(id和用户名)通过新建结构体的方式进行返回。验证部分:

  1. 首先我们需要对输入进行验证,保证输入不为空
  2. 之后,要保证输入的密码与确认密码一致
  3. 最后,对用户数据库进行遍历,发现没有重复的用户名
func (u UserController) Register(c *gin.Context) {
//接受用户名 密码以及确认密码
username := c.DefaultPostForm("username", "")
password := c.DefaultPostForm("password", "")
confirmPassword := c.DefaultPostForm("confirm_password", "")

//验证 输入是否存在某项为空 密码和确认密码是否一致 是否已经存在该用户
if username == "" || password == "" || confirmPassword == "" {
ReturnError(c, 4001, "输入的用户名、密码、确认密码其中有空项")
return
}
if password != confirmPassword {
ReturnError(c, 4002, "密码和确认密码不一致")
return
}
user1, _ := models.CheckUserExist(username)
if user1.Id != 0 {
ReturnError(c, 4003, "该用户已存在")
return
}

//创建用户
userapi, err2 := models.AddUser(username, EncryMd5(password))
if err2 != nil {
ReturnError(c, 4004, "保存用户失败")
return
}

ReturnSuccess(c, 0, "注册成功", userapi, 1)
}

函数说明:

// 判断用户名是否已经存在
func CheckUserExist(username string) (User, error) {
var user User
err := dao.Db.Where("username =?", username).First(&user).Error
return user, err
}

// 保存用户
func AddUser(username, password string) (UserApi, error) {
user := User{Username: username, Password: password, AddTime: time.Now().Unix(), UpdateTime: time.Now().Unix()}
err := dao.Db.Create(&user).Error
userapi := UserApi{Username: username, Userid: user.Id}
return userapi, err
}

登陆

登陆时,设计思路与上面的注册一致,只是在验证环节需要将输入的密码和数据库里面的加密版本进行比较,看是否一致

// 登陆
func (u UserController) Login(c *gin.Context) {
//接受用户名 密码
username := c.DefaultPostForm("username", "")
password := c.DefaultPostForm("password", "")

//验证 用户名或者密码为空 用户名不存在 密码错误
if username == "" || password == "" {
ReturnError(c, 4011, "用户名或密码为空")
return
}
user1, err := models.CheckUserExist(username)
if err != nil {
ReturnError(c, 4012, "用户名不存在")
return
}
if user1.Password != EncryMd5(password) {
ReturnError(c, 4013, "密码错误")
return
}

使用sessions
//session := sessions.Default(c)
//session.Set("Login"+strconv.Itoa(user1.Id), user1.Id)
//session.Save()

//返回登录信息
date := UserLoginApi{
Id:       user1.Id,
Username: user1.Username,
}
ReturnSuccess(c, 0, "登录成功", date, 1)
}

函数说明:

// 通过Id来查找用户
func CheckUserById(id int) (User, error) {
var user User
err := dao.Db.Where("id =?", id).First(&user).Error
return user, err
}

投票

在实现这个功能的时候,需要注意:我们既要像注册功能一样在vote表中更新一条记录,又要对参赛者的字段进行更新。字段的更新我们使用Gorm提供的语句:

db.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3 AND quantity > 1;

源代码:

type VoteController struct{}

func (v VoteController) AddVote(c *gin.Context) {
//获取数据
userIdStr := c.DefaultPostForm("user_id", "0")
playerIdStr := c.DefaultPostForm("player_id", "0")
userId, _ := strconv.Atoi(userIdStr)
playerId, _ := strconv.Atoi(playerIdStr)

//检查数输入
if userId == 0 || playerId == 0 {
ReturnError(c, 4031, "输入参数为空,请重新输入")
}
user, _ := models.CheckUserById(userId)
if user.Id == 0 {
ReturnError(c, 4032, "用户不存在")
}
player, _ := models.GetPlayerById(playerId)
if player.Id == 0 {
ReturnError(c, 4033, "参赛者不存在")
}

//检查是否已经vote了 返回值重复投票
vote, _ := models.GetVoteInfo(userId, playerId)
if vote.Id != 0 { //已经投过票了
ReturnError(c, 4034, "已经投票过了")
}

//添加vote
rs, err := models.AddVote(userId, playerId)
if err == nil {
models.UpdateScoreByVote(playerId)
ReturnSuccess(c, 0, "投票成功", rs, 1)
return
}

ReturnError(c, 4035, err.Error())
}

函数说明:

// 通过投票来更新得分 player models
func UpdateScoreByVote(id int) {
var player Player
dao.Db.Model(&player).Where("id =?", id).UpdateColumn("score", gorm.Expr("score + ?", 1))
}

//下面两个都是在vote models
// 用来检查是否投过票了
func GetVoteInfo(userId int, playerId int) (Vote, error) {
var vote Vote
err := dao.Db.Where("user_id =? AND player_id =?", userId, playerId).First(&vote).Error
return vote, err
}

// 实现投票的记录
func AddVote(userId int, playerId int) (int, error) {
vote := Vote{
UserId:   userId,
PlayerId: playerId,
AddTime:  time.Now().Unix(),
}
err := dao.Db.Create(&vote).Error
return vote.Id, err
}

排行榜

这里使用了一个order关键字 定义排序字段以及顺序

func (p PlayerController) GetRanking(c *gin.Context) {
//获取活动编号
aidStr := c.DefaultPostForm("aid", "0")
aid, _ := strconv.Atoi(aidStr)

rs, err := models.GetPlayers(aid, "score desc")
if err != nil {
ReturnError(c, 4021, "获取排名失败")
return
}

ReturnSuccess(c, 0, "获取成功", rs, 1)
return
}

函数说明:

// 获取某种顺序排列的某一活动的玩家列表 DESC降序 ASC升序
func GetPlayers(aid int, sort string) ([]Player, error) {
var players []Player
err := dao.Db.Where("aid =?", aid).Order(sort).Find(&players).Error
return players, err
}

原文地址:https://blog.csdn.net/Hock2023/article/details/142897415

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!