当前位置: 首页 > news >正文

重学SpringBoot3-集成Redis(十二)之点赞功能实现

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍

重学SpringBoot3-集成Redis(十二)之点赞功能实现

  • 1. 点赞功能的场景分析
  • 2. 项目环境配置
    • 2.1. 依赖引入
    • 2.2. Redis 配置
  • 3. 点赞功能的实现
    • 3.1. 点赞服务层
    • 3.2. 点赞控制器
    • 3.3. 演示
      • 点赞操作
      • 获取点赞数
      • 检查用户是否点赞
      • 取消点赞
  • 4. 点赞功能的详细解释
    • 4.1. 用户点赞和取消点赞
    • 4.2. 统计点赞数
    • 4.3. 判断用户是否点赞
  • 5. Redis Set 数据结构的优势
  • 6. 总结

在现代的应用中,点赞功能是一个非常常见的需求,尤其在社交媒体、博客等平台上。Redis 作为一个高性能的键值存储系统,由于其读写速度快支持丰富的数据结构,因此非常适合用来实现实时的点赞功能。本文将介绍如何结合 Spring Boot 3Redis 来实现一个高效的点赞功能。


1. 点赞功能的场景分析

点赞功能通常涉及以下场景:

  • 用户点赞或取消点赞:某个用户对某篇文章或某条评论进行点赞或取消操作。
  • 统计点赞数量:实时显示某个对象(如文章、视频、评论)的总点赞数。
  • 用户点赞状态查询:判断某个用户是否对某个对象点赞过。

Redis 通过Set 数据结构可以很好地解决这些问题。Redis 的 Set 不允许重复元素,且支持快速添加、删除、判断成员是否存在等操作。

点赞场景


2. 项目环境配置

2.1. 依赖引入

首先,在 pom.xml 中引入 Spring Boot 3Redis 的相关依赖,具体参考重学SpringBoot3-集成Redis(一)之基本使用:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2.2. Redis 配置

application.yml 中配置 Redis 连接:

spring:data:redis:host: localhostport: 6379            # Redis 端口password: redis123456 # 如果有密码可以在这里配置lettuce:pool:max-active: 100    # 最大并发连接数max-idle: 50       # 最大空闲连接数min-idle: 10       # 最小空闲连接数

3. 点赞功能的实现

在实现点赞功能时,通常会用 Redis 的 Set 数据结构来存储每个对象(如文章、视频)的点赞用户列表。每次点赞操作就是往这个 Set 中添加用户 ID,取消点赞则是从 Set 中移除用户 ID。

3.1. 点赞服务层

package com.coderjia.boot310redis.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;/*** @author CoderJia* @create 2024/10/10 下午 09:45* @Description**/
@Service
public class LikeService {@Autowiredprivate StringRedisTemplate redisTemplate;// Redis Key 前缀private static final String LIKE_KEY_PREFIX = "like:";  // 用户点赞public void likePost(String postId, String userId) {String redisKey = LIKE_KEY_PREFIX + postId;redisTemplate.opsForSet().add(redisKey, userId);}// 用户取消点赞public void unlikePost(String postId, String userId) {String redisKey = LIKE_KEY_PREFIX + postId;redisTemplate.opsForSet().remove(redisKey, userId);}// 查询某个帖子点赞数public Long getLikeCount(String postId) {String redisKey = LIKE_KEY_PREFIX + postId;return redisTemplate.opsForSet().size(redisKey);}// 判断用户是否点赞public boolean hasLiked(String postId, String userId) {String redisKey = LIKE_KEY_PREFIX + postId;return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(redisKey, userId));}
}

3.2. 点赞控制器

package com.coderjia.boot310redis.demos.web;import com.coderjia.boot310redis.service.LikeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author CoderJia* @create 2024/10/10 下午 09:46* @Description**/
@RestController
@RequestMapping("/like")
public class LikeController {@Autowiredprivate LikeService likeService;// 点赞操作@PostMapping("/like")public String like(@RequestParam String postId, @RequestParam String userId) {likeService.likePost(postId, userId);return "Liked post: " + postId + " by user: " + userId;}// 取消点赞@PostMapping("/unlike")public String unlike(@RequestParam String postId, @RequestParam String userId) {likeService.unlikePost(postId, userId);return "Unliked post: " + postId + " by user: " + userId;}// 获取点赞数@GetMapping("/count")public Long getLikeCount(@RequestParam String postId) {return likeService.getLikeCount(postId);}// 检查用户是否点赞@GetMapping("/status")public boolean hasLiked(@RequestParam String postId, @RequestParam String userId) {return likeService.hasLiked(postId, userId);}
}

3.3. 演示

点赞操作

curl -X POST http://localhost:8080/like/like?postId=p101&userId=1

点赞

获取点赞数

curl http://localhost:8080/like/count?postId=p101

获取点赞数

检查用户是否点赞

curl http://localhost:8080/like/status?postId=p101&userId=1

检查用户是否点赞

取消点赞

curl -X POST http://localhost:8080/like/unlike?postId=p101&userId=1

