当前位置:网站首页>11. Redis implements follow, unfollow, and follow and follower lists
11. Redis implements follow, unfollow, and follow and follower lists
2022-07-31 02:40:00 【A snicker】
实现关注、取消关注

- value的数据类型时zset,有序集合,Sort by time of interest
followee:userId:entityType -> zset(entityId,now) 某个用户关注的实体(Entities include posts、评论、用户),Stored separately by entity
follower:entityType:entityId -> zset(userId,now) 某个实体拥有的粉丝(Entities include posts、评论、用户)
- This function is requested asynchronously
1、RedisKeyUtil
private static final String PREFIX_FOLLOWEE = "followee";
private static final String PREFIX_FOLLOWER = "follower";
// 某个用户关注的实体(Entities include posts、用户)
// followee:userId:entityType -> zset(entityId,now)
public static String getFolloweeKey(int userId, int entityType) {
return PREFIX_FOLLOWEE + SPLIT + userId + SPLIT + entityType;
}
// 某个实体拥有的粉丝(Entities include posts、用户)
// follower:entityType:entityId -> zset(userId,now)
public static String getFollowerKey(int entityType, int entityId) {
return PREFIX_FOLLOWER + SPLIT + entityType + SPLIT + entityId;
}
2、FollowService
@Service
public class FollowService {
@Autowired
private RedisTemplate redisTemplate;
public void follow(int userId, int entityType, int entityId) {
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
// 某个用户关注的实体
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
// 某个实体拥有的粉丝
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
operations.multi();
operations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
operations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
return operations.exec();
}
});
}
public void unfollow(int userId, int entityType, int entityId) {
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
operations.multi();
operations.opsForZSet().remove(followeeKey, entityId);
operations.opsForZSet().remove(followerKey, userId);
return operations.exec();
}
});
}
// 查询关注的实体的数量
public long findFolloweeCount(int userId, int entityType) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
return redisTemplate.opsForZSet().zCard(followeeKey);
}
// 查询实体的粉丝的数量
public long findFollowerCount(int entityType, int entityId){
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
return redisTemplate.opsForZSet().zCard(followerKey);
}
// 查询当前用户是否已关注该实体(the user to such entitiesid有一个清单zset)
public boolean hasFollowed(int userId, int entityType, int entityId) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
}
}
3、profile.js
$(function(){
$(".follow-btn").click(follow);
});
function follow() {
var btn = this;
if($(btn).hasClass("btn-info")) {
// 关注TA
$.post(
CONTEXT_PATH + "/follow",
{
"entityType":3,"entityId":$(btn).prev().val()},
function(data) {
data = $.parseJSON(data);
if(data.code == 0) {
window.location.reload();
} else {
alert(data.msg);
}
}
);
// $(btn).text("已关注").removeClass("btn-info").addClass("btn-secondary");
} else {
// 取消关注
$.post(
CONTEXT_PATH + "/unfollow",
{
"entityType":3,"entityId":$(btn).prev().val()},
function(data) {
data = $.parseJSON(data);
if(data.code == 0) {
window.location.reload();
} else {
alert(data.msg);
}
}
);
//$(btn).text("关注TA").removeClass("btn-secondary").addClass("btn-info");
}
}
关注列表和粉丝列表

