使用Python+Redis实现文章投票网站后端功能

完整源码:

import time
ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60

def article_vote(r, user_id, article_id):
    cutoff = time.time() - ONE_WEEK_IN_SECONDS

    
    cutoff = time.time() - ONE_WEEK_IN_SECONDS  
    if r.zscore('time', article_id) < cutoff:  
        return
    if r.sadd('voted:' + article_id, user_id):  
        r.zincrby('score', article_id, 1)  
    

def post_article(r, user, title, link):
    article_id = str(r.incr('article'))

    voted = 'voted:' + article_id
    r.sadd(voted, user)  
    r.expire(voted, ONE_WEEK_IN_SECONDS)
    now = time.time()
    article = 'article:' + article_id
    
    r.hmset(article, {  
        'title': title,  
        'link': link,  
        'poster': user,  
    })
    r.zadd('score', article_id, 1)  
    r.zadd('time', article_id, now)
    

    return article_id

def get_articles(r, start, end, order='score'):
    articles = []
    ids = r.zrevrange(order, start, end) 
    
    for id in ids:  
        article_data = r.hgetall(id)  
        article_data['id'] = id  
        articles.append(article_data)

    return articles
实现投票功能

实现投票功能,要注重文章的时效性与投票的公平性,所以需要给投票功能加上一些约束条件:

  • 文章发布满一个星期后,不再允许用户对该文章投票
  • 一个用户对一篇文章只能投一次票

所以我们需要使用:

  • 一个有序集合 time,存储文章的发布时间
  • 一个集合 voted:*,存储已投票用户名单
    • 其中 * 是被投票文章的 ID
  • 一个有序集合 score,存储文章的得票数
ONE_WEEK_IN_SECONDS = 7 * 24 * 60 * 60

def article_vote(r, user_id, article_id):
# 使用 time.time() 获取当前时间
# 减去一周的秒数,从而获取一周前的Unix时间
cutoff = time.time() - ONE_WEEK_IN_SECONDS
if r.zscore('time', article_id) < cutoff:
return

if r.sadd('voted:' + article_id, user_id):
r.zincrby('score', article_id, 1)

 

当用户尝试投票时,使用 ZSCORE 命令读取 time 有序集合,得到这篇文章的发布时间,再判断文章的发布时间是否超过一周。ZSCORE 命令的语法如下:

r.zscore(key, member)

  • key :是有序集合的键名
  • member :是有序集合中的某个成员

若未超过,则使用 SADD 命令尝试将用户追加到这篇文章的已投票用户名单中,如果添加成功,则说明该用户未投过票。SADD 命令的语法是:

r.sadd(key, member)

  • key :是集合的键名
  • member :是要添加进集合的元素

由于集合中的元素是唯一的,所以sadd函数会根据member是否存在在集合中做出不同返回:

  • 若该元素不存在在集合中,返回 True
  • 若该元素已存在在集合中,返回 False

所以返回为 True 时使用 ZINCRBY 命令来为文章的投票数加 1zincrby 函数语法如下:

r.zincrby(key, member, increment)

  • key :是有序集合的键名
  • member :是有序集合中要增加分值的成员
  • increment :是要增加的分值
创建文章数据

现在系统中还缺少文章数据,所以我们要提供一个创建文章的函数,并把文章数据存储到 Redis 中。创建文章的步骤如下:

  • 创建新的文章 ID
  • 将文章作者加入到这篇文章的已投票用户名单中
  • 存储文章详细信息到 Redis 
  • 将文章的发布时间和初始投票数加入到 time 和 score 两个有序集合中
def post_article(r, user, title, link):
# 创建新的文章ID,使用一个整数计数器对 article 键执行自增
# 如果该键不存在,article 的值会先被初始化为 0
# 然后再执行自增命令
article_id = str(r.incr('article'))

voted = 'voted:' + article_id
r.sadd(voted, user)
r.expire(voted, ONE_WEEK_IN_SECONDS)

now = time.time()
article = 'article:' + article_id
r.hmset(article, {
'title': title,
'link': link,
'poster': user,
})

r.zadd('score', article_id, 1)
r.zadd('time', article_id, now)

return article_id

将文章作者加入已投票用户名单中和之前一样,这里不再赘述,但在这里我们需要为这个已投票用户名单设置一个过期时间,让它在一周后(到期后)自动删除,减少 Redis 的内存消耗。为设置过期时间的命令是:

r.expire(key, seconds)

  • key :要设置过期时间的键名
  • seconds :过期时间的长度(单位:秒)

这里我们要设置的时间是一周,所以我们可以使用上面定义好的全局变量 ONE_WEEK_IN_SECONDS

接下来要存储文章详细信息了,前面介绍过 hset 可以执行单个字段(域)的设置,这里我们使用 hmset 一次性设置多个字段(域),其语法如下:

r.hmset(key, {field: value, [field: value ...]})

我们可以使用 Python 的散列来一次性存储多个字段(域)到 Redis,只需要将整个散列当作 key 对应的值通过 hmset 函数设置进去就行。