取消点赞

4. 点赞功能的详细解释

4.1. 用户点赞和取消点赞

每当用户点赞时,我们将用户 ID 存入 Redis 的 Set 中。由于 Redis 的 Set 不允许重复元素,用户多次点赞同一篇文章也只会被记录一次。

redisTemplate.opsForSet().add(redisKey, userId);

取消点赞则是将用户 ID 从 Set 中移除:

redisTemplate.opsForSet().remove(redisKey, userId);

4.2. 统计点赞数

统计点赞数非常简单,直接调用 Redis 的 size() 方法即可:

redisTemplate.opsForSet().size(redisKey);

这比使用传统数据库查询要快得多,尤其在大量用户点赞的情况下,Redis 能保持高性能。

4.3. 判断用户是否点赞

可以通过 Redis 的 isMember() 方法来判断某个用户是否已经对某篇文章点赞:

redisTemplate.opsForSet().isMember(redisKey, userId);

这一点对前端显示用户是否已点赞的状态非常重要,用户体验更好。


5. Redis Set 数据结构的优势

Redis 的 Set 数据结构非常适合用来存储点赞功能的用户列表,原因有以下几点:

  1. 唯一性:Redis Set 不允许重复元素,确保用户对同一篇文章只能点赞一次。
  2. 高性能:Redis 是内存级存储,读写速度极快,适合大规模的点赞操作。
  3. 丰富的操作:Set 提供了丰富的操作,如添加成员、删除成员、计算数量、检查成员是否存在等,这些操作都是 O(1) 复杂度,性能非常高。

6. 总结

通过结合 Spring Boot 3Redis,我们可以轻松实现高效的点赞功能,并利用 Redis 的 Set 数据结构实现去重、快速统计等操作。相比于传统的数据库操作,使用 Redis 实现的点赞功能性能更高、扩展性更好,尤其适合用户量大、点赞操作频繁的应用场景。

持久化到数据库

仅使用 Redis:适用于对数据一致性要求不高的场景,比如短期有效的点赞数据,或者系统对少量点赞数据丢失不敏感。

Redis + MySQL方案:适用于对数据一致性要求高的场景,比如电商、社交平台中,点赞数据不能丢失,且需要长期保存。通常采用异步持久化,具体流程可以是:

  1. 用户点赞时,首先将数据写入 Redis。
  2. 通过定时任务(如每隔几分钟)或消息队列,将 Redis 中的点赞数据同步到数据库。
  3. 在定时任务或队列消费过程中,可以批量将点赞数据写入数据库,降低数据库的写入压力。

相关文章:

重学SpringBoot3-集成Redis(十二)之点赞功能实现

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;十二&#xff09;之点赞功能实现 1. 点赞功能的场景分析2. 项目环境配置2.1. 依赖引入2.2. Redis 配置 3. 点赞功能的实现3.1. 点…...

Django-rest-framework(DRF)怎么实现Excel文件导出

目录 一、安装openpyxl库 二、openpyxl库介绍 1、工作簿 a、创建工作簿 b、加载工作簿 c、保存工作簿 2、工作表 a、获取工作表 b、创建和删除工作表 c、工作表属性设置 3、单元格 a、获取单元格 b、合并单元格 C、设置单元格样式 三、django集成openpyxl库 一、…...

零基础MySQL数据库入门一天学完

目录 课程介绍数据库的存在意义数据库历史及MySQL简介MySQL安装指南MySQL客户端工具介绍库操作详解表操作指南单表查询技巧多表查询实践MySQL函数速览新增、修改、删除操作索引优化策略视图应用实例事务处理机制数据备份与恢复日常维护与安全建议 1. 课程介绍 本指南旨在为初…...

【CSS Tricks】鼠标滚轮驱动css动画播放,使用js还是css?

目录 引言一、js实现1. 实现思路2. 实现案例3. 看下效果 二、css实现1. 代码修改2. 属性介绍2.1 看下浏览器支持性2.2 常用属性值2.2.1 scroll&#xff08;&#xff09;2.2.2 view&#xff08;&#xff09; 三、总结 引言 本篇为css的一个小技巧 页面中的动画效果随着滚轮的转动…...

《Electron 基础知识》设置 Vue 中引用的文件路径别名

vite.renderer.config.mjs 文件中配置 代码第1行&#xff0c;引入 resolve &#xff1b;代码第 6 - 10 行&#xff0c;设置路径别名&#xff0c;注意没有后缀 /&#xff1b; import { resolve } from pathexport default defineConfig((env) > {return {resolve: {alias: …...

day 20 二叉树 part05

654.最大二叉树 注意类似用数组构造二叉树的题目&#xff0c;每次分隔尽量不要定义新的数组&#xff0c;而是通过下标索引直接在原数组上操作&#xff0c;这样可以节约时间和空间上的开销。 题目链接/文章讲解&#xff1a;代码随想录 lass Solution { private:// 在左闭右开…...

003 Springboot操作RabbitMQ

