fix:bug修改

This commit is contained in:
dzc committed 2026-07-30 20:20:55 +08:00
1 parent f2e2469b61
commit 00a0ab327c
8 files changed
+65 -2

No files matched your search

@@ -36,6 +36,10 @@ public class IMClient {
return imSender.isOnline(userId,terminal);
}
public Map<Long, Long> getLastActiveTime(List<Long> userIds) {
return imSender.getLastActiveTime(userIds);
}
/**
* 判断多个用户是否在线
@@ -259,4 +259,20 @@ public class IMSender {
public List<Long> getOnlineUser(List<Long> userIds) {
return new LinkedList<>(getOnlineTerminal(userIds).keySet());
}
public Map<Long, Long> getLastActiveTime(List<Long> userIds) {
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyMap();
}
List<Object> fields = userIds.stream().map(id -> (Object) String.valueOf(id)).toList();
List<Object> values = redisMQTemplate.opsForHash().multiGet(IMRedisKey.IM_USER_LAST_ACTIVE, fields);
Map<Long, Long> result = new HashMap<>();
for (int i = 0; i < userIds.size(); i++) {
Object value = values.get(i);
if (value instanceof Number) {
result.put(userIds.get(i), ((Number) value).longValue());
}
}
return result;
}
}
@@ -11,6 +11,10 @@ public final class IMRedisKey {
* 用户ID所连接的IM-server的ID
*/
public static final String IM_USER_SERVER_ID = "im:user:server_id";
/**
* 用户最后活跃时间,hash field 为用户ID,value 为毫秒时间戳
*/
public static final String IM_USER_LAST_ACTIVE = "im:user:last_active";
/**
* 系统消息队列
*/
@@ -26,7 +26,11 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 第三方用户
@@ -111,12 +115,29 @@ public class ThirdUserServiceImpl extends ServiceImpl<UserMapper, User> implemen
.select(User::getId)
.in(User::getId, dto.getUserIdList())
);
List<Long> userIds = userIdList.stream().map(User::getId).toList();
Set<Long> onlineUserIds = new HashSet<>(imClient.getOnlineUser(userIds));
Map<Long, Long> lastActiveTimes = getLastActiveTimeSafely(userIds);
long now = System.currentTimeMillis();
return userIdList.stream().map(item -> {
ThirdUserOnLineStatusVo entity = new ThirdUserOnLineStatusVo();
entity.setId(item.getId());
entity.setOnline(imClient.isOnline(item.getId()));
entity.setOnline(onlineUserIds.contains(item.getId()));
entity.setLastActiveTime(lastActiveTimes.get(item.getId()));
if (Boolean.TRUE.equals(entity.getOnline()) && entity.getLastActiveTime() == null) {
entity.setLastActiveTime(now);
}
return entity;
}).toList();
}
private Map<Long, Long> getLastActiveTimeSafely(List<Long> userIds) {
try {
return imClient.getLastActiveTime(userIds);
} catch (Exception e) {
log.warn("查询用户最后活跃时间失败,userIds:{}", userIds, e);
return Collections.emptyMap();
}
}
}
@@ -15,4 +15,7 @@ public class ThirdUserOnLineStatusVo {
@Schema(description = "是否在线")
private Boolean online;
@Schema(description = "最后活跃时间,毫秒时间戳")
private Long lastActiveTime;
}
@@ -74,6 +74,11 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
RedisMQTemplate redisTemplate = SpringContextHolder.getBean(RedisMQTemplate.class);
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), terminal.toString());
redisTemplate.delete(key);
try {
redisTemplate.opsForHash().put(IMRedisKey.IM_USER_LAST_ACTIVE, userId.toString(), System.currentTimeMillis());
} catch (Exception e) {
log.warn("记录用户最后活跃时间失败,userId:{}", userId, e);
}
log.info("断开连接,userId:{},终端类型:{},{}", userId, terminal, ctx.channel().id().asLongText());
}
}
@@ -96,4 +101,4 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
}
}
}
}
@@ -42,6 +42,11 @@ public class HeartbeatProcessor extends AbstractMessageProcessor<IMHeartbeatInfo
Integer terminal = ctx.channel().attr(terminalAttr).get();
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), terminal.toString());
redisMQTemplate.expire(key, IMConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS);
try {
redisMQTemplate.opsForHash().put(IMRedisKey.IM_USER_LAST_ACTIVE, userId.toString(), System.currentTimeMillis());
} catch (Exception e) {
log.warn("记录用户最后活跃时间失败,userId:{}", userId, e);
}
}
AttributeKey<Long> userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID);
Long userId = ctx.channel().attr(userIdAttr).get();
@@ -68,6 +68,11 @@ public class LoginProcessor extends AbstractMessageProcessor<IMLoginInfo> {
// 在redis上记录每个user的channelId,15秒没有心跳,则自动过期
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), terminal.toString());
redisMQTemplate.opsForValue().set(key, IMServerGroup.serverId, IMConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS);
try {
redisMQTemplate.opsForHash().put(IMRedisKey.IM_USER_LAST_ACTIVE, userId.toString(), System.currentTimeMillis());
} catch (Exception e) {
log.warn("记录用户最后活跃时间失败,userId:{}", userId, e);
}
// 响应ws
IMSendInfo<Object> sendInfo = new IMSendInfo<>();
sendInfo.setCmd(IMCmdType.LOGIN.code());