1、FollowService
// 查询某用户关注的人
public List<Map<String, Object>> findFollowees(int userId, int offset, int limit) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
if (targetIds == null) {
return null;
}
List<Map<String, Object>> list = new ArrayList<>();
for (Integer targetId : targetIds) {
Map<String, Object> map = new HashMap<>();
User user = userService.findUserById(targetId);
map.put("user", user);
Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
map.put("followTime", new Date(score.longValue()));
list.add(map);
}
return list;
}
// 查询某用户的粉丝
public List<Map<String, Object>> findFollowers(int userId, int offset, int limit) {
String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit + 1);
if (targetIds == null) {
return null;
}
List<Map<String, Object>> list = new ArrayList<>();
for (Integer targetId : targetIds) {
Map<String, Object> map = new HashMap<>();
User user = userService.findUserById(targetId);
map.put("user", user);
Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
map.put("followTime", new Date(score.longValue()));
list.add(map);
}
return list;
}
2、FollowController
@RequestMapping(path = "/followees/{userId}", method = RequestMethod.GET)
public String getFollowees(@PathVariable("userId") int userId, Page page, Model model) {
User user = userService.findUserById(userId);
if (user == null) {
throw new RuntimeException("该用户不存在!");
}
model.addAttribute("user", user);
page.setLimit(5);
page.setPath("/followees/" + userId);
page.setRows((int) followService.findFolloweeCount(userId, ENTITY_TYPE_USER));
List<Map<String, Object>> userList = followService.findFollowees(userId, page.getOffset(), page.getLimit());
if (userList != null) {
for (Map<String, Object> map : userList) {
User u = (User) map.get("user");
map.put("hasFollowed", hasFollowed(u.getId()));
}
}
model.addAttribute("users", userList);// 里面存了user、followTime、hasFollowed
return "/site/followee";
}
@RequestMapping(path = "/followers/{userId}", method = RequestMethod.GET)
public String getFollowers(@PathVariable("userId") int userId, Page page, Model model) {
User user = userService.findUserById(userId);
if (user == null) {
throw new RuntimeException("该用户不存在!");
}
model.addAttribute("user", user);
page.setLimit(5);
page.setPath("/followers/" + userId);
page.setRows((int) followService.findFollowerCount(ENTITY_TYPE_USER, userId));
List<Map<String, Object>> userList = followService.findFollowers(userId, page.getOffset(), page.getLimit());
if (userList != null) {
for (Map<String, Object> map : userList) {
User u = (User) map.get("user");
map.put("hasFollowed", hasFollowed(u.getId()));
}
}
model.addAttribute("users", userList);
return "/site/follower";
}
private boolean hasFollowed(int userId) {
if (hostHolder.getUser() == null) {
return false;
}
return followService.hasFollowed(hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
}
边栏推荐
- General introduction to the Unity interface
- AI在医疗影像设备全流程应用
- f.grid_sample
- 【shell基础】判断目录是否为空
- Drools basic introduction, introductory case, basic syntax
- Unity3D Button mouse hover enter and mouse hover exit button events
- Project development software directory structure specification
- Go 项目实战-获取多级分类下的全部商品
- 1. Non-type template parameters 2. Specialization of templates 3. Explanation of inheritance
- First acquaintance with C language -- array
猜你喜欢

Introduction to flask series 】 【 flask - using SQLAlchemy

SQL注入 Less54(限制次数的SQL注入+union注入)

完整复制虚拟机原理(云计算)

Discourse 自定义头部链接(Custom Header Links)

Installation, start and stop of redis7 under Linux

StringJoiner详解

Tower of Hanoi problem

【Android】Room —— SQLite的替代品

There is a problem with the multiplayer-hlap package and the solution cannot be upgraded

跨专业考研难度大?“上岸”成功率低?这份实用攻略请收下!
随机推荐
7. List of private messages
General introduction to the Unity interface
AI在医疗影像设备全流程应用
print task sorting js od huawei
YOLOV5学习笔记(三)——网络模块详解
JS 函数 this上下文 运行时点语法 圆括号 数组 IIFE 定时器 延时器 self.备份上下文 call apply
1. Non-type template parameters 2. Specialization of templates 3. Explanation of inheritance
Project development software directory structure specification
AtCoder Beginner Contest 261 部分题解
Draw Your Cards
15. Website Statistics
4、敏感词过滤(前缀树)
Intranet Infiltration - Privilege Escalation
共模电感的仿真应用来了,满满的干货送给大家
SQL注入 Less54(限制次数的SQL注入+union注入)
mmdetection trains a model related command
CentOS7下mysql5.7.37的卸载【完美方案】
[1154] How to convert string to datetime
[1153] The boundary range of between in mysql
Go 项目实战-获取多级分类下的全部商品