Springboot+redis 做实时在线人数统计
利用redis 有序集合进行系统实时在线人数统计
·
介绍
利用redis 有序集合实现。
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。 有序集合的成员是唯一的,但分数(score)却可以重复。
zset命令
- 新增成员
zadd:新增成员 - 删除成员
zrem:根据指定key进行删除
zremrangebylex:根据指定集合区间进行删除
zremrangebyrank:根据指定排名区间进行删除
zremrangebyscore:根据分数区间进行删除 - 查询成员
zcard:查询集合成员数量
zcount:分数区间成员数量
zlexcount:成员区间成员数量
zscore:指定key和值,获取分数
zrange:获取成员信息
zrank:指定key和值,获取下标
zrangebylex:指定集合区间,获取列表
zrangebyscore:指定分数区间,获取列表
zrevrange:倒序展示列表
zrevrangebyscore:根据分数区间,倒序展示列表
zreverank:倒序获取成员下标
最终呈现效果
这里使用的工具是AnotherRedisDesktopManager
实现
因为zset中每个元素都有关联的分数,并且可以通过分数区间查询删除数据,所以我们可以将分数设置为时间戳。
1、后端编写一个用户心跳接口(注意这个接口需要放开权限)
/**
* 用户心跳保持接口
* @param :
* @return boolean
* @author LuckyDog 19:08 2021/12/10
**/
@GetMapping("heartbeat")
@ResponseBody
public boolean heartbeat(HttpServletRequest request) {
User sessionUser = CommonUtil.getSessionUser(request);
if(sessionUser!=null&&sessionUser.getId()!=null&&sessionUser.getId()!=0){
fyStatisticsUtil.userOnline(sessionUser.getId());
return true;
}
return false;
}
fyStatisticsUtil 一个工具类
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
/**
* @author LuckyDog
*/
@Component
public class FyStatisticsUtil {
private static final String ONLINE_USER = "online_user";
@Resource
private FyRedisUtil fyRedisUtil;
//region 在线用户统计相关
public void userOnline(Long userId) {
fyRedisUtil.zsetSet(ONLINE_USER, userId, System.currentTimeMillis());
}
public Long userOnlineCount() {
return fyRedisUtil.zsetCount(ONLINE_USER);
}
public Long userOfflineClean() {
DateTime dateTime = DateTime.now();
DateTime offset = dateTime.offset(DateField.MINUTE, -2);
return fyRedisUtil.zsetRemove(ONLINE_USER, 0L, offset.getTime());
}
//endregion
}
fyRedisUtil 部分代码
public Boolean zsetSet(String key, Object value, long score){
try {
return redisTemplate.opsForZSet().add(key, value, score);
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
public Long zsetCount(String key){
try {
return redisTemplate.opsForZSet().size(key);
}
catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
public Long zsetRemove(String key,Long minScore,Long maxScore){
try {
return redisTemplate.opsForZSet().removeRangeByScore(key,minScore,maxScore);
}
catch (Exception e) {
e.printStackTrace();
return 0L;
}
}
定时器,定时清理已过期用户数量
/**
* @author LuckyDog
*/
@Component
@ConditionalOnProperty(prefix = "website", name = "run", havingValue = "analysisTimer")
public class StatisticsTimer {
@Resource
FyStatisticsUtil fyStatisticsUtil;
@Scheduled(cron = "0 0/2 * * * ?")
public void clearOfflineUser() {
Long aLong = fyStatisticsUtil.userOfflineClean();
System.out.println("清除已过期用户数量:" + aLong);
}
}
最后找一个前端页面最外层框架页里,写上一个定时请求心跳接口的js就行了,我这里设置的是一分钟心跳一次
let timer;
$(function(){
beat();
timer = setInterval("beat()",60000);
})
function beat(){
$.get("/heartbeat",null,function(res){
if(!res){
clearInterval(timer);
}
});
}
大功告成。这种方案实现的实时在线人数相对来说是比较准确的。只要用户访问网站,每分钟就会心跳一次。每次心跳都会更新redis里面的时间戳。如果用户心跳中断,就意味着用户已经离线。后端也有一个定时器,设置的每两分钟清理一次离线用户。
更多推荐
已为社区贡献2条内容
所有评论(0)