1.新增公告消息、转发处理器

2.新增合并消息发送
3.调整解散群聊逻辑
This commit is contained in:
乾乾
2025-04-27 12:06:25 +08:00
parent fc19af1ac4
commit 5fe6d5f731
17 changed files with 348 additions and 20 deletions

View File

@@ -23,9 +23,11 @@ import com.hula.core.chat.domain.vo.request.room.AnnouncementsParam;
import com.hula.core.chat.domain.vo.request.room.ReadAnnouncementsParam;
import com.hula.core.chat.domain.vo.request.room.RoomGroupReq;
import com.hula.core.chat.domain.vo.response.ChatMemberListResp;
import com.hula.core.chat.domain.vo.response.ChatMessageResp;
import com.hula.core.chat.domain.vo.response.MemberResp;
import com.hula.core.chat.service.IGroupMemberService;
import com.hula.core.chat.service.RoomAppService;
import com.hula.core.user.domain.vo.req.MergeMessageReq;
import com.hula.core.user.domain.vo.resp.ws.ChatMemberResp;
import com.hula.domain.vo.res.ApiResult;
import com.hula.utils.RequestHolder;
@@ -196,4 +198,9 @@ public class RoomController {
return ApiResult.success(roomService.readAnnouncement(RequestHolder.get().getUid(), param));
}
@Operation(summary = "合并消息")
@PostMapping("mergeMessage")
public ApiResult<ChatMessageResp> mergeMessage(@RequestBody MergeMessageReq req){
return ApiResult.success(roomService.mergeMessage(RequestHolder.get().getUid(), req));
}
}

View File

@@ -0,0 +1,34 @@
package com.hula.core.chat.domain.entity.msg;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
/**
* 合并消息实体
* @author 乾乾
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class MergeMsg implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description ="内容")
private String content;
@Schema(description = "发送时间")
private Date createdTime;
@Schema(description ="发送人名称")
private String name;
}

View File

@@ -0,0 +1,33 @@
package com.hula.core.chat.domain.entity.msg;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 合并消息入参
* @author 乾乾
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class MergeMsgDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description ="合并的内容")
private List<MergeMsg> messages;
@Schema(description ="回复的消息id")
private Long replyMsgId;
@Schema(description ="父消息如果没有父消息返回的是null")
private ReplyMsg reply;
}

View File

@@ -39,8 +39,12 @@ public class MessageExtra implements Serializable {
private SoundMsgDTO soundMsgDTO;
//文件消息
private VideoMsgDTO videoMsgDTO;
//公告消息
private NoticeMsgDTO noticeMsgDTO;
//合并的消息
private MergeMsgDTO mergeMsgDTO;
/**
/**
* 表情图片信息
*/
private EmojisMsgDTO emojisMsgDTO;

View File

@@ -0,0 +1,48 @@
package com.hula.core.chat.domain.entity.msg;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 公告消息入参
* @author 乾乾
*/
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class NoticeMsgDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description ="公告id")
private Long id;
@Schema(description = "房间id")
private Long roomId;
@Schema(description = "公告发布人")
private Long uid;
@Schema(description ="公告内容")
private String content;
@Schema(description = "发布时间")
private LocalDateTime publishTime;
@Schema(description = "置顶")
private Boolean top;
@Schema(description ="回复的消息id")
private Long replyMsgId;
@Schema(description ="父消息如果没有父消息返回的是null")
private ReplyMsg reply;
}

View File

@@ -71,4 +71,6 @@ public interface ChatService {
CursorPageBaseResp<ChatMessageReadResp> getReadPage(Long uid, ChatMessageReadReq request);
void msgRead(Long uid, ChatMessageMemberReq request);
List<Message> getMsgByIds(List<Long> messageIds);
}

View File

