六,Redis实现点赞排行表

一,点赞功能

需求:

  • 同一个用户只能点赞一次,再次点击则取消点赞
  • 如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段Blog类的isLike属性)

实现步骤:

  1. 给Blog类中添加一个isLike字段,标识是否被当前用户点赞

  2. 修改点赞功能,利用Redis的set集合判断是否点赞过,未点赞则点赞数+1,已点赞则点赞数-1(key是博客id,value是用户id,存储已经点赞的用户id)

    java 复制代码
    public Result likeBlog(Long id){
        //1.获取登录用户(从ThreadLocal里面获取)
        Long userId=UserHolder.getUser().getId();
        //2.判断当前登录用户是否已经点赞(查redis即可)
        String key="blog:liked:"+id;
        Boolean isMember=stringRedisTemplate.opsForSet().isMember(key,userId.toString());
        if(BooleanUtil.isFalse(isMember)){
            //3.如果未点赞,可以点赞
            //3.1 数据库点赞数+1
            boolean isSuccess=update().setSql("liked=liked+1").eq("id",id).update();
        	//3.2 保存用户到Redis的set集合
            if(isSuccess){
                stringRedisTemplate.opsForSet().add(key,userId.toString());
            }
        }else{
            //4.如果已经点赞,取消点赞
        	//4.1 数据库点赞数-1
            boolean isSuccess=update().setSql("liked=liked-1").eq("id",id).update();
        	//4.2 把用户从Redis的set集合取消
            if(isSuccess){
                stringRedisTemplate.opsForSet().remove(key,userId.toString());
            }
        }
    }
  3. 修改根据id查询Blog的业务,判断当前登录用户是否点赞过,赋值给isLike字段

  4. 修改分页查Blog业务,判断当前登录用户是否点赞过,赋值给isLike字段

二,排行榜功能

  1. 修改点赞业务,将Set改成SortedSet

    java 复制代码
    public Result likeBlog(Long id){
        //1.获取登录用户(从ThreadLocal里面获取)
        Long userId=UserHolder.getUser().getId();
        //2.判断当前登录用户是否已经点赞(查redis即可)
        String key="blog:liked:"+id;
        Double score=stringRedisTemplate.opsForZSet().score(key,userId.toString());
        if(score == null){
            //3.如果未点赞,可以点赞
            //3.1 数据库点赞数+1
            boolean isSuccess=update().setSql("liked=liked+1").eq("id",id).update();
        	//3.2 保存用户到Redis的SortedSet集合
            if(isSuccess){
                stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());
            }
        }else{
            //4.如果已经点赞,取消点赞
        	//4.1 数据库点赞数-1
            boolean isSuccess=update().setSql("liked=liked-1").eq("id",id).update();
        	//4.2 把用户从Redis的SortedSet集合取消
            if(isSuccess){
                stringRedisTemplate.opsForZSet().remove(key,userId.toString());
            }
        }
    }
  2. 实现点赞列表查询逻辑

    java 复制代码
    public Result queryBlogLikes(Long id){
        //1.查询top5的点赞用户 zrange key 0 4
        String key="blog:liked:"+id;
        Set<String> top5Id=stringRedisTemplate.opsForZSet().rank(key,0,4);
        if(top5Id == null || top5Id.isEmpty()){
            return Result.ok(Collections.emptyList());
        }
        //2. 解析出其中的用户id
        List<Long> ids=top5Id.stream().map(Long::valueOf).collect(Collectors.toList());
        //3. 根据用户id查询用户(如果直接查询in(5,1) 会自动排序成1,5)
        //需要我们order by field(id,5,1)手动指定即可实现5,1
        String idStr=StrUtil.join(",",ids);
        List<User> users=userService.query().in("id",ids).last("ORDER BY FIELD(id,"+idStr+")").list();
        //4. 返回
        return Result,ok(users);
    }
相关推荐
陈果然DeepVersion14 分钟前
Java大厂面试真题:从Spring Boot到AI微服务的三轮技术拷问(二)
spring boot·redis·spring cloud·微服务·ai·java面试·rag
过客随尘3 小时前
Redis主从同步以及Redis-Shake数据同步实战
redis·云原生
Fency咖啡6 小时前
redis进阶 - 底层数据结构
数据结构·数据库·redis
知其然亦知其所以然6 小时前
面试官笑了:我用这套方案搞定了“2000w vs 20w”的Redis难题!
redis·后端·面试
The Sheep 20236 小时前
MicroService(Redis)
数据库·redis·c#
无心水8 小时前
【中间件:Redis】1、Redis面试核心:线程模型深度解析(6.0前后变化+工作流程)
数据库·redis·面试·redis面试·redis原理·redis线程模型·后端技术
像风一样自由202010 小时前
Redis与MinIO:两大存储利器的区别与联系
数据库·redis·缓存·minio
无心水10 小时前
【中间件:Redis】2、单线程Redis高并发原理:I/O多路复用+3大优化点(附多线程对比)
redis·中间件·php·后端面试·i/o多路复用·redis原理·redis高并发
无心水10 小时前
【中间件:Redis】4、Redis缓存实战:穿透/击穿/雪崩的5种解决方案(附代码实现)
redis·缓存·中间件·缓存穿透·缓存雪崩·分布式缓存·redis缓存问题