最后,将初始投票数和创建时间设置到 scoretime 中都可以通过 ZADD 命令来实现:

r.zadd(key, member, score)

  • key :有序集合的键名
  • member :要加入有序集合的成员
  • score :该成员的分值

这里需要注意的是,因为该篇文章的作者已经被加入到该文章已投票用户名单中,为了保持数据一致性,我们需要将文章的初始投票数设为 1

对文章进行排序

实现了文章投票和创建文章功能,接下来我们就需要将评分最高的文章最新发布的文章Redis 中取出了。

  • 首先我们要根据排序方式的不同:

    • 按评分排序,则从 score 有序集合中取出一定量的文章 IDscore有序集合存放文章ID和对应的投票数)
    • 按时间排序,则从 time 有序集合中取出一定量的文章 IDtime有序集合存放文章ID和对应的发布时间)
  • 构成一个有序文章信息列表,每个元素都:

    • 使用 HGETALL 命令,取出每篇文章的全部信息
def get_articles(r, start, end, order='score'):
ids = r.zrevrange(order, start, end)
articles = []
for id in ids:
article_data = r.hgetall(id)
article_data['id'] = id
articles.append(article_data)

return articles

这里因为需要对有序集合进行排序,所以我们在取出文章 ID 时需要使用到 ZREVRANGE 命令,以分值从大到小的排序方式取出文章 IDZREVRANGE 命令的语法是:

r.zrevrange(key, start, stop)

  • key :有序集合的键名
  • start :开始的数组下标
  • stop :结束的数组下标

得到多个文章 ID 后,我们还需要根据每一个文章 ID 获取文章的全部信息,这时就需要使用到 HGETALL 命令,它的语法如下:

r.hgetall(key)

  • key :哈希的键名

我们取出文章的全部信息后,还为文章信息添加了一个字段 id。这是因为文章 IDRedis 中是作为键名存储的,不在值当中,所以我们需要附加这个字段到文章信息中。

实现这些方法后,我们大体实现了一个文章投票的后端处理逻辑,能够为文章投票并能根据投票结果改变文章的排序情况。

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,这里提供一个简单的示例代码实现微信好友添加同意功能: 首先,需要在 Spring Boot 项目中引入 Redis 相关依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 然后,在 Redis 中添加一个集合,用于存储已同意添加好友的用户: ```java @Component public class RedisUtils { @Autowired private RedisTemplate<String, Object> redisTemplate; /** * 获取 Redis 集合 */ public Set<Object> getSet(String key) { return redisTemplate.opsForSet().members(key); } /** * 添加元素到 Redis 集合 */ public Boolean addToSet(String key, Object value) { return redisTemplate.opsForSet().add(key, value) > 0; } } ``` 在处理好友添加请求时,先判断该用户是否已经同意添加好友,如果已经同意,则直接返回成功,否则将请求添加到 Redis 队列中,并返回等待审核的提示信息: ```java @RestController @RequestMapping("/friend") public class FriendController { @Autowired private RedisUtils redisUtils; private static final String FRIEND_REQUEST_QUEUE = "friend_request_queue"; private static final String FRIEND_AGREED_SET = "friend_agreed_set"; /** * 处理好友添加请求 */ @PostMapping("/request") public String handleFriendRequest(@RequestParam String userId, @RequestParam String friendId) { // 判断该用户是否已经同意添加好友 if (redisUtils.getSet(FRIEND_AGREED_SET).contains(userId)) { return "您已同意添加该好友,请勿重复操作!"; } // 将请求添加到 Redis 队列中 redisUtils.addToSet(FRIEND_REQUEST_QUEUE, userId + ":" + friendId); return "好友添加请求已发送,等待审核!"; } } ``` 最后,另外开启一个线程来处理 Redis 队列中的好友添加请求,并将每个已审核的用户添加到 Redis 集合中: ```java @Component public class FriendRequestHandler { @Autowired private RedisUtils redisUtils; private static final String FRIEND_REQUEST_QUEUE = "friend_request_queue"; private static final String FRIEND_AGREED_SET = "friend_agreed_set"; @PostConstruct public void start() { new Thread(() -> { while (true) { // 从 Redis 队列中取出一条待审核的好友添加请求 Set<Object> set = redisUtils.getSet(FRIEND_REQUEST_QUEUE); if (CollectionUtils.isEmpty(set)) { continue; } Object[] array = set.toArray(); String request = (String) array[0]; redisUtils.redisTemplate.opsForSet().remove(FRIEND_REQUEST_QUEUE, request); // 审核通过,将用户添加到已同意的好友集合中 String[] userIdAndFriendId = request.split(":"); redisUtils.addToSet(FRIEND_AGREED_SET, userIdAndFriendId[0]); } }).start(); } } ``` 以上就是使用 Spring Boot 和 Redis 实现微信好友添加同意功能的示例代码。需要注意的是,这只是一个简单的示例,实际项目中还需要考虑更多的安全性和异常处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuhao_

谢谢你打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值