Redis笔记点赞排行榜的实现示例

目录
  • 一、发布探店笔记
  • 二、实现查看笔记接口
  • 三、点赞功能
  • 四、点赞排行榜
    • 1、修改点赞逻辑
    • 2、点赞排行榜功能

一、发布探店笔记

探店笔记类似点评网站的评价,往往是图文结合。对应的表有两个

  • 探店笔记表(主键、商户id、用户id、标题、文字、图片、探店文字描述、点赞数量、评论数量)
  • 评价表(笔记的评价)

先上传图片请求一次保存图片接口,再点发布请求发布接口。这两个接口已经写好

二、实现查看笔记接口

BlogController

@RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @GetMapping("/hot")
    public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {

        return blogService.queryHotBlog(current);
    }

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") String id){
        return blogService.queryBlogById(id);
    }
}

IBlogService

public interface IBlogService extends IService<Blog> {

    Result queryBlogById(String id);

    Result queryHotBlog(Integer current);
}

BlogServiceImpl

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Autowired
    private IUserService userService;

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(this::queryBlogUser);
        return Result.ok(records);
    }

    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryBlogById(String id) {
        Blog blog = getById(id);

        if(blog == null){
            return Result.fail("笔记不存在!");
        }

        queryBlogUser(blog);

        return Result.ok(blog);
    }
}

三、点赞功能

现在已经写好的点赞接口

问题:这样写接口,可以一直按点赞重复点赞

需求

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

实现步骤

  • 给Blog类中添加一个isLike字段,表示是否被当前用户点赞
  • 修改点赞功能,利用redis的set集合判断用户是否赞过,未赞则点赞数+1,赞过则-1
  • 修改根据id查询blog的业务,判断当前用户是否点赞过,赋值给isLike字段
  • 修改分页查询blog业务,判断当前用户是否赞过,赋值isLike字段

业务实现

@RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @PutMapping("/like/{id}")
    public Result likeBlog(@PathVariable("id") Long id) {
        return blogService.likeBlog(id);
    }

    @GetMapping("/hot")
    public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
        return blogService.queryHotBlog(current);
    }

    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") String id){
        return blogService.queryBlogById(id);
    }
}

编写完点赞操作的接口后还要修改之前的查询接口,增加查询是否已经点赞

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Autowired
    private IUserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog -> {
            this.queryBlogUser(blog);
            this.isBlogLiked(blog);
        });
        return Result.ok(records);
    }

    @Override
    public Result likeBlog(Long id) {
        // 1、获取登录用户
        UserDTO user = UserHolder.getUser();
        // 2、判断当前登录用户是否已经点赞
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(RedisConstants.BLOG_LIKED_KEY + id, user.getId().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(RedisConstants.BLOG_LIKED_KEY + id, user.getId().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(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
            }
        }
        return Result.ok();
    }

    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryBlogById(String id) {
        Blog blog = getById(id);

        if(blog == null){
            return Result.fail("笔记不存在!");
        }

        queryBlogUser(blog);
        // 查询 Blog 是否被点赞
        isBlogLiked(blog);

        return Result.ok(blog);
    }

    private void isBlogLiked(Blog blog) {
        Long userId = blog.getUserId();
        String key = RedisConstants.BLOG_LIKED_KEY + blog.getId();
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        blog.setIsLike(BooleanUtil.isTrue(isMember));
    }
}

四、点赞排行榜

查出给这个笔记点赞的人,类似微信朋友圈的点赞,可以展示谁点赞了,而且我们要进行排序

所以我们得用SortedSet这种数据类型

1、修改点赞逻辑

把原本存入set改为存入zset多加个分数,分数就是时间戳

@Override
    public Result likeBlog(Long id) {
        // 1、获取登录用户
        UserDTO user = UserHolder.getUser();
        // 2、判断当前登录用户是否已经点赞
        Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
        if(score == null) {
            // 3、如果未点赞,可以点赞
            // 3.1、数据库点赞数 +1
            boolean isSuccess = update().setSql("liked = liked+1").eq("id", id).update();
            // 3.2、保存用户到 Redis 的 set 集合
            if(isSuccess){
                // 时间作为 key 的 score
                stringRedisTemplate.opsForZSet().add(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString(), System.currentTimeMillis());
            }
        } else {
            // 4、如果已点赞,取消点赞
            // 4.1、数据库点赞数 -1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
            // 4.2、把用户从 Redis 的 set 集合移除
            if(isSuccess){
                stringRedisTemplate.opsForZSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
            }
        }
        return Result.ok();
    }

然后是否被点赞的方法也要修改,根据key取出分数,分数不为null就是点赞过了

 private void isBlogLiked(Blog blog) {
        UserDTO user = UserHolder.getUser();
        if(user == null){
            return;
        }
        Long userId = user.getId();
        String key = RedisConstants.BLOG_LIKED_KEY + blog.getId();
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        blog.setIsLike(score != null);
    }

2、点赞排行榜功能

需求:实现前五个点赞的用户返回

我们先用动态id去redis中查询出前五个点赞用户的id

