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

仿牛客网项目---点赞模块的实现

本篇文章介绍一下项目中的点赞模块。

点赞模块是一个通过使用Redis实现的功能模块,它提供了点赞操作的处理逻辑和数据存取功能。通过服务类和控制器类的配合,点赞模块实现了用户对实体的点赞、点赞数量的查询、点赞状态的查询等功能。该模块使用了Redis作为数据存储,通过Redis的事务支持和数据结构操作,实现了点赞操作的原子性和高效性。同时,通过依赖注入和控制反转的思想,实现了代码的解耦和灵活性,使得点赞模块具有良好的可维护性和可扩展性。

首先我们写一个RedisKeyUtil的工具类,这个工具类提供了一些用于在Redis中生成键的方法。

public class RedisKeyUtil {// 某个实体的赞// like:entity:entityType:entityId -> set(userId)public static String getEntityLikeKey(int entityType, int entityId) {return PREFIX_ENTITY_LIKE + SPLIT + entityType + SPLIT + entityId;}// 某个用户的赞// like:user:userId -> intpublic static String getUserLikeKey(int userId) {return PREFIX_USER_LIKE + SPLIT + userId;}// 某个用户关注的实体// followee:userId:entityType -> zset(entityId,now)public static String getFolloweeKey(int userId, int entityType) {return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType;}// 某个实体拥有的粉丝// follower:entityType:entityId -> zset(userId,now)public static String getFollowerKey(int entityType, int entityId) {return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId;}// 登录验证码public static String getKaptchaKey(String owner) {return PREFIX_KAPTCHA + SPLIT + owner;}// 登录的凭证public static String getTicketKey(String ticket) {return PREFIX_TICKET + SPLIT + ticket;}// 用户public static String getUserKey(int userId) {return PREFIX_USER + SPLIT + userId;}// 单日UVpublic static String getUVKey(String date) {return PREFIX_UV + SPLIT + date;}// 区间UVpublic static String getUVKey(String startDate, String endDate) {return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;}// 单日活跃用户public static String getDAUKey(String date) {return PREFIX_DAU + SPLIT + date;}// 区间活跃用户public static String getDAUKey(String startDate, String endDate) {return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;}// 帖子分数public static String getPostScoreKey() {return PREFIX_POST + SPLIT + "score";}}

举例来说,通过使用getEntityLikeKey方法,可以生成一个用于存储特定实体点赞记录的键,通过使用getUserLikeKey方法,可以生成一个用于存储特定用户点赞记录的键。其他方法则可以生成用于存储用户数据、关注关系、验证码、登录凭证等的键。

看到这里,你应该会觉得很奇怪,为什么没有DAO层呢?

因为点赞数据的存储和查询需求可以完全由Redis满足,并且Redis作为一个高性能的内存数据库能够提供快速的读写操作,简化了数据访问的复杂性和开销,同时满足了性能要求。此外,点赞数据可能具有相对简单的数据结构,可以直接使用Redis的数据结构进行存储和查询,而不需要传统的数据库访问层。

所以说DAO层在这个项目就没有用到了,我这个项目的点赞模块用的是Redis,关于一些点赞的信息我是用redis来存的。

然后再来写LikeService文件,即service层。

@Service
public class LikeService {@Autowiredprivate RedisTemplate redisTemplate;// 点赞public void like(int userId, int entityType, int entityId, int entityUserId) {redisTemplate.execute(new SessionCallback() {@Overridepublic Object execute(RedisOperations operations) throws DataAccessException {String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId);boolean isMember = operations.opsForSet().isMember(entityLikeKey, userId);operations.multi();if (isMember) {operations.opsForSet().remove(entityLikeKey, userId);operations.opsForValue().decrement(userLikeKey);} else {operations.opsForSet().add(entityLikeKey, userId);operations.opsForValue().increment(userLikeKey);}return operations.exec();}});}// 查询某实体点赞的数量public long findEntityLikeCount(int entityType, int entityId) {String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);return redisTemplate.opsForSet().size(entityLikeKey);}// 查询某人对某实体的点赞状态public int findEntityLikeStatus(int userId, int entityType, int entityId) {String entityLikeKey = RedisKeyUtil.getEntityLikeKey(entityType, entityId);return redisTemplate.opsForSet().isMember(entityLikeKey, userId) ? 1 : 0;}// 查询某个用户获得的赞public int findUserLikeCount(int userId) {String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey);return count == null ? 0 : count.intValue();}}
  1. like(int userId, int entityType, int entityId, int entityUserId):点赞方法,用于给特定实体点赞。它首先生成实体点赞的键和用户点赞的键,然后通过Redis的事务支持(multi()exec()方法)来保证点赞操作的原子性。根据用户是否已经点赞,执行相应的操作(添加或移除点赞),并更新用户点赞数。

