【Redis实战】快速简单搭建聊天室04——实现页面功能

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis实战】快速简单搭建聊天室04——实现页面功能

实现获取聊天消息的功能


聊天消息保存在Redis里名为“chat_list”列表中,新的消息在列表右侧,老的消息在列表左侧。每次返回最右侧的20条信息。获取聊天消息的功能对应的方法为get_chat_list()。修改这个方法,实现获取消息列表:

01    def get_chat_list(self):
02        """
03        你需要实现这个方法
04     
05        获取聊天消息列表。
06        使用Redis的列表实现。Key为self.chat_list属性中保存的字符串,可以直接使用。
07        获取列表右端20条信息,但不要删除。
08     
09        需要注意,从Redis中获取的数据一个列表,列表里面是bytes型的字符串,所以需要
10        先把这个列表展开,把里面的bytes型的字符串解密为普通字符串以后再用json解析为
11        字典。接下来讲解析出来的字典放入一个新的列表中。最后返回新的列表。
12        :return: 包含字典的列表
13        """
14        chat_list = self.client.lrange(self.chat_list, -20, -1)
15        chat_info_list = []
16        for chat in chat_list:
17            chat_info = json.loads(chat.decode())
18            chat_info_list.append(chat_info)
19        return chat_info_list


其中,主要说明如下:

  • 14行:使用列表的lrange命令获取但不删除列表中的信息。-20表示从右往左数第20条信息,-1表示最右边的信息
  • 16-18行:由于lrange返回的数据是包含bytes型数据的列表,所以需要把列表里的每一条bytes的数据先解码为字符串,再用JSON模块解析为字典
  • 19行:将最终生成的包含字典的列表返回

                                             

获取聊天信息


修改完成代码以后重启网站,可以看到聊天室消息还是一片空白。现在,人工向Redis中添加几天数据:

01    127.0.0.1:6379> lpush chat_list '{"msg": "我是人工添加的消息", "nick": "青南", "post_time": "2018-07-22 16:15:00"}'
02    (integer) 1
03    127.0.0.1:6379> lpush chat_list '{"msg": "我是青南的助手", "nick": "青南的助手", "post_time": "2018-07-22 16:15:00"}'
04    (integer) 2
05    127.0.0.1:6379>





redis-cli中手动添加聊天信息


添加好聊天信息以后,可以看到聊天室里已经出现了手动添加的内容。

手动添加的内容已经出现在聊天窗口


2. 实现发送新信息的功能

发送新信息的原理非常简单,把新信息字典转换为JSON格式并存入chat_list列表的右侧即可。发现信息对应的方法为push_chat_info(),完善它的代码:


01    def push_chat_info(self, chat_info):
02        """
03        把聊天信息存入列表的右侧。
04     
05        使用Redis的集合实现,对应的Key为self.chat_list中保存的字符串。
06        把chat_info字典先转化为JSON字符串,再存入Redis中列表中。
07     
08        为了防止列表消息太长,因此需要使用ltrim命令删除多余的信息,只保留
09        列表最右侧的20条
10        :param chat_info: 字典,格式为{'msg': '信息', 'nick': '青南', 'post_time': '2018-07-22 10:00:12'}
11        :return: None
12        """
13        self.client.rpush(self.chat_list, json.dumps(chat_info))
14        self.client.ltrim(self.chat_list, -20, -1)

其中,主要说明如下:

  • 13行:先把聊天信息对应的字典转换为JSON字符串。然后添加的列表的右侧
  • 14行:chat_list列表只保留最右侧的20条,多余的信息全部删除

这里引入一个新的知识点,列表的ltrim命令。这个命令的作用是从列表里面删除保留一段数据并删除其他数据。

代码第14行调用ltrim命令,传入了三个参数。

第一个参数是列表的Key。

第二个参数是保留数据起始位置,第三个参数是保留数据截至位置。所以这一行代码的作用是除了右边数第20条数据(含)到右边第一条数据(含)外,删除列表中的其他数据。

本项目使用ltrim是为了节约服务器内存,加速读取列表的时间。这并不是必需的,如果服务器内存足够的话,或者信息不多的话,也可以不删除。


实现发布新信息的功能


修改完成代码以后网站,可以看到发帖功能已经正常。

发帖功能开发完成


到目前为止基本功能已经开发完成,但还有一个小问题需要解决。

用户无限制刷屏


如果不限制同一个用户发送同一条信息的频率,可能会出现一个用户短时间发送大量相同信息的刷屏的行为。



3. 设定刷屏检查字符串

本项目将会限制同一个昵称发送完全相同信息的频率。两次完全相同的信息的发送时间间隔为120秒。

Redis天然就具有实现这一功能的能力。在Redis中,Key可以设置过期时间。时间到了以后Redis会自动删除这个Key

那么如果设置一个字符串,Key为:“昵称-发言内容”。

例如“青南-我在灌水”。然后把这个Key的过期时间设置为120秒。这个字符串的值无所谓,随便设置什么都可以。那么只要这个KeyRedis中,就说明这个用户昵称,在120秒内已经发送过这条信息了。只要这个Key不在Redis中,就说明这个用户从来没有发送过这条信息或者发送已经超过了两分钟,KeyRedis自动删除了。

而且Redis可以使用ttl命令查询一个Key的过期时间还剩多少秒。这样还可以实现提醒功能。

设置Key的过期时间,对应的方法为set_nick_msg_expire_time()修改代码:


01    def set_nick_msg_expire_time(self, nick, msg):
02        """
03        你需要实现这个方法
04     
05        设定Key的过期时间,这个功能的目的是限定同一个用户在2分钟内不能发送同样的内容。
06        为了防止信息太长,因此把信息编码为md5以后再与昵称拼接以缩短Key的长度。
07        使用Redis的字符串实现,字符串的Key为昵称+信息的md5编码,值为1.使用set命令的
08        ex参数设定Key的过期时间为120秒,时间到了以后Redis会自动删除这个Key
09        :param nick: 昵称
10        :param msg: 信息
11        :return: None
12        """
13        msg_md5 = hashlib.md5(msg.encode()).hexdigest()
14        duplicate_msg_check_flag = nick + msg_md5
15        self.client.set(duplicate_msg_check_flag, 1, ex=120)

13行:先把信息转换为MD5。这样做的好处是缩短信息的长度,避免太长到信息导出超出Redis Key的限制

14行:把用户昵称与消息的MD5值拼成一个长字符串,作为Key

15行:Redis中设定一个字符串,Key为昵称与消息的MD5值,值为1,通过ex参数设定过期时间为120,过期时间一到Redis就会删除这个Key


设定刷屏检查字符串及其过期时间



4、读取刷屏限制剩余时间

当用户要发送新内容的时候,网站先检查Redis是否有“昵称+新信息MD5值”这个Key,如果有,说明用户在120秒类发送了相同的内容,此时返回解除刷屏限制的剩余时间。如果不存在这个Key,就返回None。对应的方法为get_nick_msg_expire_time()。修改现有代码:

01    def get_nick_msg_expire_time(self, nick, msg):
02        """
03        获取某一个昵称发送某一条消息的过期时间。这个功能的作用是
04        为了防止同一个用户短时间发送大量相同信息刷屏。
05     
06        为了防止信息太长,因此把信息编码为md5以后再与昵称拼接以缩短Key的长度。
07        使用Redis的ttl命令来实现,ttl命令如果返回None,说明不存在这个Key,
08        返回None。如果ttl返回-1,说明这个Key没有设定过期时间,这个Key可以一直存在
09        如果ttl返回一个大于0的正整数,说明在这个整数对应的秒过于以后,Redis会自动
10        删除这个Key
11     
12        :param nick: 昵称
13        :param msg: 信息
14        :return: None 或者 数字
15        """
16        msg_md5 = hashlib.md5(msg.encode()).hexdigest()
17        duplicate_msg_check_flag = nick + msg_md5
18        expire_time = self.client.ttl(duplicate_msg_check_flag)
19        return expire_time

其中,主要说明如下:

  • 16行:获得消息的MD5
  • 17行:把昵称与消息的MD5值拼成一个Key
  • 使用Redisttl命令检查Key的剩余时间。如果Key不存在,返回None,如果Key没有过期时间,返回-1,如果Key有过期时间,返回剩余时间(正整数)


读取刷屏限制过期时间


修改完成以后重启网站,尝试连续发送相同的信息,发现得到网站提示。

提示不能在两分钟内发送同样的内容


5、总结

本系列推送通过开发简易聊天室网站来巩固Redis的基础知识。同时也引入了列表裁剪,Key添加过期时间与检查Key剩余过期时间这三个知识点。读者在开发的过程中,可以经常使用redis-cli观察Redis中的Key的变化情况,以便于更好理解代码和命令的作用。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
15天前
|
存储 NoSQL PHP
如何用Redis高效实现点赞功能?用Set?还是Bitmap?
在众多软件应用中,点赞功能几乎成为标配。本文从实际需求出发,探讨如何利用 Redis 的 `Set` 和 `Bitmap` 数据结构设计高效点赞系统,分析其优缺点,并提供 PHP 实现示例。通过对比两种方案,帮助开发者选择最适合的存储方式。
28 3
|
26天前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
56 5
|
1月前
|
缓存 NoSQL Java
Spring Boot与Redis:整合与实战
【10月更文挑战第15天】本文介绍了如何在Spring Boot项目中整合Redis,通过一个电商商品推荐系统的案例,详细展示了从添加依赖、配置连接信息到创建配置类的具体步骤。实战部分演示了如何利用Redis缓存提高系统响应速度,减少数据库访问压力,从而提升用户体验。
74 2
|
1月前
|
缓存 分布式计算 NoSQL
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
29 2
|
1月前
|
SQL 分布式计算 NoSQL
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
25 2
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
62 2
|
2月前
|
缓存 NoSQL 应用服务中间件
Redis实战篇
Redis实战篇
|
3月前
|
运维 监控 NoSQL
【Redis】哨兵(Sentinel)原理与实战全解~炒鸡简单啊
Redis 的哨兵模式(Sentinel)是一种用于实现高可用性的机制。它通过监控主节点和从节点,并在主节点故障时自动进行切换,确保集群持续提供服务。哨兵模式包括主节点、从节点和哨兵实例,具备监控、通知、自动故障转移等功能,能显著提高系统的稳定性和可靠性。本文详细介绍了哨兵模式的组成、功能、工作机制以及其优势和局限性,并提供了单实例的安装和配置步骤,包括系统优化、安装、配置、启停管理和性能监控等。此外,还介绍了如何配置主从复制和哨兵,确保在故障时能够自动切换并恢复服务。
|
3月前
|
缓存 NoSQL Java
惊!Spring Boot遇上Redis,竟开启了一场缓存实战的革命!
【8月更文挑战第29天】在互联网时代,数据的高速读写至关重要。Spring Boot凭借简洁高效的特点广受开发者喜爱,而Redis作为高性能内存数据库,在缓存和消息队列领域表现出色。本文通过电商平台商品推荐系统的实战案例,详细介绍如何在Spring Boot项目中整合Redis,提升系统响应速度和用户体验。
67 0
下一篇
无影云桌面