java
package com.kongjs.im.message.service;
import com.alibaba.fastjson2.JSON;
import com.kongjs.im.common.dto.UserDeviceOnlineDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import java.util.*;
@Slf4j
@Service
public class ImOnlineService {
private static final String USER_ONLINE = "im:online:device:{%s}";
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 【同步非响应式】
* 批量获取多个用户的 完整在线设备信息(Hash 全量数据)
*
* @param userIds 用户ID列表
* @return Map<userId, Map<deviceId, UserDeviceOnlineDTO>>
*/
public Map<Long, Map<String, UserDeviceOnlineDTO>> batchGetUserOnlineInfo(List<Long> userIds) {
if (userIds == null || userIds.isEmpty()) {
return Collections.emptyMap();
}
// 1. 构建批量 KEY
List<String> keys = new ArrayList<>();
for (Long userId : userIds) {
keys.add(String.format(USER_ONLINE, userId));
}
// 2. Lua 脚本:批量 hgetall
DefaultRedisScript<List<List<String>>> script = new DefaultRedisScript<>();
script.setScriptText("""
local result = {}
for i = 1, #KEYS do
local data = redis.call('HGETALL', KEYS[i])
table.insert(result, data)
end
return result
""");
//script.setResultType(List.class);
// 3. 执行 Lua(同步)
List<List<String>> rawResult = stringRedisTemplate.execute(script, keys);
// 4. 解析结果
Map<Long, Map<String, UserDeviceOnlineDTO>> finalMap = new HashMap<>(rawResult.size());
for (int i = 0; i < userIds.size(); i++) {
Long userId = userIds.get(i);
List<String> hashData = rawResult.get(i);
Map<String, UserDeviceOnlineDTO> deviceMap = new HashMap<>();
for (int j = 0; j < hashData.size(); j += 2) {
String deviceId = hashData.get(j);
String json = hashData.get(j + 1);
// JSON 转你的 DTO
UserDeviceOnlineDTO dto = null;
try {
dto = JSON.parseObject(json, UserDeviceOnlineDTO.class);
} catch (Exception e) {
log.error("{}", e.getMessage());
}
if (dto != null) {
deviceMap.put(deviceId, dto);
}
}
finalMap.put(userId, deviceMap);
}
return finalMap;
}
}