需求: 统计页面的当前在线用户统计。
由于不是socket连接,所以不是真实的实时在线用户,是对用户登录或者普通操作的时间进行标记时间戳,时间戳之后多少分钟内,都是算作在线的,限定时间之后就算作离线。
在我当前项目中我有一个统一的token验证方法,我就把标记时间戳的方法加在该方法中。
代码语言:javascript复制 /**
* 在线用户统计
* @param uid uid
*/
//用户在线时间戳
private void onlineUser(int uid) {
redisTemplate.opsForZSet().add("onlineUserCount", uid "", ServerTimer.getDayHourMinute());
}
/**
* 公共登陆验证
*
* @param name 用户名
* @param token token
* @return result
*/
private String CommonLogin(String name, String token) {
User user1 = userRedisDao.getOneByName(name);
if (user1 == null) {
return "用户" name "不存在";
}
User user = userRedisDao.getOneByToken(token);
if (user == null) {
return "登陆过期,请重新登陆";
}
if (user.getUid() != user1.getUid()) {
return "已在其他设备登陆,请退出应用重新登陆";
}
this.onlineUser(user.getUid());
return "success";
}
这里的ServerTimer.getHourMinute()是将当前时间存为HHmm的一个int,作为时间戳存入“onlineUserCount”这个key的一个member的分数中,用于之后自动判断过期清除。
代码语言:javascript复制 //ServerTimer.getHourMinute()
public static int getDayHourMinute() {
String timeHm = ServerTimer.getTimeHm();
return Integer.parseInt(timeHm);
}
public static String getTimedHm() {
Calendar now = Calendar.getInstance();
SimpleDateFormat s = new SimpleDateFormat("ddHHmm");
return s.format(now.getTime());
}
存入时间戳的步骤就到这里,之后我们还需要一个定时任务用于自动清除过期的member:
代码语言:javascript复制 //5分钟未操作清除用户在线统计
@Scheduled(fixedDelay = 60000)
public void clearOnlineUser() {
Calendar now = Calendar.getInstance();
now.add(Calendar.MINUTE,-5);
SimpleDateFormat s = new SimpleDateFormat("ddHHmm");
int score = Integer.parseInt(s.format(now.getTime()));
Long count = redisTemplate.opsForZSet().removeRangeByScore("onlineUserCount", -1, score);
log.info("当前在线用户:{}",count);
}
查询方法:
代码语言:javascript复制 /**
* 获取当前在线用户数
*
* @return 当前在线用户数
*/
public Object getOnlineUser() {
return redisTemplate.opsForZSet().count("onlineUserCount", -1, 999999);
}
以上就是基于redis Zset在线用户的解决方案,相较于心跳,减少了与前端的交互,纯后端实现, 且内存占用性能占用均在可接受的范围内。
Post Views: 233