@@ -24,8 +24,10 @@ import com.hula.core.chat.domain.vo.request.room.ReadAnnouncementsParam;
import com.hula.core.chat.domain.vo.request.room.RoomGroupReq;
import com.hula.core.chat.domain.vo.response.AnnouncementsResp;
import com.hula.core.chat.domain.vo.response.ChatMemberListResp;
import com.hula.core.chat.domain.vo.response.ChatMessageResp;
import com.hula.core.chat.domain.vo.response.ChatRoomResp;
import com.hula.core.chat.domain.vo.response.MemberResp;
import com.hula.core.user.domain.vo.req.MergeMessageReq;
import com.hula.core.user.domain.vo.resp.ws.ChatMemberResp;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.RequestParam;
@@ -141,4 +143,10 @@ public interface RoomAppService {
* @return
*/
Boolean setShield(Long uid, ContactShieldReq request);
/**
* 合并消息
* @return
*/
ChatMessageResp mergeMessage(Long uid, MergeMessageReq req);
}

View File

@@ -5,6 +5,9 @@ import com.hula.common.enums.YesOrNoEnum;
import com.hula.core.chat.domain.entity.Announcements;
import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.MessageMark;
import com.hula.core.chat.domain.entity.msg.MergeMsg;
import com.hula.core.chat.domain.entity.msg.MergeMsgDTO;
import com.hula.core.chat.domain.entity.msg.NoticeMsgDTO;
import com.hula.core.chat.domain.enums.MessageMarkTypeEnum;
import com.hula.core.chat.domain.enums.MessageStatusEnum;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
@@ -89,6 +92,19 @@ public class MessageAdapter {
return chatMessageReq;
}
/**
* 合并消息
*/
public static ChatMessageReq buildMergeMsg(Long roomId, List<MergeMsg> messages) {
ChatMessageReq chatMessageReq = new ChatMessageReq();
chatMessageReq.setRoomId(roomId);
chatMessageReq.setMsgType(MessageTypeEnum.MERGE.getType());
MergeMsgDTO mergeMsgDTO = new MergeMsgDTO();
mergeMsgDTO.setMessages(messages);
chatMessageReq.setBody(mergeMsgDTO);
return chatMessageReq;
}
/**
* 群公告消息
*/
@@ -96,7 +112,14 @@ public class MessageAdapter {
ChatMessageReq chatMessageReq = new ChatMessageReq();
chatMessageReq.setRoomId(roomId);
chatMessageReq.setMsgType(MessageTypeEnum.NOTICE.getType());
chatMessageReq.setBody(announcements);
NoticeMsgDTO noticeMsgDTO = new NoticeMsgDTO();
noticeMsgDTO.setId(announcements.getId());
noticeMsgDTO.setUid(announcements.getUid());
noticeMsgDTO.setTop(announcements.getTop());
noticeMsgDTO.setRoomId(announcements.getRoomId());
noticeMsgDTO.setContent(announcements.getContent());
noticeMsgDTO.setPublishTime(announcements.getPublishTime());
chatMessageReq.setBody(noticeMsgDTO);
return chatMessageReq;
}

View File