Springboot整合RabbitMQ 文章目录 Springboot整合RabbitMQ1.pom依赖2.yml配置3.配置队列、交换机方式一&#xff1a;直接通过配置类配置bean方式二&#xff1a;消息监听通过注解配置 4.编写消息监听发送测试5.其他类型交换机配置1.FanoutExchange2.TopicExchange3.HeadersExcha…...

小猿口算脚本

实现原理&#xff1a;安卓adb截图传到电脑&#xff0c;然后用python裁剪获得两张数字图片&#xff0c;使用ddddocr识别数字&#xff0c;比较大小&#xff0c;再用adb命令模拟安卓手势实现>< import os import ddddocr from time import sleep from PIL import Imagedef …...

从 Reno TCP 到 Scalable TCP,HighSpeed TCP

前文 Scalable TCP 如何优化长肥管道 介绍了 Scalable TCP&#xff0c;但联系另一个类似的算法 HighSpeed TCP(简称 HSTCP)&#xff0c;就会看到一个类似从 Reno TCP 经 BIC 到 CUBIC 的路线&#xff0c;但采用了不同的策略。 Reno TCP 经 BIC 到 CUBIC 路线的核心在于 “在长…...

使用Java调用OpenAI API并解析响应:详细教程

使用Java调用OpenAI API并解析响应&#xff1a;详细教程 在现代应用程序中&#xff0c;API调用是一个非常常见的任务。本文将通过一个完整的示例&#xff0c;讲解如何使用Java调用OpenAI的ChatGPT API&#xff0c;并通过ObjectMapper处理JSON响应。本文的示例不仅适用于OpenAI…...

深入学习并发编程中的 synchronized

文章目录 并发编程中的三个问题可见性原子性有序性 了解Java内存模型JMMsynchronized 保证三大特性synchronized 保证原子性synchronized 保证可见性synchronized 保证有序性 synchronized 的特性可重入特性不可中断特性 通过反汇编学习synchronized原理当修饰代码块时当修饰方…...

AMD R9-9950X相比较I9-14900K有哪些提升

AMD R9-9950X相比较I9-14900K有哪些提升&#xff1f;在处理器领域&#xff0c;AMD与英特尔的竞争从未停歇&#xff0c;每一次新品发布都引发业界的高度关注。近日&#xff0c;AMD推出了其新一代桌面级旗舰处理器——Ryzen 9 9950X&#xff08;简称R9-9950X&#xff09;&#xf…...

计算机毕业设计 基于Python的个性化旅游线路推荐系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…...

总结:Flink之DataStream各API介绍

一、介绍 本文主要是详细介绍 DataStream<T> 类中的各个方法,并给出它们的使用场景。 二、基本方法 getId(): 作用:返回转换操作的唯一标识符。场景:当需要调试或日志记录时,有时候需要知道操作的 ID。getParallelism(): 作用:获取流的并行度。场景:在优化作业时…...

设计一个日志管理系统,支持多级别日志记录

设计一个日志管理系统,支持多级别日志记录 作为一名Python程序软件专家,我经常被问到关于日志管理系统的设计和实现。今天,我将分享一篇关于设计一个日志管理系统,支持多级别日志记录的博文,希望能够帮助大家更好地理解和使用Python语言。 日志管理系统的需求 在软件开…...

Javascript动态规划算法

JavaScript中的动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;是一种通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。它主要致力于将“合适”的问题拆分成更小的子目标&#xff0c;并通过建立状态转移方程、缓存并复用以往结果以及按…...

Java 循环里怎么删除元素才安全

首先 在 Java 中&#xff0c;当你在循环中遍历集合时&#xff0c;直接删除元素可能会引发 ConcurrentModificationException。为了安全地删除元素&#xff0c;推荐使用 Iterator 来进行删除操作。 以下是使用 Iterator 删除元素的常见模式&#xff1a; import java.util.Arr…...

LabVIEW晶体振荡器自动化测试系统

基于LabVIEW平台的晶体振荡器自动化测试系统解决了传统手工测试晶体振荡器繁琐且易出错的问题。该系统通过高度自动化的测试流程&#xff0c;提高了测试效率和精度&#xff0c;实现了数据的自动采集与处理&#xff0c;适用于电子、通信等领域的晶振测试需求。 项目背景与意义 …...

3.6.xx版本SpringBoot创建基于Swagger接口文档

介绍 基于Swagger构建的JavaAPI文档工具&#xff0c;实现后端功能的测试&#xff0c;并撰写API接口文档。 方法 pom.xml中引入依赖,要注意的是&#xff0c;本依赖使用的SpringBoot版本为3.6.xx <!--Knife4j--><dependency><groupId>com.github.xiaoymin<…...

Oracle 12201非PDBS模式单机部署(静默安装)

一、创建Oracle数据库的用户 groupadd oinstall groupadd dba groupadd asmadmin groupadd asmdba useradd -g oinstall -G dba,asmdba oracle -d /home/oracle passwd oracle二、配置Linux 服务器参数 cat /home/oracle/.bash_profile export ORACLE_HOSTNAMEH_orcle01 expo…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...