一、项目详情
1.1项目介绍
项目地址
本项目是黑马程序员的Redis实战项目,使用Go语言重构的版本。目前项目还在开发中,本文会持续更新。
1.2使用技术栈
二、达人探店
达人探店,类似于博客、笔记等功能。涉及到基于基于SortSet的点赞列表和点赞排行。
2.1发布博客
图片不直接存在数据库中,而是存储图片的地址,故发布博客的实现分为两个步骤 流程如上图:
- 上传图片,获得图片地址
- 发布博客
前端提交后向数据库插入一条记录
u := utils.GetUser(h.Context).GetID()
req.UserId = u
if !errors.Is(mysql.DB.Create(&req).Error, nil) {
return nil, errors.New("创建失败")
}
req.Icon = utils.GetUser(h.Context).GetIcon()
req.NickName = utils.GetUser(h.Context).GetNickName()
req.IsLiked = false
2.2 查看博客
查看博客时,除了显示博客内容以外还要显示用户头像、是否关注等信息
用户信息使用userDto结构体定义,需要通过user对象转换而来,避免频繁转换,直接将字段定义才Blog结构体中,并使用gorm:-表示不属于blog表的字段,需要忽略
struct Blog {
1: i64 id (go.tag='gorm:"id"');
2: i64 shopId (go.tag='gorm:"shop_id"')
3: i64 userId (go.tag='gorm:"user_id"')
4: string title (go.tag='gorm:"title"')
5: string images (go.tag='gorm:"images"')
6: string content (go.tag='gorm:"content"')
7: i64 liked (go.tag='gorm:"liked"')
8: i64 comments (go.tag='gorm:"comments"')
9: string createTime (go.tag='gorm:"create_time"');
10: string updateTime (go.tag='gorm:"update_time"');
11: string icon (go.tag='gorm:"-"');
12: string nickName (go.tag='gorm:"-"');
13: bool isLiked (go.tag='gorm:"-"');
}
查询逻辑分为3步,1、查询博客数据,2、查询用户信息,3、查询点赞状态
if !errors.Is(mysql.DB.First(&resp, "id = ?", req).Error, nil) {
return nil, errors.New("未找到该博客")
}
userId := resp.UserId
user, err := mysql.GetById(h.Context, userId)
if err != nil {
return nil, err
}
resp.Icon = user.Icon
resp.NickName = user.NickName
resp.IsLiked = false
// 获取点赞状态
u := utils.GetUser(h.Context).GetID()
key := constants.BLOG_LIKED_KEY + *req
isLike, err := redis.IsLiked(h.Context, key, strconv.FormatInt(u, 10))
if err != nil {
return nil, err
}
resp.IsLiked = isLike
return resp, nil
2.3点赞博客
点赞前判断是否已经点赞,如果已经点赞则取消
var interBlog blog.Blog
err = mysql.DB.Where("id=?", req).First(&interBlog).Error
if !errors.Is(err, nil) {
return nil, errors.New("博客不存在")
}
// 判断是否已经点赞
u := utils.GetUser(h.Context).GetID()
idStr := strconv.FormatInt(u, 10)
key := constants.BLOG_LIKED_KEY + *req
isLike, err := redis.IsLiked(h.Context, key, idStr)
if err != nil {
hlog.Debugf("like redis error: %+v", err)
return nil, err
}
fmt.Printf("isLike = %+v", isLike)
// 如果已经点赞则取消点赞
if isLike {
if !errors.Is(redis.RedisClient.ZRem(h.Context, key, idStr).Err(), nil) {
return nil, errors.New("取消点赞失败")
}
// 同步减少点赞数
mysql.DB.Model(&blog.Blog{}).Where("id = ?", req).UpdateColumn("liked", gorm.Expr("liked - ?", 1))
return &blog.LikeResp{IsLiked: false}, nil
}
// 否则点赞
if !errors.Is(redis.RedisClient.ZAdd(h.Context, key, &redis2.Z{
Score: float64(time.Now().Unix()),
Member: idStr,
}).Err(), nil) {
return nil, errors.New("点赞失败")
}
// 同步增加点赞数
mysql.DB.Model(&blog.Blog{}).Where("id = ?", req).UpdateColumn("liked", gorm.Expr("liked + ?", 1))