redis实战-实现笔记点赞和点赞排行榜

发布探店笔记

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

tb_blog:探店笔记表,包含笔记中的标题、文字、图片等

tb_blog_comments:其他用户对探店笔记的评价

 

 保存笔记service层

@Overridepublic Result saveBlog(Blog blog) {// 获取登录用户UserDTO user = UserHolder.getUser();blog.setUserId(user.getId());// 保存探店博文save(blog);// 返回idreturn Result.ok(blog.getId());}

注意修改图片保存路径为自己的目录

 查看探店笔记

 对应的查询接口

@Override
public Result queryBlogById(Long id) {// 1.查询blogBlog blog = getById(id);if (blog == null) {return Result.fail("笔记不存在!");}// 2.查询blog有关的用户queryBlogUser(blog);return Result.ok(blog);
}

实现点赞

初步实现

初始代码,即用户一点击点赞按钮,请求这一接口直接访问数据库将这篇笔记的点赞数量+1,没有任何限制,这并不符合我们常规的点赞逻辑,我们应该实现的是一人一赞,当用户点赞之后,点赞按钮会高亮,再次点击按钮之后会取消点赞

@GetMapping("/likes/{id}")
public Result queryBlogLikes(@PathVariable("id") Long id) {//修改点赞数量blogService.update().setSql("liked = liked +1 ").eq("id",id).update();return Result.ok();
}

 完善功能

需求:

  • 同一个用户只能点赞一次,再次点击则取消点赞

  • 如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段Blog类的isLike属性)

实现步骤:

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

  • 修改点赞功能,利用Redis的set集合判断是否点赞过,未点赞过则点赞数+1,已点赞过则点赞数-1,将这篇笔记点赞过的用户id存储到set集合中,实现去重

  • 修改根据id查询Blog的业务,判断当前登录用户是否点赞过,赋值给isLike字段

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

首先给blog类添加isLike字段,@TableField(exist = false)表示该字段不属于数据库字段

 先从redis中的set集合中判断该用户是否点过赞,如果已经点赞过会从set集合移除该用户,表示取消点赞,否则会先走数据库,并将用户id存入set集合中

 @Overridepublic Result likeBlog(Long id){// 1.获取登录用户Long userId = UserHolder.getUser().getId();// 2.判断当前登录用户是否已经点赞String key = BLOG_LIKED_KEY + id;Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());if(BooleanUtil.isFalse(isMember)){//3.如果未点赞,可以点赞//3.1 数据库点赞数+1boolean 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 数据库点赞数-1boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();//4.2 把用户从Redis的set集合移除if(isSuccess){stringRedisTemplate.opsForSet().remove(key,userId.toString());}}

点赞状态查询

 在用户进行点赞之后,我们还需要完善对应的查询笔记接口,以保证用户点赞后的高亮响应

对判断当前用户是否点赞该笔记,以及笔记对象要封装对应的用户信息这两个方法封装,原因是首页笔记分页查询以及笔记详情都要用到,实现代码复用

//笔记需要封装对应的用户信息 
void fillUserToBlog(Blog blog) {Long userId = blog.getUserId();User user = userService.getById(userId);blog.setName(user.getNickName());blog.setIcon(user.getIcon());}
//判断当前用户是否已经点赞笔记void isLikeBlog(Blog blog) {UserDTO user = UserHolder.getUser();
//这里进行空指针判断,原因是首页并不需要登录就能访问,所以当user为空时直接结束if (user == null) {return;}Long userId = user.getId();String key = BLOG_LIKED_KEY + blog.getId();Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());blog.setIsLike(score != null);}

首先就是点进笔记,查看笔记详情时,有个点赞状态查询,我们需要找到对应的接口方法进行改造

  @Overridepublic Result queryBlogById(Long id) {Blog blog = getById(id);fillUserToBlog(blog);isLikeBlog(blog);return Result.ok(blog);}

对首页笔记分页查询的方法也需要进行改造,完善点赞状态和用户信息

@Overridepublic 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 -> {fillUserToBlog(blog);isLikeBlog(blog);});return Result.ok(records);}

点赞排行榜

在探店笔记的详情页面,会把给该笔记点赞的人显示出来,比如最早点赞的TOP5,形成点赞排行榜,就像朋友圈的点赞的一样,按照时间顺序排序点赞的人,这要求我们采用能排序的数据结构来存储点赞用户的id而不是像set一样是无序的,list虽然能实现按添加顺序排序,但是list元素不能唯一,不能实现一人一赞的功能,故最后sortedSet来实现

改进点赞功能

我们现在要将点赞用户的id存储在sortedSet中,需要在原有代码的基础上进行改善,换成存储在sortedSet中,由于sortedSet没有直接判断该value是否在这一集合中的方法,只能获取该value的score值来判断是否存在