然后根据id去数据库中查询信息封装到dto再返回

    @GetMapping("/likes/{id}")
    public Result queryBlogLikes(@PathVariable("id") String id) {
        return blogService.queryBlogLikes(id);
    }
    @Override
    public Result queryBlogLikes(String id) {
        String key = RedisConstants.BLOG_LIKED_KEY + id;
        // 查询 top5 的点赞用户
        Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
        if(top5 == null){
            return Result.ok(Collections.emptyList());
        }
        // 解析出其中的用户id
        List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
        String join = StrUtil.join(",", ids);
        // 根据用户id查询用户
        List<UserDTO> userDTOS = userService.query().in("id", ids).last("order by filed(id, "+join+")").list()
                .stream()
                .map(user -> BeanUtil.copyProperties(user, UserDTO.class))
                .collect(Collectors.toList());

        return Result.ok(userDTOS);
    }

注意:如果我们mp直接用in来查询根本不能保证点赞的顺序,因为in查询出来的是按照id顺序返回的,没有排序,我们要按照查询id的顺序来查,order by field(id,5,1)这样

到此这篇关于Redis笔记点赞排行榜的实现示例的文章就介绍到这了,更多相关Redis笔记点赞内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 利用Redis实现点赞功能的示例代码

    目录 MySQL 和 Redis优缺点 1.Redis 缓存设计及实现 部分代码如下 Redis 存储结构如图 2.数据库设计 3.开启定时任务持久化存储到数据库 部分代码如下 提到点赞,大家一想到的是不是就是朋友圈的点赞呀?其实点赞对我们来说并不陌生,我们经常会在手机软件或者网页中看到它,今天就让我们来了解一下它的实现吧.我们常见的设计思路大概分为两种:一种自然是用 MySQL 等数据库直接落地存储, 另外一种就是将点赞的数据保存到 Redis 等缓存里,在一定时间后刷回 MySQL 等数据库

  • 点赞功能使用MySQL还是Redis

    目录 1. 新手常犯的错误 2. 使用Iterator的remove()方法 3. 使用for循环正序遍历 4. 使用for循环倒序遍历 5. 使用Iterator的remove()方法 6. 使用for循环正序遍历 7. 使用for循环倒序遍历 这是最近面试时被问到的1道面试题,本篇博客对此问题进行总结分享. 1. 新手常犯的错误 可能很多新手(包括当年的我,哈哈)第一时间想到的写法是下面这样的: public static void main(String[] args) { List<St

  • 手把手教你用Redis 实现点赞功能并且与数据库同步

    目录 一.Redis 缓存设计及实现 SpringBoot整合Redis 二.点赞数据在 Redis 中的存储格式 用 Redis 存储两种数据: 三.数据库设计 四.开启定时任务持久化存储到数据库 1. 添加依赖 2. 编写配置文件 3. 编写执行任务的类继承自 QuartzJobBean 五.注意事项 一.Redis 缓存设计及实现 Linux下安装Redis或者Docker下安装Redis并且启动(redis-server) SpringBoot整合Redis 1.在 pom.xml 中引

  • 使用 Redis 缓存实现点赞和取消点赞的示例代码

    点赞功能是很多平台都会提供的一个功能,那么,我们要如何实现点赞和取消点赞呢? 这篇文章总结了我在项目中实现点赞的方法. 缓存 vs 数据库? 首先我们要考虑的是数据要放到哪里,很多时候我们都会把数据放到数据库(如 MySQL),由于关系型数据库的稳定性,大部分场景下我们也都会使用关系数据库来存储数据. 不过,在一些特殊的场景下,传统的关系型数据库很可能无法满足我们的需求.比如,在访问量较大的情况下,数据库很可能会宕机或者访问速度非常慢.这对用户来说是不能容忍的.因此就有了非关系型数据库,如 Re

  • 使用Redis实现点赞取消点赞的详细代码

    前言 异步实现 代码实现: /** * * @param userId 点赞的人 * @param type 点赞与取消点赞的表示 * @param textId 文章ID * @param entityUserId -- 被点赞的人,文章作者 */ private void like(long userId,int type,int textId,long entityUserId){ redisTemplate.execute(new SessionCallback() { @Overrid

  • 基于redis实现的点赞功能设计思路详解

    前言 点赞其实是一个很有意思的功能.基本的设计思路有大致两种, 一种自然是用mysql等 数据库直接落地存储, 另外一种就是利用点赞的业务特征来扔到redis(或memcache)中, 然后离线刷回mysql等. 直接写入Mysql 直接写入Mysql是最简单的做法. 做两个表即可, 1.post_like 记录文章被赞的次数,已有多少人赞过这种数据就可以直接从表中查到; 2.user_like_post 记录用户赞过了哪些文章, 当打开文章列表时,显示的有没有赞过的数据就在这里面; 缺点 1.

  • Redis笔记点赞排行榜的实现示例

    目录 一.发布探店笔记 二.实现查看笔记接口 三.点赞功能 四.点赞排行榜 1.修改点赞逻辑 2.点赞排行榜功能 一.发布探店笔记 探店笔记类似点评网站的评价,往往是图文结合.对应的表有两个 探店笔记表(主键.商户id.用户id.标题.文字.图片.探店文字描述.点赞数量.评论数量) 评价表(笔记的评价) 先上传图片请求一次保存图片接口,再点发布请求发布接口.这两个接口已经写好 二.实现查看笔记接口 BlogController @RestController @RequestMapping("/

  • Redis 抽奖大转盘的实战示例

    目录 1. 项目介绍 2. 项目演示 3. 表结构 4. 项目搭建 4.1 依赖 4.2 YML配置 4.3 代码生成 4.4 Redis 配置 4.5 常量管理 4.6 业务代码 4.7 总结 5. 项目地址 1. 项目介绍 这是一个基于Spring boot + Mybatis Plus + Redis 的简单案例. 主要是将活动内容.奖品信息.记录信息等缓存到Redis中,然后所有的抽奖过程全部从Redis中做数据的操作. 大致内容很简单,具体操作下面慢慢分析. 2. 项目演示 话不多说,

  • Java设计模式笔记之抽象工厂代码示例

    上一篇说到了工厂模式,那么学习了工厂模式,抽象工厂也得学习一下.实际上,抽象工厂模式实际上就是在工厂模式的基础上再嵌套一层工厂模式而已,通过父工厂制造子工厂.只是,也并不完全是嵌套一层,各个工厂会被抽象成一个集多个工厂共同点的抽象类.通过工厂制造器,创建出该抽象工厂的子类. 好比如说,一个博客页面有个换肤系统.那么假如有两套风格,黑和白.那么,我选择了黑色风格的,实际这步就相当通过换肤系统这个工厂制造器,创建出一个黑色主题的工厂,该黑色主题的工厂内可以生产各种黑色风格的产品,比如黑色头像挂饰,黑

  • PHP基于redis计数器类定义与用法示例

    本文实例讲述了PHP基于redis计数器类定义与用法.分享给大家供大家参考,具体如下: Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 这里使用其incr(自增),get(获取),delete(清除)方法来实现计数器类. 1.Redis计数器类代码及演示实例 RedisCounter.class.php <?php /** * PHP基于Redis计数器类 * Date: 2017-10-28 * Aut

  • 基于redis实现世界杯排行榜功能项目实战

    题外话: 小编先给大家推荐一个不错的微信公众号: 感兴趣的朋友可以关注小编的微信公众号[码农那点事儿],更多网页制作特效源码及学习干货哦!!! 需求 前段时间,做了一个世界杯竞猜积分排行榜.对世界杯64场球赛胜负平进行猜测,猜对+1分,错误+0分,一人一场只能猜一次. 1.展示前一百名列表. 2.展示个人排名(如:张三,您当前的排名106579). 分析 一开始打算直接使用mysql数据库来做,遇到一个问题,每个人的分数都会变化,如何能够获取到个人的排名呢?数据库可以通过分数进行row_num排

  • springboot +redis 实现点赞、浏览、收藏、评论等数量的增减操作

    springboot +redis 实现点赞.浏览.收藏.评论等数量的增减操作 前言 第一次写博客,记录一下: 最近做了一个帖子的收藏.点赞数量的功能,其实之前也做过类似的功能,因为之前一直使用的mysql 总是感觉对于这种频繁需要改变的值,不应该给予Mysql过大的压力,本文章采用的是redis 做了持久化.下面贴出关键代码:DataResponse是项目中使用的结果封装实体类:forumDTO是此功能的参数实体,如果有需要请留言. 常量如下: private static final Str

  • Java利用Redis实现高并发计数器的示例代码

    业务需求中经常有需要用到计数器的场景:譬如一个手机号一天限制发送5条短信.一个接口一分钟限制多少请求.一个接口一天限制调用多少次等等.使用Redis的Incr自增命令可以轻松实现以上需求.以一个接口一天限制调用次数为例: /** * 是否拒绝服务 * @return */ private boolean denialOfService(String userId){ long count=JedisUtil.setIncr(DateUtil.getDate()+"&"+user

  • 使用Redis实现实时排行榜功能

    游戏中存在各种各样的排行榜,比如玩家的等级排名.分数排名等.玩家在排行榜中的名次是其实力的象征,位于榜单前列的玩家在虚拟世界中拥有无尚荣耀,所以名次也就成了核心玩家的追求目标. 一个典型的游戏排行榜包括以下常见功能: 1. 能够记录每个玩家的分数: 2. 能够对玩家的分数进行更新: 3. 能够查询每个玩家的分数和名次: 4. 能够按名次查询排名前N名的玩家: 5. 能够查询排在指定玩家前后M名的玩家. 更进一步,上面的操作都需要在短时间内实时完成,这样才能最大程度发挥排行榜的效用. 由于一个玩家

  • Vue transition实现点赞动画效果的示例

    目录 效果一览 爱心效果 数字滚动动画 点赞动画 效果一览 爱心效果 材料:爱心图标两个,没有我这种 icon 组件的用 png 图片代替 <transition :name=" isLike ? 'zoom' : '' " mode="out-in"> <!-- 爱心图标 --> <icon data="@icon/like.svg" color="#FF0000" v-if="isL

随机推荐