From 951cd7249d7a0dc285e3423b2b5c96ac1f5fb07a Mon Sep 17 00:00:00 2001 From: KilLze Date: Mon, 5 Jan 2026 21:33:03 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E5=8A=9F=E8=83=BD=E3=80=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=85=A5=E5=BA=93=E5=92=8C=E5=88=9B=E5=BB=BA=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bao/dating/config/RedisConfig.java | 4 +- .../bao/dating/config/WebSocketConfig.java | 35 ++++++ .../dating/handler/ChatWebSocketHandler.java | 107 +++++++++++++++++ .../dating/interceptor/TokenInterceptor.java | 6 +- .../dating/interceptor/WsAuthInterceptor.java | 113 ++++++++++++++++++ .../bao/dating/mapper/ChatRecordsMapper.java | 13 ++ .../bao/dating/mapper/ChatSessionsMapper.java | 39 ++++++ .../com/bao/dating/message/WsMessage.java | 17 +++ .../dating/pojo/dto/ChatRecordSendDTO.java | 17 +++ .../bao/dating/pojo/dto/ChatRecordsDTO.java | 32 +++++ .../dating/pojo/dto/ChatSessionCreateDTO.java | 20 ++++ .../dating/pojo/dto/ChatSessionUpdateDTO.java | 23 ++++ .../bao/dating/pojo/entity/ChatRecords.java | 35 ++++++ .../bao/dating/pojo/entity/ChatSessions.java | 40 +++++++ .../com/bao/dating/pojo/vo/ChatRecordsVO.java | 29 +++++ .../dating/pojo/vo/ChatSessionDetailVO.java | 15 +++ .../bao/dating/pojo/vo/ChatSessionsVO.java | 30 +++++ .../com/bao/dating/service/ChatService.java | 14 +++ .../dating/service/impl/ChatServiceImpl.java | 83 +++++++++++++ .../bao/dating/session/WsSessionManager.java | 51 ++++++++ .../bao/dating/mapper/ChatRecordsMapper.xml | 34 ++++++ .../bao/dating/mapper/ChatSessionsMapper.xml | 62 ++++++++++ 22 files changed, 814 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/bao/dating/config/WebSocketConfig.java create mode 100644 src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java create mode 100644 src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java create mode 100644 src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java create mode 100644 src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java create mode 100644 src/main/java/com/bao/dating/message/WsMessage.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatRecordSendDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/entity/ChatRecords.java create mode 100644 src/main/java/com/bao/dating/pojo/entity/ChatSessions.java create mode 100644 src/main/java/com/bao/dating/pojo/vo/ChatRecordsVO.java create mode 100644 src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java create mode 100644 src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java create mode 100644 src/main/java/com/bao/dating/service/ChatService.java create mode 100644 src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java create mode 100644 src/main/java/com/bao/dating/session/WsSessionManager.java create mode 100644 src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml create mode 100644 src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml diff --git a/src/main/java/com/bao/dating/config/RedisConfig.java b/src/main/java/com/bao/dating/config/RedisConfig.java index 93dcbbd..358649a 100644 --- a/src/main/java/com/bao/dating/config/RedisConfig.java +++ b/src/main/java/com/bao/dating/config/RedisConfig.java @@ -14,9 +14,9 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { // 创建RedisTemplate对象 - RedisTemplate redisTemplate = new RedisTemplate<>(); + RedisTemplate redisTemplate = new RedisTemplate<>(); // 设置redis的连接工厂对象 redisTemplate.setConnectionFactory(redisConnectionFactory); diff --git a/src/main/java/com/bao/dating/config/WebSocketConfig.java b/src/main/java/com/bao/dating/config/WebSocketConfig.java new file mode 100644 index 0000000..774b3aa --- /dev/null +++ b/src/main/java/com/bao/dating/config/WebSocketConfig.java @@ -0,0 +1,35 @@ +package com.bao.dating.config; + + +import com.bao.dating.handler.ChatWebSocketHandler; +import com.bao.dating.interceptor.WsAuthInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +/** + * WebSocket 配置类 + * @author lenovo + */ +@Configuration +@EnableWebSocket +public class WebSocketConfig implements WebSocketConfigurer { + @Autowired + private ChatWebSocketHandler chatWebSocketHandler; + + @Autowired + private WsAuthInterceptor wsAuthInterceptor; + + /** + * 注册 WebSocket 处理器 + * @param registry + */ + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(chatWebSocketHandler, "/ws/chat") + .addInterceptors(wsAuthInterceptor) + .setAllowedOrigins("*"); + } +} diff --git a/src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java new file mode 100644 index 0000000..64288c6 --- /dev/null +++ b/src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java @@ -0,0 +1,107 @@ +package com.bao.dating.handler; + +import com.bao.dating.message.WsMessage; +import com.bao.dating.pojo.dto.ChatRecordSendDTO; +import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.service.ChatService; +import com.bao.dating.session.WsSessionManager; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +/** + * WebSocket处理器类 + * @author lenovo + */ +@Slf4j +@Component +public class ChatWebSocketHandler extends TextWebSocketHandler { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ChatService chatService; + + @Autowired + private WsSessionManager sessionManager; + + + /** + * 用户建立连接(上线) + * @param session + */ + @Override + public void afterConnectionEstablished(WebSocketSession session) { + Long userId = (Long) session.getAttributes().get("userId"); + sessionManager.addSession(userId, session); + log.info("用户 " + userId + " 已上线"); + } + + /** + * 接收并处理消息 + * @param session + * @param message + */ + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception{ + // 获取当前用户ID + Long senderUserId = (Long) session.getAttributes().get("userId"); + if (senderUserId == null) { + log.error("WebSocket session 中未找到 userId"); + return; + } + // 解析消息 + WsMessage wsMessage = + objectMapper.readValue(message.getPayload(), + new TypeReference>(){}); + + // 处理私聊消息 + if ("chat".equals(wsMessage.getType())) { + handlePrivateChat(senderUserId, wsMessage.getData()); + } + } + + /** + * 私聊处理 + */ + private void handlePrivateChat(Long senderUserId, ChatRecordSendDTO dto) throws Exception { + + // 1. 消息入库 + 会话更新 + ChatRecordsVO chatRecordsVO = chatService.createSession(senderUserId, dto); + + // 2. 推送给接收方 + WebSocketSession receiverSession = + sessionManager.getSession(dto.getReceiverUserId()); + + if (receiverSession != null && receiverSession.isOpen()) { + WsMessage pushMsg = new WsMessage<>(); + pushMsg.setType("chat"); + pushMsg.setData(chatRecordsVO); + + receiverSession.sendMessage( + new TextMessage(objectMapper.writeValueAsString(pushMsg)) + ); + } + } + + + /** + * 用户断开连接(下线) + * @param session + * @param status + */ + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status){ + // 下线处理 + Long userId = (Long) session.getAttributes().get("userId"); + sessionManager.removeSession(userId); + log.info("用户 " + userId + " 已下线"); + } +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java index 8e11f59..3203fc9 100644 --- a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java +++ b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java @@ -23,7 +23,7 @@ import org.springframework.web.servlet.HandlerInterceptor; public class TokenInterceptor implements HandlerInterceptor { @Autowired - private RedisTemplate redisTemplate; + private RedisTemplate redisTemplate; /** * 在请求处理之前进行拦截 @@ -68,7 +68,7 @@ public class TokenInterceptor implements HandlerInterceptor { } // 解析 token - String userId = JwtUtil.getSubjectFromToken(token); + Long userId = Long.valueOf(JwtUtil.getSubjectFromToken(token)); // 从Redis获取存储的token进行比对 Object redisTokenObj = redisTemplate.opsForValue().get("login:token:" + userId); @@ -85,7 +85,7 @@ public class TokenInterceptor implements HandlerInterceptor { log.info("用户: {}", userId); // 保存 userId 到 ThreadLocal - UserContext.setUserId(Long.valueOf(userId)); + UserContext.setUserId(userId); return true; } catch (Exception e) { log.error("Token 校验失败: {}", e.getMessage()); diff --git a/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java new file mode 100644 index 0000000..4b29ca8 --- /dev/null +++ b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java @@ -0,0 +1,113 @@ +package com.bao.dating.interceptor; + +import com.bao.dating.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * WebSocket 认证拦截器 + */ +@Slf4j +@Component +public class WsAuthInterceptor implements HandshakeInterceptor { + + @Autowired + private RedisTemplate redisTemplate; + /** + * 拦截WebSocket连接请求 + */ + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception { + log.info("开始WebSocket握手认证"); + + // 获取请求参数 + if (!(request instanceof ServletServerHttpRequest)) { + log.error("WebSocket握手失败:非HTTP请求"); + return false; + } + + // 获取HttpServletRequest对象 + HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); + + // 从URL参数中获取token + String token = servletRequest.getParameter("token"); + log.info("从URL参数获取到的token: {}", token != null ? "存在" : "不存在"); + + if (StringUtils.isBlank(token)) { + log.error("WebSocket握手失败:令牌丢失"); + return false; + } + + try { + // 验证 token 是否有效(包括是否过期) + if (!JwtUtil.validateToken(token)) { + log.error("Token无效或已过期: {}", token); + return false; + } + + // 检查 token 是否在黑名单中 + String blacklistKey = "jwt:blacklist:" + token; + Object blacklistToken = redisTemplate.opsForValue().get(blacklistKey); + if (blacklistToken != null) { + log.error("Token已在黑名单中: {}", token); + return false; + } + + // 验证token并获取用户ID + String userIdStr = JwtUtil.getSubjectFromToken(token); + log.info("从token解析出的用户ID: {}", userIdStr); + + if (StringUtils.isBlank(userIdStr) || !userIdStr.matches("\\d+")) { + log.error("无效的用户ID格式: {}", userIdStr); + return false; + } + + Long userId = Long.valueOf(userIdStr); + + // 从Redis获取存储的token进行比对 + String redisTokenKey = "login:token:" + userId; + Object redisTokenObj = redisTemplate.opsForValue().get(redisTokenKey); + String redisToken = redisTokenObj != null ? redisTokenObj.toString() : null; + log.info("Redis中存储的token: {}", redisToken != null ? "存在" : "不存在"); + + // 验证Redis中的token是否存在且匹配 + if (redisToken == null || !redisToken.equals(token)) { + log.error("登录已失效 - Redis中token不存在或不匹配"); + return false; + } + + log.info("WebSocket认证成功,用户ID: {}", userId); + // 将用户ID保存到attributes中 + attributes.put("userId", userId); + return true; + } + catch (NumberFormatException e) { + log.error("用户ID格式转换异常: {}", e.getMessage()); + return false; + } + catch (Exception e) { + log.error("WebSocket握手失败:{}", e.getMessage(), e); + return false; + } + } + + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { + if (exception != null) { + log.error("WebSocket握手后出现异常:", exception); + } else { + log.info("WebSocket握手完成"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java new file mode 100644 index 0000000..49b21ab --- /dev/null +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -0,0 +1,13 @@ +package com.bao.dating.mapper; + + +import com.bao.dating.pojo.entity.ChatRecords; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface ChatRecordsMapper { + /** + * 插入聊天记录 + */ + int insert(ChatRecords chatRecords); +} diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java new file mode 100644 index 0000000..3cc92a5 --- /dev/null +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -0,0 +1,39 @@ +package com.bao.dating.mapper; + + +import com.bao.dating.pojo.entity.ChatRecords; +import com.bao.dating.pojo.entity.ChatSessions; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface ChatSessionsMapper { + /** + * 如果发送方不存在会话则创建 + * @param chatSessions 会话 + * @return 影响行数 + */ + int insertIfNotExistsForSender(ChatSessions chatSessions); + + /** + * 如果接收方不存在会话则创建 + * @param chatSessions 会话 + * @return 影响行数 + */ + int insertIfNotExistsForReceiver(ChatSessions chatSessions); + + /** + * 更新发送方的会话信息 + * @param chatSessions 会话 + * @return 影响行数 + */ + int updateSessionForSender(ChatSessions chatSessions); + + /** + * 更新接收方的会话信息 + * @param chatSessions 会话 + * @return 影响行数 + */ + int updateSessionForReceiver(ChatSessions chatSessions); + +} diff --git a/src/main/java/com/bao/dating/message/WsMessage.java b/src/main/java/com/bao/dating/message/WsMessage.java new file mode 100644 index 0000000..a9df3fb --- /dev/null +++ b/src/main/java/com/bao/dating/message/WsMessage.java @@ -0,0 +1,17 @@ +package com.bao.dating.message; + +import lombok.Data; + +/** + * WebSocket 消息 + * @author KilLze + */ +@Data +public class WsMessage { + + /** 消息类型:chat / read / system */ + private String type; + + /** 消息体 */ + private T data; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatRecordSendDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatRecordSendDTO.java new file mode 100644 index 0000000..68e8efd --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatRecordSendDTO.java @@ -0,0 +1,17 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 聊天记录发送数据传输对象 + * @author KilLze + */ +@Data +public class ChatRecordSendDTO { + /** 接收者用户ID */ + private Long receiverUserId; + /** 消息内容 */ + private String messageContent; + /** 消息类型 (1-文本消息,2-文件消息) */ + private Integer messageType; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java new file mode 100644 index 0000000..dc2d6b8 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java @@ -0,0 +1,32 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 聊天记录数据传输对象 + * @author KilLze + */ +@Data +public class ChatRecordsDTO { + + /** 聊天记录ID */ + private Long chatId; + /** 发送者用户ID */ + private Long senderUserId; + /** 接收者用户ID */ + private Long receiverUserId; + /** 消息内容 */ + private String messageContent; + /** 消息类型 (1-文本消息,2-文件消息) */ + private Integer messageType; + /** 阅读状态 (0-未读,1-已读) */ + private Integer readStatus; + /** 阅读时间 */ + private LocalDateTime readTime; + /** 发送时间 */ + private LocalDateTime sendTime; + /** 消息状态 (1-正常,2-已撤回,3-已删除) */ + private Integer messageStatus; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java new file mode 100644 index 0000000..51ff00a --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java @@ -0,0 +1,20 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 创建会话数据传输对象 + * @author KilLze + */ +@Data +public class ChatSessionCreateDTO { + + /** 所属用户ID */ + private Long userId; + + /** 目标用户ID */ + private Long targetUserId; + + /** 会话名称 */ + private String sessionName; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java new file mode 100644 index 0000000..b020868 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java @@ -0,0 +1,23 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 会话更新数据传输对象 + * @author KilLze + */ +@Data +public class ChatSessionUpdateDTO { + /** 会话ID */ + private Long sessionId; + /** 最后一条消息ID (关联chat_records.chat_id) */ + private Long lastMessageId; + /** 最后一条消息内容 */ + private String lastMessageContent; + /** 最后一条消息时间 */ + private LocalDateTime lastMessageTime; + /** 未读消息数量 */ + private Integer unreadCount; +} diff --git a/src/main/java/com/bao/dating/pojo/entity/ChatRecords.java b/src/main/java/com/bao/dating/pojo/entity/ChatRecords.java new file mode 100644 index 0000000..6bd8237 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/entity/ChatRecords.java @@ -0,0 +1,35 @@ +package com.bao.dating.pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 聊天记录表 + * @author lenovo + */ +@Data +public class ChatRecords { + /** 聊天记录ID */ + private Long chatId; + /** 发送者用户ID */ + private Long senderUserId; + /** 接收者用户ID */ + private Long receiverUserId; + /** 消息内容 */ + private String messageContent; + /** 消息类型 (1-文本消息,2-文件消息) */ + private Integer messageType; + /** 阅读状态 (0-未读,1-已读) */ + private Integer readStatus; + /** 阅读时间 */ + private LocalDateTime readTime; + /** 发送时间 */ + private LocalDateTime sendTime; + /** 消息状态 (1-正常,2-已撤回,3-已删除) */ + private Integer messageStatus; + /** 创建时间 */ + private LocalDateTime createdAt; + /** 更新时间 */ + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/bao/dating/pojo/entity/ChatSessions.java b/src/main/java/com/bao/dating/pojo/entity/ChatSessions.java new file mode 100644 index 0000000..5b85c72 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/entity/ChatSessions.java @@ -0,0 +1,40 @@ +package com.bao.dating.pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 会话表 + * @author KilLze + */ +@Data +public class ChatSessions { + /** 会话ID */ + private Long sessionId; + /** 所属用户ID */ + private Long userId; + /** 目标用户ID */ + private Long targetUserId; + /** 会话名称 */ + private String sessionName; + /** 最后一条消息ID (关联chat_records.chat_id) */ + private Long lastMessageId; + /** 最后一条消息内容 */ + private String lastMessageContent; + /** 最后一条消息时间 */ + private LocalDateTime lastMessageTime; + /** 未读消息数量 */ + private Integer unreadCount; + /** 会话状态 (1-正常,2-已隐藏,3-已删除) */ + private Integer sessionStatus; + /** 置顶状态 (0-未置顶,1-已置顶) */ + private Integer topStatus; + /** 免打扰状态 (0-正常提醒,1-免打扰) */ + private Integer muteStatus; + /** 创建时间 */ + private LocalDateTime createdAt; + /** 更新时间 */ + private LocalDateTime updatedAt; + +} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatRecordsVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatRecordsVO.java new file mode 100644 index 0000000..deb9f92 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/vo/ChatRecordsVO.java @@ -0,0 +1,29 @@ +package com.bao.dating.pojo.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 聊天记录返回数据 + * @author KilLze + */ +@Data +public class ChatRecordsVO { + /** 聊天记录ID */ + private Long chatId; + /** 发送者用户ID */ + private Long senderUserId; + /** 接收者用户ID */ + private Long receiverUserId; + /** 消息内容 */ + private String messageContent; + /** 消息类型 (1-文本消息,2-文件消息) */ + private Integer messageType; + /** 阅读状态 (0-未读,1-已读) */ + private Integer readStatus; + /** 发送时间 */ + private LocalDateTime sendTime; + /** 消息状态 (1-正常,2-已撤回,3-已删除) */ + private Integer messageStatus; +} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java new file mode 100644 index 0000000..2ede2d8 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java @@ -0,0 +1,15 @@ +package com.bao.dating.pojo.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class ChatSessionDetailVO { + + /** 会话信息 */ + private ChatSessionsVO session; + + /** 聊天记录列表 */ + private List records; +} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java new file mode 100644 index 0000000..22fa0ed --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java @@ -0,0 +1,30 @@ +package com.bao.dating.pojo.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class ChatSessionsVO { + + /** 会话ID */ + private Long sessionId; + /** 当前用户ID */ + private Long userId; + /** 对方用户ID */ + private Long targetUserId; + /** 会话名称 */ + private String sessionName; + /** 最后一条消息内容 */ + private String lastMessageContent; + /** 最后一条消息时间 */ + private LocalDateTime lastMessageTime; + /** 未读消息数量 */ + private Integer unreadCount; + /** 会话状态 */ + private Integer sessionStatus; + /** 置顶状态 */ + private Integer topStatus; + /** 免打扰状态 */ + private Integer muteStatus; +} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java new file mode 100644 index 0000000..a4042a2 --- /dev/null +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -0,0 +1,14 @@ +package com.bao.dating.service; + +import com.bao.dating.pojo.dto.ChatRecordSendDTO; +import com.bao.dating.pojo.vo.ChatRecordsVO; + +public interface ChatService { + /** + * 消息入库,如果会话不存在则创建会话 + * @param senderUserId 发送方用户ID + * @param dto 发送参数 + * @return 聊天记录VO + */ + ChatRecordsVO createSession(Long senderUserId, ChatRecordSendDTO dto); +} diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java new file mode 100644 index 0000000..153215d --- /dev/null +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -0,0 +1,83 @@ +package com.bao.dating.service.impl; + +import com.bao.dating.mapper.ChatRecordsMapper; +import com.bao.dating.mapper.ChatSessionsMapper; +import com.bao.dating.pojo.dto.ChatRecordSendDTO; +import com.bao.dating.pojo.entity.ChatRecords; +import com.bao.dating.pojo.entity.ChatSessions; +import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.service.ChatService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; + + + + +/** + * 聊天服务实现类 + * @author lenovo + */ +@Slf4j +@Service +public class ChatServiceImpl implements ChatService { + @Autowired + private ChatRecordsMapper chatRecordsMapper; + + @Autowired + private ChatSessionsMapper chatSessionsMapper; + + /** + * 消息入库,如果会话不存在则创建会话 + * @param senderUserId 发送者用户ID + * @param dto 消息 + * @return 聊天记录 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public ChatRecordsVO createSession(Long senderUserId, ChatRecordSendDTO dto) { + ChatRecords record = new ChatRecords(); + record.setSenderUserId(senderUserId); + record.setReceiverUserId(dto.getReceiverUserId()); + record.setMessageContent(dto.getMessageContent()); + record.setMessageType(dto.getMessageType()); + record.setReadStatus(0); + record.setMessageStatus(1); + record.setSendTime(LocalDateTime.now()); + + // 插入消息记录 + chatRecordsMapper.insert(record); + + // 创建接收方会话 + ChatSessions sessions = new ChatSessions(); + sessions.setUserId(senderUserId); + sessions.setTargetUserId(dto.getReceiverUserId()); + sessions.setSessionName(""); + sessions.setLastMessageId(record.getChatId()); + sessions.setLastMessageContent(record.getMessageContent()); + sessions.setLastMessageTime(record.getSendTime()); + + chatSessionsMapper.insertIfNotExistsForSender(sessions); + chatSessionsMapper.updateSessionForSender(sessions); + + // 创建接收方会话 + sessions.setUserId(dto.getReceiverUserId()); + sessions.setTargetUserId(senderUserId); + sessions.setSessionName(""); + + chatSessionsMapper.insertIfNotExistsForReceiver(sessions); + chatSessionsMapper.updateSessionForReceiver(sessions); + + + + // 3. 返回 VO + ChatRecordsVO vo = new ChatRecordsVO(); + BeanUtils.copyProperties(record, vo); + return vo; + } + +} diff --git a/src/main/java/com/bao/dating/session/WsSessionManager.java b/src/main/java/com/bao/dating/session/WsSessionManager.java new file mode 100644 index 0000000..90eea45 --- /dev/null +++ b/src/main/java/com/bao/dating/session/WsSessionManager.java @@ -0,0 +1,51 @@ +package com.bao.dating.session; + +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * WebSocketSession 管理类 + * @author KilLze + */ +@Component +public class WsSessionManager { + + private final Map SESSION_MAP = new ConcurrentHashMap<>(); + /** + * 添加 WebSocketSession + * @param userId 用户ID + * @param session WebSocketSession + */ + public void addSession(Long userId, WebSocketSession session) { + SESSION_MAP.put(userId, session); + } + + /** + * 移除 WebSocketSession + * @param userId 用户ID + */ + public void removeSession(Long userId) { + SESSION_MAP.remove(userId); + } + + /** + * 获取 WebSocketSession + * @param userId 用户ID + * @return WebSocketSession + */ + public WebSocketSession getSession(Long userId) { + return SESSION_MAP.get(userId); + } + + /** + * 判断用户是否在线 + * @param userId 用户ID + * @return true-在线,false-离线 + */ + public boolean isOnline(Long userId) { + return SESSION_MAP.containsKey(userId); + } +} diff --git a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml new file mode 100644 index 0000000..91be40d --- /dev/null +++ b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml @@ -0,0 +1,34 @@ + + + + + + + INSERT INTO chat_records + ( + sender_user_id, + receiver_user_id, + message_content, + message_type, + read_status, + send_time, + message_status, + created_at, + updated_at + ) + VALUES + ( + #{senderUserId}, + #{receiverUserId}, + #{messageContent}, + #{messageType}, + #{readStatus}, + #{sendTime}, + #{messageStatus}, + NOW(), + NOW() + ) + + + \ No newline at end of file diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml new file mode 100644 index 0000000..d3d829c --- /dev/null +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -0,0 +1,62 @@ + + + + + + + INSERT INTO chat_sessions + (user_id, target_user_id, session_name, last_message_id, last_message_content, last_message_time, + unread_count, session_status, top_status, mute_status, created_at, updated_at) + SELECT + #{userId}, #{targetUserId}, #{sessionName}, #{lastMessageId}, #{lastMessageContent}, #{lastMessageTime}, + 0, 1, 0, 0, NOW(), NOW() + FROM DUAL + WHERE NOT EXISTS ( + SELECT 1 FROM chat_sessions + WHERE user_id = #{userId} AND target_user_id = #{targetUserId} + ); + + + + + INSERT INTO chat_sessions + (user_id, target_user_id, session_name, last_message_id, last_message_content, last_message_time, + unread_count, session_status, top_status, mute_status, created_at, updated_at) + SELECT + #{userId}, #{targetUserId}, #{sessionName}, #{lastMessageId}, #{lastMessageContent}, #{lastMessageTime}, + 0, 1, 0, 0, NOW(), NOW() + FROM DUAL + WHERE NOT EXISTS ( + SELECT 1 FROM chat_sessions + WHERE user_id = #{userId} AND target_user_id = #{targetUserId} + ) + + + + + UPDATE chat_sessions + SET + last_message_id = #{lastMessageId}, + last_message_content = #{lastMessageContent}, + last_message_time = #{lastMessageTime}, + unread_count = 0, + updated_at = NOW() + WHERE user_id = #{userId} + AND target_user_id = #{targetUserId}; + + + + + UPDATE chat_sessions + SET + last_message_id = #{lastMessageId}, + last_message_content = #{lastMessageContent}, + last_message_time = #{lastMessageTime}, + unread_count = unread_count + 1, + updated_at = NOW() + WHERE user_id = #{userId} + AND target_user_id = #{targetUserId} + + + \ No newline at end of file From fb2b7823b852d90bed8f59019941eb7dc9801410 Mon Sep 17 00:00:00 2001 From: KilLze Date: Mon, 5 Jan 2026 22:48:53 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E6=B7=BB=E5=8A=A0=E5=AF=B9=E6=96=B9=E6=98=B5?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bao/dating/config/WebConfig.java | 14 +++++++- .../bao/dating/pojo/dto/UserNicknameDTO.java | 13 ++++++++ .../dating/pojo/vo/ChatSessionDetailVO.java | 4 +++ .../bao/dating/pojo/vo/ChatSessionsVO.java | 4 +++ .../com/bao/dating/service/UserService.java | 8 +++++ .../dating/service/impl/ChatServiceImpl.java | 32 +++++++++++++++++-- .../dating/service/impl/UserServiceImpl.java | 20 ++++++++++++ 7 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java diff --git a/src/main/java/com/bao/dating/config/WebConfig.java b/src/main/java/com/bao/dating/config/WebConfig.java index 98a0683..37e08aa 100644 --- a/src/main/java/com/bao/dating/config/WebConfig.java +++ b/src/main/java/com/bao/dating/config/WebConfig.java @@ -4,7 +4,9 @@ package com.bao.dating.config; import com.bao.dating.interceptor.TokenInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** @@ -32,4 +34,14 @@ public class WebConfig implements WebMvcConfigurer { "/user/login" ); } -} + + /** + * 配置静态资源映射 + * @param registry 静态资源注册器 + */ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/**") + .addResourceLocations("classpath:/static/"); + } +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java b/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java new file mode 100644 index 0000000..8b2afd1 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 用户昵称数据传输对象 + * @author KilLze + */ +@Data +public class UserNicknameDTO { + private Long userId; + private String nickname; +} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java index 2ede2d8..e619a07 100644 --- a/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java @@ -4,6 +4,10 @@ import lombok.Data; import java.util.List; +/** + * 聊天会话详情 + * @author KilLze + */ @Data public class ChatSessionDetailVO { diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java index 22fa0ed..276bfd1 100644 --- a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java @@ -4,6 +4,10 @@ import lombok.Data; import java.time.LocalDateTime; +/** + * 会话信息 + * @author KilLze + */ @Data public class ChatSessionsVO { diff --git a/src/main/java/com/bao/dating/service/UserService.java b/src/main/java/com/bao/dating/service/UserService.java index 8dd074c..6b620d2 100644 --- a/src/main/java/com/bao/dating/service/UserService.java +++ b/src/main/java/com/bao/dating/service/UserService.java @@ -2,6 +2,7 @@ package com.bao.dating.service; import com.bao.dating.pojo.dto.UserInfoUpdateDTO; import com.bao.dating.pojo.dto.UserLoginDTO; +import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserLoginVO; import org.springframework.web.multipart.MultipartFile; @@ -52,4 +53,11 @@ public interface UserService { * @return 更新后的用户信息 */ UserInfoVO updateUserInfo(UserInfoUpdateDTO userInfoUpdateDTO); + + /** + * 根据用户ID查询用户昵称 + * @param userId 用户ID + * @return 用户 + */ + UserNicknameDTO getUserNicknameById(Long userId); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 153215d..2da21b0 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -3,10 +3,12 @@ package com.bao.dating.service.impl; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; import com.bao.dating.pojo.dto.ChatRecordSendDTO; +import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.ChatRecords; import com.bao.dating.pojo.entity.ChatSessions; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; +import com.bao.dating.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +33,9 @@ public class ChatServiceImpl implements ChatService { @Autowired private ChatSessionsMapper chatSessionsMapper; + @Autowired + private UserService userService; + /** * 消息入库,如果会话不存在则创建会话 * @param senderUserId 发送者用户ID @@ -56,7 +61,19 @@ public class ChatServiceImpl implements ChatService { ChatSessions sessions = new ChatSessions(); sessions.setUserId(senderUserId); sessions.setTargetUserId(dto.getReceiverUserId()); - sessions.setSessionName(""); + // 获取接收方昵称作为发送方会话名称 + try { + UserNicknameDTO receiverNicknameInfo = userService.getUserNicknameById(dto.getReceiverUserId()); + if (receiverNicknameInfo != null && receiverNicknameInfo.getNickname() != null) { + sessions.setSessionName(receiverNicknameInfo.getNickname()); + } else { + log.warn("接收用户ID获取用户信息时出现错误: {} , 使用默认id", dto.getReceiverUserId()); + sessions.setSessionName("用户" + dto.getReceiverUserId()); + } + } catch (Exception e) { + log.error("接收用户ID获取用户信息时出现错误: {} , 使用默认id", dto.getReceiverUserId(), e); + sessions.setSessionName("用户" + dto.getReceiverUserId()); + } sessions.setLastMessageId(record.getChatId()); sessions.setLastMessageContent(record.getMessageContent()); sessions.setLastMessageTime(record.getSendTime()); @@ -67,7 +84,18 @@ public class ChatServiceImpl implements ChatService { // 创建接收方会话 sessions.setUserId(dto.getReceiverUserId()); sessions.setTargetUserId(senderUserId); - sessions.setSessionName(""); + try { + UserNicknameDTO senderNicknameInfo = userService.getUserNicknameById(senderUserId); + if (senderNicknameInfo != null && senderNicknameInfo.getNickname() != null) { + sessions.setSessionName(senderNicknameInfo.getNickname()); + } else { + log.warn("接收用户ID获取用户信息时出现错误: {} , 使用默认id", senderUserId); + sessions.setSessionName("用户" + senderUserId); + } + } catch (Exception e) { + log.error("接收用户ID获取用户信息时出现错误: {} , 使用默认id", senderUserId, e); + sessions.setSessionName("用户" + senderUserId); + } chatSessionsMapper.insertIfNotExistsForReceiver(sessions); chatSessionsMapper.updateSessionForReceiver(sessions); diff --git a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java index 189b7e3..7118a08 100644 --- a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java @@ -10,6 +10,7 @@ import com.bao.dating.context.UserContext; import com.bao.dating.mapper.UserMapper; import com.bao.dating.pojo.dto.UserInfoUpdateDTO; import com.bao.dating.pojo.dto.UserLoginDTO; +import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.User; import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserLoginVO; @@ -311,4 +312,23 @@ public class UserServiceImpl implements UserService { BeanUtils.copyProperties(updatedUser, userInfoVO); return userInfoVO; } + + /** + * 根据用户ID获取用户昵称 + * + * @param userId 用户ID + * @return 用户昵称 + */ + @Override + public UserNicknameDTO getUserNicknameById(Long userId) { + // 查询数据库获取昵称 + User user = userMapper.selectByUserId(userId); + if (user == null) { + throw new RuntimeException("没有此用户"); + } + UserNicknameDTO dto = new UserNicknameDTO(); + dto.setUserId(user.getUserId()); + dto.setNickname(user.getNickname()); + return dto; + } } From 2a9acb946e6b6bf0b7e951e644a16023192d496c Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 6 Jan 2026 02:25:36 +0800 Subject: [PATCH 03/17] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=EF=BC=8C=E9=A1=BA=E4=BE=BF=E5=87=86=E5=A4=87=E5=86=99=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E8=81=8A=E5=A4=A9=E8=AE=B0=E5=BD=95=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/bao/dating/config/WebSocketConfig.java | 2 +- .../java/com/bao/dating/controller/ChatController.java | 9 +++++++++ .../websocket}/ChatWebSocketHandler.java | 2 +- .../com/bao/dating/interceptor/WsAuthInterceptor.java | 2 -- 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/bao/dating/controller/ChatController.java rename src/main/java/com/bao/dating/{handler => controller/websocket}/ChatWebSocketHandler.java (98%) diff --git a/src/main/java/com/bao/dating/config/WebSocketConfig.java b/src/main/java/com/bao/dating/config/WebSocketConfig.java index 774b3aa..67bf631 100644 --- a/src/main/java/com/bao/dating/config/WebSocketConfig.java +++ b/src/main/java/com/bao/dating/config/WebSocketConfig.java @@ -1,7 +1,7 @@ package com.bao.dating.config; -import com.bao.dating.handler.ChatWebSocketHandler; +import com.bao.dating.controller.websocket.ChatWebSocketHandler; import com.bao.dating.interceptor.WsAuthInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java new file mode 100644 index 0000000..74efc7f --- /dev/null +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -0,0 +1,9 @@ +package com.bao.dating.controller; + +/** + * 聊天控制器 + * @author lenovo + */ +public class ChatController { + +} diff --git a/src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java similarity index 98% rename from src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java rename to src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java index 64288c6..07ae197 100644 --- a/src/main/java/com/bao/dating/handler/ChatWebSocketHandler.java +++ b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java @@ -1,4 +1,4 @@ -package com.bao.dating.handler; +package com.bao.dating.controller.websocket; import com.bao.dating.message.WsMessage; import com.bao.dating.pojo.dto.ChatRecordSendDTO; diff --git a/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java index 4b29ca8..a01153c 100644 --- a/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java +++ b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java @@ -42,7 +42,6 @@ public class WsAuthInterceptor implements HandshakeInterceptor { // 从URL参数中获取token String token = servletRequest.getParameter("token"); - log.info("从URL参数获取到的token: {}", token != null ? "存在" : "不存在"); if (StringUtils.isBlank(token)) { log.error("WebSocket握手失败:令牌丢失"); @@ -66,7 +65,6 @@ public class WsAuthInterceptor implements HandshakeInterceptor { // 验证token并获取用户ID String userIdStr = JwtUtil.getSubjectFromToken(token); - log.info("从token解析出的用户ID: {}", userIdStr); if (StringUtils.isBlank(userIdStr) || !userIdStr.matches("\\d+")) { log.error("无效的用户ID格式: {}", userIdStr); From c0969406b34b45dd7a46ee359fc4675e9dedec80 Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 6 Jan 2026 04:18:30 +0800 Subject: [PATCH 04/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E6=9F=A5=E8=AF=A2=EF=BC=8C=E5=B9=B6=E4=B8=94?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E9=80=9A=E8=BF=87=E5=86=85=E5=AE=B9=E6=A8=A1?= =?UTF-8?q?=E7=B3=8A=E6=9F=A5=E8=AF=A2=EF=BC=8C=E9=80=9A=E8=BF=87=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=9F=A5=E8=AF=A2=EF=BC=8C=E9=80=9A=E8=BF=87=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E7=B1=BB=E5=9E=8B=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 ++ .../bao/dating/common/result/PageResult.java | 28 +++++++++ .../java/com/bao/dating/config/WebConfig.java | 14 +---- .../bao/dating/controller/ChatController.java | 33 ++++++++++ .../bao/dating/mapper/ChatRecordsMapper.java | 17 +++++ .../dating/pojo/dto/ChatHistoryQueryDTO.java | 23 +++++++ .../com/bao/dating/service/ChatService.java | 15 +++++ .../dating/service/impl/ChatServiceImpl.java | 63 ++++++++++++++++++- .../bao/dating/mapper/ChatRecordsMapper.xml | 26 ++++++++ 9 files changed, 210 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/bao/dating/common/result/PageResult.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java diff --git a/pom.xml b/pom.xml index 73d13a3..167f2a4 100644 --- a/pom.xml +++ b/pom.xml @@ -171,6 +171,12 @@ spring-boot-starter-data-redis + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.4.7 + + diff --git a/src/main/java/com/bao/dating/common/result/PageResult.java b/src/main/java/com/bao/dating/common/result/PageResult.java new file mode 100644 index 0000000..f1634ef --- /dev/null +++ b/src/main/java/com/bao/dating/common/result/PageResult.java @@ -0,0 +1,28 @@ +package com.bao.dating.common.result; + +import lombok.Data; + +import java.util.List; + +@Data +public class PageResult { + /** 总记录数 */ + private Long total; + /** 当前页码 */ + private Integer page; + /** 每页大小 */ + private Integer size; + /** 总页数 */ + private Integer pages; + /** 当前页数据 */ + private List records; + + public PageResult(Long total, Integer page, Integer size, List records) { + this.total = total; + this.page = page; + this.size = size; + this.records = records; + // 计算总页数 + this.pages = (int) Math.ceil((double) total / size); + } +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/config/WebConfig.java b/src/main/java/com/bao/dating/config/WebConfig.java index 37e08aa..98a0683 100644 --- a/src/main/java/com/bao/dating/config/WebConfig.java +++ b/src/main/java/com/bao/dating/config/WebConfig.java @@ -4,9 +4,7 @@ package com.bao.dating.config; import com.bao.dating.interceptor.TokenInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** @@ -34,14 +32,4 @@ public class WebConfig implements WebMvcConfigurer { "/user/login" ); } - - /** - * 配置静态资源映射 - * @param registry 静态资源注册器 - */ - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/**") - .addResourceLocations("classpath:/static/"); - } -} \ No newline at end of file +} diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 74efc7f..95acbce 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -1,9 +1,42 @@ package com.bao.dating.controller; +import com.bao.dating.common.Result; +import com.bao.dating.common.ResultCode; +import com.bao.dating.common.result.PageResult; +import com.bao.dating.context.UserContext; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; +import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.service.ChatService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + /** * 聊天控制器 * @author lenovo */ +@Slf4j +@RestController +@RequestMapping("/chat") public class ChatController { + @Autowired + private ChatService chatService; + /** + * 获取聊天记录 + * @param targetUserId 目标用户ID + * @param queryDTO 查询参数 + * @return 聊天记录列表 + */ + @GetMapping("/history/{targetUserId}") + public Result> getChatHistory( + @PathVariable Long targetUserId, + ChatHistoryQueryDTO queryDTO){ + Long currentUserId = UserContext.getUserId(); + PageResult history = chatService.getChatHistory(currentUserId, targetUserId, queryDTO); + return Result.success(ResultCode.SUCCESS, "获取聊天记录成功", history); + } } diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index 49b21ab..2e37587 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -1,8 +1,13 @@ package com.bao.dating.mapper; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.entity.ChatRecords; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDateTime; +import java.util.List; @Mapper public interface ChatRecordsMapper { @@ -10,4 +15,16 @@ public interface ChatRecordsMapper { * 插入聊天记录 */ int insert(ChatRecords chatRecords); + + /** + * 根据用户ID和接收方用户ID查询聊天记录 + */ + List selectByUsersAndConditions( + @Param("currentUserId") Long currentUserId, + @Param("targetUserId") Long targetUserId, + @Param("messageContent") String messageContent, + @Param("startTime") LocalDateTime startTime, + @Param("endTime") LocalDateTime endTime, + @Param("messageType") Integer messageType + ); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java new file mode 100644 index 0000000..96816d6 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java @@ -0,0 +1,23 @@ +package com.bao.dating.pojo.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; + +/** + * 聊天记录查询参数 + * @author KilLze + */ +@Data +public class ChatHistoryQueryDTO { + private Integer page; + private Integer size; + private Long targetUserId; + private String messageContent; + @JsonFormat(pattern = "yyyy-MM-dd") + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) + private LocalDate date; + private Integer messageType; +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index a4042a2..c9aa62a 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -1,8 +1,14 @@ package com.bao.dating.service; +import com.bao.dating.common.result.PageResult; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; +/** + * 聊天服务 + * @author lenovo + */ public interface ChatService { /** * 消息入库,如果会话不存在则创建会话 @@ -11,4 +17,13 @@ public interface ChatService { * @return 聊天记录VO */ ChatRecordsVO createSession(Long senderUserId, ChatRecordSendDTO dto); + + /** + * 获取聊天记录 + * @param currentUserId 发送方用户ID + * @param targetUserId 接收方用户ID + * @param queryDTO 查询参数 + * @return 聊天记录VO列表 + */ + PageResult getChatHistory(Long currentUserId, Long targetUserId, ChatHistoryQueryDTO queryDTO); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 2da21b0..a7f668c 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -1,7 +1,9 @@ package com.bao.dating.service.impl; +import com.bao.dating.common.result.PageResult; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.ChatRecords; @@ -9,6 +11,8 @@ import com.bao.dating.pojo.entity.ChatSessions; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; import com.bao.dating.service.UserService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -16,8 +20,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; - - +import java.time.LocalTime; +import java.util.List; +import java.util.stream.Collectors; /** @@ -108,4 +113,58 @@ public class ChatServiceImpl implements ChatService { return vo; } + /** + * 获取聊天记录 + * @param currentUserId 当前用户ID + * @param targetUserId 目标用户ID + * @param queryDTO 查询参数 + * @return 聊天记录列表 + */ + @Override + public PageResult getChatHistory(Long currentUserId, Long targetUserId, ChatHistoryQueryDTO queryDTO) { + Integer page = queryDTO.getPage(); + if (page == null || page < 1) { + page = 1; + } + Integer size = queryDTO.getSize(); + if (size == null || size < 1 || size > 100) { + size = 50; + } + + LocalDateTime startTime = null; + LocalDateTime endTime = null; + if (queryDTO.getDate() != null) { + startTime = queryDTO.getDate().atStartOfDay(); + endTime = queryDTO.getDate().atTime(LocalTime.MAX); + } + + // 分页 + PageHelper.startPage(page, size); + + // 查询 + List recordsList = chatRecordsMapper.selectByUsersAndConditions( + currentUserId, + targetUserId, + queryDTO.getMessageContent(), + startTime, + endTime, + queryDTO.getMessageType() + ); + + // 使用 PageInfo 封装查询结果 + PageInfo pageInfo = new PageInfo<>(recordsList); + + // 转换为 VO + List voList = recordsList.stream() + .map(record -> { + ChatRecordsVO vo = new ChatRecordsVO(); + BeanUtils.copyProperties(record, vo); + return vo; + }) + .collect(Collectors.toList()); + + // 使用 PageInfo 的信息创建 PageResult + return new PageResult<>(pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPageSize(), voList); + } + } diff --git a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml index 91be40d..273a47e 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml @@ -31,4 +31,30 @@ ) + + \ No newline at end of file From 1d179da910c2254099fd2fcc91a7d30c0943c5cc Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 6 Jan 2026 23:38:11 +0800 Subject: [PATCH 05/17] =?UTF-8?q?=E5=B0=86=E6=9F=A5=E8=AF=A2=E5=8E=86?= =?UTF-8?q?=E5=8F=B2=E6=B6=88=E6=81=AF=E4=BF=AE=E6=94=B9=E4=B8=BA=E5=8F=AA?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=B6=88=E6=81=AF=EF=BC=8C=E4=B8=8D=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E5=A4=9A=E4=BD=99=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 17 +++++----- .../bao/dating/mapper/ChatRecordsMapper.java | 10 ++---- .../dating/pojo/dto/ChatHistoryQueryDTO.java | 23 ------------- .../bao/dating/pojo/dto/ChatRecordsDTO.java | 32 ------------------- .../dating/pojo/vo/ChatSessionDetailVO.java | 19 ----------- .../com/bao/dating/service/ChatService.java | 12 +++---- .../dating/service/impl/ChatServiceImpl.java | 27 +++------------- .../bao/dating/mapper/ChatRecordsMapper.xml | 27 +++++----------- 8 files changed, 28 insertions(+), 139 deletions(-) delete mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java delete mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java delete mode 100644 src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 95acbce..b335a60 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -4,15 +4,11 @@ import com.bao.dating.common.Result; import com.bao.dating.common.ResultCode; import com.bao.dating.common.result.PageResult; import com.bao.dating.context.UserContext; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * 聊天控制器 @@ -28,15 +24,18 @@ public class ChatController { /** * 获取聊天记录 * @param targetUserId 目标用户ID - * @param queryDTO 查询参数 - * @return 聊天记录列表 + * @param page 页码 + * @param size 页大小 */ @GetMapping("/history/{targetUserId}") public Result> getChatHistory( @PathVariable Long targetUserId, - ChatHistoryQueryDTO queryDTO){ + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "50") Integer size){ Long currentUserId = UserContext.getUserId(); - PageResult history = chatService.getChatHistory(currentUserId, targetUserId, queryDTO); + PageResult history = chatService.getChatHistory(currentUserId, targetUserId, page, size); return Result.success(ResultCode.SUCCESS, "获取聊天记录成功", history); } + + } diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index 2e37587..ba4d569 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -1,12 +1,10 @@ package com.bao.dating.mapper; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.entity.ChatRecords; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; -import java.time.LocalDateTime; import java.util.List; @Mapper @@ -19,12 +17,8 @@ public interface ChatRecordsMapper { /** * 根据用户ID和接收方用户ID查询聊天记录 */ - List selectByUsersAndConditions( + List selectChatWindowHistory( @Param("currentUserId") Long currentUserId, - @Param("targetUserId") Long targetUserId, - @Param("messageContent") String messageContent, - @Param("startTime") LocalDateTime startTime, - @Param("endTime") LocalDateTime endTime, - @Param("messageType") Integer messageType + @Param("targetUserId") Long targetUserId ); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java deleted file mode 100644 index 96816d6..0000000 --- a/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.bao.dating.pojo.dto; - -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDate; - -/** - * 聊天记录查询参数 - * @author KilLze - */ -@Data -public class ChatHistoryQueryDTO { - private Integer page; - private Integer size; - private Long targetUserId; - private String messageContent; - @JsonFormat(pattern = "yyyy-MM-dd") - @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) - private LocalDate date; - private Integer messageType; -} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java deleted file mode 100644 index dc2d6b8..0000000 --- a/src/main/java/com/bao/dating/pojo/dto/ChatRecordsDTO.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bao.dating.pojo.dto; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 聊天记录数据传输对象 - * @author KilLze - */ -@Data -public class ChatRecordsDTO { - - /** 聊天记录ID */ - private Long chatId; - /** 发送者用户ID */ - private Long senderUserId; - /** 接收者用户ID */ - private Long receiverUserId; - /** 消息内容 */ - private String messageContent; - /** 消息类型 (1-文本消息,2-文件消息) */ - private Integer messageType; - /** 阅读状态 (0-未读,1-已读) */ - private Integer readStatus; - /** 阅读时间 */ - private LocalDateTime readTime; - /** 发送时间 */ - private LocalDateTime sendTime; - /** 消息状态 (1-正常,2-已撤回,3-已删除) */ - private Integer messageStatus; -} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java deleted file mode 100644 index e619a07..0000000 --- a/src/main/java/com/bao/dating/pojo/vo/ChatSessionDetailVO.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bao.dating.pojo.vo; - -import lombok.Data; - -import java.util.List; - -/** - * 聊天会话详情 - * @author KilLze - */ -@Data -public class ChatSessionDetailVO { - - /** 会话信息 */ - private ChatSessionsVO session; - - /** 聊天记录列表 */ - private List records; -} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index c9aa62a..8e84e63 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -1,7 +1,6 @@ package com.bao.dating.service; import com.bao.dating.common.result.PageResult; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; @@ -20,10 +19,11 @@ public interface ChatService { /** * 获取聊天记录 - * @param currentUserId 发送方用户ID - * @param targetUserId 接收方用户ID - * @param queryDTO 查询参数 - * @return 聊天记录VO列表 + * @param currentUserId 当前用户ID + * @param targetUserId 目标用户ID + * @param page 页码 + * @param size 页大小 + * @return 聊天记录列表 */ - PageResult getChatHistory(Long currentUserId, Long targetUserId, ChatHistoryQueryDTO queryDTO); + PageResult getChatHistory(Long currentUserId, Long targetUserId, Integer page, Integer size); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index a7f668c..3b0d073 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -3,7 +3,6 @@ package com.bao.dating.service.impl; import com.bao.dating.common.result.PageResult; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.ChatRecords; @@ -20,7 +19,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; -import java.time.LocalTime; import java.util.List; import java.util.stream.Collectors; @@ -115,41 +113,24 @@ public class ChatServiceImpl implements ChatService { /** * 获取聊天记录 - * @param currentUserId 当前用户ID - * @param targetUserId 目标用户ID - * @param queryDTO 查询参数 * @return 聊天记录列表 */ @Override - public PageResult getChatHistory(Long currentUserId, Long targetUserId, ChatHistoryQueryDTO queryDTO) { - Integer page = queryDTO.getPage(); + public PageResult getChatHistory(Long currentUserId, Long targetUserId, Integer page, Integer size) { + if (page == null || page < 1) { page = 1; } - Integer size = queryDTO.getSize(); if (size == null || size < 1 || size > 100) { size = 50; } - LocalDateTime startTime = null; - LocalDateTime endTime = null; - if (queryDTO.getDate() != null) { - startTime = queryDTO.getDate().atStartOfDay(); - endTime = queryDTO.getDate().atTime(LocalTime.MAX); - } - // 分页 PageHelper.startPage(page, size); // 查询 - List recordsList = chatRecordsMapper.selectByUsersAndConditions( - currentUserId, - targetUserId, - queryDTO.getMessageContent(), - startTime, - endTime, - queryDTO.getMessageType() - ); + List recordsList = + chatRecordsMapper.selectChatWindowHistory(currentUserId, targetUserId); // 使用 PageInfo 封装查询结果 PageInfo pageInfo = new PageInfo<>(recordsList); diff --git a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml index 273a47e..b5a5647 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml @@ -31,30 +31,19 @@ ) - - SELECT chat_id, sender_user_id, receiver_user_id, message_content, message_type, read_status, read_time, send_time, message_status, created_at, updated_at FROM chat_records - WHERE ( + WHERE + message_status = 1 + AND ( (sender_user_id = #{currentUserId} AND receiver_user_id = #{targetUserId}) - OR (sender_user_id = #{targetUserId} AND receiver_user_id = #{currentUserId}) - ) - AND message_status = 1 - - - AND message_content LIKE CONCAT('%', #{messageContent}, '%') - - - AND send_time >= #{startTime} - - - AND send_time <= #{endTime} - - - AND message_type = #{messageType} - + OR + (sender_user_id = #{targetUserId} AND receiver_user_id = #{currentUserId}) + ) ORDER BY send_time DESC \ No newline at end of file From 0bb69075f74c9c1118d6e02d7e2d90995e2ff74a Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 00:47:38 +0800 Subject: [PATCH 06/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E6=B6=88=E6=81=AF=E8=87=AA=E5=8A=A8=E5=B7=B2?= =?UTF-8?q?=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 19 ++++--- .../bao/dating/mapper/ChatRecordsMapper.java | 16 +++++- .../bao/dating/mapper/ChatSessionsMapper.java | 7 +++ .../dating/pojo/dto/ChatCursorPageDTO.java | 21 ++++++++ .../com/bao/dating/service/ChatService.java | 15 +++++- .../dating/service/impl/ChatServiceImpl.java | 53 +++++++++++-------- .../bao/dating/mapper/ChatRecordsMapper.xml | 24 +++++++-- .../bao/dating/mapper/ChatSessionsMapper.xml | 11 ++++ 8 files changed, 132 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index b335a60..8c62c9a 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -4,12 +4,15 @@ import com.bao.dating.common.Result; import com.bao.dating.common.ResultCode; import com.bao.dating.common.result.PageResult; import com.bao.dating.context.UserContext; +import com.bao.dating.pojo.dto.ChatCursorPageDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.List; + /** * 聊天控制器 * @author lenovo @@ -24,16 +27,20 @@ public class ChatController { /** * 获取聊天记录 * @param targetUserId 目标用户ID - * @param page 页码 - * @param size 页大小 + * @param pageDTO 分页参数 + * @return 聊天记录列表 */ @GetMapping("/history/{targetUserId}") - public Result> getChatHistory( + public Result> getChatHistory( @PathVariable Long targetUserId, - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "50") Integer size){ + ChatCursorPageDTO pageDTO){ Long currentUserId = UserContext.getUserId(); - PageResult history = chatService.getChatHistory(currentUserId, targetUserId, page, size); + chatService.markChatMessagesAsRead(currentUserId, targetUserId); + List history = chatService.getChatHistory( + currentUserId, + targetUserId, + pageDTO.getCursor(), + pageDTO.getSize()); return Result.success(ResultCode.SUCCESS, "获取聊天记录成功", history); } diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index ba4d569..b716e5e 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -5,6 +5,7 @@ import com.bao.dating.pojo.entity.ChatRecords; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; @Mapper @@ -17,8 +18,19 @@ public interface ChatRecordsMapper { /** * 根据用户ID和接收方用户ID查询聊天记录 */ - List selectChatWindowHistory( + List selectChatHistoryByCursor( @Param("currentUserId") Long currentUserId, - @Param("targetUserId") Long targetUserId + @Param("targetUserId") Long targetUserId, + @Param("cursor") LocalDateTime cursor, + @Param("size") Integer size + ); + + /** + * 标记消息为已读 + */ + int markMessagesAsRead( + @Param("senderUserId") Long senderUserId, + @Param("receiverUserId") Long receiverUserId, + @Param("readTime") LocalDateTime readTime ); } diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java index 3cc92a5..d32d91e 100644 --- a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -36,4 +36,11 @@ public interface ChatSessionsMapper { */ int updateSessionForReceiver(ChatSessions chatSessions); + /** + * 清空会话未读数 + */ + int clearUnreadCount( + @Param("userId") Long userId, + @Param("targetUserId") Long targetUserId + ); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java new file mode 100644 index 0000000..d50cd35 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java @@ -0,0 +1,21 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Data +public class ChatCursorPageDTO { + + /** + * 时间游标:最后一条消息的发送时间 + */ + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private LocalDateTime cursor; + + /** + * 拉取条数 + */ + private Integer size; +} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index 8e84e63..0f2287b 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -4,6 +4,9 @@ import com.bao.dating.common.result.PageResult; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; +import java.time.LocalDateTime; +import java.util.List; + /** * 聊天服务 * @author lenovo @@ -21,9 +24,17 @@ public interface ChatService { * 获取聊天记录 * @param currentUserId 当前用户ID * @param targetUserId 目标用户ID - * @param page 页码 + * @param cursor 时间游标 * @param size 页大小 * @return 聊天记录列表 */ - PageResult getChatHistory(Long currentUserId, Long targetUserId, Integer page, Integer size); + List getChatHistory(Long currentUserId, Long targetUserId, LocalDateTime cursor, Integer size); + + + /** + * 标记聊天记录为已读 + * @param currentUserId 当前用户ID + * @param targetUserId 目标用户ID + */ + void markChatMessagesAsRead(Long currentUserId, Long targetUserId); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 3b0d073..1f27239 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -19,6 +19,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -116,36 +117,46 @@ public class ChatServiceImpl implements ChatService { * @return 聊天记录列表 */ @Override - public PageResult getChatHistory(Long currentUserId, Long targetUserId, Integer page, Integer size) { + public List getChatHistory(Long currentUserId, Long targetUserId, LocalDateTime cursor, Integer size) { - if (page == null || page < 1) { - page = 1; - } if (size == null || size < 1 || size > 100) { size = 50; } - // 分页 - PageHelper.startPage(page, size); - // 查询 - List recordsList = - chatRecordsMapper.selectChatWindowHistory(currentUserId, targetUserId); + List records = + chatRecordsMapper.selectChatHistoryByCursor( + currentUserId, + targetUserId, + cursor, + size + ); - // 使用 PageInfo 封装查询结果 - PageInfo pageInfo = new PageInfo<>(recordsList); + Collections.reverse(records); - // 转换为 VO - List voList = recordsList.stream() - .map(record -> { - ChatRecordsVO vo = new ChatRecordsVO(); - BeanUtils.copyProperties(record, vo); - return vo; - }) - .collect(Collectors.toList()); + return records.stream().map(record -> { + ChatRecordsVO vo = new ChatRecordsVO(); + BeanUtils.copyProperties(record, vo); + return vo; + }).collect(Collectors.toList()); + } - // 使用 PageInfo 的信息创建 PageResult - return new PageResult<>(pageInfo.getTotal(), pageInfo.getPageNum(), pageInfo.getPageSize(), voList); + @Override + @Transactional(rollbackFor = Exception.class) + public void markChatMessagesAsRead(Long currentUserId, Long targetUserId) { + + // 1. 更新 chat_records:把对方发给我的未读消息设为已读 + chatRecordsMapper.markMessagesAsRead( + targetUserId, + currentUserId, + LocalDateTime.now() + ); + + // 2. 更新 chat_sessions:清空当前会话的未读数 + chatSessionsMapper.clearUnreadCount( + currentUserId, + targetUserId + ); } } diff --git a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml index b5a5647..0238dd8 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml @@ -32,18 +32,36 @@ - SELECT chat_id, sender_user_id, receiver_user_id, message_content, message_type, read_status, read_time, send_time, message_status, created_at, updated_at FROM chat_records WHERE message_status = 1 - AND ( + AND ( (sender_user_id = #{currentUserId} AND receiver_user_id = #{targetUserId}) OR (sender_user_id = #{targetUserId} AND receiver_user_id = #{currentUserId}) - ) + ) + + AND send_time < #{cursor} + ORDER BY send_time DESC + LIMIT #{size} + + + + UPDATE chat_records + SET + read_status = 1, + read_time = #{readTime}, + updated_at = NOW() + WHERE + sender_user_id = #{senderUserId} + AND receiver_user_id = #{receiverUserId} + AND read_status = 0 + AND message_status = 1 + \ No newline at end of file diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml index d3d829c..6ecb9b3 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -59,4 +59,15 @@ AND target_user_id = #{targetUserId} + + + UPDATE chat_sessions + SET + unread_count = 0, + updated_at = NOW() + WHERE + user_id = #{userId} + AND target_user_id = #{targetUserId} + AND session_status = 1 + \ No newline at end of file From 74d47d586f1e84300047fd0eeebf3fc103bf1caf Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 00:49:32 +0800 Subject: [PATCH 07/17] =?UTF-8?q?=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bao/dating/mapper/ChatRecordsMapper.java | 15 +++++++++++++-- .../com/bao/dating/mapper/ChatSessionsMapper.java | 5 ++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index b716e5e..646fe67 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -12,11 +12,18 @@ import java.util.List; public interface ChatRecordsMapper { /** * 插入聊天记录 + * @param chatRecords 聊天记录 + * @return 影响行数 */ int insert(ChatRecords chatRecords); /** - * 根据用户ID和接收方用户ID查询聊天记录 + * 根据时间游标查询聊天记录 + * @param currentUserId 当前用户ID + * @param targetUserId 目标用户ID + * @param cursor 时间游标 + * @param size 页大小 + * @return 聊天记录列表 */ List selectChatHistoryByCursor( @Param("currentUserId") Long currentUserId, @@ -26,7 +33,11 @@ public interface ChatRecordsMapper { ); /** - * 标记消息为已读 + * 标记聊天记录为已读 + * @param senderUserId 发送方用户ID + * @param receiverUserId 接收方用户ID + * @param readTime 已读时间 + * @return 影响行数 */ int markMessagesAsRead( @Param("senderUserId") Long senderUserId, diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java index d32d91e..f0afc7e 100644 --- a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -37,7 +37,10 @@ public interface ChatSessionsMapper { int updateSessionForReceiver(ChatSessions chatSessions); /** - * 清空会话未读数 + * 清空会话的未读数 + * @param userId 用户ID + * @param targetUserId 目标用户ID + * @return 影响行数 */ int clearUnreadCount( @Param("userId") Long userId, From e30a0dba97654d192bee986e9277e01289ffcb59 Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 01:12:28 +0800 Subject: [PATCH 08/17] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 12 ++++--- .../bao/dating/mapper/ChatRecordsMapper.java | 24 ++++---------- .../dating/pojo/dto/ChatCursorPageDTO.java | 4 +++ .../dating/pojo/dto/ChatHistoryQueryDTO.java | 17 ++++++++++ .../bao/dating/pojo/dto/ChatMarkReadDTO.java | 16 +++++++++ .../dating/pojo/dto/ChatSessionCreateDTO.java | 20 ----------- .../dating/pojo/dto/ChatSessionUpdateDTO.java | 23 ------------- .../com/bao/dating/service/ChatService.java | 8 ++--- .../dating/service/impl/ChatServiceImpl.java | 33 +++++++++---------- 9 files changed, 69 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatMarkReadDTO.java delete mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java delete mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 8c62c9a..683d9cd 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -5,6 +5,7 @@ import com.bao.dating.common.ResultCode; import com.bao.dating.common.result.PageResult; import com.bao.dating.context.UserContext; import com.bao.dating.pojo.dto.ChatCursorPageDTO; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; import lombok.extern.slf4j.Slf4j; @@ -35,12 +36,13 @@ public class ChatController { @PathVariable Long targetUserId, ChatCursorPageDTO pageDTO){ Long currentUserId = UserContext.getUserId(); + ChatHistoryQueryDTO queryDTO = new ChatHistoryQueryDTO(); + queryDTO.setCurrentUserId(currentUserId); + queryDTO.setTargetUserId(targetUserId); + queryDTO.setCursor(pageDTO.getCursor()); + queryDTO.setSize(pageDTO.getSize()); chatService.markChatMessagesAsRead(currentUserId, targetUserId); - List history = chatService.getChatHistory( - currentUserId, - targetUserId, - pageDTO.getCursor(), - pageDTO.getSize()); + List history = chatService.getChatHistory(queryDTO); return Result.success(ResultCode.SUCCESS, "获取聊天记录成功", history); } diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index 646fe67..e3a37b0 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -1,6 +1,8 @@ package com.bao.dating.mapper; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; +import com.bao.dating.pojo.dto.ChatMarkReadDTO; import com.bao.dating.pojo.entity.ChatRecords; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -19,29 +21,15 @@ public interface ChatRecordsMapper { /** * 根据时间游标查询聊天记录 - * @param currentUserId 当前用户ID - * @param targetUserId 目标用户ID - * @param cursor 时间游标 - * @param size 页大小 + * @param queryDTO 查询参数 * @return 聊天记录列表 */ - List selectChatHistoryByCursor( - @Param("currentUserId") Long currentUserId, - @Param("targetUserId") Long targetUserId, - @Param("cursor") LocalDateTime cursor, - @Param("size") Integer size - ); + List selectChatHistoryByCursor(ChatHistoryQueryDTO queryDTO); /** * 标记聊天记录为已读 - * @param senderUserId 发送方用户ID - * @param receiverUserId 接收方用户ID - * @param readTime 已读时间 + * @param markReadDTO 标记参数 * @return 影响行数 */ - int markMessagesAsRead( - @Param("senderUserId") Long senderUserId, - @Param("receiverUserId") Long receiverUserId, - @Param("readTime") LocalDateTime readTime - ); + int markMessagesAsRead(ChatMarkReadDTO markReadDTO); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java index d50cd35..08fa92c 100644 --- a/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java +++ b/src/main/java/com/bao/dating/pojo/dto/ChatCursorPageDTO.java @@ -5,6 +5,10 @@ import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +/** + * 聊天记录分页参数 + * @author lenovo + */ @Data public class ChatCursorPageDTO { diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java new file mode 100644 index 0000000..f02b7e3 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatHistoryQueryDTO.java @@ -0,0 +1,17 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 聊天记录查询参数 + * @author KilLze + */ +@Data +public class ChatHistoryQueryDTO { + private Long currentUserId; + private Long targetUserId; + private LocalDateTime cursor; + private Integer size; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatMarkReadDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatMarkReadDTO.java new file mode 100644 index 0000000..5308a68 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatMarkReadDTO.java @@ -0,0 +1,16 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 聊天记录已读参数 + * @author lenovo + */ +@Data +public class ChatMarkReadDTO { + private Long senderUserId; + private Long receiverUserId; + private LocalDateTime readTime; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java deleted file mode 100644 index 51ff00a..0000000 --- a/src/main/java/com/bao/dating/pojo/dto/ChatSessionCreateDTO.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.bao.dating.pojo.dto; - -import lombok.Data; - -/** - * 创建会话数据传输对象 - * @author KilLze - */ -@Data -public class ChatSessionCreateDTO { - - /** 所属用户ID */ - private Long userId; - - /** 目标用户ID */ - private Long targetUserId; - - /** 会话名称 */ - private String sessionName; -} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java deleted file mode 100644 index b020868..0000000 --- a/src/main/java/com/bao/dating/pojo/dto/ChatSessionUpdateDTO.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.bao.dating.pojo.dto; - -import lombok.Data; - -import java.time.LocalDateTime; - -/** - * 会话更新数据传输对象 - * @author KilLze - */ -@Data -public class ChatSessionUpdateDTO { - /** 会话ID */ - private Long sessionId; - /** 最后一条消息ID (关联chat_records.chat_id) */ - private Long lastMessageId; - /** 最后一条消息内容 */ - private String lastMessageContent; - /** 最后一条消息时间 */ - private LocalDateTime lastMessageTime; - /** 未读消息数量 */ - private Integer unreadCount; -} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index 0f2287b..fa11fcd 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -1,6 +1,7 @@ package com.bao.dating.service; import com.bao.dating.common.result.PageResult; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; @@ -22,13 +23,10 @@ public interface ChatService { /** * 获取聊天记录 - * @param currentUserId 当前用户ID - * @param targetUserId 目标用户ID - * @param cursor 时间游标 - * @param size 页大小 + * @param dto 查询参数 * @return 聊天记录列表 */ - List getChatHistory(Long currentUserId, Long targetUserId, LocalDateTime cursor, Integer size); + List getChatHistory(ChatHistoryQueryDTO dto); /** diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 1f27239..5a5d507 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -3,6 +3,8 @@ package com.bao.dating.service.impl; import com.bao.dating.common.result.PageResult; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; +import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; +import com.bao.dating.pojo.dto.ChatMarkReadDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.ChatRecords; @@ -117,21 +119,17 @@ public class ChatServiceImpl implements ChatService { * @return 聊天记录列表 */ @Override - public List getChatHistory(Long currentUserId, Long targetUserId, LocalDateTime cursor, Integer size) { + public List getChatHistory(ChatHistoryQueryDTO dto) { + Integer size = dto.getSize(); if (size == null || size < 1 || size > 100) { - size = 50; + dto.setSize(50); } - // 查询 - List records = - chatRecordsMapper.selectChatHistoryByCursor( - currentUserId, - targetUserId, - cursor, - size - ); + // 查询聊天记录 + List records = chatRecordsMapper.selectChatHistoryByCursor(dto); + // 倒序 Collections.reverse(records); return records.stream().map(record -> { @@ -144,15 +142,16 @@ public class ChatServiceImpl implements ChatService { @Override @Transactional(rollbackFor = Exception.class) public void markChatMessagesAsRead(Long currentUserId, Long targetUserId) { + // 更新 chat_records:把对方发给我的未读消息设为已读 + ChatMarkReadDTO markReadDTO = new ChatMarkReadDTO(); + // 因为读的是对方发给我的消息所以要把填入的参数反过来 + markReadDTO.setSenderUserId(targetUserId); + markReadDTO.setReceiverUserId(currentUserId); + markReadDTO.setReadTime(LocalDateTime.now()); - // 1. 更新 chat_records:把对方发给我的未读消息设为已读 - chatRecordsMapper.markMessagesAsRead( - targetUserId, - currentUserId, - LocalDateTime.now() - ); + chatRecordsMapper.markMessagesAsRead(markReadDTO); - // 2. 更新 chat_sessions:清空当前会话的未读数 + // 更新 chat_sessions:清空当前会话的未读数 chatSessionsMapper.clearUnreadCount( currentUserId, targetUserId From 5e1f3b7e8a125c63639f4cfdbca5bbbfe537358b Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 01:36:23 +0800 Subject: [PATCH 09/17] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/websocket/ChatWebSocketHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java index 07ae197..a0ad6e2 100644 --- a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java +++ b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java @@ -58,7 +58,7 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { return; } // 解析消息 - WsMessage wsMessage = + WsMessage wsMessage = objectMapper.readValue(message.getPayload(), new TypeReference>(){}); From f6769c8c69eb14a1631d0b0d46464dcf01add42b Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 02:58:44 +0800 Subject: [PATCH 10/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 12 ++- .../bao/dating/controller/UserController.java | 5 +- .../bao/dating/mapper/ChatSessionsMapper.java | 32 +++---- .../com/bao/dating/mapper/UserMapper.java | 4 +- ...serInfoUpdateDTO.java => UserInfoDTO.java} | 4 +- .../bao/dating/pojo/dto/UserNicknameDTO.java | 13 --- .../bao/dating/pojo/vo/ChatSessionsVO.java | 6 +- .../com/bao/dating/service/ChatService.java | 8 ++ .../com/bao/dating/service/UserService.java | 9 +- .../dating/service/impl/ChatServiceImpl.java | 45 +++++++--- .../dating/service/impl/UserServiceImpl.java | 12 ++- .../bao/dating/mapper/ChatSessionsMapper.xml | 86 ++++++++----------- 12 files changed, 121 insertions(+), 115 deletions(-) rename src/main/java/com/bao/dating/pojo/dto/{UserInfoUpdateDTO.java => UserInfoDTO.java} (84%) delete mode 100644 src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 683d9cd..51d7799 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -7,6 +7,7 @@ import com.bao.dating.context.UserContext; import com.bao.dating.pojo.dto.ChatCursorPageDTO; import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.pojo.vo.ChatSessionsVO; import com.bao.dating.service.ChatService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -46,5 +47,14 @@ public class ChatController { return Result.success(ResultCode.SUCCESS, "获取聊天记录成功", history); } - + /** + * 获取会话列表 + * @return 会话列表 + */ + @GetMapping("/sessions") + public Result> getSessionList() { + Long currentUserId = UserContext.getUserId(); + List list = chatService.getSessionList(currentUserId); + return Result.success(ResultCode.SUCCESS, "获取会话列表成功", list); + } } diff --git a/src/main/java/com/bao/dating/controller/UserController.java b/src/main/java/com/bao/dating/controller/UserController.java index aad6328..760e554 100644 --- a/src/main/java/com/bao/dating/controller/UserController.java +++ b/src/main/java/com/bao/dating/controller/UserController.java @@ -4,12 +4,11 @@ import com.bao.dating.anno.Log; import com.bao.dating.common.Result; import com.bao.dating.common.ResultCode; import com.bao.dating.context.UserContext; -import com.bao.dating.pojo.dto.UserInfoUpdateDTO; +import com.bao.dating.pojo.dto.UserInfoDTO; import com.bao.dating.pojo.dto.UserLoginDTO; import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserLoginVO; import com.bao.dating.service.UserService; -import io.jsonwebtoken.Jwt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -91,7 +90,7 @@ public class UserController { */ @Log @PostMapping("/info/update") - public Result userInfoUpdate(@RequestBody UserInfoUpdateDTO userInfoUpdateDTO) { + public Result userInfoUpdate(@RequestBody UserInfoDTO userInfoUpdateDTO) { Long userId = UserContext.getUserId(); userInfoUpdateDTO.setUserId(userId); UserInfoVO userInfoVO =userService.updateUserInfo(userInfoUpdateDTO); diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java index f0afc7e..2351070 100644 --- a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -6,35 +6,24 @@ import com.bao.dating.pojo.entity.ChatSessions; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.List; + @Mapper public interface ChatSessionsMapper { + /** - * 如果发送方不存在会话则创建 + * 如果发送方存在会话则更新,不存在则创建 * @param chatSessions 会话 * @return 影响行数 */ - int insertIfNotExistsForSender(ChatSessions chatSessions); + int upsertSessionForSender(ChatSessions chatSessions); /** - * 如果接收方不存在会话则创建 + * 如果接收方存在会话则更新,不存在则创建 * @param chatSessions 会话 * @return 影响行数 */ - int insertIfNotExistsForReceiver(ChatSessions chatSessions); - - /** - * 更新发送方的会话信息 - * @param chatSessions 会话 - * @return 影响行数 - */ - int updateSessionForSender(ChatSessions chatSessions); - - /** - * 更新接收方的会话信息 - * @param chatSessions 会话 - * @return 影响行数 - */ - int updateSessionForReceiver(ChatSessions chatSessions); + int upsertSessionForReceiver(ChatSessions chatSessions); /** * 清空会话的未读数 @@ -46,4 +35,11 @@ public interface ChatSessionsMapper { @Param("userId") Long userId, @Param("targetUserId") Long targetUserId ); + + /** + * 查询当前用户的会话列表 + * @param userId 当前用户ID + * @return 会话列表 + */ + List selectSessionsByUserId(@Param("userId") Long userId); } diff --git a/src/main/java/com/bao/dating/mapper/UserMapper.java b/src/main/java/com/bao/dating/mapper/UserMapper.java index b15f293..8448312 100644 --- a/src/main/java/com/bao/dating/mapper/UserMapper.java +++ b/src/main/java/com/bao/dating/mapper/UserMapper.java @@ -1,6 +1,6 @@ package com.bao.dating.mapper; -import com.bao.dating.pojo.dto.UserInfoUpdateDTO; +import com.bao.dating.pojo.dto.UserInfoDTO; import com.bao.dating.pojo.entity.User; import org.apache.ibatis.annotations.Mapper; @@ -31,6 +31,6 @@ public interface UserMapper { * 更新用户信息 * @param userInfoUpdateDTO 用户信息更新参数 */ - void updateUserInfoByUserId(UserInfoUpdateDTO userInfoUpdateDTO); + void updateUserInfoByUserId(UserInfoDTO userInfoUpdateDTO); } diff --git a/src/main/java/com/bao/dating/pojo/dto/UserInfoUpdateDTO.java b/src/main/java/com/bao/dating/pojo/dto/UserInfoDTO.java similarity index 84% rename from src/main/java/com/bao/dating/pojo/dto/UserInfoUpdateDTO.java rename to src/main/java/com/bao/dating/pojo/dto/UserInfoDTO.java index a3bc0ab..3d11b03 100644 --- a/src/main/java/com/bao/dating/pojo/dto/UserInfoUpdateDTO.java +++ b/src/main/java/com/bao/dating/pojo/dto/UserInfoDTO.java @@ -8,11 +8,11 @@ import java.time.LocalDateTime; import java.util.List; /** - * 用户信息更新数据传输对象 + * 用户信息数据传输对象 * @author KilLze */ @Data -public class UserInfoUpdateDTO implements Serializable { +public class UserInfoDTO implements Serializable { private Long userId; private String userName; private String nickname; diff --git a/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java b/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java deleted file mode 100644 index 8b2afd1..0000000 --- a/src/main/java/com/bao/dating/pojo/dto/UserNicknameDTO.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.bao.dating.pojo.dto; - -import lombok.Data; - -/** - * 用户昵称数据传输对象 - * @author KilLze - */ -@Data -public class UserNicknameDTO { - private Long userId; - private String nickname; -} diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java index 276bfd1..3e28e5b 100644 --- a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java @@ -13,20 +13,18 @@ public class ChatSessionsVO { /** 会话ID */ private Long sessionId; - /** 当前用户ID */ - private Long userId; /** 对方用户ID */ private Long targetUserId; /** 会话名称 */ private String sessionName; + /** 对方用户头像 */ + private String avatarUrl; /** 最后一条消息内容 */ private String lastMessageContent; /** 最后一条消息时间 */ private LocalDateTime lastMessageTime; /** 未读消息数量 */ private Integer unreadCount; - /** 会话状态 */ - private Integer sessionStatus; /** 置顶状态 */ private Integer topStatus; /** 免打扰状态 */ diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index fa11fcd..564000e 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -4,6 +4,7 @@ import com.bao.dating.common.result.PageResult; import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.pojo.vo.ChatSessionsVO; import java.time.LocalDateTime; import java.util.List; @@ -35,4 +36,11 @@ public interface ChatService { * @param targetUserId 目标用户ID */ void markChatMessagesAsRead(Long currentUserId, Long targetUserId); + + /** + * 获取会话列表 + * @param currentUserId 当前用户ID + * @return 会话列表 + */ + List getSessionList(Long currentUserId); } diff --git a/src/main/java/com/bao/dating/service/UserService.java b/src/main/java/com/bao/dating/service/UserService.java index 6b620d2..01c8c1f 100644 --- a/src/main/java/com/bao/dating/service/UserService.java +++ b/src/main/java/com/bao/dating/service/UserService.java @@ -1,8 +1,7 @@ package com.bao.dating.service; -import com.bao.dating.pojo.dto.UserInfoUpdateDTO; +import com.bao.dating.pojo.dto.UserInfoDTO; import com.bao.dating.pojo.dto.UserLoginDTO; -import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserLoginVO; import org.springframework.web.multipart.MultipartFile; @@ -52,12 +51,12 @@ public interface UserService { * @param userInfoUpdateDTO 用户信息 * @return 更新后的用户信息 */ - UserInfoVO updateUserInfo(UserInfoUpdateDTO userInfoUpdateDTO); + UserInfoVO updateUserInfo(UserInfoDTO userInfoUpdateDTO); /** - * 根据用户ID查询用户昵称 + * 根据用户ID查询用户信息 * @param userId 用户ID * @return 用户 */ - UserNicknameDTO getUserNicknameById(Long userId); + UserInfoDTO getUserInfoById(Long userId); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 5a5d507..32d4fec 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -1,19 +1,17 @@ package com.bao.dating.service.impl; -import com.bao.dating.common.result.PageResult; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; import com.bao.dating.pojo.dto.ChatMarkReadDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; -import com.bao.dating.pojo.dto.UserNicknameDTO; +import com.bao.dating.pojo.dto.UserInfoDTO; import com.bao.dating.pojo.entity.ChatRecords; import com.bao.dating.pojo.entity.ChatSessions; import com.bao.dating.pojo.vo.ChatRecordsVO; +import com.bao.dating.pojo.vo.ChatSessionsVO; import com.bao.dating.service.ChatService; import com.bao.dating.service.UserService; -import com.github.pagehelper.PageHelper; -import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -32,7 +30,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class ChatServiceImpl implements ChatService { +public class ChatServiceImpl implements ChatService { @Autowired private ChatRecordsMapper chatRecordsMapper; @@ -63,13 +61,13 @@ public class ChatServiceImpl implements ChatService { // 插入消息记录 chatRecordsMapper.insert(record); - // 创建接收方会话 + // 创建发送方会话 ChatSessions sessions = new ChatSessions(); sessions.setUserId(senderUserId); sessions.setTargetUserId(dto.getReceiverUserId()); // 获取接收方昵称作为发送方会话名称 try { - UserNicknameDTO receiverNicknameInfo = userService.getUserNicknameById(dto.getReceiverUserId()); + UserInfoDTO receiverNicknameInfo = userService.getUserInfoById(dto.getReceiverUserId()); if (receiverNicknameInfo != null && receiverNicknameInfo.getNickname() != null) { sessions.setSessionName(receiverNicknameInfo.getNickname()); } else { @@ -84,14 +82,13 @@ public class ChatServiceImpl implements ChatService { sessions.setLastMessageContent(record.getMessageContent()); sessions.setLastMessageTime(record.getSendTime()); - chatSessionsMapper.insertIfNotExistsForSender(sessions); - chatSessionsMapper.updateSessionForSender(sessions); + chatSessionsMapper.upsertSessionForSender(sessions); // 创建接收方会话 sessions.setUserId(dto.getReceiverUserId()); sessions.setTargetUserId(senderUserId); try { - UserNicknameDTO senderNicknameInfo = userService.getUserNicknameById(senderUserId); + UserInfoDTO senderNicknameInfo = userService.getUserInfoById(senderUserId); if (senderNicknameInfo != null && senderNicknameInfo.getNickname() != null) { sessions.setSessionName(senderNicknameInfo.getNickname()); } else { @@ -103,8 +100,8 @@ public class ChatServiceImpl implements ChatService { sessions.setSessionName("用户" + senderUserId); } - chatSessionsMapper.insertIfNotExistsForReceiver(sessions); - chatSessionsMapper.updateSessionForReceiver(sessions); + chatSessionsMapper.upsertSessionForReceiver(sessions); + @@ -158,4 +155,28 @@ public class ChatServiceImpl implements ChatService { ); } + /** + * 获取会话列表 + * @return 会话列表 + */ + @Override + public List getSessionList(Long currentUserId) { + List sessions = chatSessionsMapper.selectSessionsByUserId(currentUserId); + + return sessions.stream().map(session -> { + ChatSessionsVO vo = new ChatSessionsVO(); + BeanUtils.copyProperties(session, vo); + + UserInfoDTO targetUser = userService.getUserInfoById(session.getTargetUserId()); + if (targetUser != null){ + vo.setSessionName(targetUser.getNickname()); + vo.setAvatarUrl(targetUser.getAvatarUrl()); + }else { + vo.setSessionName("用户" + session.getTargetUserId()); + vo.setAvatarUrl(null); + } + return vo; + }).collect(Collectors.toList()); + } + } diff --git a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java index 7118a08..c0287a3 100644 --- a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java @@ -5,12 +5,10 @@ import com.bao.dating.common.aliyun.GreenImageScan; import com.bao.dating.common.aliyun.GreenTextScan; import com.bao.dating.common.result.AliOssResult; import com.bao.dating.common.result.GreenAuditResult; -import com.bao.dating.config.RedisConfig; import com.bao.dating.context.UserContext; import com.bao.dating.mapper.UserMapper; -import com.bao.dating.pojo.dto.UserInfoUpdateDTO; +import com.bao.dating.pojo.dto.UserInfoDTO; import com.bao.dating.pojo.dto.UserLoginDTO; -import com.bao.dating.pojo.dto.UserNicknameDTO; import com.bao.dating.pojo.entity.User; import com.bao.dating.pojo.vo.UserInfoVO; import com.bao.dating.pojo.vo.UserLoginVO; @@ -232,7 +230,7 @@ public class UserServiceImpl implements UserService { * @param userInfoUpdateDTO 用户信息更新参数 */ @Override - public UserInfoVO updateUserInfo(UserInfoUpdateDTO userInfoUpdateDTO) { + public UserInfoVO updateUserInfo(UserInfoDTO userInfoUpdateDTO) { Long userId = userInfoUpdateDTO.getUserId(); User user = userMapper.selectByUserId(userId); if (user == null) { @@ -314,19 +312,19 @@ public class UserServiceImpl implements UserService { } /** - * 根据用户ID获取用户昵称 + * 根据用户ID获取用户昵称和头像 * * @param userId 用户ID * @return 用户昵称 */ @Override - public UserNicknameDTO getUserNicknameById(Long userId) { + public UserInfoDTO getUserInfoById(Long userId) { // 查询数据库获取昵称 User user = userMapper.selectByUserId(userId); if (user == null) { throw new RuntimeException("没有此用户"); } - UserNicknameDTO dto = new UserNicknameDTO(); + UserInfoDTO dto = new UserInfoDTO(); dto.setUserId(user.getUserId()); dto.setNickname(user.getNickname()); return dto; diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml index 6ecb9b3..015bf04 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -3,61 +3,41 @@ "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - - + + INSERT INTO chat_sessions (user_id, target_user_id, session_name, last_message_id, last_message_content, last_message_time, - unread_count, session_status, top_status, mute_status, created_at, updated_at) - SELECT + unread_count, session_status, top_status, mute_status, created_at, updated_at) + VALUES + ( #{userId}, #{targetUserId}, #{sessionName}, #{lastMessageId}, #{lastMessageContent}, #{lastMessageTime}, 0, 1, 0, 0, NOW(), NOW() - FROM DUAL - WHERE NOT EXISTS ( - SELECT 1 FROM chat_sessions - WHERE user_id = #{userId} AND target_user_id = #{targetUserId} - ); - - - - - INSERT INTO chat_sessions - (user_id, target_user_id, session_name, last_message_id, last_message_content, last_message_time, - unread_count, session_status, top_status, mute_status, created_at, updated_at) - SELECT - #{userId}, #{targetUserId}, #{sessionName}, #{lastMessageId}, #{lastMessageContent}, #{lastMessageTime}, - 0, 1, 0, 0, NOW(), NOW() - FROM DUAL - WHERE NOT EXISTS ( - SELECT 1 FROM chat_sessions - WHERE user_id = #{userId} AND target_user_id = #{targetUserId} ) + ON DUPLICATE KEY UPDATE + last_message_id = VALUES(last_message_id), + last_message_content = VALUES(last_message_content), + last_message_time = VALUES(last_message_time), + unread_count = 0, + updated_at = NOW(); - - - UPDATE chat_sessions - SET - last_message_id = #{lastMessageId}, - last_message_content = #{lastMessageContent}, - last_message_time = #{lastMessageTime}, - unread_count = 0, - updated_at = NOW() - WHERE user_id = #{userId} - AND target_user_id = #{targetUserId}; - - - - - UPDATE chat_sessions - SET - last_message_id = #{lastMessageId}, - last_message_content = #{lastMessageContent}, - last_message_time = #{lastMessageTime}, - unread_count = unread_count + 1, - updated_at = NOW() - WHERE user_id = #{userId} - AND target_user_id = #{targetUserId} - + + + INSERT INTO chat_sessions + (user_id, target_user_id, session_name, last_message_id, last_message_content, last_message_time, + unread_count, session_status, top_status, mute_status, created_at, updated_at) + VALUES + ( + #{userId}, #{targetUserId}, #{sessionName}, #{lastMessageId}, #{lastMessageContent}, #{lastMessageTime}, + 1, 1, 0, 0, NOW(), NOW() + ) + ON DUPLICATE KEY UPDATE + last_message_id = VALUES(last_message_id), + last_message_content = VALUES(last_message_content), + last_message_time = VALUES(last_message_time), + unread_count = unread_count + 1, + updated_at = NOW(); + @@ -70,4 +50,14 @@ AND target_user_id = #{targetUserId} AND session_status = 1 + + + \ No newline at end of file From b6953cb8d0abf108cc19ba384e8bb9fdb725ada0 Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 03:33:34 +0800 Subject: [PATCH 11/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2=E5=B9=B6=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/common/result/ChatSendResult.java | 15 +++++++++++++++ .../com/bao/dating/mapper/ChatSessionsMapper.java | 10 ++++++++++ .../bao/dating/service/impl/ChatServiceImpl.java | 11 +++++++---- .../com/bao/dating/mapper/ChatSessionsMapper.xml | 1 + 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/bao/dating/common/result/ChatSendResult.java diff --git a/src/main/java/com/bao/dating/common/result/ChatSendResult.java b/src/main/java/com/bao/dating/common/result/ChatSendResult.java new file mode 100644 index 0000000..cb694bd --- /dev/null +++ b/src/main/java/com/bao/dating/common/result/ChatSendResult.java @@ -0,0 +1,15 @@ +package com.bao.dating.common.result; + +import com.bao.dating.pojo.vo.ChatRecordsVO; +import lombok.Data; + +/** + * 聊天发送结果 + * @author KilLze + */ +@Data +public class ChatSendResult { + private boolean success; + private String message; + private ChatRecordsVO record; +} diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java index 2351070..ed53feb 100644 --- a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -5,6 +5,7 @@ import com.bao.dating.pojo.entity.ChatRecords; import com.bao.dating.pojo.entity.ChatSessions; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import java.util.List; @@ -18,6 +19,15 @@ public interface ChatSessionsMapper { */ int upsertSessionForSender(ChatSessions chatSessions); + /** + * 获取会话 + * @param userId 用户ID + * @param targetUserId 目标用户ID + * @return 会话 + */ + @Select("SELECT * FROM chat_sessions WHERE user_id = #{userId} AND target_user_id = #{targetUserId} LIMIT 1") + ChatSessions getSession(@Param("userId") Long userId, @Param("targetUserId") Long targetUserId); + /** * 如果接收方存在会话则更新,不存在则创建 * @param chatSessions 会话 diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 32d4fec..2347d18 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -30,7 +30,7 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class ChatServiceImpl implements ChatService { +public class ChatServiceImpl implements ChatService { @Autowired private ChatRecordsMapper chatRecordsMapper; @@ -49,6 +49,12 @@ public class ChatServiceImpl implements ChatService { @Override @Transactional(rollbackFor = Exception.class) public ChatRecordsVO createSession(Long senderUserId, ChatRecordSendDTO dto) { + + ChatSessions session = chatSessionsMapper.getSession(senderUserId, dto.getReceiverUserId()); + if (session != null && session.getSessionStatus() == 3) { + throw new RuntimeException("会话已删除,无法发送消息"); + } + ChatRecords record = new ChatRecords(); record.setSenderUserId(senderUserId); record.setReceiverUserId(dto.getReceiverUserId()); @@ -102,9 +108,6 @@ public class ChatServiceImpl implements ChatService { chatSessionsMapper.upsertSessionForReceiver(sessions); - - - // 3. 返回 VO ChatRecordsVO vo = new ChatRecordsVO(); BeanUtils.copyProperties(record, vo); diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml index 015bf04..2e73961 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -58,6 +58,7 @@ FROM chat_sessions WHERE user_id = #{userId} AND session_status = 1 + AND session_status in (1,2) ORDER BY top_status DESC, last_message_time DESC \ No newline at end of file From 21c0a94a5d9d1635d9dce2749ef6eaad8ce65439 Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 03:43:33 +0800 Subject: [PATCH 12/17] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=EF=BC=8C=E5=BD=93=E5=AF=B9=E5=88=A0=E9=99=A4=E7=9A=84=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E5=8F=91=E9=80=81=E4=BF=A1=E6=81=AF=E6=97=B6=E8=BF=94?= =?UTF-8?q?=E5=9B=9Eerror?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/websocket/ChatWebSocketHandler.java | 12 +++++++++--- .../com/bao/dating/service/impl/ChatServiceImpl.java | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java index a0ad6e2..3624643 100644 --- a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java +++ b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java @@ -64,18 +64,24 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { // 处理私聊消息 if ("chat".equals(wsMessage.getType())) { - handlePrivateChat(senderUserId, wsMessage.getData()); + handlePrivateChat(session, senderUserId, wsMessage.getData()); } } /** * 私聊处理 */ - private void handlePrivateChat(Long senderUserId, ChatRecordSendDTO dto) throws Exception { + private void handlePrivateChat(WebSocketSession session, Long senderUserId, ChatRecordSendDTO dto) throws Exception { // 1. 消息入库 + 会话更新 ChatRecordsVO chatRecordsVO = chatService.createSession(senderUserId, dto); - + if (chatRecordsVO == null){ + WsMessage errorMsg = new WsMessage<>(); + errorMsg.setType("error"); + errorMsg.setData("会话已删除,无法发送消息"); + session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMsg))); + return; + } // 2. 推送给接收方 WebSocketSession receiverSession = sessionManager.getSession(dto.getReceiverUserId()); diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 2347d18..85be330 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -52,7 +52,8 @@ public class ChatServiceImpl implements ChatService { ChatSessions session = chatSessionsMapper.getSession(senderUserId, dto.getReceiverUserId()); if (session != null && session.getSessionStatus() == 3) { - throw new RuntimeException("会话已删除,无法发送消息"); + log.warn("会话已删除,无法发送消息"); + return null; } ChatRecords record = new ChatRecords(); From 0a1425c7abea38ed407d219c0d9b7bfaafa11d96 Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 22:59:46 +0800 Subject: [PATCH 13/17] =?UTF-8?q?Ciallo=EF=BD=9E(=E2=88=A0=C2=B7=CF=89<=20?= =?UTF-8?q?)=E2=8C=92=E2=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bao/dating/DatingApplication.java | 23 ++++++++++++++++++- .../websocket/ChatWebSocketHandler.java | 10 ++++---- src/main/resources/ciallo.txt | 9 ++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 src/main/resources/ciallo.txt diff --git a/src/main/java/com/bao/dating/DatingApplication.java b/src/main/java/com/bao/dating/DatingApplication.java index 6295922..c092e78 100644 --- a/src/main/java/com/bao/dating/DatingApplication.java +++ b/src/main/java/com/bao/dating/DatingApplication.java @@ -4,11 +4,32 @@ import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + @MapperScan("com.bao.dating.mapper") @SpringBootApplication public class DatingApplication { public static void main(String[] args) { SpringApplication.run(DatingApplication.class, args); + // 读取并打印 ciallo.txt 文件内容 + printCialloFile(); } -} + /** + * 读取并打印 ciallo.txt 文件内容 + */ + private static void printCialloFile() { + try (InputStream inputStream = DatingApplication.class.getClassLoader().getResourceAsStream("ciallo.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + } catch (IOException e) { + System.err.println("读取 ciallo.txt 文件时发生错误: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java index 3624643..e8afa10 100644 --- a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java +++ b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java @@ -35,7 +35,7 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { /** * 用户建立连接(上线) - * @param session + * @param session WebSocketSession */ @Override public void afterConnectionEstablished(WebSocketSession session) { @@ -46,8 +46,8 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { /** * 接收并处理消息 - * @param session - * @param message + * @param session WebSocketSession + * @param message 消息 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception{ @@ -100,8 +100,8 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { /** * 用户断开连接(下线) - * @param session - * @param status + * @param session WebSocketSession + * @param status 断开原因 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status){ diff --git a/src/main/resources/ciallo.txt b/src/main/resources/ciallo.txt new file mode 100644 index 0000000..76ee823 --- /dev/null +++ b/src/main/resources/ciallo.txt @@ -0,0 +1,9 @@ + + ▄▄▄▄ ██ ▄▄▄▄ ▄▄▄▄ ▄▄ ▄▄ + ██▀▀▀▀█ ▀▀ ▀▀██ ▀▀██ ██ ▄▄ ██ + ██▀ ████ ▄█████▄ ██ ██ ▄████▄ ▄▄▄ ▄█▀ ▄█▀ ██ █▄ ▄▄▄█ ▀█▄ ▄▄▄▄ + ██ ██ ▀ ▄▄▄██ ██ ██ ██▀ ▀██ ▀ ▀▀▄▄ ▄ ██ ▄█▀ ██ ██ ██ ▄▄█▀▀▀ ██ █▀▀ ▀█▄ █▄ + ██▄ ██ ▄██▀▀▀██ ██ ██ ██ ██ ▀▀▀ ██ ▄█▄▄▄▄▄ ▀▀ ██ ██ ██ ▀▀█▄▄▄ ██ █▀ █ ▀▀████▀ + ██▄▄▄▄█ ▄▄▄██▄▄▄ ██▄▄▄███ ██▄▄▄ ██▄▄▄ ▀██▄▄██▀ ▀█▄ ▀▀▀▀▀▀▀▀ ██▄██▄██ ▀▀▀█ ▄█▀ █▀▀█ + ▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀▀▀ ▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ██ ▀▀▀ ▀▀▀ ██ + ▀▀ ▀▀ From a4e66b39d12d079ba7b3b984a63477afaa21e45f Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 7 Jan 2026 23:35:49 +0800 Subject: [PATCH 14/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0=E3=80=81=E7=BD=AE=E9=A1=B6?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0=E3=80=81=E5=85=8D=E6=89=93?= =?UTF-8?q?=E6=89=B0=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 36 ++++++++++++++- .../bao/dating/mapper/ChatSessionsMapper.java | 33 +++++++++++++ .../dating/pojo/dto/ChatSessionMuteDTO.java | 13 ++++++ .../dating/pojo/dto/ChatSessionStatusDTO.java | 13 ++++++ .../dating/pojo/dto/ChatSessionTopDTO.java | 13 ++++++ .../com/bao/dating/service/ChatService.java | 24 +++++++++- .../dating/service/impl/ChatServiceImpl.java | 46 +++++++++++++++++-- .../bao/dating/mapper/ChatSessionsMapper.xml | 28 +++++++++++ 8 files changed, 198 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionMuteDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionStatusDTO.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatSessionTopDTO.java diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 51d7799..0466ecc 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -4,8 +4,7 @@ import com.bao.dating.common.Result; import com.bao.dating.common.ResultCode; import com.bao.dating.common.result.PageResult; import com.bao.dating.context.UserContext; -import com.bao.dating.pojo.dto.ChatCursorPageDTO; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; +import com.bao.dating.pojo.dto.*; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.pojo.vo.ChatSessionsVO; import com.bao.dating.service.ChatService; @@ -57,4 +56,37 @@ public class ChatController { List list = chatService.getSessionList(currentUserId); return Result.success(ResultCode.SUCCESS, "获取会话列表成功", list); } + + /** + * 更新会话状态 + * @param dto 会话状态 + * @return 无 + */ + @PostMapping("/session/status") + public Result updateSessionStatus(@RequestBody ChatSessionStatusDTO dto) { + chatService.updateSessionStatus(UserContext.getUserId(), dto); + return Result.success(ResultCode.SUCCESS, null); + } + + /** + * 置顶会话 + * @param dto 置顶状态 + * @return 无 + */ + @PostMapping("/session/top") + public Result updateTopStatus(@RequestBody ChatSessionTopDTO dto) { + chatService.updateTopStatus(UserContext.getUserId(), dto); + return Result.success(ResultCode.SUCCESS, null); + } + + /** + * 静音会话 + * @param dto 静音状态 + * @return 无 + */ + @PostMapping("/session/mute") + public Result updateMuteStatus(@RequestBody ChatSessionMuteDTO dto) { + chatService.updateMuteStatus(UserContext.getUserId(), dto); + return Result.success(ResultCode.SUCCESS, null); + } } diff --git a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java index ed53feb..5647550 100644 --- a/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatSessionsMapper.java @@ -52,4 +52,37 @@ public interface ChatSessionsMapper { * @return 会话列表 */ List selectSessionsByUserId(@Param("userId") Long userId); + + /** + * 更新会话状态 + * @param userId 用户ID + * @param targetUserId 目标用户ID + * @param sessionStatus 会话状态 + * @return 影响行数 + */ + int updateSessionStatus(@Param("userId") Long userId, + @Param("targetUserId") Long targetUserId, + @Param("sessionStatus") Integer sessionStatus); + + /** + * 更新会话置顶状态 + * @param userId 用户ID + * @param targetUserId 目标用户ID + * @param topStatus 置顶状态 + * @return 影响行数 + */ + int updateTopStatus(@Param("userId") Long userId, + @Param("targetUserId") Long targetUserId, + @Param("topStatus") Integer topStatus); + + /** + * 更新会话免打扰状态 + * @param userId 用户ID + * @param targetUserId 目标用户ID + * @param muteStatus 免打扰状态 + * @return 影响行数 + */ + int updateMuteStatus(@Param("userId") Long userId, + @Param("targetUserId") Long targetUserId, + @Param("muteStatus") Integer muteStatus); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionMuteDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionMuteDTO.java new file mode 100644 index 0000000..b932220 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatSessionMuteDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 聊天会话静音参数 + * @author lenovo + */ +@Data +public class ChatSessionMuteDTO { + private Long targetUserId; + private Integer muteStatus; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionStatusDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionStatusDTO.java new file mode 100644 index 0000000..b637c39 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatSessionStatusDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 会话状态参数 + * @author lenovo + */ +@Data +public class ChatSessionStatusDTO { + private Long targetUserId; + private Integer sessionStatus; +} diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatSessionTopDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatSessionTopDTO.java new file mode 100644 index 0000000..2cbdf18 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatSessionTopDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 会话置顶参数 + * @author lenovo + */ +@Data +public class ChatSessionTopDTO { + private Long targetUserId; + private Integer topStatus; +} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index 564000e..9b47425 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -1,8 +1,7 @@ package com.bao.dating.service; import com.bao.dating.common.result.PageResult; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; -import com.bao.dating.pojo.dto.ChatRecordSendDTO; +import com.bao.dating.pojo.dto.*; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.pojo.vo.ChatSessionsVO; @@ -43,4 +42,25 @@ public interface ChatService { * @return 会话列表 */ List getSessionList(Long currentUserId); + + /** + * 更新会话状态 + * @param userId 用户ID + * @param dto 更新参数 + */ + void updateSessionStatus(Long userId, ChatSessionStatusDTO dto); + + /** + * 置顶会话 + * @param userId 用户ID + * @param dto 置顶参数 + */ + void updateTopStatus(Long userId, ChatSessionTopDTO dto); + + /** + * 免打扰会话 + * @param userId 用户ID + * @param dto 免打扰参数 + */ + void updateMuteStatus(Long userId, ChatSessionMuteDTO dto); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 85be330..93e5f0e 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -2,10 +2,7 @@ package com.bao.dating.service.impl; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; -import com.bao.dating.pojo.dto.ChatHistoryQueryDTO; -import com.bao.dating.pojo.dto.ChatMarkReadDTO; -import com.bao.dating.pojo.dto.ChatRecordSendDTO; -import com.bao.dating.pojo.dto.UserInfoDTO; +import com.bao.dating.pojo.dto.*; import com.bao.dating.pojo.entity.ChatRecords; import com.bao.dating.pojo.entity.ChatSessions; import com.bao.dating.pojo.vo.ChatRecordsVO; @@ -183,4 +180,45 @@ public class ChatServiceImpl implements ChatService { }).collect(Collectors.toList()); } + /** + * 更新会话状态 + * @param userId 用户ID + * @param dto 会话状态 + */ + @Override + public void updateSessionStatus(Long userId, ChatSessionStatusDTO dto) { + chatSessionsMapper.updateSessionStatus( + userId, + dto.getTargetUserId(), + dto.getSessionStatus() + ); + } + + /** + * 置顶会话 + * @param userId 用户ID + * @param dto 置顶状态 + */ + @Override + public void updateTopStatus(Long userId, ChatSessionTopDTO dto) { + chatSessionsMapper.updateTopStatus( + userId, + dto.getTargetUserId(), + dto.getTopStatus() + ); + } + + /** + * 免打扰会话 + * @param userId 用户ID + * @param dto 免打扰状态 + */ + @Override + public void updateMuteStatus(Long userId, ChatSessionMuteDTO dto) { + chatSessionsMapper.updateMuteStatus( + userId, + dto.getTargetUserId(), + dto.getMuteStatus() + ); + } } diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml index 2e73961..79bb6a9 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -61,4 +61,32 @@ AND session_status in (1,2) ORDER BY top_status DESC, last_message_time DESC + + + + UPDATE chat_sessions + SET session_status = #{sessionStatus}, + updated_at = NOW() + WHERE user_id = #{userId} + AND target_user_id = #{targetUserId} + + + + + UPDATE chat_sessions + SET top_status = #{topStatus}, + updated_at = NOW() + WHERE user_id = #{userId} + AND target_user_id = #{targetUserId} + + + + + UPDATE chat_sessions + SET mute_status = #{muteStatus}, + updated_at = NOW() + WHERE user_id = #{userId} + AND target_user_id = #{targetUserId} + + \ No newline at end of file From 448ce1d3d605c51a3fcd613f8b445689b8c5d4b0 Mon Sep 17 00:00:00 2001 From: KilLze Date: Thu, 8 Jan 2026 00:06:10 +0800 Subject: [PATCH 15/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=8A=E4=BC=A0OSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/ChatController.java | 12 ++++ .../com/bao/dating/service/ChatService.java | 8 +++ .../dating/service/impl/ChatServiceImpl.java | 56 +++++++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/src/main/java/com/bao/dating/controller/ChatController.java b/src/main/java/com/bao/dating/controller/ChatController.java index 0466ecc..56ae9c4 100644 --- a/src/main/java/com/bao/dating/controller/ChatController.java +++ b/src/main/java/com/bao/dating/controller/ChatController.java @@ -11,6 +11,7 @@ import com.bao.dating.service.ChatService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -25,6 +26,17 @@ public class ChatController { @Autowired private ChatService chatService; + /** + * 上传文件 + * @param file 文件 + * @return 文件URL + */ + @PostMapping("/upload") + public Result uploadVideo(@RequestParam MultipartFile file) { + String url = chatService.uploadChat(file); + return Result.success(ResultCode.SUCCESS, "文件上传成功", url); + } + /** * 获取聊天记录 * @param targetUserId 目标用户ID diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index 9b47425..5a7dc28 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -4,6 +4,7 @@ import com.bao.dating.common.result.PageResult; import com.bao.dating.pojo.dto.*; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.pojo.vo.ChatSessionsVO; +import org.springframework.web.multipart.MultipartFile; import java.time.LocalDateTime; import java.util.List; @@ -21,6 +22,13 @@ public interface ChatService { */ ChatRecordsVO createSession(Long senderUserId, ChatRecordSendDTO dto); + /** + * 上传媒体文件 + * @param file 文件 + * @return 文件URL列表 + */ + String uploadChat(MultipartFile file); + /** * 获取聊天记录 * @param dto 查询参数 diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 93e5f0e..bdfa589 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -1,5 +1,8 @@ package com.bao.dating.service.impl; +import com.bao.dating.common.aliyun.AliOssUtil; +import com.bao.dating.common.result.AliOssResult; +import com.bao.dating.context.UserContext; import com.bao.dating.mapper.ChatRecordsMapper; import com.bao.dating.mapper.ChatSessionsMapper; import com.bao.dating.pojo.dto.*; @@ -9,15 +12,22 @@ import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.pojo.vo.ChatSessionsVO; import com.bao.dating.service.ChatService; import com.bao.dating.service.UserService; +import com.bao.dating.util.FileUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; @@ -34,6 +44,9 @@ public class ChatServiceImpl implements ChatService { @Autowired private ChatSessionsMapper chatSessionsMapper; + @Autowired + private AliOssUtil ossUtil; + @Autowired private UserService userService; @@ -112,6 +125,49 @@ public class ChatServiceImpl implements ChatService { return vo; } + /** + * 上传媒体文件 + * @return 上传后的文件URL + */ + @Override + public String uploadChat(MultipartFile file) { + // 参数校验 + if (file == null || file.isEmpty()) { + throw new RuntimeException("文件不存在"); + } + + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null) { + throw new RuntimeException("文件名非法"); + } + + String fileType = FileUtil.getFileType(originalFilename); + // 仅支持图片和视频文件上传 + if (!AliOssResult.IMAGE.equals(fileType) && !AliOssResult.VIDEO.equals(fileType)) { + throw new RuntimeException("仅支持图片和视频文件上传"); + } + + //生成 OSS 路径 + String extension = FileUtil.getFileExtension(originalFilename); + String fileName = UUID.randomUUID().toString().replace("-", "") + "." + extension; + Long userId = UserContext.getUserId(); + String objectKey = "chat/" + userId + "/" + fileName; + + try { + byte[] fileBytes = file.getBytes(); + String ossUrl = ossUtil.upload(fileBytes, objectKey); + + if (ossUrl == null || ossUrl.isEmpty()) { + throw new RuntimeException("图片上传失败"); + } + + return ossUrl; + + } catch (Exception e) { + throw new RuntimeException("上传图片失败", e); + } + } + /** * 获取聊天记录 * @return 聊天记录列表 From 0a17eb8debe5d6fae749099828c07cb3d29c3f22 Mon Sep 17 00:00:00 2001 From: KilLze Date: Thu, 8 Jan 2026 00:07:25 +0800 Subject: [PATCH 16/17] =?UTF-8?q?=E7=AE=80=E5=8D=95=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/bao/dating/controller/PostController.java | 4 ---- src/main/java/com/bao/dating/controller/UserController.java | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/main/java/com/bao/dating/controller/PostController.java b/src/main/java/com/bao/dating/controller/PostController.java index b4fb20b..799e9eb 100644 --- a/src/main/java/com/bao/dating/controller/PostController.java +++ b/src/main/java/com/bao/dating/controller/PostController.java @@ -31,7 +31,6 @@ public class PostController { * @param files 媒体文件数组 * @return 上传后的文件URL列表 */ - @Log @PostMapping(value = "/upload", consumes = "multipart/form-data") public Result> uploadMedia(@RequestParam("files") MultipartFile[] files) { List fileUrls = postService.uploadMedia(files); @@ -43,7 +42,6 @@ public class PostController { * @param postDTO 动态信息 * @return 发布的动态对象 */ - @Log @PostMapping( "/createPost") public Result createPostJson(@RequestBody PostRequestDTO postDTO) { // 调用 Service 层处理发布动态业务逻辑 @@ -57,7 +55,6 @@ public class PostController { * @param postIds 动态ID * @return 删除结果 */ - @Log @PostMapping("/deletePost") public Result deleteById(@RequestBody List postIds){ int deletedCount = postService.deletePostById(postIds); @@ -81,7 +78,6 @@ public class PostController { * @param postRequestDTO 动态信息 * @return 更新后的动态对象 */ - @Log @PostMapping("/{postId}/updatePost") public Result updatePost(@PathVariable Long postId, @RequestBody PostRequestDTO postRequestDTO) { PostEditVO result = postService.updatePost(postId, postRequestDTO); diff --git a/src/main/java/com/bao/dating/controller/UserController.java b/src/main/java/com/bao/dating/controller/UserController.java index 760e554..1494467 100644 --- a/src/main/java/com/bao/dating/controller/UserController.java +++ b/src/main/java/com/bao/dating/controller/UserController.java @@ -64,7 +64,6 @@ public class UserController { * @param file 头像文件 * @return 上传后的文件URL列表 */ - @Log @PostMapping(value = "/info/uploadAvatar", consumes = "multipart/form-data") public Result uploadAvatar(@RequestParam("file") MultipartFile file) { String fileUrl = userService.uploadAvatar(file); @@ -76,7 +75,6 @@ public class UserController { * @param file 背景文件 * @return 上传后的文件URL列表 */ - @Log @PostMapping(value = "/info/uploadBackground", consumes = "multipart/form-data") public Result uploadBackground(@RequestParam("file") MultipartFile file) { String fileUrl = userService.uploadBackground(file); @@ -88,7 +86,6 @@ public class UserController { * @param userInfoUpdateDTO 用户信息更新参数 * @return 更新后的用户信息 */ - @Log @PostMapping("/info/update") public Result userInfoUpdate(@RequestBody UserInfoDTO userInfoUpdateDTO) { Long userId = UserContext.getUserId(); From cf6f9b8b7c2f38add571331d9f31543c8af23f57 Mon Sep 17 00:00:00 2001 From: KilLze Date: Thu, 8 Jan 2026 01:20:11 +0800 Subject: [PATCH 17/17] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=92=A4=E5=9B=9E=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../websocket/ChatWebSocketHandler.java | 66 +++++++++++++++++-- .../bao/dating/mapper/ChatRecordsMapper.java | 16 +++++ .../bao/dating/pojo/dto/ChatRecallDTO.java | 13 ++++ .../com/bao/dating/service/ChatService.java | 8 +++ .../dating/service/impl/ChatServiceImpl.java | 45 +++++++++++++ .../bao/dating/mapper/ChatRecordsMapper.xml | 25 +++++++ .../bao/dating/mapper/ChatSessionsMapper.xml | 1 - 7 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/bao/dating/pojo/dto/ChatRecallDTO.java diff --git a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java index e8afa10..ed8cc43 100644 --- a/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java +++ b/src/main/java/com/bao/dating/controller/websocket/ChatWebSocketHandler.java @@ -1,11 +1,13 @@ package com.bao.dating.controller.websocket; import com.bao.dating.message.WsMessage; +import com.bao.dating.pojo.dto.ChatRecallDTO; import com.bao.dating.pojo.dto.ChatRecordSendDTO; import com.bao.dating.pojo.vo.ChatRecordsVO; import com.bao.dating.service.ChatService; import com.bao.dating.session.WsSessionManager; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -57,14 +59,23 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { log.error("WebSocket session 中未找到 userId"); return; } - // 解析消息 - WsMessage wsMessage = - objectMapper.readValue(message.getPayload(), - new TypeReference>(){}); - // 处理私聊消息 - if ("chat".equals(wsMessage.getType())) { - handlePrivateChat(session, senderUserId, wsMessage.getData()); + JsonNode node = objectMapper.readTree(message.getPayload()); + String type = node.get("type").asText(); + // 根据消息类型解析消息 + WsMessage wsMessage = objectMapper.readValue(message.getPayload(), WsMessage.class); + + // 先获取消息类型,再根据类型进行相应处理和转换 + if ("chat".equals(type)) { + // 处理私聊消息 + WsMessage chatWsMessage = + objectMapper.convertValue(node, new TypeReference>(){}); + handlePrivateChat(session, senderUserId, chatWsMessage.getData()); + } else if ("recall".equals(type)) { + // 处理撤回消息 + WsMessage recallWsMessage = + objectMapper.convertValue(node, new TypeReference>(){}); + handleRecallMessage(session, senderUserId, recallWsMessage.getData()); } } @@ -79,6 +90,7 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { WsMessage errorMsg = new WsMessage<>(); errorMsg.setType("error"); errorMsg.setData("会话已删除,无法发送消息"); + // 返回错误信息 session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMsg))); return; } @@ -97,6 +109,46 @@ public class ChatWebSocketHandler extends TextWebSocketHandler { } } + /** + * 消息撤回处理 + */ + private void handleRecallMessage(WebSocketSession session, Long senderUserId, Object data) throws Exception { + + // 转 DTO + ChatRecallDTO dto = objectMapper.convertValue(data, ChatRecallDTO.class); + + // 撤回逻辑 + boolean success = chatService.recallMessage(senderUserId, dto.getChatId()); + // 如果返回false,说明消息撤回失败 + if (!success) { + WsMessage errorMsg = new WsMessage<>(); + errorMsg.setType("error"); + errorMsg.setData("撤回失败,消息可能无法撤回或不存在"); + // 返回错误信息 + session.sendMessage(new TextMessage(objectMapper.writeValueAsString(errorMsg))); + return; + } + + // 创建撤回通知消息 + WsMessage pushMsg = new WsMessage<>(); + pushMsg.setType("recall"); + pushMsg.setData(dto); + + // 通知自己 + if (session.isOpen()) { + session.sendMessage(new TextMessage(objectMapper.writeValueAsString(pushMsg))); + } + + // 通知对方 + WebSocketSession receiverSession = + sessionManager.getSession(dto.getReceiverUserId()); + + if (receiverSession != null && receiverSession.isOpen()) { + receiverSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(pushMsg)) + ); + } + } + /** * 用户断开连接(下线) diff --git a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java index e3a37b0..630b5a6 100644 --- a/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java +++ b/src/main/java/com/bao/dating/mapper/ChatRecordsMapper.java @@ -32,4 +32,20 @@ public interface ChatRecordsMapper { * @return 影响行数 */ int markMessagesAsRead(ChatMarkReadDTO markReadDTO); + + /** + * 根据ID查询聊天记录 + * @param chatId 聊天记录ID + * @return 聊天记录 + */ + ChatRecords selectById(@Param("chatId") Long chatId); + + /** + * 撤回聊天记录 + * @param chatId 聊天记录ID + * @param senderUserId 发送者ID + * @return 影响行数 + */ + int recallMessage(@Param("chatId") Long chatId, + @Param("senderUserId") Long senderUserId); } diff --git a/src/main/java/com/bao/dating/pojo/dto/ChatRecallDTO.java b/src/main/java/com/bao/dating/pojo/dto/ChatRecallDTO.java new file mode 100644 index 0000000..12cfb1d --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/ChatRecallDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; + +import lombok.Data; + +/** + * 聊天记录撤回参数 + * @author lenovo + */ +@Data +public class ChatRecallDTO { + private Long chatId; + private Long receiverUserId; +} diff --git a/src/main/java/com/bao/dating/service/ChatService.java b/src/main/java/com/bao/dating/service/ChatService.java index 5a7dc28..8cc4cf1 100644 --- a/src/main/java/com/bao/dating/service/ChatService.java +++ b/src/main/java/com/bao/dating/service/ChatService.java @@ -71,4 +71,12 @@ public interface ChatService { * @param dto 免打扰参数 */ void updateMuteStatus(Long userId, ChatSessionMuteDTO dto); + + /** + * 撤回消息 + * @param senderUserId 发送方ID + * @param chatId 聊天记录ID + * @return 撤回结果 + */ + boolean recallMessage(Long senderUserId, Long chatId); } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index bdfa589..517eb9c 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -21,6 +21,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -193,6 +194,9 @@ public class ChatServiceImpl implements ChatService { }).collect(Collectors.toList()); } + /** + * 标记聊天消息为已读 + */ @Override @Transactional(rollbackFor = Exception.class) public void markChatMessagesAsRead(Long currentUserId, Long targetUserId) { @@ -277,4 +281,45 @@ public class ChatServiceImpl implements ChatService { dto.getMuteStatus() ); } + + + /** + * 撤回消息 + * @param senderUserId 发送者用户ID + * @param chatId 聊天记录ID + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean recallMessage(Long senderUserId, Long chatId) { + + // 查询聊天记录 + ChatRecords record = chatRecordsMapper.selectById(chatId); + // 消息不存在 + if (record == null) { + log.info("消息不存在,chatId: {}", chatId); + return false; + } + + // 只能撤回自己发的 + if (!record.getSenderUserId().equals(senderUserId)) { + log.info("不能撤回别人发的消息,chatId: {},当前用户: {},消息发送者: {}", chatId, senderUserId, record.getSenderUserId()); + return false; + } + + // 已撤回或已删除 + if (record.getMessageStatus() != 1) { + log.info("消息已撤回或已删除,chatId: {},当前状态: {}", chatId, record.getMessageStatus()); + return false; + } + + // 时间限制(2 分钟) + Duration duration = Duration.between(record.getSendTime(), LocalDateTime.now()); + if (duration.toMinutes() > 2) { + log.info("消息已超过 2 分钟,不能撤回,chatId: {},发送时间: {}", chatId, record.getSendTime()); + return false; + } + + return chatRecordsMapper.recallMessage(chatId, senderUserId) > 0; + } } diff --git a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml index 0238dd8..5d3ddda 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatRecordsMapper.xml @@ -64,4 +64,29 @@ AND read_status = 0 AND message_status = 1 + + + + + + + UPDATE chat_records + SET + message_status = 2, + updated_at = NOW() + WHERE + chat_id = #{chatId} + AND sender_user_id = #{senderUserId} + AND message_status = 1 + + \ No newline at end of file diff --git a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml index 79bb6a9..1688893 100644 --- a/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml +++ b/src/main/resources/com/bao/dating/mapper/ChatSessionsMapper.xml @@ -57,7 +57,6 @@ last_message_time, unread_count, top_status, mute_status FROM chat_sessions WHERE user_id = #{userId} - AND session_status = 1 AND session_status in (1,2) ORDER BY top_status DESC, last_message_time DESC