1.发布探店笔记
2.点赞
利用Redis中的Set集合来判断是否点赞过。
3.点赞排行榜
可以通过SortedSet来按点赞时间进行排序。
4.好友关注
4.1.关注和取关
4.2.共同关注
- 可以通过set实现交集的功能
4.3.关注推送
4.3.1 拉模式
- 拉模式(Pull),也叫读扩散:
- 在拉模式中,消费者负责主动从消息队列或者消息服务器中拉取消息。
- 消费者会定期轮询消息队列或者订阅主题,检查是否有新的消息可供处理。
- 消费者决定何时拉取消息,以及每次拉取多少消息。
- 这种方式相对消耗资源较少,因为消费者可以控制消息的获取速度,但可能导致消费者轮询频繁或者消息获取不及时的问题。
4.3.2 推模式
- 推模式(Push),也叫写扩散:
- 在推模式中,消息生产者直接将消息推送给消费者,而无需消费者主动请求。
- 生产者在消息就绪后即时地将消息发送给订阅者或者消息队列。
- 消费者无需关心何时有新消息,只需要等待消息到达并及时处理。
- 这种方式可以实时地将消息推送给消费者,但可能导致消费者处理不及时或者消息堆积的问题。
4.3.3 推拉模式
- 推拉模式结合了拉模式和推模式的优点。
- 消费者可以通过订阅主题或者注册监听器等方式订阅消息,同时可以根据需要主动拉取消息。
- 当有新消息到达时,消息服务器会主动推送消息给消费者;当消费者需要获取消息时,也可以主动拉取消息。
- 这种方式结合了实时性和资源控制的优势,消费者可以根据自己的需求选择何时主动获取消息,何时等待消息推送。
- 根据不同的用户提供不同的方案
4.3.4 方案比较
5.基于推模式实现关注推送功能
- 需求一
- 在保存blog到数据库的同时,推送到粉丝的收件箱(即利用SortedSet创建一个对应的redis字段,key为粉丝的id,结合中的内容为博客id和创建时间)
5.1 Feed流的分页问题
Feed流中的数据会不断更新,所以数据的角标也在变化,因此不能采用传统的分页模式。
解决办法:
使用滚动分页
5.2 实现关注页面的分页查询
- 利用每次查询都记住上一次查询的最小值
- 第一页利用
ZREVRANGEBYSCORE z1 maxValue 0 WITHSCORES LIMIT 0 sizeOfPage
- 下一次可以通过利用上一次的最小值继续查询
ZREVRANGEBYSCORE z1 lastMinValue 0 WITHSCORES LIMIT sizeOfLastValue sizeOfPage
- 但有可能会出现score分数相同的情况,所以上面的偏移1可能会出问题
- 所以这个偏移量应该是和上次最小值相同的个数
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {
// 1.获取当前用户
Long userId = UserHolder.getUser().getId();
// 2.查询收件箱
String key = FEED_KEY + userId;
Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
.reverseRangeByScoreWithScores(key, 0, max, offset, 2);
// 3.非空判断
if (typedTuples == null || typedTuples.isEmpty()){
return Result.ok();
}
// 4.解析收件箱:blogId、score(时间戳)、offset根我上次查询出的值
ArrayList<Long> ids = new ArrayList<>(typedTuples.size());
long minTime = 0;
int os = 1;
for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
// 4.1.获取id
ids.add(Long.valueOf(tuple.getValue()));
// 4.2.获取分数(时间戳)
long time = tuple.getScore().longValue();
if(time == minTime){
os++;
}else{
minTime = time;
os = 1;
}
}
// 5.根据id查询blog
String idStr = StrUtil.join(",", ids);
List<Blog> blogs = query()
.in("id",ids)
.last("ORDER BY FIELD(id,"+idStr+")").list();
for (Blog blog : blogs) {
queryBlogUser(blog);
isBlockLiked(blog);
}
// 6.封装并返回
ScrollResult r = new ScrollResult();
r.setList(blogs);
r.setOffset(os);
r.setMinTime(minTime);
return Result.ok(r);
}