Feed流实现方案
我们关注了博主之后,当用户发布了动态后我们应该把这些数据推送给粉丝,关注推送也叫作Feed(投喂)流
,通过无限下拉刷新获取新的信息
Feed流实现的两种模式
Timeline
: 对发布的信息不做内容筛选,简单的按照内容发布时间排序,常用于好友或关注(朋友圈等)
智能排序
:利用智能算法屏蔽掉违规的、用户不感兴趣的内容,推送用户感兴趣的信息来吸引用户
个人页面一般就是基于关注的好友来做Feed流,因此采用Timeline
方式只需要拿到我们关注用户的发布的内容然后按照时间排序
即可
优点节约空间
:系统只会将用户关注的博主发布的动态放入到用户的收件箱,用户每次从自己的收件箱中读取信息缺点拉取信息有延迟
:只要用户读取数据时就会去他关注的所有人的发件箱中拉取信息,假设该用户关注了海量用户此时就会拉取很多信息对服务器压力巨大
推模式
也叫写扩散,推模式没有发件箱
推拉结合
也叫读写混合,兼具推和拉两种模式的优点,只要大v才有发件箱
推送笔记ID到粉丝收件箱
需求: 修改新增探店笔记的业务,在保存Blog对象到数据库的同时推送笔记到粉丝的收件箱
传统的分页模式
: 查询数据时要求数据库中的数据角标必须固定,否则可能会出现数据重复读取的情况
Feed流的滚动分页
: 记录每次查询操作的最后一条数据,下次查询时会从上次读取的最后一条数据之后开始读取数据
第一步: 修改BlogController
中保存笔记的方法,当博主发布完探店笔记后还要将发布笔记的Id推送到所有粉丝的收件箱中,score值是当前的时间戳(默认升序)
// 在RedsiConstants类声明一个常量作为用户收件箱的前缀
public static final String FEED_KEY = "feed:";
@Resource
private IFollowService followService;
@Override
public Result saveBlog(Blog blog) {
// 获取登录用户
UserDTO user = UserHolder.getUser();
blog.setUserId(user.getId());
// 保存探店博文
boolean isSuccess = save(blog);
if(!isSuccess){
return Result.fail("新增笔记失败");
}
// 条件构造器
LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
// 从follow表中查找博主的所有粉丝select * from follow where follow_user_id = user_id
queryWrapper.eq(Follow::getFollowUserId, user.getId());
List<Follow> follows = followService.list(queryWrapper);
for (Follow follow : follows) {
// 获取粉丝Id
Long userId = follow.getUserId();
// 推送发布笔记的Id到每个粉丝的收件箱(score值是当前时间戳),每个粉丝都有一个自己的收件箱
String key = FEED_KEY + userId;
stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
}
// 返回笔记的id
return Result.ok(blog.getId());
}
查询推送笔记
需求: 在个人主页的关注栏中查询并展示推送的Blog信息
ZREVRANGEBYSCORE key 最大值范围 最小值范围 WITHSCORES LIMIT offSet(偏移量) 查询到的个数
: 获取指定的score范围内的元素并按照降序排序
最小时间戳
: 每次分页查询完成之后要记录查询的最小时间戳,将这个最小时间戳作为下一次分页查询的条件编译量
: 设置要从上次查询的最大值后面跳过几个元素,0表示不跳过元素,1表示跳过一个元素,偏移量的值取决于当前集合内有几个元素和上次查询到的最大值相同
第一步: 业务中不一定只对Blog
进行分页查询,可以使用泛型做一个通用的分页查询
@Data
public class ScrollResult {
// 封装查询到的数据
private List<?> list;
// 记录本次查询的最小时间戳,作为下一次查询的最大值(起始值)
private Long minTime;
// 记录偏移量
private Integer offset;
}
第二步: 在BlogController
中创建对应的分页查询方法, 具体实现逻辑在BlogServiceImpl
中完成
@GetMapping("/of/follow")
// 由于第一次查询的时候没有传递offset参数,可以设置默认值为0
public Result queryBlogOfFollow(
@RequestParam("lastId") Long max, @RequestParam(value = "offset",defaultValue = "0") Integer offset){
return blogService.queryBlogOfFollow(max,offset);
}
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {
//1. 获取当前用户的Id
Long userId = UserHolder.getUser().getId();
//2. 查询该用户的收件箱获取该用户对应的SortedSet集合中所有的笔记Id及score值看是否有关注的博主发了笔记
String key = FEED_KEY + userId;
Set<ZSetOperations.TypedTuple<String>> typeTuples = stringRedisTemplate.opsForZSet()
.reverseRangeByScoreWithScores(key, 0, max, offset, 2);
//3. 非空判断
if (typeTuples == null || typeTuples.isEmpty()){
return Result.ok(Collections.emptyList());
}
//4. 获取SortedSet集合中所有的笔记Id及score值,List集合的大小和Set集合一致,可以略微提高效率避免长度重置
ArrayList<Long> ids = new ArrayList<>(typeTuples.size());
// 保存最小的时间戳
long minTime = 0;
// 记录最小时间戳的个数即偏移量
int os = 1;
for (ZSetOperations.TypedTuple<String> typeTuple : typeTuples) {
//4.1 获取推送的Blog的Id
String id = typeTuple.getValue();
ids.add(Long.valueOf(id));
//4.2 将笔记对应的score(时间戳)转换为long类型
long time = typeTuple.getScore().longValue();
if (time == minTime){// 如果当前的时间戳等于最小时间戳则最小时间戳个数+1
os++;
}else {// 如果当前时间戳不等于最小时间戳,则把当前时间作为最小时间戳同时把最小时间戳的个数重置为1
minTime = time;
os = 1;
}
}
// 解决MySQL的in语句的自动按照id大小的排序问题,手动指定排序方式为传入的ids集合中的顺序
String idsStr = StrUtil.join(",");
//5. 根据推送的ids集合查询所有的blog
List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idsStr + ")").list()
for (Blog blog : blogs) {
//5.1 查询发布该blog的用户信息
queryBlogUser(blog);
//5.2 查询当前用户是否给该blog点过赞
isBlogLiked(blog);
}
//6. 封装结果并返回
ScrollResult scrollResult = new ScrollResult();
scrollResult.setList(blogs);
scrollResult.setOffset(os);
scrollResult.setMinTime(minTime);
return Result.ok(scrollResult);
}
原文地址:https://blog.csdn.net/qq_57005976/article/details/134623418
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_4415.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!