diff --git a/docs/txt/0509TODO.txt b/docs/txt/0509TODO.txt index c3b9d29..db40120 100644 --- a/docs/txt/0509TODO.txt +++ b/docs/txt/0509TODO.txt @@ -1,3 +1 @@ -进度表 - webChat diff --git a/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java b/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java index e98d656..fb0879c 100644 --- a/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java +++ b/src/main/java/com/guwan/backend/config/MybatisPlusConfig.java @@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; -import com.guwan.backend.Handler.MyMetaObjectHandler; +import com.guwan.backend.handler.MyMetaObjectHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/guwan/backend/config/NettyConfig.java b/src/main/java/com/guwan/backend/config/NettyConfig.java new file mode 100644 index 0000000..7d44468 --- /dev/null +++ b/src/main/java/com/guwan/backend/config/NettyConfig.java @@ -0,0 +1,49 @@ +package com.guwan.backend.config; + +import com.guwan.backend.netty.chat.CourseChatWebSocketHandler; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.codec.http.HttpServerCodec; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class NettyConfig { + + @Bean + public EventLoopGroup bossGroup() { + return new NioEventLoopGroup(1); + } + + @Bean + public EventLoopGroup workerGroup() { + return new NioEventLoopGroup(); + } + + @Bean + public ServerBootstrap serverBootstrap(EventLoopGroup bossGroup, + EventLoopGroup workerGroup, + CourseChatWebSocketHandler chatHandler) { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) { + ChannelPipeline pipeline = ch.pipeline(); + pipeline.addLast(new HttpServerCodec()); + pipeline.addLast(new HttpObjectAggregator(65536)); + pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); + pipeline.addLast(chatHandler); + } + }); + return bootstrap; + } +} diff --git a/src/main/java/com/guwan/backend/config/WebSocketConfig.java b/src/main/java/com/guwan/backend/config/WebSocketConfig.java index 0f28ff3..9f142c1 100644 --- a/src/main/java/com/guwan/backend/config/WebSocketConfig.java +++ b/src/main/java/com/guwan/backend/config/WebSocketConfig.java @@ -1,12 +1,10 @@ package com.guwan.backend.config; -import com.guwan.backend.Handler.CourseWebSocketHandler; -import com.guwan.backend.Handler.CoursesWebSocketHandler; +import com.guwan.backend.handler.CourseWebSocketHandler; +import com.guwan.backend.handler.CoursesWebSocketHandler; import com.guwan.backend.websocket.ChatWebSocketHandler; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; diff --git a/src/main/java/com/guwan/backend/controller/ChatMessagesController.java b/src/main/java/com/guwan/backend/controller/ChatMessagesController.java new file mode 100644 index 0000000..a78d2df --- /dev/null +++ b/src/main/java/com/guwan/backend/controller/ChatMessagesController.java @@ -0,0 +1,64 @@ +package com.guwan.backend.controller; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.guwan.backend.common.Result; +import com.guwan.backend.mapper.ChatMessagesMapper; +import com.guwan.backend.mapper.UserMapper; +import com.guwan.backend.pojo.entity.ChatMessages; +import com.guwan.backend.pojo.entity.User; +import com.guwan.backend.pojo.response.HistotyMessageVO; +import com.guwan.backend.service.ChatMessagesService; +import com.guwan.backend.service.UserService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/chatMessages") +@RequiredArgsConstructor +public class ChatMessagesController { + + private final ChatMessagesService chatMessagesService; + + private final UserService userService; + + private final UserMapper userMapper; + + @GetMapping("/getHistoryMessage") + public Result getHistoryMessage(@RequestParam String courseId, @RequestParam Integer limit) { + + List latest30Messages = chatMessagesService.list( + new LambdaQueryWrapper() + .eq(ChatMessages::getType, "chat") + .eq(ChatMessages::getCourseId, courseId) + .orderByDesc(ChatMessages::getCreatedAt) + .last("LIMIT " + limit) + ); + List histotyMessageVOS = latest30Messages.stream().map( + chatMessages -> { + HistotyMessageVO histotyMessageVO = new HistotyMessageVO(); + //id content imageUrl + BeanUtils.copyProperties(chatMessages, histotyMessageVO); + + User user = userMapper.selectById(chatMessages.getSenderId()); + histotyMessageVO.setSenderName(user.getUsername()); + histotyMessageVO.setSenderAvatar(user.getAvatar()); + histotyMessageVO.setTimestamp(chatMessages.getCreatedAt().getTime()); + histotyMessageVO.setType(chatMessages.getInfoType()); + return histotyMessageVO; + } + ).toList(); + + return Result.success(histotyMessageVOS); + } + +} diff --git a/src/main/java/com/guwan/backend/Handler/CourseWebSocketHandler.java b/src/main/java/com/guwan/backend/handler/CourseWebSocketHandler.java similarity index 96% rename from src/main/java/com/guwan/backend/Handler/CourseWebSocketHandler.java rename to src/main/java/com/guwan/backend/handler/CourseWebSocketHandler.java index 0250660..b8dffc3 100644 --- a/src/main/java/com/guwan/backend/Handler/CourseWebSocketHandler.java +++ b/src/main/java/com/guwan/backend/handler/CourseWebSocketHandler.java @@ -1,4 +1,4 @@ -package com.guwan.backend.Handler; +package com.guwan.backend.handler; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -46,7 +46,8 @@ public class CourseWebSocketHandler extends TextWebSocketHandler { try { JsonNode jsonNode = new ObjectMapper().readTree(message.getPayload()); String type = jsonNode.get("type").asText(); - String courseId = jsonNode.get("courseId").asText(); + JsonNode dataNode = jsonNode.get("data"); + String courseId = dataNode.get("courseId").asText(); if ("JOIN_COURSE".equals(type)) { courseSessions.computeIfAbsent(courseId, k -> ConcurrentHashMap.newKeySet()).add(session); diff --git a/src/main/java/com/guwan/backend/Handler/CoursesWebSocketHandler.java b/src/main/java/com/guwan/backend/handler/CoursesWebSocketHandler.java similarity index 98% rename from src/main/java/com/guwan/backend/Handler/CoursesWebSocketHandler.java rename to src/main/java/com/guwan/backend/handler/CoursesWebSocketHandler.java index 225580f..8536229 100644 --- a/src/main/java/com/guwan/backend/Handler/CoursesWebSocketHandler.java +++ b/src/main/java/com/guwan/backend/handler/CoursesWebSocketHandler.java @@ -1,4 +1,4 @@ -package com.guwan.backend.Handler; +package com.guwan.backend.handler; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java b/src/main/java/com/guwan/backend/handler/MyMetaObjectHandler.java similarity index 64% rename from src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java rename to src/main/java/com/guwan/backend/handler/MyMetaObjectHandler.java index c6fb8ba..818435b 100644 --- a/src/main/java/com/guwan/backend/Handler/MyMetaObjectHandler.java +++ b/src/main/java/com/guwan/backend/handler/MyMetaObjectHandler.java @@ -1,16 +1,8 @@ -package com.guwan.backend.Handler; +package com.guwan.backend.handler; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; -import com.baomidou.mybatisplus.core.toolkit.ReflectionKit; -import com.guwan.backend.annotation.RecoverIfDeleted; -import com.guwan.backend.util.ReflectUtil; import org.apache.ibatis.reflection.MetaObject; -import org.apache.ibatis.session.SqlSession; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.time.LocalDateTime; diff --git a/src/main/java/com/guwan/backend/mapper/ChatMessagesMapper.java b/src/main/java/com/guwan/backend/mapper/ChatMessagesMapper.java new file mode 100644 index 0000000..ddbd5c8 --- /dev/null +++ b/src/main/java/com/guwan/backend/mapper/ChatMessagesMapper.java @@ -0,0 +1,18 @@ +package com.guwan.backend.mapper; + +import com.guwan.backend.pojo.entity.ChatMessages; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author 12455 +* @description 针对表【chat_messages】的数据库操作Mapper +* @createDate 2025-05-13 17:04:56 +* @Entity com.guwan.backend.pojo.entity.ChatMessages +*/ +public interface ChatMessagesMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/guwan/backend/netty/chat/ChatMessage.java b/src/main/java/com/guwan/backend/netty/chat/ChatMessage.java index a9bea22..31d0090 100644 --- a/src/main/java/com/guwan/backend/netty/chat/ChatMessage.java +++ b/src/main/java/com/guwan/backend/netty/chat/ChatMessage.java @@ -2,10 +2,17 @@ package com.guwan.backend.netty.chat; import lombok.Data; +import java.util.List; + @Data public class ChatMessage { - private String type; // 消息类型: CONNECT, CHAT, DISCONNECT - private String from; // 发送者 - private String content; // 消息内容 - private Long timestamp; // 时间戳 -} \ No newline at end of file + private String id; + private String courseId; + private String content; + private String imageUrl; + private String senderId; + private String senderName; + private String senderAvatar; + private Long timestamp; + private List mentionedUsers; +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/netty/chat/ChatServer.java b/src/main/java/com/guwan/backend/netty/chat/ChatServer.java index 8f00f0b..3b4f3c6 100644 --- a/src/main/java/com/guwan/backend/netty/chat/ChatServer.java +++ b/src/main/java/com/guwan/backend/netty/chat/ChatServer.java @@ -1,15 +1,6 @@ package com.guwan.backend.netty.chat; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.RequiredArgsConstructor; @@ -17,8 +8,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; - - @Slf4j @Component @RequiredArgsConstructor @@ -27,45 +16,20 @@ public class ChatServer { @Value("${netty.chat.port}") private int port; - private final ChatServerHandler chatServerHandler; - private EventLoopGroup bossGroup; - private EventLoopGroup workerGroup; + // ✅ 注入 ServerBootstrap + private final ServerBootstrap serverBootstrap; + // ✅ 启动服务器 @PostConstruct public void start() throws Exception { - bossGroup = new NioEventLoopGroup(1); - workerGroup = new NioEventLoopGroup(); - - try { - ServerBootstrap bootstrap = new ServerBootstrap() - .group(bossGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - protected void initChannel(SocketChannel ch) { - ch.pipeline() - .addLast(new HttpServerCodec()) - .addLast(new HttpObjectAggregator(65536)) - .addLast(new WebSocketServerProtocolHandler("/ws/chat")) - .addLast(chatServerHandler); - } - }); - - ChannelFuture future = bootstrap.bind(port).sync(); - log.info("聊天服务器启动成功,WebSocket端口: {}", port); - } catch (Exception e) { - log.error("聊天服务器启动失败", e); - throw e; - } + serverBootstrap.bind(port).sync(); + log.info("WebSocket server started on port {}", port); } + // ✅ 优雅关闭 @PreDestroy public void stop() { - if (bossGroup != null) { - bossGroup.shutdownGracefully(); - } - if (workerGroup != null) { - workerGroup.shutdownGracefully(); - } + // 可添加 shutdown 逻辑 + log.info("WebSocket server stopping..."); } -} \ No newline at end of file +} diff --git a/src/main/java/com/guwan/backend/netty/chat/ChatServerHandler.java b/src/main/java/com/guwan/backend/netty/chat/ChatServerHandler.java index 67b5c99..eb4a6ea 100644 --- a/src/main/java/com/guwan/backend/netty/chat/ChatServerHandler.java +++ b/src/main/java/com/guwan/backend/netty/chat/ChatServerHandler.java @@ -1,3 +1,4 @@ +/* package com.guwan.backend.netty.chat; import com.fasterxml.jackson.databind.ObjectMapper; @@ -89,4 +90,4 @@ public class ChatServerHandler extends SimpleChannelInboundHandler { + + private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + private static final Map> courseChannels = new ConcurrentHashMap<>(); + private static final Map channelUsers = new ConcurrentHashMap<>(); + + private final ChatMessagesService chatMessagesService; + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) { + try { + WebSocketMessage message = JSON.parseObject(frame.text(), WebSocketMessage.class); + handleMessage(ctx, message); + } catch (Exception e) { + log.error("Error handling message", e); + sendError(ctx, "消息处理失败"); + } + } + + private void handleMessage(ChannelHandlerContext ctx, WebSocketMessage message) { + switch (message.getType()) { + case JOIN_COURSE: + handleJoinCourse(ctx, message); + break; + case LEAVE_COURSE: + handleLeaveCourse(ctx, message); + break; + case CHAT_MESSAGE: + handleChatMessage(ctx, message); + break; + default: + sendError(ctx, "未知的消息类型"); + } + } + + private void handleJoinCourse(ChannelHandlerContext ctx, WebSocketMessage message) { + Map data = (Map) message.getData(); + String courseId = (String) data.get("courseId"); + //TODO userId 变 String + String userId = data.get("userId").toString(); + String username = (String) data.get("username"); + + // 保存用户信息 + UserInfo userInfo = new UserInfo(userId, username); + channelUsers.put(ctx.channel().id().asLongText(), userInfo); + + // 添加到课程频道 + courseChannels.computeIfAbsent(courseId, k -> new ConcurrentHashSet<>()) + .add(ctx.channel()); + + // 广播用户列表更新 + broadcastUserList(courseId); + + // 发送系统消息 + sendSystemMessage(courseId, username + " 加入了聊天室"); + } + + private void handleLeaveCourse(ChannelHandlerContext ctx, WebSocketMessage message) { + Map data = (Map) message.getData(); + String courseId = (String) data.get("courseId"); + //String userId = (String) data.get("userId"); + String username = (String) data.get("username"); + + // 从课程频道中移除用户 + Set channels = courseChannels.get(courseId); + if (channels != null) { + channels.remove(ctx.channel()); + + // 如果课程没有用户了,可以移除整个课程频道 + if (channels.isEmpty()) { + courseChannels.remove(courseId); + } else { + // 广播用户列表更新 + broadcastUserList(courseId); + + // 发送系统消息 + sendSystemMessage(courseId, username + " 离开了聊天室"); + } + } + + // 注意:这里不移除channelUsers中的用户信息,因为用户可能加入了多个课程 + // 这部分在handlerRemoved方法中处理,当连接完全断开时 + } + + private void handleChatMessage(ChannelHandlerContext ctx, WebSocketMessage message) { + ChatMessage chatMessage = JSON.parseObject(JSON.toJSONString(message.getData()), ChatMessage.class); + String courseId = chatMessage.getCourseId(); + + // 保存消息到数据库 + saveMessage(chatMessage); + + // 广播消息给课程内的所有用户 + broadcastMessage(courseId, chatMessage); + + // 处理@消息 + if (chatMessage.getMentionedUsers() != null && !chatMessage.getMentionedUsers().isEmpty()) { + handleMentions(courseId, chatMessage); + } + } + + private void broadcastMessage(String courseId, ChatMessage message) { + WebSocketMessage wsMessage = new WebSocketMessage(); + wsMessage.setType(CHAT_MESSAGE); + wsMessage.setData(message); + + String messageJson = JSON.toJSONString(wsMessage); + Set channels = courseChannels.get(courseId); + if (channels != null) { + channels.forEach(channel -> { + if (channel.isActive()) { + channel.writeAndFlush(new TextWebSocketFrame(messageJson)); + } + }); + } + } + + private void broadcastUserList(String courseId) { + Set channels = courseChannels.get(courseId); + if (channels != null) { + List users = channels.stream() + .map(channel -> channelUsers.get(channel.id().asLongText())) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + WebSocketMessage message = new WebSocketMessage(); + message.setType(MessageType.USER_LIST); + message.setData(users); + + String messageJson = JSON.toJSONString(message); + channels.forEach(channel -> { + if (channel.isActive()) { + channel.writeAndFlush(new TextWebSocketFrame(messageJson)); + } + }); + } + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) { + String channelId = ctx.channel().id().asLongText(); + UserInfo userInfo = channelUsers.remove(channelId); + + if (userInfo != null) { + // 从所有课程频道中移除 + courseChannels.forEach((courseId, channels) -> { + if (channels.remove(ctx.channel())) { + broadcastUserList(courseId); + sendSystemMessage(courseId, userInfo.getUsername() + " 离开了聊天室"); + } + }); + } + } + + + private void handleMentions(String courseId, ChatMessage chatMessage) { + // 处理@消息的逻辑 + for (String mentionedUserId : chatMessage.getMentionedUsers()) { + // 查找被@用户的Channel + Set channels = courseChannels.get(courseId); + if (channels != null) { + for (Channel channel : channels) { + UserInfo userInfo = channelUsers.get(channel.id().asLongText()); + if (userInfo != null && userInfo.getUserId().equals(mentionedUserId)) { + // 向被@用户发送通知 + WebSocketMessage notification = new WebSocketMessage(); + notification.setType(MessageType.SYSTEM_MESSAGE); + notification.setData("您被 " + chatMessage.getSenderName() + " 提及:" + chatMessage.getContent()); + channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(notification))); + break; + } + } + } + } + } + + private void sendSystemMessage(String courseId, String message) { + WebSocketMessage wsMessage = new WebSocketMessage(); + wsMessage.setType(MessageType.SYSTEM_MESSAGE); + + ChatMessage chatMessage1 = new ChatMessage(); + + chatMessage1.setCourseId(UUIDUtil.uuid()); + chatMessage1.setContent(message); + + wsMessage.setData(chatMessage1); + + String messageJson = JSON.toJSONString(wsMessage); + Set channels = courseChannels.get(courseId); + if (channels != null) { + channels.forEach(channel -> { + if (channel.isActive()) { + channel.writeAndFlush(new TextWebSocketFrame(messageJson)); + } + }); + } + +// ChatMessage chatMessage = new ChatMessages(); +// chatMessage.setCourseId(courseId); + + + } + + private void sendError(ChannelHandlerContext ctx, String errorMessage) { + WebSocketMessage wsMessage = new WebSocketMessage(); + wsMessage.setType(MessageType.ERROR); + wsMessage.setData(errorMessage); + + ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(wsMessage))); + } + + private void saveMessage(ChatMessage chatMessage) { + // 在实际项目中,这里应该将消息保存到数据库 + // 例如使用JPA或MyBatis等ORM框架 + try { + // 设置消息ID和时间戳(如果未设置) + if (chatMessage.getId() == null) { + chatMessage.setId(UUIDUtil.uuid()); + } + + if (chatMessage.getTimestamp() == null) { + chatMessage.setTimestamp(System.currentTimeMillis()); + } + + ChatMessages chatMessages = new ChatMessages(); + BeanUtils.copyProperties(chatMessage, chatMessages); + + chatMessages.setInfoType("USER"); + chatMessages.setType("CHAT"); + chatMessages.setCreatedAt(new Date(chatMessage.getTimestamp())); + System.out.println("chatMessages = " + chatMessages); + + // 这里应该调用消息服务或存储库来持久化消息 + chatMessagesService.save(chatMessages); + log.info("保存消息: {}", chatMessage); + } catch (Exception e) { + log.error("保存消息失败", e); + } + } + + +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/netty/chat/UserInfo.java b/src/main/java/com/guwan/backend/netty/chat/UserInfo.java new file mode 100644 index 0000000..8927971 --- /dev/null +++ b/src/main/java/com/guwan/backend/netty/chat/UserInfo.java @@ -0,0 +1,18 @@ +package com.guwan.backend.netty.chat; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UserInfo { + private String userId; + private String username; + private String avatar; + + public UserInfo(String userId, String username) { + this.userId = userId; + this.username = username; + this.avatar = null; // 可以设置默认头像URL + } +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/netty/chat/WebSocketMessage.java b/src/main/java/com/guwan/backend/netty/chat/WebSocketMessage.java new file mode 100644 index 0000000..8413001 --- /dev/null +++ b/src/main/java/com/guwan/backend/netty/chat/WebSocketMessage.java @@ -0,0 +1,10 @@ +package com.guwan.backend.netty.chat; + +import com.guwan.backend.pojo.enums.MessageType; +import lombok.Data; + +@Data +public class WebSocketMessage { + private MessageType type; + private Object data; +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/pojo/entity/ChatMessages.java b/src/main/java/com/guwan/backend/pojo/entity/ChatMessages.java new file mode 100644 index 0000000..94ec6ef --- /dev/null +++ b/src/main/java/com/guwan/backend/pojo/entity/ChatMessages.java @@ -0,0 +1,53 @@ +package com.guwan.backend.pojo.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.util.Date; +import lombok.Data; + +/** + * + * @TableName chat_messages + */ +@TableName(value ="chat_messages") +@Data +public class ChatMessages { + /** + * + */ + @TableId + private String id; + + /** + * + */ + private String courseId; + + /** + * + */ + private String senderId; + + /** + * + */ + private String content; + + /** + * + */ + private String imageUrl; + + + private String infoType; + + /** + * 来源 直播还是聊天室 + */ + private String type; + + /** + * + */ + private Date createdAt; +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/pojo/entity/Course.java b/src/main/java/com/guwan/backend/pojo/entity/Course.java index 6cb24ba..bd21ea7 100644 --- a/src/main/java/com/guwan/backend/pojo/entity/Course.java +++ b/src/main/java/com/guwan/backend/pojo/entity/Course.java @@ -96,6 +96,8 @@ public class Course implements Serializable { */ private Integer totalDuration; + private String liveUrl; + /** * 创建时间 */ diff --git a/src/main/java/com/guwan/backend/pojo/enums/MessageType.java b/src/main/java/com/guwan/backend/pojo/enums/MessageType.java new file mode 100644 index 0000000..6b45f7c --- /dev/null +++ b/src/main/java/com/guwan/backend/pojo/enums/MessageType.java @@ -0,0 +1,10 @@ +package com.guwan.backend.pojo.enums; + +public enum MessageType { + JOIN_COURSE, + LEAVE_COURSE, + CHAT_MESSAGE, + USER_LIST, + SYSTEM_MESSAGE, + ERROR +} \ No newline at end of file diff --git a/src/main/java/com/guwan/backend/pojo/response/CourseCenterVO.java b/src/main/java/com/guwan/backend/pojo/response/CourseCenterVO.java index ed5efc5..0066d3b 100644 --- a/src/main/java/com/guwan/backend/pojo/response/CourseCenterVO.java +++ b/src/main/java/com/guwan/backend/pojo/response/CourseCenterVO.java @@ -17,7 +17,7 @@ public class CourseCenterVO { private Integer ratingCount; private BigDecimal price; private Integer studentCount; - + private String liveUrl; private String teacher; } diff --git a/src/main/java/com/guwan/backend/pojo/response/HistotyMessageVO.java b/src/main/java/com/guwan/backend/pojo/response/HistotyMessageVO.java new file mode 100644 index 0000000..6d8385e --- /dev/null +++ b/src/main/java/com/guwan/backend/pojo/response/HistotyMessageVO.java @@ -0,0 +1,16 @@ +package com.guwan.backend.pojo.response; + +import lombok.Data; + +@Data +public class HistotyMessageVO { + + private String id; + private String senderName; + private String senderAvatar; + private Long timestamp; + private String content; + private String imageUrl; + private String type; + +} diff --git a/src/main/java/com/guwan/backend/pojo/response/courseDetail/CourseDetailVO.java b/src/main/java/com/guwan/backend/pojo/response/courseDetail/CourseDetailVO.java index 054cace..258d56e 100644 --- a/src/main/java/com/guwan/backend/pojo/response/courseDetail/CourseDetailVO.java +++ b/src/main/java/com/guwan/backend/pojo/response/courseDetail/CourseDetailVO.java @@ -48,6 +48,9 @@ public class CourseDetailVO { private Boolean enrolled; private String coverImg; + + private String liveUrl; + @JsonProperty("chapters") private List chapterVOS; @JsonProperty("reviews") diff --git a/src/main/java/com/guwan/backend/service/ChatMessagesService.java b/src/main/java/com/guwan/backend/service/ChatMessagesService.java new file mode 100644 index 0000000..5b2f331 --- /dev/null +++ b/src/main/java/com/guwan/backend/service/ChatMessagesService.java @@ -0,0 +1,13 @@ +package com.guwan.backend.service; + +import com.guwan.backend.pojo.entity.ChatMessages; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author 12455 +* @description 针对表【chat_messages】的数据库操作Service +* @createDate 2025-05-13 17:04:56 +*/ +public interface ChatMessagesService extends IService { + +} diff --git a/src/main/java/com/guwan/backend/service/WebSocketService.java b/src/main/java/com/guwan/backend/service/WebSocketService.java index e176ad5..81950c6 100644 --- a/src/main/java/com/guwan/backend/service/WebSocketService.java +++ b/src/main/java/com/guwan/backend/service/WebSocketService.java @@ -1,6 +1,6 @@ package com.guwan.backend.service; -import com.guwan.backend.Handler.CoursesWebSocketHandler; +import com.guwan.backend.handler.CoursesWebSocketHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/guwan/backend/service/impl/ChatMessagesServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/ChatMessagesServiceImpl.java new file mode 100644 index 0000000..1563bb1 --- /dev/null +++ b/src/main/java/com/guwan/backend/service/impl/ChatMessagesServiceImpl.java @@ -0,0 +1,22 @@ +package com.guwan.backend.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.guwan.backend.mapper.ChatMessagesMapper; +import com.guwan.backend.service.ChatMessagesService; +import com.guwan.backend.pojo.entity.ChatMessages; +import org.springframework.stereotype.Service; + +/** +* @author 12455 +* @description 针对表【chat_messages】的数据库操作Service实现 +* @createDate 2025-05-13 17:04:56 +*/ +@Service +public class ChatMessagesServiceImpl extends ServiceImpl + implements ChatMessagesService { + +} + + + +