使用Redis 中的set类型实现关注功能呢
- @Autowired
- StringRedisTemplate stringRedisTemplate;
-
- private static final String FOLLOW_KEY_PREFIX = "follow:user:";
-
- /**
- * 关注和取关
- *
- * @param followUserId 关注和取关的userId
- * @param isFollow 关注 ,取关 true是关注,false是取关
- * @param userId 自己的userId
- */
- public void follow(Long followUserId, Boolean isFollow, Long userId) {
- String key = FOLLOW_KEY_PREFIX + userId;
- if (isFollow) {
- stringRedisTemplate.opsForSet().add(key, followUserId.toString());
- } else {
- stringRedisTemplate.opsForSet().remove(key, followUserId.toString());
- }
- }
- /**
- * 是否已经关注
- *
- * @param followUserId 关注和取关的userId
- * @param userId 自己的userId
- * @return true已关注,false未关注
- */
- public boolean isFollow(Long followUserId, Long userId) {
- String key = FOLLOW_KEY_PREFIX + userId;
- Boolean member = stringRedisTemplate.opsForSet().isMember(key, followUserId);
- return BooleanUtil.isTrue(member);
- }
- /**
- * 获取共同关注的好友
- * @param friendId 好友的id
- * @param userId 我的Id
- * @return 所有的共同好友
- */
- public Set
commonFollow(Long friendId, Long userId) { - String myKey = FOLLOW_KEY_PREFIX + userId;
- String friendKey = FOLLOW_KEY_PREFIX + friendId;
- Set
intersect = stringRedisTemplate.opsForSet().intersect(myKey, friendKey); - if (CollectionUtil.isEmpty(intersect)){
- return null;
- }
- List
ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList()); - //模拟数据库根绝userId 集合查询User对象
- Set
userSet = new HashSet<>(); - return userSet;
- }
当被关注的人发朋友圈时,推送给关注的人内容
方便起见使用推模式
- @Component
- public class BlogService {
-
- @Autowired
- StringRedisTemplate stringRedisTemplate;
-
- /**
- * 保存自己发送的朋友圈, 推送到粉丝的收件箱中
- *
- * @param blog
- */
- public void saveBlog(Blog blog) {
- //1.模拟保存数据库
- //saveBolg(blog);
- //2.保存完了将id发送给粉丝
- //从数据库查询关系表中followId为 userId的所有userId
- //select * from follow where follow_id = ?
- List
users = new ArrayList<>(); - for (Long userId : users) {
- String key = "feed:" + userId;
- stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
- }
- }
-
- /**
- * 查看自己收件箱的朋友圈信息,不是一次全部查出来,根绝传入的参数,获取时间戳小于max,跳过offset个后的3条数据
- * 这样查询的目的,如果按照角标查询,如果在查询的过程中,又有新的数据插入,则角标变化,导致查询到重复数据,则使用以下方式
- * 当第一次查询时max = System.currentTimeMillis(), offset =0的三条记录
- * 当第二次时,max = 第一次返回的maxTime, offset 为第一次返回的os记录.
- * 这样就可以避免查询到重复的数据
- * 在查询过程中,如果想获取最新的第一条数据,则,max = System.currentTimeMillis(), offset =0 就可以查询到最新的朋友圈
- * @param max 查询时间戳小于max的记录
- * @param offset 在时间戳小于max后跳过几条记录
- * @param userId 查询谁的收件箱
- * @return ScrollResult
- * data为朋友圈详情
- * maxTime 查询时间戳的最大值限制
- * offset 跳过的个数
- */
- public ScrollResult getFriendsBlog(Long max, Integer offset, Long userId) {
- //查询收件箱
- String key = "feed:" + userId;
- Set
> typedTuples = - stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 3);
- if (CollectionUtil.isEmpty(typedTuples)) {
- return null;
- }
- //解析数据: blogId , minTime(时间戳), offset--跟最小值相同的个数
- List
ids = new ArrayList<>(typedTuples.size()); - long minTime = 0;
- int os = 1;
- for (ZSetOperations.TypedTuple
tuple : typedTuples) { - //获取id
- ids.add(Long.valueOf(tuple.getValue()));
- //获取分数(时间戳)
- long time = tuple.getScore().longValue();
- if (minTime == time) {
- os++;
- } else {
- minTime = time;
- os = 1;
- }
- }
- //存在一个问题,ids的顺序虽然符合需求的,但是数据库查询时in(...)时,就会乱,则
- //sql 改为: select * from Blog where id (5,1) order by FIELD(id , 5,1)
- List
list = new ArrayList<>(); - ScrollResult scrollResult = new ScrollResult(list, minTime, os);
-
- return scrollResult;
- }
- }
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- class ScrollResult {
- List> data;
- long maxTime;
- int offset;
- }