@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private IUserService userService;
@Override
public Result follow(Long followUserId, Boolean isFollow) {
//1.获取登陆的用户
Long userId = UserHolder.getUser().getId();
//1.判断是关注还是取关
if(isFollow){
//关注,新增数据
Follow follow = new Follow();
follow.setUserId(userId);
follow.setFollowUserId(followUserId);
boolean isSuccess = this.save(follow);
if(isSuccess){
// 把关注用户的id,放入到redis的set集合 sadd userId followerUserId
String key = "follows:" + userId;
stringRedisTemplate.opsForSet().add(key, followUserId.toString());
}
}else {
//取关,删除
QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("follow_user_id", followUserId).eq("user_id", userId);
boolean isSuccess = this.remove(queryWrapper);
if(isSuccess){
//从redis集合中移除
String key = "follows:" + userId;
stringRedisTemplate.opsForSet().remove(key, followUserId.toString());
}
}
return Result.ok();
}
@Override
public Result isFollow(Long followUserId) {
//1.获取登陆的用户
Long userId = UserHolder.getUser().getId();
//查询是否关注
Integer count = this.query().eq("follow_user_id", followUserId).eq("user_id", userId).count();
return Result.ok(count > 0);
}
@Override
public Result followCommons(Long id) {
//获取当前的用户
Long userId = UserHolder.getUser().getId();
//知道两个用户在Redis中求交集
String key1 = "follows:" + userId;
String key2 = "follows:" + id;
Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);
if(intersect == null || intersect.isEmpty()){
//无交集
return Result.ok(Collections.emptyList());
}
//通过Set集合解析出Id集合
List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());
//查询用户
List<UserDTO> users = userService.listByIds(ids)
.stream()
.map(user -> BeanUtil.copyProperties(user, UserDTO.class))
.collect(Collectors.toList());
return Result.ok(users);
}
博客推送与分页查询
查询的控制层
@GetMapping("/of/follow")
public Result queryBlogOfFollow(@RequestParam("lastId") Long max, @RequestParam(value = "offset", defaultValue = "0") Integer offset){
return blogService.queryBlogOfFollow(max, offset);
}
发布与查询的服务层
//大V发布,并进行推送
@Override
public Result saveBlog(Blog blog) {
// 获取登录用户
UserDTO user = UserHolder.getUser();
blog.setUserId(user.getId());
// 保存探店博文
boolean isSuccess = this.save(blog);
if(!isSuccess){
return Result.fail("新增笔记失败");
}
//查询笔记作者的所有粉丝 follow_user_id时大V的id
List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();
//推送笔记id给所有粉丝
for (Follow follow : follows) {
//获取粉丝id
Long userId = follow.getUserId();
//推送
String key = "feed:" + userId;
stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
}
// 返回id
return Result.ok(blog.getId());
}
//粉丝收到,并实现滚动分页查询
@Override
public Result queryBlogOfFollow(Long max, Integer offset) {
//1.获取当前用户
Long userId = UserHolder.getUser().getId();
//2.查询收件箱 ZREVRANGEBYSCORE key max min limit offset count
String key = FEED_KEY + userId;
Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
.reverseRangeByScoreWithScores(key, 0, max, offset, 2);
//非空判断
if(typedTuples == null || typedTuples.isEmpty()){
return Result.ok();
}
//3.解析数据:blogId,minTime(时间戳)、offset
List<Long> ids = new ArrayList<>(typedTuples.size());
long minTime = 0;
int os = 1; //最少为一个与最小一样
for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
//获取id
ids.add(Long.valueOf(typedTuple.getValue()));
//获取分数
long time = typedTuple.getScore().longValue();
if(time == minTime){
os++;
}else {
minTime = time;
os = 1;
}
}
//4.根据id查询blog
String idStr = StrUtil.join(",", ids);
List<Blog> blogs = this.query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
for (Blog blog : blogs) {
//查询blog有关的用户
this.queryBlogUser(blog);
//查询blog是否被点赞
this.isBlogLiked(blog);
}
//5.封装并返回
ScrollResult r = new ScrollResult();
r.setList(blogs);
r.setOffset(os);
r.setMinTime(minTime);
return Result.ok(r);
}