当前位置:网站首页>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);
}
边栏推荐
- AI software development process in medical imaging field
- Draw Your Cards
- AI中的数学思想
- Force buckled brush the stairs (7/30)
- [1153] The boundary range of between in mysql
- Discourse 自定义头部链接(Custom Header Links)
- Fiddler captures packets to simulate weak network environment testing
- 经典链表OJ强训题——快慢双指针高效解法
- 【银行系列第一期】中国人民银行
- SQL注入 Less46(order by后的注入+rand()布尔盲注)
猜你喜欢
工程(五)——小目标检测tph-yolov5
STM32CUBEMX开发GD32F303(11)----ADC在DMA模式下扫描多个通道
FPGA-based vending machine
【Android】Room —— SQLite的替代品
字体压缩神器font-spider的使用
Intranet Infiltration - Privilege Escalation
CentOS7下mysql5.7.37的安装【完美方案】
Introduction to flask series 】 【 flask - using SQLAlchemy
完整复制虚拟机原理(云计算)
软件积累 -- 截图软件ScreenToGif
随机推荐
php 网站的多语言设置(IP地址区分国内国外)
Static route analysis (the longest mask matching principle + active and standby routes)
Uninstallation of mysql5.7.37 under CentOS7 [perfect solution]
mmdetection训练一个模型相关命令
Clustering index, and what is the difference between a clustering index
ShardingJDBC usage summary
YOLOV5学习笔记(二)——环境安装+运行+训练
Pythagorean tuple od js
Brute Force/Adjacency Matrix Breadth First Directed Weighted Graph Undirected Weighted Graph
软件积累 -- 截图软件ScreenToGif
8. Unified exception handling (controller notifies @ControllerAdvice global configuration class, @ExceptionHandler handles exceptions uniformly)
mycat的主从关系 垂直分库 水平分表 以及mycat分片联表查询的配置详解(mysql5.7系列)
How to build a private yum source
cudaMemcpy study notes
Difference between CMOS and TTL?
f.grid_sample
Shell script to loop through values in log file to sum and calculate average, max and min
Unity3D Button mouse hover enter and mouse hover exit button events
Refuse to work overtime, a productivity tool set developed by programmers
汉源高科8路HDMI综合多业务高清视频光端机8路HDMI视频+8路双向音频+8路485数据+8路E1+32路电话+4路千兆物理隔离网络