|
|
|
@ -14,6 +14,7 @@ import com.bx.imcommon.enums.IMTerminalType; |
|
|
|
import com.bx.imcommon.model.IMGroupMessage; |
|
|
|
import com.bx.imcommon.model.IMUserInfo; |
|
|
|
import com.bx.imcommon.util.CommaTextUtils; |
|
|
|
import com.bx.imcommon.util.ThreadPoolExecutorFactory; |
|
|
|
import com.bx.implatform.contant.Constant; |
|
|
|
import com.bx.implatform.contant.RedisKey; |
|
|
|
import com.bx.implatform.dto.GroupMessageDTO; |
|
|
|
@ -40,19 +41,21 @@ import org.springframework.stereotype.Service; |
|
|
|
import org.springframework.transaction.annotation.Transactional; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.util.concurrent.ScheduledThreadPoolExecutor; |
|
|
|
import java.util.concurrent.atomic.AtomicInteger; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
@Slf4j |
|
|
|
@Service |
|
|
|
@RequiredArgsConstructor |
|
|
|
public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, GroupMessage> implements |
|
|
|
GroupMessageService { |
|
|
|
public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, GroupMessage> |
|
|
|
implements GroupMessageService { |
|
|
|
private final GroupService groupService; |
|
|
|
private final GroupMemberService groupMemberService; |
|
|
|
private final RedisTemplate<String, Object> redisTemplate; |
|
|
|
private final IMClient imClient; |
|
|
|
private final SensitiveFilterUtil sensitiveFilterUtil; |
|
|
|
private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor(); |
|
|
|
|
|
|
|
@Override |
|
|
|
public GroupMessageVO sendMessage(GroupMessageDTO dto) { |
|
|
|
@ -67,7 +70,8 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
List<Long> userIds = groupMemberService.findUserIdsByGroupId(group.getId()); |
|
|
|
if (dto.getReceipt() && userIds.size() > Constant.MAX_LARGE_GROUP_MEMBER) { |
|
|
|
// 大群的回执消息过于消耗资源,不允许发送
|
|
|
|
throw new GlobalException(String.format("当前群聊大于%s人,不支持发送回执消息", Constant.MAX_LARGE_GROUP_MEMBER)); |
|
|
|
throw new GlobalException( |
|
|
|
String.format("当前群聊大于%s人,不支持发送回执消息", Constant.MAX_LARGE_GROUP_MEMBER)); |
|
|
|
} |
|
|
|
// 不用发给自己
|
|
|
|
userIds = userIds.stream().filter(id -> !session.getUserId().equals(id)).collect(Collectors.toList()); |
|
|
|
@ -82,7 +86,6 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
msg.setContent(sensitiveFilterUtil.filter(dto.getContent())); |
|
|
|
} |
|
|
|
this.save(msg); |
|
|
|
|
|
|
|
// 群发
|
|
|
|
GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); |
|
|
|
msgInfo.setAtUserIds(dto.getAtUserIds()); |
|
|
|
@ -140,7 +143,6 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
return msgInfo; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
public void pullOfflineMessage(Long minId) { |
|
|
|
UserSession session = SessionContext.getSession(); |
|
|
|
@ -153,44 +155,48 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
Set<Long> groupIds = groupMemberMap.keySet(); |
|
|
|
if (CollectionUtil.isEmpty(groupIds)) { |
|
|
|
// 关闭加载中标志
|
|
|
|
this.sendLoadingMessage(false); |
|
|
|
this.sendLoadingMessage(false, session); |
|
|
|
return; |
|
|
|
} |
|
|
|
// 开启加载中标志
|
|
|
|
this.sendLoadingMessage(true); |
|
|
|
// 只能拉取最近3个月的,最多拉取3000条
|
|
|
|
|
|
|
|
// 只能拉取最近3个月的,移动端只拉最近一个月
|
|
|
|
int months = session.getTerminal().equals(IMTerminalType.APP.code()) ? 1 : 3; |
|
|
|
Date minDate = DateUtils.addMonths(new Date(), -months); |
|
|
|
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); |
|
|
|
wrapper.gt(GroupMessage::getId, minId) |
|
|
|
.gt(GroupMessage::getSendTime, minDate) |
|
|
|
.in(GroupMessage::getGroupId, groupIds) |
|
|
|
.orderByAsc(GroupMessage::getId); |
|
|
|
wrapper.gt(GroupMessage::getId, minId).gt(GroupMessage::getSendTime, minDate) |
|
|
|
.in(GroupMessage::getGroupId, groupIds).orderByAsc(GroupMessage::getId); |
|
|
|
List<GroupMessage> messages = this.list(wrapper); |
|
|
|
// 通过群聊对消息进行分组
|
|
|
|
Map<Long, List<GroupMessage>> messageGroupMap = messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId)); |
|
|
|
Map<Long, List<GroupMessage>> messageGroupMap = |
|
|
|
messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId)); |
|
|
|
// 退群前的消息
|
|
|
|
List<GroupMember> quitMembers = groupMemberService.findQuitInMonth(session.getUserId()); |
|
|
|
for (GroupMember quitMember : quitMembers) { |
|
|
|
wrapper = Wrappers.lambdaQuery(); |
|
|
|
wrapper.gt(GroupMessage::getId, minId) |
|
|
|
.between(GroupMessage::getSendTime, minDate,quitMember.getQuitTime()) |
|
|
|
wrapper.gt(GroupMessage::getId, minId).between(GroupMessage::getSendTime, minDate, quitMember.getQuitTime()) |
|
|
|
.eq(GroupMessage::getGroupId, quitMember.getGroupId()) |
|
|
|
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()) |
|
|
|
.orderByAsc(GroupMessage::getId); |
|
|
|
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByAsc(GroupMessage::getId); |
|
|
|
List<GroupMessage> groupMessages = this.list(wrapper); |
|
|
|
messageGroupMap.put(quitMember.getGroupId(), groupMessages); |
|
|
|
groupMemberMap.put(quitMember.getGroupId(), quitMember); |
|
|
|
} |
|
|
|
EXECUTOR.execute(() -> { |
|
|
|
// 开启加载中标志
|
|
|
|
this.sendLoadingMessage(true, session); |
|
|
|
// 推送消息
|
|
|
|
AtomicInteger sendCount = new AtomicInteger(); |
|
|
|
messageGroupMap.forEach((groupId, groupMessages) -> { |
|
|
|
// 第一次拉取时,一个群最多推送1w条消息,防止前端接收能力溢出导致卡顿
|
|
|
|
List<GroupMessage> sendMessages = groupMessages; |
|
|
|
if (minId <= 0 && groupMessages.size() > 10000) { |
|
|
|
sendMessages = groupMessages.subList(groupMessages.size() - 10000, groupMessages.size()); |
|
|
|
} |
|
|
|
// 填充消息状态
|
|
|
|
String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId); |
|
|
|
Object o = redisTemplate.opsForHash().get(key, session.getUserId().toString()); |
|
|
|
long readedMaxId = Objects.isNull(o) ? -1 : Long.parseLong(o.toString()); |
|
|
|
Map<Object, Object> maxIdMap = null; |
|
|
|
for(GroupMessage m:groupMessages){ |
|
|
|
for (GroupMessage m : sendMessages) { |
|
|
|
// 排除加群之前的消息
|
|
|
|
GroupMember member = groupMemberMap.get(m.getGroupId()); |
|
|
|
if (DateUtil.compare(member.getCreatedTime(), m.getSendTime()) > 0) { |
|
|
|
@ -229,8 +235,9 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
} |
|
|
|
}); |
|
|
|
// 关闭加载中标志
|
|
|
|
this.sendLoadingMessage(false); |
|
|
|
this.sendLoadingMessage(false, session); |
|
|
|
log.info("拉取离线群聊消息,用户id:{},数量:{}", session.getUserId(), sendCount.get()); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -238,9 +245,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
UserSession session = SessionContext.getSession(); |
|
|
|
// 取出最后的消息id
|
|
|
|
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); |
|
|
|
wrapper.eq(GroupMessage::getGroupId, groupId) |
|
|
|
.orderByDesc(GroupMessage::getId) |
|
|
|
.last("limit 1") |
|
|
|
wrapper.eq(GroupMessage::getGroupId, groupId).orderByDesc(GroupMessage::getId).last("limit 1") |
|
|
|
.select(GroupMessage::getId); |
|
|
|
GroupMessage message = this.getOne(wrapper); |
|
|
|
if (Objects.isNull(message)) { |
|
|
|
@ -276,7 +281,8 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
List<Long> userIds = groupMemberService.findUserIdsByGroupId(groupId); |
|
|
|
Map<Object, Object> maxIdMap = redisTemplate.opsForHash().entries(key); |
|
|
|
for (GroupMessage receiptMessage : receiptMessages) { |
|
|
|
Integer readedCount = getReadedUserIds(maxIdMap, receiptMessage.getId(),receiptMessage.getSendId()).size(); |
|
|
|
Integer readedCount = |
|
|
|
getReadedUserIds(maxIdMap, receiptMessage.getId(), receiptMessage.getSendId()).size(); |
|
|
|
// 如果所有人都已读,记录回执消息完成标记
|
|
|
|
if (readedCount >= userIds.size() - 1) { |
|
|
|
receiptMessage.setReceiptOk(true); |
|
|
|
@ -333,7 +339,8 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
// 查询聊天记录,只查询加入群聊时间之后的消息
|
|
|
|
QueryWrapper<GroupMessage> wrapper = new QueryWrapper<>(); |
|
|
|
wrapper.lambda().eq(GroupMessage::getGroupId, groupId).gt(GroupMessage::getSendTime, member.getCreatedTime()) |
|
|
|
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(GroupMessage::getId).last("limit " + stIdx + "," + size); |
|
|
|
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(GroupMessage::getId) |
|
|
|
.last("limit " + stIdx + "," + size); |
|
|
|
List<GroupMessage> messages = this.list(wrapper); |
|
|
|
List<GroupMessageVO> messageInfos = |
|
|
|
messages.stream().map(m -> BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList()); |
|
|
|
@ -354,8 +361,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro |
|
|
|
return userIds; |
|
|
|
} |
|
|
|
|
|
|
|
private void sendLoadingMessage(Boolean isLoadding){ |
|
|
|
UserSession session = SessionContext.getSession(); |
|
|
|
private void sendLoadingMessage(Boolean isLoadding, UserSession session) { |
|
|
|
GroupMessageVO msgInfo = new GroupMessageVO(); |
|
|
|
msgInfo.setType(MessageType.LOADING.code()); |
|
|
|
msgInfo.setContent(isLoadding.toString()); |
|
|
|
|