  2. findEntityLikeCount(int entityType, int entityId):查询某实体的点赞数量。它使用RedisKeyUtil生成实体点赞的键,并通过Redis的opsForSet().size()方法获取集合的大小,即点赞数量。

  3. findEntityLikeStatus(int userId, int entityType, int entityId):查询某人对某实体的点赞状态。它使用RedisKeyUtil生成实体点赞的键,并通过Redis的opsForSet().isMember()方法判断用户是否已经点赞。

  4. findUserLikeCount(int userId):查询某个用户获得的赞数量。它使用RedisKeyUtil生成用户点赞的键,并通过Redis的opsForValue().get()方法获取用户点赞数。

最后写controller层,即LikeController。

@Controller
public class LikeController implements CommunityConstant {//省略了注入LikeService、HostHolder、EventProducer和RedisTemplate来处理点赞逻辑的代码@RequestMapping(path = "/like", method = RequestMethod.POST)@ResponseBodypublic String like(int entityType, int entityId, int entityUserId, int postId) {User user = hostHolder.getUser();// 点赞likeService.like(user.getId(), entityType, entityId, entityUserId);// 数量long likeCount = likeService.findEntityLikeCount(entityType, entityId);// 状态int likeStatus = likeService.findEntityLikeStatus(user.getId(), entityType, entityId);// 返回的结果Map<String, Object> map = new HashMap<>();map.put("likeCount", likeCount);map.put("likeStatus", likeStatus);// 触发点赞事件if (likeStatus == 1) {Event event = new Event().setTopic(TOPIC_LIKE).setUserId(hostHolder.getUser().getId()).setEntityType(entityType).setEntityId(entityId).setEntityUserId(entityUserId).setData("postId", postId);eventProducer.fireEvent(event);}if(entityType == ENTITY_TYPE_POST) {// 计算帖子分数String redisKey = RedisKeyUtil.getPostScoreKey();redisTemplate.opsForSet().add(redisKey, postId);}return CommunityUtil.getJSONString(0, null, map);}}

上面这段代码是一个名为LikeController的控制器类,用于处理点赞相关的请求。它通过注入LikeServiceHostHolderEventProducerRedisTemplate来处理点赞逻辑。

控制器中的主要方法是like()方法,用于处理点赞请求。该方法接受实体类型、实体ID、实体创建者ID和帖子ID作为参数。在方法中,首先获取当前用户信息,然后调用likeService的点赞方法,对实体进行点赞操作。

接下来,通过调用likeService的方法获取点赞数量和点赞状态,并将结果存储在一个Map对象中。然后,根据点赞状态触发相应的点赞事件,创建一个Event对象,并通过eventProducer发送事件。

如果实体类型是帖子(ENTITY_TYPE_POST),则计算帖子的分数并存储到Redis中。

最后,通过CommunityUtil.getJSONString()方法将结果封装成JSON字符串并返回给前端。

控制器类通过调用likeService处理点赞逻辑,而不是使用DAO层进行数据访问。这是因为点赞操作的数据存储和查询可以完全由Redis满足,并且通过调用likeService提供的方法,可以直接在控制器中处理点赞逻辑,避免了引入额外的DAO层。

相关文章:

仿牛客网项目---点赞模块的实现

本篇文章介绍一下项目中的点赞模块。 点赞模块是一个通过使用Redis实现的功能模块&#xff0c;它提供了点赞操作的处理逻辑和数据存取功能。通过服务类和控制器类的配合&#xff0c;点赞模块实现了用户对实体的点赞、点赞数量的查询、点赞状态的查询等功能。该模块使用了Redis…...

【AI视野·今日CV 计算机视觉论文速览 第300期】Fri, 1 Mar 2024

AI视野今日CS.CV 计算机视觉论文速览 Fri, 1 Mar 2024 Totally 114 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers DistriFusion: Distributed Parallel Inference for High-Resolution Diffusion Models Authors Muyang Li, Tianle Cai, J…...

【单片机学习的准备】

文章目录 前言一、找一个视频是二、画图软件三、装keil5 仿真protues总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 项目需要&#xff1a; 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、找一个视频是 https://www.b…...

力扣hot100:438.找到字符串中所有字母异位词

26个字符&#xff0c;我复制怎么了&#xff1f;26个字符我比较个数怎么了&#xff1f; 顶多时间复杂度*26 本题用固定窗口大小的滑动窗口每次比较包含26个元素的数组次数&#xff0c;最容易写。 动态窗口大小哈希表存数值&#xff08;双指针差值&#xff09;难想难写。 一、动态…...

Kali Linux 2024.1

Kali Linux 2024.1刚刚发布&#xff0c;标志着这个备受欢迎的安全重点Linux发行版在今年的首次重大更新。以其先进的渗透测试和安全审计功能而闻名&#xff0c;它是安全专业人员和爱好者的首选工具。 Kali 2024.1 亮点 本次发布由 Linux 内核 6.6 提供支持&#xff0c;突出了…...

springboot启动加载

目录 使用PostConstruct注解 实现InitializingBean接口 实现CommandLineRunner接口 实现ApplicationRunner接口 使用EventListener注解监听ApplicationReadyEvent事件 应用启动完成之前或者之后&#xff0c;我们需要拿数据库中的一些数据加载到本地缓存中。这些数据一般都…...

基于Java的智能停车场管理系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容A. 车主端功能B. 停车工作人员功能C. 系统管理员功能1. 停车位模块2. 车辆模块3. 停车记录模块4. IC卡模块5. IC卡挂失模块 三、界面展示3.1 登录注册3.2 车辆模块3.3 停车位模块3.4 停车数据模块3.5 IC卡档案模块3.6 IC卡挂…...

ESD Clamp cell是什么?

ESD CLAMP cell&#xff08;静电放电钳位单元&#xff09;是一种专门设计来保护集成电路&#xff08;IC&#xff09;免受静电放电&#xff08;ESD&#xff09;损害的电路元件。静电放电是在电子设备的组件之间或内部发生的突然电流放电&#xff0c;它可能会损坏电路或降低其性能…...

费率电能表

费率电能表是一种用于测量家庭、商业和工业用电的设备&#xff0c;有效的实现分段计费、分时计费&#xff0c;优化用电效率。费率电能表的产生是为了缓解高峰期的用电负荷&#xff0c;平衡各时间段的用电负荷&#xff1b;根据当地用电负荷曲线情况制定时段费率 在费率电能表中…...

2张图2秒钟3D重建!这款AI工具火爆GitHub,网友:忘掉Sora

只需2张图片&#xff0c;无需测量任何额外数据—— 当当&#xff0c;一个完整的3D小熊就有了&#xff1a; 这个名为DUSt3R的新工具&#xff0c;火得一塌糊涂&#xff0c;才上线没多久就登上GitHub热榜第二。 ▲image 有网友实测&#xff0c;拍两张照片&#xff0c;真的就重建…...

C++高级面试题:请解释 C++ 中的指针和引用之间的区别。

请解释 C 中的指针和引用之间的区别。 在 C 中&#xff0c;指针&#xff08;Pointers&#xff09;和引用&#xff08;References&#xff09;都是用于处理内存地址的工具&#xff0c;但它们有一些重要的区别&#xff1a; 语法和用法&#xff1a; 指针使用 * 运算符来访问其所…...

Git 配置处理客户端无法正常访问到 github 原网站时,npm 下载依赖包失败的问题

Git 配置处理客户端无法正常访问到 github 原网站时&#xff0c;npm 下载依赖包失败的问题 使用 github 的镜像网站地址或类似的替代产品地址&#xff0c;代替到 npm 拉取依赖包的 git 地址本地Git配置 例如&#xff1a;执行一下命令&#xff0c;则是以https://kgithub.com 替…...

前端爬虫+可视化Demo

爬虫简介 可以把互联网比做成一张 “大网”&#xff0c;爬虫就是在这张大网上不断爬取信息的程序。 爬虫是请求网站并提取数据的自动化程序。 省流&#xff1a;Demo实现前置知识&#xff1a; JS 基础Node 基础 &#xff08;1&#xff09;爬虫基本工作流程&#xff1a; 向…...

keepAlive

router c.js const view (name) > () > import(/views/文件夹名/ name) export const c [ {path: /xxx,name: aaa,meta: {title: 哈哈哈,admin: true,keepAlive:true //加这个},component: view(xxx) }, ]adminMain.vue <keep-alive><router-view v-if"…...

蓝桥杯练习题——dp

五部曲&#xff08;代码随想录&#xff09; 1.确定 dp 数组以及下标含义 2.确定递推公式 3.确定 dp 数组初始化 4.确定遍历顺序 5.debug 入门题 1.斐波那契数 思路 1.f[i]&#xff1a;第 i 个数的值 2.f[i] f[i - 1] f[i - 2] 3.f[0] 0, f[1] 1 4.顺序遍历 5.记得特判 …...

kotlin基础语法

1.变量 var a:Int 2 //声明类型的可变变量 var b 3 //代码推测可变变量类型 val c 6 //代码推测不可变常量类型 var d:String?null //可为null的String类型的可变变量 latei…...

淘宝天猫商家爬虫工具 电商采集软件使用教程

介绍&#xff1a; 淘宝和天猫是中国最大的电商平台之一&#xff0c;商家在这里销售各种商品。在市场竞争激烈的环境下&#xff0c;了解竞争对手的商品信息和价格变化对于电商运营来说非常重要。本文将介绍如何使用Python编写一个简单的淘宝天猫商家爬虫工具&#xff0c;以获取商…...

建库建表时,最容易忽略的10个细节

大家使用 DolphinDB 创建数据库和表时&#xff0c;有时对于分区列、分区类型和排序列的选择并不十分清晰。如果不加注意&#xff0c;可能导致查询速度变慢、数据丢失或插入错误等问题。合理地设置分区列、排序列和分区类型&#xff0c;有助于加快查询速度&#xff0c;减少内存使…...

【基础知识】什么是 PPO(Proximal Policy Optimization,近端策略优化)

什么是 PPO&#xff08;Proximal Policy Optimization&#xff0c;近端策略优化&#xff09; PPO&#xff08;Proximal Policy Optimization&#xff0c;近端策略优化&#xff09;是一种强化学习算法&#xff0c;由John Schulman等人在2017年提出。PPO属于策略梯度方法&#x…...

程序员如何选择职业赛道?

程序员如何选择职业赛道&#xff1f; 程序员的职业赛道就像是一座迷宫&#xff0c;充满了各种各样的岔路口。每个岔路口都代表着不同的方向&#xff0c;不同的技术领域&#xff0c;不同的职业发展道路。 前端开发 前端开发就像迷宫中的美丽花园&#xff0c;它是用户与网站或应…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解

文章目录 一、开启慢查询日志&#xff0c;定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...