目录
一、前言
微信朋友圈只有共同好友才能看见点赞和评论,可以想一下如果要通过数据库来实现获取共同好友,要么将两个用户的好友都查询出来作为临时表,然后在对两个用户好友临时表做INNER JOIN
查询获取两个用户共同好友,或者将两个用户的好友都查询出来通过代码取出共同好友,微信的用户好友关联关系非常庞大,就算做了分库分表查询压力还是比较大的,这里肯定会使用到缓存。
- 使用缓存有两个方向
- 1、将查询到的共同好友信息存储到缓存中
这种方式会存在一个问题,每用户都有很多个好友,比如 A有好友B C,如果将一个用户和其它好友的共同好友信息存储到缓存,那么这里就要存储一个A与B共同好友和A与C共同好友的缓存,那如果A有100个1000个好友那需要的内存是非常庞大的,而且更新也很麻烦,这种方案不太可取。
- 2、将各自好友信息存储到缓存中,然后在取交集(使用)
将用户各自的好友信息存储在缓存中,使用Redis Set 集合存储,如果要查询A用户和B用户的共同好友只需要对两个用户的好友信息缓存做取交集存在即可获取到共同好友。
- 1、将查询到的共同好友信息存储到缓存中
需要Redis常用命令集文章可以查看:https://blog.csdn.net/weixin_44606481/article/details/133672258
二、使用Redis Set 集合实现取共同好友操作
这里会将各自好友信息存储到缓存中,然后在取交集得出共同好友,假设现在有5个用户U001、U002、U003、U004、U005
,缓存key前缀为FRIEND:
,用户 U001
与 U002、U003、U004
是好友,用户 U002
与 U001、U003、U005
是好友。
2.1、添加用户U001、U002 好友集合缓存
127.0.0.1:6379> sadd FRIEND:U001 U002 U003 U004
(integer) 3
127.0.0.1:6379> sadd FRIEND:U002 U001 U003 U005
(integer) 3
2.2、取出U001、U002 共同好友
127.0.0.1:6379> sinter FRIEND:U001 FRIEND:U002
1) "U003"
三、SpringBoot 集成 Redis 实现模拟微信朋友圈只有共同好友才能看见点赞和评论功能
需要SpringBoot集成Redis文章可以查看:https://blog.csdn.net/weixin_44606481/article/details/133907103
还会额外使用两个工具包:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<optional>true</optional>
</dependency>
3.1、创建朋友圈实体对象
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WeChatFriendCircle implements Serializable {
/**
* 朋友圈数据ID
*/
private Integer id;
/**
* 用户编号
*/
private String uid;
/**
* 朋友圈内容
*/
private String content;
/**
* 创建时间
*/
private Long createTime;
}
3.2、朋友圈核心逻辑实现
import com.redisscene.entity.WeChatFriendCircle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class WeChatFriendCircleService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 朋友圈 朋友信息缓存key
private String friendCahceKey = "FRIEND_CIRCLE:FRIEND:";
// 朋友圈 点赞信息缓存key
private String likeCahceKey = "FRIEND_CIRCLE:LIKE:";
// 朋友圈 评论信息缓存key
private String commentCahceKey = "FRIEND_CIRCLE:COMMENT:";
// 朋友圈数据 这里不引入数据库,直接在内存中模拟
private static List<WeChatFriendCircle> friendCircleList = new ArrayList();
/**
* 初始化朋友圈和好友关联信息
*/
public void initData() {
// 1、初始化朋友圈信息
long timeMillis = 1701187220000L;
WeChatFriendCircle weChatFriendCircle1 = WeChatFriendCircle.builder().id(1).uid("U001").content("PHP是世界上最好的语言!").createTime(timeMillis + 1).build();
WeChatFriendCircle weChatFriendCircle2 = WeChatFriendCircle.builder().id(2).uid("U002").content("Python是世界上最好的语言!").createTime(timeMillis + 2).build();
WeChatFriendCircle weChatFriendCircle3 = WeChatFriendCircle.builder().id(3).uid("U004").content("C++是世界上最好的语言!").createTime(timeMillis + 3).build();
friendCircleList.add(weChatFriendCircle1);
friendCircleList.add(weChatFriendCircle2);
friendCircleList.add(weChatFriendCircle3);
// 2、初始化点赞
// 设置U003、U004都给朋友圈id为1的数据点赞
redisTemplate.delete(likeCahceKey + weChatFriendCircle1.getId());
redisTemplate.opsForSet().add(likeCahceKey + weChatFriendCircle1.getId(), "U003", "U004");
// 3、初始化评论信息 评论信息使用hash结构存储,缓存key使用前缀加上朋友圈ID
// 设置U003、U005都给朋友圈id为2的数据评论 这里为了方便多条评论用-_-分割
redisTemplate.delete(commentCahceKey + weChatFriendCircle2.getId());
redisTemplate.opsForHash().put(commentCahceKey + weChatFriendCircle2.getId(), "U003", "uid=U003 content=啊 对对对 time=1701187220009-_-uid=U003 content=你说的都对 time=1701187220005");
redisTemplate.opsForHash().put(commentCahceKey + weChatFriendCircle2.getId(), "U005", "uid=U005 content=英雄所见略同 time=1701187220001");
// 4、初始化用户好友关联信息
// 给U001添加好友U002 U003 U004 这里需要把自己也加进来
redisTemplate.delete(friendCahceKey + "U001");
redisTemplate.opsForSet().add(friendCahceKey + "U001", "U001","U002", "U003", "U004");
// 给U002添加好友U001 U003 U005 这里需要把自己也加进来
redisTemplate.delete(friendCahceKey + "U002");
redisTemplate.opsForSet().add(friendCahceKey + "U002", "U001","U002", "U003", "U005");
}
/**
* 查看朋友圈列表
* @param uid 用户ID
*/
public List queryFriendCircleList(String uid) {
// 1、查询用户好友列表
Set<String> friends = redisTemplate.opsForSet().members(friendCahceKey + uid);
friends.add(uid); // 将自己也加入到好友列表中 因为也需要查询自己发送的朋友圈数据
// 2、查询用户能看到的朋友圈列表
List<Map> resultList = new ArrayList<>();
for (WeChatFriendCircle weChatFriendCircle : friendCircleList) {
if(friends.contains(weChatFriendCircle.getUid())) {
// 3、获取用户和当前朋友圈用户的共同好友信息
Set<String> commonFriends = redisTemplate.opsForSet().intersect(friendCahceKey + uid, friendCahceKey + weChatFriendCircle.getUid());
// 4、查询当前朋友圈共同好友点赞列表 取共同好友列表与点赞列表的交集
Set<String> likes = redisTemplate.opsForSet().intersect(likeCahceKey + weChatFriendCircle.getId(),friendCahceKey + uid);
// 5、查询当前朋友圈共同好友评论信息列表
HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
List<String> comments = hashOperations.multiGet(commentCahceKey + weChatFriendCircle.getId(), commonFriends);
// 组装数据
Map dataMap = new HashMap();
dataMap.put("id", weChatFriendCircle.getId());
dataMap.put("uid", weChatFriendCircle.getUid());
dataMap.put("content", weChatFriendCircle.getContent());
dataMap.put("createTime", weChatFriendCircle.getCreateTime());
dataMap.put("likes", likes);
dataMap.put("comments", comments.stream().filter(item->item!=null).collect(Collectors.toList()));
resultList.add(dataMap);
}
}
return resultList;
}
}
3.3、朋友圈查询测试
import com.alibaba.fastjson.JSON;
import com.redisscene.service.WeChatFriendCircleService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class WeChatFriendCircleTest {
@Autowired
private WeChatFriendCircleService weChatFriendCircleService;
@Test
public void t1(){
// 初始化数据
weChatFriendCircleService.initData();
// 查询用户U001的朋友圈
List list = weChatFriendCircleService.queryFriendCircleList("U001");
System.out.println(JSON.toJSONString(list));
// 查询用户U002的朋友圈
List list2 = weChatFriendCircleService.queryFriendCircleList("U002");
System.out.println(JSON.toJSONString(list2));
}
}
运行得到U001
的数据为:
[
{
"uid":"U001",
"comments":[
],
"createTime":1701187220001,
"id":1,
"content":"PHP是世界上最好的语言!",
"likes":[
"U003",
"U004"
]
},
{
"uid":"U002",
"comments":[
"uid=U003 content=啊 对对对 time=1701187220009-_-uid=U003 content=你说的都对 time=1701187220005"
],
"createTime":1701187220002,
"id":2,
"content":"Python是世界上最好的语言!",
"likes":[
]
},
{
"uid":"U004",
"comments":[
],
"createTime":1701187220003,
"id":3,
"content":"C++是世界上最好的语言!",
"likes":[
]
}
]
运行得到U002
的数据为:
[
{
"uid":"U001",
"comments":[
],
"createTime":1701187220001,
"id":1,
"content":"PHP是世界上最好的语言!",
"likes":[
"U003"
]
},
{
"uid":"U002",
"comments":[
"uid=U003 content=啊 对对对 time=1701187220009-_-uid=U003 content=你说的都对 time=1701187220005",
"uid=U005 content=英雄所见略同 time=1701187220001"
],
"createTime":1701187220002,
"id":2,
"content":"Python是世界上最好的语言!",
"likes":[
]
}
]