@Overridepublic Result likeBlog(Long id) {//获取登录用户Long userId = UserHolder.getUser().getId();//判断该用户是否已经点过赞String key = BLOG_LIKED_KEY + id;Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());if (score == null) {boolean isSuccess = update().setSql("liked=liked+1").eq("id", id).update();if (isSuccess) {stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());}} else {boolean isSuccess = update().setSql("liked=liked-1").eq("id", id).update();if (isSuccess) {stringRedisTemplate.opsForZSet().remove(key, userId.toString());}}return Result.ok();}
void isLikeBlog(Blog blog) {UserDTO user = UserHolder.getUser();if (user == null) {return;}Long userId = user.getId();String key = BLOG_LIKED_KEY + blog.getId();Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());blog.setIsLike(score != null);

 我们先将点赞用户的前五位从sortset中取出来,需要注意的是,由于我们使用的是stringRedisTemplate,取出的元素是string类型的,我们需要对获取的id集合进行处理,这里使用stream流,将id集合都转化为Long类型,由于sql语句中的in查询出来的用户列表,又重新以id排序了,故我们需要拼接上order by进行排序

  @Overridepublic Result queryBlogLikes(Long id) {String key = BLOG_LIKED_KEY + id;Long userId = UserHolder.getUser().getId();Set<String> range = stringRedisTemplate.opsForZSet().range(key, 0, 4);List<Long> ids = range.stream().map(item -> Long.valueOf(item)).collect(Collectors.toList());String joinIds = StrUtil.join(",", ids);List<UserDTO> userDTOS = userService.query().in("id", ids).last("order by FIELD(id," + joinIds + "  )").list().stream().map(user ->BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());return Result.ok(userDTOS);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/115899.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI语言大模型】文心一言功能使用介绍

一、前言 文心一言是一个知识增强的大语言模型&#xff0c;基于飞桨深度学习平台和文心知识增强大模型&#xff0c;持续从海量数据和大规模知识中融合学习具备知识增强、检索增强和对话增强的技术特色。 最近收到百度旗下产品【文心一言】的产品&#xff0c;抱着试一试的心态体…

【自学开发之旅】Flask-会话保持-API授权-注册登录

http - 无状态-无法记录是否已经登陆过 #会话保持 – session cookie session – 保存一些在服务端 cookie – 保存一些数据在客户端 session在单独服务器D上保存&#xff0c;前面数个服务器A,B,C上去取就好了&#xff0c;业务解耦。—》》现在都是基于token的验证。 以上是基…

SpringCloud Alibaba - Sentinel篇

一、Sentinel快速入门 Sentinel官网地址&#xff1a;https://sentinelguard.io/zh-cn/index.html Sentinel项目地址&#xff1a;https://github.com/alibaba/Sentinel Sentinel是阿里巴巴开源的一款微服务流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量限流、熔…

电子信息工程专业课复习知识点总结:(五)通信原理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 第一章通信系统概述——通信系统的构成、各部分性质、性能指标1.通信系统的组成&#xff1f;2.通信系统的分类&#xff1f;3.调制、解调是什么&#xff1f;有什么用…

抖 X-Bongus 参数逆向 python案例实战

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 知识点&#xff1a; 动态数据抓包 requests发送请求 X-Bogus 参数逆向 开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests pip ins…

C++之类和函数权限访问总结(二百二十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

vue模板语法下集->事件处理器,表单的综合案例,组件通信

事件处理器表单的综合案例组件通信 1.事件处理器 实现功能&#xff1a;原来每点击一下最里面颜色外层&#xff0c;有几层会弹出几下&#xff0c;加上click.stop后不管第几层只会弹一下&#xff1b;原本点击几下"点我"后台就会显示点了几下&#xff0c;加上click.onc…

【Verilog教程】2.3 Verilog 数据类型

Verilog 最常用的 2 种数据类型就是线网&#xff08;wire&#xff09;与寄存器&#xff08;reg&#xff09;&#xff0c;其余类型可以理解为这两种数据类型的扩展或辅助。 线网&#xff08;wire&#xff09; wire 类型表示硬件单元之间的物理连线&#xff0c;由其连接的器件输…

用《斗破苍穹》的视角打开C#多线程开发1(斗帝之路)

Thread.Start() 是的&#xff0c;我就是乌坦城那个斗之气三段的落魄少爷&#xff0c;在我捡到那个色眯眯的老爷爷后&#xff0c;斗气终于开始增长了。在各种软磨硬泡下&#xff0c;我终于学会了我人生中的第一个黄阶斗技——吸掌。 using System.Threading;namespace Framewo…

conda常用指令

常用conda指令 查看当前有哪些环境&#xff0c;有base环境 conda env list 创建环境 # conda create -n 你的环境名 python版本号 # 创建python3.10&#xff0c;名为env虚拟环境 conda create -n env python3.10 激活环境 conda activate env

Ubuntu--解决系统时间不正确的问题

原文网址&#xff1a;Ubuntu--解决系统时间不正确的问题_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍解决Ubuntu系统时间不正确的方法。 系统时间查看方法 用date命令。 场景1&#xff1a;时区不正确 问题描述 可以用此命令查看时区&#xff1a;date -R&#xff0c;如…

第十三章总结

一.泛型 1.定义泛型类 泛型机制语法&#xff1a; 类名<T> 其中&#xff0c;T是泛型的名称&#xff0c;代表某一种类型。 【例13.6】创建带泛型的图书类 代码&#xff1a; 结果&#xff1a; 2.泛型的常规用法 (1)定义泛型类时声明多个变量 class MyCla…