web聊天室数据同步修改
This commit is contained in:
@@ -106,7 +106,9 @@ public class WorkcaseChatContorller {
|
||||
@Operation(summary = "分页查询聊天室")
|
||||
@PreAuthorize("hasAuthority('workcase:room:view')")
|
||||
@PostMapping("/room/page")
|
||||
public ResultDomain<ChatRoomVO> getChatRoomPage(@RequestBody PageRequest<TbChatRoomDTO> pageRequest) {
|
||||
public ResultDomain<ChatRoomVO> getChatRoomPage(
|
||||
@RequestBody PageRequest<TbChatRoomDTO> pageRequest,
|
||||
@RequestParam(value = "userId", required = true) String userId) {
|
||||
ValidationResult vr = ValidationUtils.validate(pageRequest, Arrays.asList(
|
||||
ValidationUtils.requiredNumber("pageParam.page", "页码", 1, null),
|
||||
ValidationUtils.requiredNumber("pageParam.pageSize", "每页数量", 1, 100)
|
||||
@@ -114,7 +116,7 @@ public class WorkcaseChatContorller {
|
||||
if (!vr.isValid()) {
|
||||
return ResultDomain.failure(vr.getAllErrors());
|
||||
}
|
||||
return chatRoomService.getChatRoomPage(pageRequest);
|
||||
return chatRoomService.getChatRoomPage(pageRequest, userId);
|
||||
}
|
||||
|
||||
// ========================= ChatRoom成员管理 =========================
|
||||
@@ -147,6 +149,15 @@ public class WorkcaseChatContorller {
|
||||
return chatRoomService.getChatRoomMemberList(roomId);
|
||||
}
|
||||
|
||||
@Operation(summary = "获取当前用户在指定聊天室的未读消息数")
|
||||
@PreAuthorize("hasAuthority('workcase:room:member')")
|
||||
@GetMapping("/room/{roomId}/unread")
|
||||
public ResultDomain<Integer> getUnreadCount(
|
||||
@PathVariable(value = "roomId") String roomId,
|
||||
@RequestParam(value = "userId") String userId) {
|
||||
return chatRoomService.getUnreadCount(roomId, userId);
|
||||
}
|
||||
|
||||
// ========================= ChatRoom消息管理 =========================
|
||||
|
||||
@Operation(summary = "发送聊天室消息")
|
||||
@@ -156,7 +167,8 @@ public class WorkcaseChatContorller {
|
||||
ValidationResult vr = ValidationUtils.validate(message, Arrays.asList(
|
||||
ValidationUtils.requiredString("roomId", "聊天室ID"),
|
||||
ValidationUtils.requiredString("senderId", "发送者ID"),
|
||||
ValidationUtils.requiredString("content", "消息内容")
|
||||
ValidationUtils.requiredString("content", "消息内容"),
|
||||
ValidationUtils.requiredString("senderName", "发送者名称")
|
||||
));
|
||||
if (!vr.isValid()) {
|
||||
return ResultDomain.failure(vr.getAllErrors());
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import org.xyzh.api.workcase.constant.WorkcaseConstant;
|
||||
import org.xyzh.api.workcase.dto.TbChatRoomMessageDTO;
|
||||
import org.xyzh.api.workcase.vo.ChatRoomMessageVO;
|
||||
import org.xyzh.workcase.mapper.TbChatMessageMapper;
|
||||
|
||||
/**
|
||||
* @description 聊天消息Redis监听器,接收Pub/Sub消息并通过STOMP转发到WebSocket客户端
|
||||
@@ -27,6 +29,9 @@ public class ChatMessageListener implements MessageListener {
|
||||
@Autowired(required = false)
|
||||
private SimpMessagingTemplate messagingTemplate;
|
||||
|
||||
@Autowired
|
||||
private TbChatMessageMapper chatMessageMapper;
|
||||
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
try {
|
||||
@@ -46,9 +51,16 @@ public class ChatMessageListener implements MessageListener {
|
||||
// 处理聊天室消息频道: chat:room:{roomId}
|
||||
if (channel.startsWith(WorkcaseConstant.REDIS_CHAT_PREFIX)) {
|
||||
String roomId = channel.substring(WorkcaseConstant.REDIS_CHAT_PREFIX.length());
|
||||
// 转发到聊天窗口订阅者
|
||||
messagingTemplate.convertAndSend("/topic/chat/" + roomId, chatMessage);
|
||||
logger.debug("消息已转发到STOMP: /topic/chat/{}", roomId);
|
||||
|
||||
// 查询完整的VO数据(包含senderAvatar等额外字段)
|
||||
ChatRoomMessageVO messageVO = chatMessageMapper.selectChatMessageVOById(chatMessage.getMessageId());
|
||||
if (messageVO != null) {
|
||||
// 转发完整VO到聊天窗口订阅者
|
||||
messagingTemplate.convertAndSend("/topic/chat/" + roomId, messageVO);
|
||||
logger.debug("消息已转发到STOMP: /topic/chat/{}", roomId);
|
||||
} else {
|
||||
logger.warn("未找到消息VO: messageId={}", chatMessage.getMessageId());
|
||||
}
|
||||
}
|
||||
// 处理列表更新频道: chat:list:update
|
||||
else if (WorkcaseConstant.REDIS_CHAT_LIST_UPDATE.equals(channel)) {
|
||||
|
||||
@@ -53,4 +53,9 @@ public interface TbChatMessageMapper {
|
||||
*/
|
||||
long countChatMessages(@Param("filter") TbChatRoomMessageDTO filter);
|
||||
|
||||
/**
|
||||
* 根据消息ID查询完整VO
|
||||
*/
|
||||
ChatRoomMessageVO selectChatMessageVOById(@Param("messageId") String messageId);
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public interface TbChatRoomMapper {
|
||||
/**
|
||||
* 分页查询聊天室
|
||||
*/
|
||||
List<ChatRoomVO> selectChatRoomPage(@Param("filter") TbChatRoomDTO filter, @Param("pageParam") PageParam pageParam);
|
||||
List<ChatRoomVO> selectChatRoomPage(@Param("filter") TbChatRoomDTO filter, @Param("pageParam") PageParam pageParam, @Param("userId") String userId);
|
||||
|
||||
/**
|
||||
* 统计聊天室数量
|
||||
|
||||
@@ -200,14 +200,14 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<ChatRoomVO> getChatRoomPage(PageRequest<TbChatRoomDTO> pageRequest) {
|
||||
public ResultDomain<ChatRoomVO> getChatRoomPage(PageRequest<TbChatRoomDTO> pageRequest, String userId) {
|
||||
TbChatRoomDTO filter = pageRequest.getFilter();
|
||||
if (filter == null) {
|
||||
filter = new TbChatRoomDTO();
|
||||
}
|
||||
|
||||
PageParam pageParam = pageRequest.getPageParam();
|
||||
List<ChatRoomVO> list = chatRoomMapper.selectChatRoomPage(filter, pageParam);
|
||||
List<ChatRoomVO> list = chatRoomMapper.selectChatRoomPage(filter, pageParam, userId);
|
||||
long total = chatRoomMapper.countChatRooms(filter);
|
||||
pageParam.setTotal((int)total);
|
||||
|
||||
@@ -246,6 +246,7 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
member.setStatus("active");
|
||||
}
|
||||
member.setJoinTime(new Date());
|
||||
member.setCreator(member.getUserId());
|
||||
|
||||
int rows = chatRoomMemberMapper.insertChatRoomMember(member);
|
||||
if (rows > 0) {
|
||||
@@ -332,6 +333,23 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
return ResultDomain.failure("更新失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<Integer> getUnreadCount(String roomId, String userId) {
|
||||
logger.info("查询未读消息数: roomId={}, userId={}", roomId, userId);
|
||||
|
||||
TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO();
|
||||
filter.setRoomId(roomId);
|
||||
filter.setUserId(userId);
|
||||
List<ChatMemberVO> members = chatRoomMemberMapper.selectChatRoomMemberList(filter);
|
||||
|
||||
if (members.isEmpty()) {
|
||||
return ResultDomain.success("查询成功", 0);
|
||||
}
|
||||
|
||||
Integer unreadCount = members.get(0).getUnreadCount();
|
||||
return ResultDomain.success("查询成功", unreadCount != null ? unreadCount : 0);
|
||||
}
|
||||
|
||||
// ========================= 聊天消息管理 ==========================
|
||||
|
||||
@Override
|
||||
@@ -357,6 +375,7 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
if (message.getStatus() == null || message.getStatus().isEmpty()) {
|
||||
message.setStatus("sent");
|
||||
}
|
||||
message.setCreator(message.getSenderId());
|
||||
|
||||
// 使用Redis保证消息时间戳递增,避免并发乱序
|
||||
String lockKey = WorkcaseConstant.REDIS_CHAT_LOCK + message.getRoomId();
|
||||
@@ -402,6 +421,9 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
updateRoom.setMessageCount(room.getMessageCount() != null ? room.getMessageCount() + 1 : 1);
|
||||
chatRoomMapper.updateChatRoom(updateRoom);
|
||||
|
||||
// 更新聊天室成员的未读数(除发送者外的所有成员 +1)
|
||||
updateMembersUnreadCount(message.getRoomId(), message.getSenderId());
|
||||
|
||||
// 发布消息到Redis Pub/Sub(聊天窗口)
|
||||
publishMessageToRedis(message);
|
||||
|
||||
@@ -693,6 +715,29 @@ public class ChatRoomServiceImpl implements ChatRoomService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新聊天室成员的未读数(除发送者外的所有成员 +1)
|
||||
*/
|
||||
private void updateMembersUnreadCount(String roomId, String senderId) {
|
||||
try {
|
||||
TbChatRoomMemberDTO filter = new TbChatRoomMemberDTO();
|
||||
filter.setRoomId(roomId);
|
||||
List<ChatMemberVO> members = chatRoomMemberMapper.selectChatRoomMemberList(filter);
|
||||
|
||||
for (ChatMemberVO member : members) {
|
||||
if (!senderId.equals(member.getUserId())) {
|
||||
TbChatRoomMemberDTO updateMember = new TbChatRoomMemberDTO();
|
||||
updateMember.setMemberId(member.getMemberId());
|
||||
updateMember.setUnreadCount((member.getUnreadCount() != null ? member.getUnreadCount() : 0) + 1);
|
||||
chatRoomMemberMapper.updateChatRoomMember(updateMember);
|
||||
}
|
||||
}
|
||||
logger.debug("已更新聊天室成员未读数: roomId={}, 更新成员数={}", roomId, members.size() - 1);
|
||||
} catch (Exception e) {
|
||||
logger.error("更新聊天室成员未读数失败: roomId={}", roomId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishMessageToRedis(TbChatRoomMessageDTO message) {
|
||||
try {
|
||||
String channel = WorkcaseConstant.REDIS_CHAT_PREFIX + message.getRoomId();
|
||||
|
||||
@@ -141,4 +141,10 @@
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="selectChatMessageVOById" resultMap="VOResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM workcase.tb_chat_room_message
|
||||
WHERE message_id = #{messageId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<result column="guest_name" property="guestName" jdbcType="VARCHAR"/>
|
||||
<result column="ai_session_id" property="aiSessionId" jdbcType="VARCHAR"/>
|
||||
<result column="message_count" property="messageCount" jdbcType="INTEGER"/>
|
||||
<result column="unread_count" property="unreadCount" jdbcType="INTEGER"/>
|
||||
<result column="last_message_time" property="lastMessageTime" jdbcType="TIMESTAMP"/>
|
||||
<result column="last_message" property="lastMessage" jdbcType="VARCHAR"/>
|
||||
<result column="closed_by" property="closedBy" jdbcType="VARCHAR"/>
|
||||
@@ -118,19 +119,24 @@
|
||||
</select>
|
||||
|
||||
<select id="selectChatRoomPage" resultMap="VOResultMap">
|
||||
SELECT <include refid="Base_Column_List"/>
|
||||
FROM workcase.tb_chat_room
|
||||
SELECT r.room_id, r.optsn, r.workcase_id, r.room_name, r.room_type, r.status,
|
||||
r.guest_id, r.guest_name, r.ai_session_id, r.message_count,
|
||||
r.last_message_time, r.last_message, r.closed_by, r.closed_time,
|
||||
r.creator, r.create_time, r.update_time, r.delete_time, r.deleted,
|
||||
COALESCE(m.unread_count, 0) as unread_count
|
||||
FROM workcase.tb_chat_room r
|
||||
LEFT JOIN workcase.tb_chat_room_member m ON r.room_id = m.room_id AND m.user_id = #{userId}
|
||||
<where>
|
||||
<if test="filter.roomId != null and filter.roomId != ''">AND room_id = #{filter.roomId}</if>
|
||||
<if test="filter.workcaseId != null and filter.workcaseId != ''">AND workcase_id = #{filter.workcaseId}</if>
|
||||
<if test="filter.roomName != null and filter.roomName != ''">AND room_name LIKE CONCAT('%', #{filter.roomName}, '%')</if>
|
||||
<if test="filter.roomType != null and filter.roomType != ''">AND room_type = #{filter.roomType}</if>
|
||||
<if test="filter.status != null and filter.status != ''">AND status = #{filter.status}</if>
|
||||
<if test="filter.guestId != null and filter.guestId != ''">AND guest_id = #{filter.guestId}</if>
|
||||
<if test="filter.guestName != null and filter.guestName != ''">AND guest_name LIKE CONCAT('%', #{filter.guestName}, '%')</if>
|
||||
AND deleted = false
|
||||
<if test="filter.roomId != null and filter.roomId != ''">AND r.room_id = #{filter.roomId}</if>
|
||||
<if test="filter.workcaseId != null and filter.workcaseId != ''">AND r.workcase_id = #{filter.workcaseId}</if>
|
||||
<if test="filter.roomName != null and filter.roomName != ''">AND r.room_name LIKE CONCAT('%', #{filter.roomName}, '%')</if>
|
||||
<if test="filter.roomType != null and filter.roomType != ''">AND r.room_type = #{filter.roomType}</if>
|
||||
<if test="filter.status != null and filter.status != ''">AND r.status = #{filter.status}</if>
|
||||
<if test="filter.guestId != null and filter.guestId != ''">AND r.guest_id = #{filter.guestId}</if>
|
||||
<if test="filter.guestName != null and filter.guestName != ''">AND r.guest_name LIKE CONCAT('%', #{filter.guestName}, '%')</if>
|
||||
AND r.deleted = false
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
ORDER BY r.create_time DESC
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user