• Go 快速开发朋友圈助力项目


    1.根据业务完成不同功能数据表的设计和编写

    在这里插入图片描述

    注册功能
    在models/user.go中定义结构体 验证用户名是否已存在 添加用户

    package models
    
    import (
    	"gin-ranking/dao"
    	"time"
    )
    
    type User struct {
    	Id         int    `json:"id"`
    	Username   string `json:"username"`
    	Password   string `json:"password"`
    	AddTime    int64  `json:"addTime"`
    	UpdateTime int64  `json:"updateTime"`
    }
    
    func (User) TableName() string {
    	return "user"
    }
    
    func GetUserInfoByUsername(username string) (User, error) {
    	var user User
    	err := dao.Db.Where("username=?", username).First(&user).Error
    	return user, err
    }
    
    func AddUser(username string, password string) (int, error) {
    	user := User{Username: username, Password: password, AddTime: time.Now().Unix(), UpdateTime: time.Now().Unix()}
    	err := dao.Db.Create(&user).Error
    	return user.Id, err
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    在 controllers/user.go中编写注册功能接口

    package controllers
    
    import (
    	"gin-ranking/models"
    	"github.com/gin-gonic/gin"
    )
    
    type UserController struct {
    }
    
    func (u UserController) Register(c *gin.Context) {
    	//获取参数信息
    	username := c.DefaultPostForm("username", "")
    	password := c.DefaultPostForm("password", "")
    	confirmPassword := c.DefaultPostForm("confirmPassword", "")
    	if username == "" || password == "" || confirmPassword == "" {
    		ReturnError(c, 4001, "请输入正确的信息")
    		return
    	}
    	if password != confirmPassword {
    		ReturnError(c, 4001, "密码和确认密码不相同")
    		return
    	}
    
    	user, err := models.GetUserInfoByUsername(username)
    	if user.Id != 0 {
    		ReturnError(c, 4001, "此用户名已存在")
    		return
    	}
    	_, err = models.AddUser(username, EncyMd5(password))
    	if err != nil {
    		ReturnError(c, 4002, "注册失败,请重试")
    		return
    	}
    
    	ReturnSuccess(c, 0, "success", "", 1)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    controllers/common.go 对密码进行加密

    func EncyMd5(s string) string {
    	ctx := md5.New()
    	ctx.Write([]byte(s))
    	return hex.EncodeToString(ctx.Sum(nil))
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    登录

    安装

    go get -u github.com/gin-contrib/sessions/redis
    go get -u github.com/gin-contrib/sessions
    
    • 1
    • 2

    登录信息保存在session redis
    config/redis.go

    package config
    
    const (
    	RedisAddress = "localhost:6379"
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    controllers/user.go

    // 如果直接使用上面的结构体 会将密码也返回  所以这里重新定义一个结构体用以返回
    type UserApi struct {
    	Id       int    `json:"id"`
    	Username string `json:"username"`
    }
    
    func (u UserController) Login(c *gin.Context) {
    	// 接收用户名和密码
    	username := c.DefaultPostForm("username", "")
    	password := c.DefaultPostForm("password", "")
    	if username == "" || password == "" {
    		ReturnError(c, 4001, "请输入用户名和密码")
    		return
    	}
    	user, _ := models.GetUserInfoByUsername(username)
    	if user.Id == 0 {
    		ReturnError(c, 4004, "用户名或密码不正确")
    		return
    	}
    
    	if user.Password != EncyMd5(password) {
    		ReturnError(c, 4004, "用户名或密码不正确")
    		return
    	}
    	// 用户信息存储到session
    	session := sessions.Default(c)
    	//Int转换为字符串
    	session.Set("login:"+strconv.Itoa(user.Id), user.Id)
    	session.Save()
    	data := UserApi{Id: user.Id, Username: user.Username}
    	ReturnSuccess(c, 0, "登录成功", data, 1)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述

    基于mysql实现投票功能

    在这里插入图片描述

    首先获取活动参赛选手接口
    在这里插入图片描述

    点击为他投票获取详情接口
    controllers/player.go

    package controllers
    
    import (
    	"gin-ranking/models"
    	"github.com/gin-gonic/gin"
    	"strconv"
    )
    
    type PlayerController struct{}
    
    func (p PlayerController) GetPlayers(c *gin.Context) {
    	aidStr := c.DefaultPostForm("aid", "0")
    	aid, _ := strconv.Atoi(aidStr)
    	rs, err := models.GetPlayers(aid, "id asc")
    	if err != nil {
    		ReturnError(c, 4004, "没有相关信息")
    
    		return
    	}
    	ReturnSuccess(c, 0, "success", rs, 1)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    models/player.go

    package models
    
    import (
    	"gin-ranking/dao"
    	"github.com/jinzhu/gorm"
    )
    
    type Player struct {
    	Id          int    `json:"id"`
    	Aid         int    `json:"aid"`
    	Ref         string `json:"ref"`
    	Nickname    string `json:"nickname"`
    	Declaration string `json:"declaration"`
    	Avatar      string `json:"avatar"`
    	Score       int    `json:"score"`
    	//AddTime     int64  `json:"addTime"`
    	//UpdateTime  int64  `json:"updateTime"`
    }
    
    func (Player) TableName() string {
    	return "player"
    }
    
    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    router/routers.go

    player := r.Group("/player")
    	{
    		player.POST("/list", controllers.PlayerController{}.GetPlayers)
    	}
    
    • 1
    • 2
    • 3
    • 4

    投票功能

    controllers/vote.go

    package controllers
    
    import (
    	"gin-ranking/models"
    	"github.com/gin-gonic/gin"
    	"strconv"
    )
    
    type VoteController struct{}
    
    func (v VoteController) AddVote(c *gin.Context) {
    	userIdStr := c.DefaultPostForm("userId", "0")
    	playerIdStr := c.DefaultPostForm("playerId", "0")
    	userId, _ := strconv.Atoi(userIdStr)
    	playerId, _ := strconv.Atoi(playerIdStr)
    
    	if userId == 0 || playerId == 0 {
    		ReturnError(c, 4001, "请输入正确的信息")
    		return
    	}
    	user, _ := models.GetUserInfo(userId)
    	if user.Id == 0 {
    		ReturnError(c, 4001, "投票用户不存在")
    		return
    	}
    	player, _ := models.GetPlayerInfo(playerId)
    	if player.Id == 0 {
    		ReturnError(c, 4001, "选手不存在")
    		return
    	}
    	vote, _ := models.GetVoteInfo(userId, playerId)
    	if vote.Id != 0 {
    		ReturnError(c, 4001, "已投票")
    		return
    	}
    
    	rs, err := models.AddVote(userId, playerId)
    	if err == nil {
    		//更新选手票数 自增1
    		models.UpdatePlayerScore(playerId)
    		//更新redis
    		//var redisKey string
    		//redisKey = "ranking:" + strconv.Itoa(player.Aid)
    		//cache.Rdb.ZIncrBy(cache.Rctx, redisKey, 1, strconv.Itoa(playerId))
    		ReturnSuccess(c, 0, "success", rs, 1)
    		return
    	}
    	ReturnError(c, 4004, "请联系管理员")
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    models/vote.go

    package models
    
    import (
    	"gin-ranking/dao"
    	"time"
    )
    
    type Vote struct {
    	Id       int   `json:"id"`
    	UserId   int   `json:"userId"`
    	PlayerId int   `json:"playerId"`
    	AddTime  int64 `json:"addTime"`
    }
    
    func (Vote) TableName() string {
    	return "vote"
    }
    
    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
    }
    
    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    router/routers.go

    vote := r.Group("/vote")
    	{
    		vote.POST("/add", controllers.VoteController{}.AddVote)
    	}
    
    • 1
    • 2
    • 3
    • 4

    models/user.go

    func GetUserInfo(id int) (User, error) {
    	var user User
    	err := dao.Db.Where("id = ?", id).First(&user).Error
    	return user, err
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    models/player.go

    func GetPlayerInfo(id int) (Player, error) {
    	var player Player
    	err := dao.Db.Where("id = ?", id).First(&player).Error
    	return player, err
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    models/player.go

    func UpdatePlayerScore(id int) {
    	var player Player
    	dao.Db.Model(&player).Where("id = ?", id).UpdateColumn("score", gorm.Expr("score + ?", 1))
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    基于mysql数据库orderby排序实现排名展示功能

    controllers/player.go

    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, 4004, "没有相关信息")
    		return
    	}
    	ReturnSuccess(c, 0, "success", rs, 1)
    	return
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    modesl/player.go

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    r.POST("/ranking", controllers.PlayerController{}.GetRanking)
    
    • 1

    使用redis的有序集合 Sorted Sets优化排行榜功能

    go get -u github.com/redis/go-redis/v9
    
    • 1

    controllers/player.go

    package controllers
    
    import (
    	"gin-ranking/cache"
    	"gin-ranking/models"
    	"github.com/gin-gonic/gin"
    	"strconv"
    	"time"
    )
    
    type PlayerController struct{}
    
    func (p PlayerController) GetPlayers(c *gin.Context) {
    	aidStr := c.DefaultPostForm("aid", "0")
    	aid, _ := strconv.Atoi(aidStr)
    	rs, err := models.GetPlayers(aid, "id asc")
    	if err != nil {
    		ReturnError(c, 4004, "没有相关信息")
    
    		return
    	}
    	ReturnSuccess(c, 0, "success", rs, 1)
    }
    
    func (p PlayerController) GetRanking(c *gin.Context) {
    	aidStr := c.DefaultPostForm("aid", "0")
    	aid, _ := strconv.Atoi(aidStr)
    
    	var redisKey string
    	// 通过aid区分活动
    	redisKey = "ranking:" + aidStr
    	// 这段代码是使用 Go 语言操作 Redis 数据库,通过 ZRevRange 方法获取有序集合中指定范围内的成员,并按照分数从大到小排序。其中,redisKey 是有序集合的键名,0 和 -1 分别表示起始位置和结束位置,-1 表示最后一个成员。
    
    	rs, err := cache.Rdb.ZRevRange(cache.Rctx, redisKey, 0, -1).Result()
    	// 如果有就直接返回
    	if err == nil && len(rs) > 0 {
    		var players []models.Player
    		for _, value := range rs {
    			id, _ := strconv.Atoi(value)
    			rsInfo, _ := models.GetPlayerInfo(id)
    			if rsInfo.Id > 0 {
    				players = append(players, rsInfo)
    			}
    		}
    		ReturnSuccess(c, 0, "success", players, 1)
    		return
    	}
    	// 如果没有就直接从数据库获取
    	rsDb, errDb := models.GetPlayers(aid, "score desc")
    	//获取到值
    	if errDb == nil {
    		// 从mysql数据库获取到的值再存入到redis中
    		for _, value := range rsDb {
    			cache.Rdb.ZAdd(cache.Rctx, redisKey, cache.Zscore(value.Id, value.Score)).Err()
    		}
    		//遍历完成以后为rediskey设置过期时间
    		cache.Rdb.Expire(cache.Rctx, redisKey, 24*time.Hour)
    		ReturnSuccess(c, 0, "success", rs, 1)
    		return
    	}
    	ReturnError(c, 4004, "没有相关信息")
    	return
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    cache/redis.go

    package cache
    
    import (
    	"context"
    	"gin-ranking/config"
    	"github.com/redis/go-redis/v9"
    )
    
    var (
    	Rdb  *redis.Client
    	Rctx context.Context
    )
    
    func init() {
    	Rdb = redis.NewClient(&redis.Options{
    		Addr:     config.RedisAddress,
    		Password: config.RedisPassword, // 没有密码,默认值
    		DB:       config.RedisDb,       // 默认DB 0
    	})
    	Rctx = context.Background()
    }
    
    func Zscore(id int, score int) redis.Z {
    	return redis.Z{Score: float64(score), Member: id}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    config/redis.go

    package config
    
    const (
    	RedisAddress  = "localhost:6379"
    	RedisPassword = "123456"
    	RedisDb       = 0
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    问题:当我们投票的时候,我们更新的是数据库,这个时候如果不更新redis,在缓存没有过期的这个时间段,它的排行榜是不变的,所以要优化一下投票的代码
    在这里插入图片描述

    前面是参赛选手的id 后面是分数
    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    如何升级nodejs版本
    TallComponents TallPDF.NET 5.X Crack
    掩苦剂树脂335
    CANoe/CAPL ,钉钉群助手消息通知
    CSS——grid网格布局的基本使用
    echars柱状图怎么每个柱子设置不同颜色
    python的有序容器:sortedcontainers(第三方模块)
    “世界首台USB-C iPhone”被拍卖,目前出价63万人民币
    《TCP/IP网络编程》阅读笔记--epoll的使用
    【内网安全】——windows信息收集
  • 原文地址:https://blog.csdn.net/weixin_47906106/article/details/133785079