好友关注-小众点评黑马点评项目Go语言实现--Hertz+Redis练手项目


好友关注涉及到取Set的增加、删除、取交集,Feed流推送

关注和取关

查看博客或则个人主页时候都会有关注/取消关注按钮,取决于用户是否关注了该博主。因此查看博客时除了请求加载博客内容,还需要发送请求获取关注状态。

已关注未关注
在这里插入图片描述在这里插入图片描述
获取关注状态,这里可以直接从redis的set中获取
	user := utils.GetUser(h.Context).GetID()
	//查找是否关注
	if !errors.Is(redis.RedisClient.SIsMember(h.Context, constants.FOLLOW_USER_KEY+strconv.FormatInt(user, 10), targetUserID).Err(), nil) {
		return &follow.IsFollowedResp{IsFollowed: false}, nil
	}
	return &follow.IsFollowedResp{IsFollowed: true}, nil

未关注时点击则关注,否则取消关注

myID := utils.GetUser(h.Context).GetID()
	isFollow := req.GetIsFollow()
	targetUserId := req.GetTargetUser()
	f := follow.Follow{
		UserId:       myID,
		FollowUserId: targetUserId,
	}
	// 如果是true,则添加关注,将用户id和被关注用户的id存入数据库
	if isFollow {
		// 判断是否已经关注
		if !errors.Is(redis.RedisClient.SIsMember(h.Context, constants.FOLLOW_USER_KEY+strconv.FormatInt(myID, 10), targetUserId).Err(), nil) {
			return &follow.FollowResp{RespBody: &f}, nil
		}
		// 将关注的用户存入redis的set中
		if !errors.Is(redis.RedisClient.SAdd(h.Context, constants.FOLLOW_USER_KEY+strconv.FormatInt(myID, 10), targetUserId).Err(), nil) {
			hlog.CtxErrorf(h.Context, "err = %s", err.Error())
			return nil, err
		}
		if !errors.Is(mysql.DB.Create(&f).Error, nil) {
			return nil, errors.New("关注失败")
		}
		return &follow.FollowResp{RespBody: &f}, nil
	}
	// 如果是false,则取消关注
	if !errors.Is(mysql.DB.Where("user_id = ? and follow_user_id = ?", myID, targetUserId).Delete(&f).Error, nil) {
		return nil, errors.New("取消关注失败")
	}
	// 将取消关注的用户从redis的set中删除
	if !errors.Is(redis.RedisClient.SRem(h.Context, constants.FOLLOW_USER_KEY+strconv.FormatInt(myID, 10), targetUserId).Err(), nil) {
		hlog.CtxErrorf(h.Context, "err = %s", err.Error())
		return nil, err
	}
	return &follow.FollowResp{RespBody: &f}, nil

共同关注

这里是再用户主页查看你们共同关注的用户,用到set求交集来完成

在这里插入图片描述

  • 步骤一:再关注时候除了将关注的用户存到数据库,还需要存入redis的set中(实现方法查看上一届节)
  • 获取时先从redis用双方的关注列表找出共同的用户(set取交集)
  • 从数据库查询交集用户的信息并转换未uderDTO
	user := utils.GetUser(h.Context).GetID()
	key1 := constants.FOLLOW_USER_KEY + strconv.FormatInt(user, 10)
	key2 := constants.FOLLOW_USER_KEY + targetUserID
	arr, err := redis.RedisClient.SInter(h.Context, key1, key2).Result()
	if err != nil {
		return nil, err
	}
	var users []*model.User
	if !errors.Is(mysql.DB.Where("id in ?", arr).Find(&users).Error, nil) {
		return nil, errors.New("查询失败")
	}
	var userDto []*model.UserDTO
	// 遍历arr,转换为userDTO
	for _, u := range users {
		d := utils.UserToUserDTO(u)
		userDto = append(userDto, d)
	}
	return &follow.CommonFollowResp{
		CommonFollows: userDto,
	}, nil

Feed流推送

在这里插入图片描述

Feed流

  • Feed 流:是提供给用户的内容流,为用户持续的提供 “沉浸式” 的体验,通过无限下拉刷新获取新的信息。比如微博的关注页,抖音的关注页视频都叫Feed流
  • Feed:Feed流中的一条信息,比如朋友发布的一条朋友圈
    本项目中Feed流用再个人主页中,查看关注的用户发布的博客

关于Feed流的这里不做赘述,可以查看redis实现Feed流推送

在本文中采取推模式作为案例。redis中实现feed流需要使用zset,当博主发布一条动态时往粉丝的收件箱(redis的zset)写一条数据。数据格式为:

{
score:一般为时间戳,
member:消息内容
}

具体实现代码
将消息写入粉丝收信箱

	fans, err := mysql.GetFansByID(h.Context, u)
	if err != nil {
		return nil, err
	}
	for _, fan := range fans {
		key := constants.FEED_KEY + strconv.FormatInt(fan.ID, 10)
		err = redis.RedisClient.ZAdd(h.Context, key, &redis2.Z{
			Score:  float64(time.Now().Unix()),
			Member: req.ID,
		}).Err()
	}

粉丝读取收信箱,需要注意的是,由于Feed流中的数据是随时间变化不断更新的,传统的分页方式为根据每页几条pageSize和当前第几页页Page来计算查询范围,这对于Feed流中的动态列表而言会有重复读的问题,应当采用滚动分页模式。

	u := utils.GetUser(h.Context).GetID()
	key := constants.FEED_KEY + strconv.FormatInt(u, 10)
	zSet, err := redis.GetBlogsByKey(h.Context, key, req.LastId, req.Offset)
	var bids []string
	for _, z := range zSet {
		bids = append(bids, z.Member.(string))
	}
	var blogs []*blog.Blog
	err = mysql.DB.Where("id in ?", bids).Find(&blogs).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, errors.New("没有更多数据")
	}
	if err != nil {
		return nil, err
	}
	//fmt.Printf("blogs: %v\n", blogs)
	var res blog.FollowBlogRresp
	res.List = blogs
	res.MinTime = "0"
	if len(zSet) > 0 {
		res.MinTime = strconv.FormatInt(int64(zSet[len(zSet)-1].Score), 10)
	}
	// 取最小分数的记录数
	var offset int64 = 0
	minScore := zSet[len(zSet)-1].Score
	for _, element := range zSet {
		if element.Score == minScore {
			offset++
		}
	}
	res.Offset = offset
  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值