@@ -291,11 +291,17 @@ public class ChatServiceImpl implements ChatService {
update.setReadTime(new Date());
contactDao.updateById(update);
} else {
contactDao.save(uid, request.getRoomId());
log.error("uid --> ", uid, "roomId --> ", request.getRoomId());
// contactDao.save(uid, request.getRoomId());
}
}
private void checkRecall(Long uid, Message message) {
@Override
public List<Message> getMsgByIds(List<Long> msgIds) {
return messageDao.listByIds(msgIds);
}
private void checkRecall(Long uid, Message message) {
AssertUtil.isNotEmpty(message, "消息有误");
AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL.getType(), "消息无法撤回");
boolean isChatManager = roleService.hasRole(uid, RoleTypeEnum.CHAT_MANAGER);

View File

@@ -129,7 +129,8 @@ public class GroupMemberServiceImpl implements IGroupMemberService {
// 4.2 删除会话
Boolean isDelContact = contactDao.removeByRoomId(roomId, Collections.EMPTY_LIST);
AssertUtil.isTrue(isDelContact, CommonErrorEnum.SYSTEM_ERROR);
// 4.3 删除群成员
// 4.3 获取并删除群成员
List<Long> memberUidList = groupMemberDao.getMemberUidList(roomGroup.getId(), null);
Boolean isDelGroupMember = groupMemberDao.removeByGroupId(roomGroup.getId(), Collections.EMPTY_LIST);
AssertUtil.isTrue(isDelGroupMember, CommonErrorEnum.SYSTEM_ERROR);
// 4.4 删除消息记录 (逻辑删除)
@@ -138,7 +139,6 @@ public class GroupMemberServiceImpl implements IGroupMemberService {
// 4.5 告知所有人群已经被解散, 这里要走groupMemberDao查询缓存中可能没有屏蔽群的用户
groupMemberCache.evictMemberUidList(room.getId());
groupMemberCache.evictAllMemberDetails();
List<Long> memberUidList = groupMemberDao.getMemberUidList(roomGroup.getId(), null);
pushService.sendPushMsg(RoomAdapter.buildGroupDissolution(roomGroup.getName()), memberUidList, uid);
} else {
// 4.6 删除会话

View File

@@ -16,6 +16,7 @@ import com.hula.core.chat.dao.GroupMemberDao;
import com.hula.core.chat.dao.MessageDao;
import com.hula.core.chat.domain.dto.RoomBaseInfo;
import com.hula.core.chat.domain.entity.*;
import com.hula.core.chat.domain.entity.msg.MergeMsg;
import com.hula.core.chat.domain.enums.GroupRoleAPPEnum;
import com.hula.core.chat.domain.enums.GroupRoleEnum;
import com.hula.core.chat.domain.enums.HotFlagEnum;
@@ -39,6 +40,7 @@ import com.hula.core.chat.domain.vo.request.room.ReadAnnouncementsParam;
import com.hula.core.chat.domain.vo.request.room.RoomGroupReq;
import com.hula.core.chat.domain.vo.response.AnnouncementsResp;
import com.hula.core.chat.domain.vo.response.ChatMemberListResp;
import com.hula.core.chat.domain.vo.response.ChatMessageResp;
import com.hula.core.chat.domain.vo.response.ChatRoomResp;
import com.hula.core.chat.domain.vo.response.MemberResp;
import com.hula.core.chat.domain.vo.response.ReadAnnouncementsResp;
@@ -56,6 +58,7 @@ import com.hula.core.user.dao.UserDao;
import com.hula.core.user.domain.entity.User;
import com.hula.core.user.domain.enums.RoleTypeEnum;
import com.hula.core.user.domain.enums.WsBaseResp;
import com.hula.core.user.domain.vo.req.MergeMessageReq;
import com.hula.core.user.domain.vo.resp.ws.ChatMemberResp;
import com.hula.core.user.domain.vo.resp.ws.WSMemberChange;
import com.hula.core.user.service.FriendService;
@@ -65,6 +68,7 @@ import com.hula.core.user.service.cache.UserCache;
import com.hula.core.user.service.cache.UserInfoCache;
import com.hula.core.user.service.impl.PushService;
import com.hula.enums.GroupErrorEnum;
import com.hula.exception.BizException;
import com.hula.utils.AssertUtil;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
@@ -438,6 +442,33 @@ public class RoomAppServiceImpl implements RoomAppService {
return contactDao.updateById(contact);
}
@Override
public ChatMessageResp mergeMessage(Long uid, MergeMessageReq req) {
// 1. 校验人员是否在群里、或者有没有对方的好友
Room room = roomCache.get(req.getRoomId());
if(ObjectUtil.isNull(room)){
throw new BizException("房间不存在");
}
if(room.getType().equals(RoomTypeEnum.GROUP.getType())){
RoomGroup roomGroup = roomGroupCache.get(req.getRoomId());
verifyGroupPermissions(uid, roomGroup);
} else {
RoomFriend roomFriend = roomFriendCache.get(req.getRoomId());
if(ObjectUtil.isNull(roomFriend) || !roomFriend.getUid1().equals(uid) && !roomFriend.getUid1().equals(uid)) {
throw new BizException("你们不是好友关系");
}
}
// 2. 当是转发单条消息的时候
List<Message> messagess = chatService.getMsgByIds(req.getMessageIds());
List<MergeMsg> msgs = messagess.stream().filter(message -> message.getRoomId().equals(req.getRoomId())).map(message -> new MergeMsg(message.getContent(), message.getCreateTime(), userInfoCache.get(message.getFromUid()).getName())).collect(Collectors.toUnmodifiableList());
// 3. 发布合并消息
Long msgId = chatService.sendMsg(MessageAdapter.buildMergeMsg(req.getRoomId(), msgs), uid);
return chatService.getMsgResp(msgId, uid);
}
@Override
public List<RoomGroup> searchGroup(RoomGroupReq req) {
return roomGroupCache.searchGroup(req.getAccount());

View File

@@ -4,7 +4,6 @@ import com.hula.core.chat.dao.MessageDao;
import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.msg.EmojisMsgDTO;
import com.hula.core.chat.domain.entity.msg.MessageExtra;
import com.hula.core.chat.domain.entity.msg.ReplyMsg;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

View File

@@ -0,0 +1,54 @@
package com.hula.core.chat.service.strategy.msg;
import com.hula.core.chat.dao.MessageDao;
import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.msg.MergeMsgDTO;
import com.hula.core.chat.domain.entity.msg.MessageExtra;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* 合并消息
* @author 乾乾
*/
@Component
@AllArgsConstructor
public class MergeMsgHandler extends AbstractMsgHandler<MergeMsgDTO> {
private MessageDao messageDao;
@Override
MessageTypeEnum getMsgTypeEnum() {
return MessageTypeEnum.MERGE;
}
@Override
protected void saveMsg(Message message, MergeMsgDTO body) {
MessageExtra extra = Optional.ofNullable(message.getExtra()).orElse(new MessageExtra());
Message update = new Message();
update.setId(message.getId());
extra.setMergeMsgDTO(body);
update.setExtra(extra);
update.setReplyMsgId(body.getReplyMsgId());
messageDao.updateById(update);
}
@Override
public Object showMsg(Message msg) {
MergeMsgDTO resp = msg.getExtra().getMergeMsgDTO();
resp.setReply(replyMsg(msg));
return resp;
}
@Override
public Object showReplyMsg(Message msg) {
return "合并消息";
}
@Override
public String showContactMsg(Message msg) {
return "[合并消息]";
}
}

View File

@@ -0,0 +1,66 @@
package com.hula.core.chat.service.strategy.msg;
import com.hula.common.utils.discover.PrioritizedUrlDiscover;
import com.hula.common.utils.discover.domain.UrlInfo;
import com.hula.common.utils.sensitiveword.SensitiveWordBs;
import com.hula.core.chat.dao.MessageDao;
import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.msg.MessageExtra;
import com.hula.core.chat.domain.entity.msg.NoticeMsgDTO;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Optional;
/**
* 公告消息
* @author 乾乾
*/
@Component
@AllArgsConstructor
public class NoticeMsgHandler extends AbstractMsgHandler<NoticeMsgDTO> {
private MessageDao messageDao;
private SensitiveWordBs sensitiveWordBs;
private static final PrioritizedUrlDiscover URL_TITLE_DISCOVER = new PrioritizedUrlDiscover();
@Override
MessageTypeEnum getMsgTypeEnum() {
return MessageTypeEnum.NOTICE;
}
@Override
protected void saveMsg(Message message, NoticeMsgDTO body) {
MessageExtra extra = Optional.ofNullable(message.getExtra()).orElse(new MessageExtra());
Message update = new Message();
update.setId(message.getId());
// 过滤公告消息的某些字符
body.setContent(sensitiveWordBs.filter(body.getContent()));
extra.setNoticeMsgDTO(body);
update.setExtra(extra);
update.setReplyMsgId(body.getReplyMsgId());
// 判断消息url跳转
Map<String, UrlInfo> urlContentMap = URL_TITLE_DISCOVER.getUrlContentMap(body.getContent());
extra.setUrlContentMap(urlContentMap);
messageDao.updateById(update);
}
@Override
public Object showMsg(Message msg) {
NoticeMsgDTO resp = msg.getExtra().getNoticeMsgDTO();
resp.setReply(replyMsg(msg));
return resp;
}
@Override
public Object showReplyMsg(Message msg) {
return "公告";
}
@Override
public String showContactMsg(Message msg) {
return "[公告]";
}
}

View File

@@ -1,8 +1,6 @@
package com.hula.core.chat.service.strategy.msg;
import cn.hutool.core.collection.CollectionUtil;
import com.hula.common.enums.YesOrNoEnum;
import com.hula.core.chat.domain.entity.msg.ReplyMsg;
import com.hula.utils.AssertUtil;
import com.hula.common.utils.discover.PrioritizedUrlDiscover;
import com.hula.common.utils.discover.domain.UrlInfo;
@@ -10,17 +8,12 @@ import com.hula.common.utils.sensitiveword.SensitiveWordBs;
import com.hula.core.chat.dao.MessageDao;
import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.msg.MessageExtra;
import com.hula.core.chat.domain.enums.MessageStatusEnum;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
import com.hula.core.chat.domain.vo.request.msg.TextMsgReq;
import com.hula.core.chat.domain.vo.response.msg.TextMsgResp;
import com.hula.core.chat.service.adapter.MessageAdapter;
import com.hula.core.chat.service.cache.MsgCache;
import com.hula.core.chat.service.cache.MsgPlusCache;
import com.hula.core.user.domain.entity.User;
import com.hula.core.user.domain.enums.RoleTypeEnum;
import com.hula.core.user.service.RoleService;
import com.hula.core.user.service.cache.UserCache;
import com.hula.core.user.service.cache.UserInfoCache;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
@@ -40,12 +33,9 @@ import java.util.stream.Collectors;
public class TextMsgHandler extends AbstractMsgHandler<TextMsgReq> {
private MessageDao messageDao;
private MsgCache msgCache;
private UserCache userCache;
private UserInfoCache userInfoCache;
private RoleService roleService;
private SensitiveWordBs sensitiveWordBs;
private MsgPlusCache msgPlusCache;
private static final PrioritizedUrlDiscover URL_TITLE_DISCOVER = new PrioritizedUrlDiscover();
@@ -94,7 +84,6 @@ public class TextMsgHandler extends AbstractMsgHandler<TextMsgReq> {
//艾特功能
if (CollectionUtil.isNotEmpty(body.getAtUidList())) {
extra.setAtUidList(body.getAtUidList());
}
messageDao.updateById(update);

View File

@@ -5,7 +5,7 @@ import com.hula.core.chat.domain.entity.Message;
import com.hula.core.chat.domain.entity.msg.MessageExtra;
import com.hula.core.chat.domain.entity.msg.VideoMsgDTO;
import com.hula.core.chat.domain.enums.MessageTypeEnum;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Optional;
@@ -15,8 +15,8 @@ import java.util.Optional;
* @author nyh
*/
@Component
@AllArgsConstructor
public class VideoMsgHandler extends AbstractMsgHandler<VideoMsgDTO> {
@Resource
private MessageDao messageDao;
@Override

View File

@@ -0,0 +1,24 @@
package com.hula.core.user.domain.vo.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 消息实体
*/
@Data
public class MergeMessageReq implements Serializable {
@Schema(description = "接收的房间ID")
@NotNull(message = "房间不能为空")
private Long roomId;
@Schema(description = "合并消息的子消息列表")
@NotEmpty(message = "请选择要转发的消息")
private List<Long> messageIds;
}