美食聚焦 -- 仿大众点评项目技术难点总结

1 实现点赞功能显示哪些用户点赞过并安装时间顺序排序

使用sort_set 进行存储,把博客id作为key,用户id作为value,时间戳作为score

但存储成功之后还是没有成功按照时间顺序排名,因为sql语句,比如最后in(5,1)、

我们要按照用户id5和3和1来显示,但sql会默认显示135,要修改sql语句order byfiled(id,5,1,3)按照自己定义的数据

@Override
    public Result like(Long id) {
        String key  =  RedisConstants.BLOG_LIKED_KEY + id;
        Blog blog = getById(id);
        //获取登录用户
        Long userId = UserHolder.getUser().getId();
        //判断当前登录用户是否点赞
        Double isMember = stringRedisTemplate.opsForZSet().score(key,userId.toString());
        //如果未点赞可以点
        if(isMember == null){
            //+1
            boolean isUpdate = update().set("liked", blog.getLiked() + 1).eq("id", id).update();
            if(BooleanUtil.isTrue(isUpdate)){
                //zadd key value score
                stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());
            }
        }else {
            stringRedisTemplate.opsForZSet().remove(key,userId.toString());
            //如果已经点赞则取消
            boolean isUpdate = update().set("liked", blog.getLiked() - 1).eq("id", id).update();
            //-1
            //从redis中去除
        }

        return null;
    }
@Override
    public Result queryBlogLikes(Long id) {
        //查询前五点赞的人
        Set<String> top5 = stringRedisTemplate.opsForZSet().range(RedisConstants.BLOG_LIKED_KEY + id, 0, 4);
        if(top5 == null || top5.isEmpty()){
            return Result.ok(Collections.emptyList());
        }
        //解析出用户id
        List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());

        List<UserDTO> userDTOS = new ArrayList<>();
        //根据id查出用户
       ids.forEach(userId -> {
           User user = userService.getById(userId);
           UserDTO userDTO = new UserDTO();
           BeanUtils.copyProperties(user,userDTO);
           userDTOS.add(userDTO);
       });
        return Result.ok(userDTOS);
    }

 

2 使用set集合记录共同关注

每个人关注时,往以自己id为key的set集合里面添加被关注的人的id,查看另一个用户的共同关注时,可以使用set集合的intersect查看交集id,再通过id流操作得到被关注的User对象

 

 @Override
    public Result followCommons(Long id) {

        if (UserHolder.getUser() != null) {
            Long userId = UserHolder.getUser().getId();

            String key = "follows:" + userId;

            String key2 = "follows" + id;

            Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key,key2);

            if(intersect == null || intersect.isEmpty()){
                return Result.ok(Collections.emptyList());
            }

            //解析id集
            //使用流操作
            List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());

            List<UserDTO> collects = userService.listByIds(ids).stream().map(user -> {
                return BeanUtil.copyProperties(user, UserDTO.class);
            }).collect(Collectors.toList());

            return Result.ok(collects);
        }
        return Result.fail("共同关注发生问题");
    }
}

 

3 使用sortedset记录滚动分页查询

修改代码,在有用户保存发送新的博客时,将查询数据库中他的所有粉丝,并以粉丝为key,博客id为value,当前时间戳为为score进行保存,在粉丝点击自己的关注时,将按照时间戳的从大到小进行分页查询,记录上一次查询到什么数据,将其时间戳的下一个作为下一次的起始,再加上偏移量,zset默认按照score从小到大进行排序

 Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(RedisConstants.FEED_KEY + userId, 0, max, offset, 2);

 查找按照分数反向排序0 - max范围内的2个数据,offset就是从第一个下面offset个开始,比如为5,5,4,2,1

按照当前查找是得到5,5(第二个5)

然后max 变成第二个5

然后后面再从中查找找到的是第一个5,所以要加上偏移量1,也就是从4开始

@Override
    public Result saveBlog(Blog blog) {
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 保存探店博文
        blogService.save(blog);
        //查询笔记作者的粉丝
        List<Follow> follows = followService.lambdaQuery().eq(Follow::getFollowUserId, user.getId()).list();
        //推送笔记id给所有粉丝
        for(Follow follow : follows){
            Long userId = follow.getUserId();
            String key = RedisConstants.FEED_KEY + userId;
            stringRedisTemplate.opsForZSet().add(key,blog.getId().toString(),System.currentTimeMillis());
        }
        // 返回id
        return Result.ok(blog.getId());
    }

    @Override
    public Result queryBlogOfFollow(Long max, Integer offset) {
        Long userId = UserHolder.getUser().getId();
        
        //查询收件箱
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(RedisConstants.FEED_KEY + userId, 0, max, offset, 2);

        if(typedTuples == null || typedTuples.isEmpty()){
            return Result.ok();
        }
        //解析数据 blogId,时间戳,offset
        List<Long> ids = new ArrayList<>(typedTuples.size());
        Long minTime = 0L;
        int os = 1;
        for(ZSetOperations.TypedTuple<String> tuple : typedTuples){
            //获取id
            String idStr = tuple.getValue();
            if (idStr != null) {
                ids.add(Long.valueOf(idStr));
            }
            //获取分数时间戳
            long time = Objects.requireNonNull(tuple.getScore()).longValue();
            if(time == minTime){
                os++;
            }else{
                minTime = time;
                os = 1;
            }


        }
        String idStr = StrUtil.join(",",ids);
        //根据id查询blog
        List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
        for (Blog blog : blogs){

            User user = userService.getById(userId);
            blog.setName(user.getNickName());
            blog.setIcon(user.getIcon());
            isLiked(blog);
        }

        ScrollResult r = new ScrollResult();
        r.setList(blogs);
        r.setOffset(os);
        r.setMinTime(minTime);
        return Result.ok(r);
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值