From e6623be1e55d316485c5647d35d6e8a3990d8065 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=AB=98=E4=BF=9D=E5=AE=89?= <1409538202@qq.com>
Date: Mon, 1 Dec 2025 10:08:41 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E6=97=B6=E9=80=9A=E8=AE=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 207 ++++++
src/main/docker/Dockerfile | 4 +
.../com/realtime/RealTimeApplication.java | 26 +
.../config/AnnotationBinaryWebSocket.java | 77 +++
.../com/realtime/config/BaiduTtsConfig.java | 15 +
.../realtime/config/ClientVoiceHandler.java | 90 +++
.../java/com/realtime/config/CorsConfig.java | 24 +
.../realtime/config/DoubaoVoiceConfig.java | 14 +
.../com/realtime/config/FileProperties.java | 17 +
.../com/realtime/config/GlobalException.java | 27 +
.../com/realtime/config/MinioComponent.java | 25 +
.../java/com/realtime/config/MinioConfig.java | 25 +
.../realtime/config/MyBatisPlusConfig.java | 21 +
.../java/com/realtime/config/NettyConfig.java | 12 +
.../realtime/config/ProtocolFrameDecoder.java | 14 +
.../java/com/realtime/config/RtasrConfig.java | 20 +
.../config/WebSocketAnnotationConfig.java | 23 +
.../controller/ChatListController.java | 47 ++
.../realtime/controller/FileController.java | 35 ++
.../controller/FriendshipController.java | 43 ++
.../realtime/controller/GroupController.java | 88 +++
.../controller/MessageController.java | 38 ++
.../realtime/controller/TtsController.java | 84 +++
.../realtime/exception/BusinessException.java | 22 +
.../com/realtime/mappers/ChatListMapper.java | 22 +
.../mappers/FriendRelationshipMapper.java | 18 +
.../com/realtime/mappers/GroupListMapper.java | 30 +
.../realtime/mappers/GroupMemberMapper.java | 34 +
.../realtime/mappers/GroupMessageMapper.java | 18 +
.../com/realtime/mappers/MessageMapper.java | 24 +
.../model/baseModel/BaseQueryModel.java | 13 +
.../com/realtime/model/pojo/ChatList.java | 47 ++
.../realtime/model/pojo/ChatListSaveReq.java | 11 +
.../model/pojo/FriendRelationship.java | 37 ++
.../com/realtime/model/pojo/GroupList.java | 48 ++
.../com/realtime/model/pojo/GroupMember.java | 31 +
.../com/realtime/model/pojo/GroupMessage.java | 63 ++
.../java/com/realtime/model/pojo/Message.java | 64 ++
.../query/ChatFriendRelationshipQueryReq.java | 12 +
.../model/query/ChatListPageQueryReq.java | 12 +
.../model/query/ChatQueryPageReq.java | 13 +
.../model/query/GroupDetailQueryReq.java | 12 +
.../model/query/GroupListQueryReq.java | 14 +
.../model/query/GroupMemberListQueryReq.java | 16 +
.../realtime/model/query/LoginQueryReq.java | 11 +
.../realtime/model/query/MessageQueryReq.java | 18 +
.../realtime/model/query/TtsOptionsReq.java | 50 ++
.../model/remove/DisbandGroupReq.java | 9 +
.../realtime/model/remove/RemoveGroupReq.java | 9 +
.../model/remove/RemovesGroupReq.java | 11 +
.../model/update/GroupInventUpdateReq.java | 9 +
.../model/update/UpdateUserPasswordReq.java | 13 +
.../model/update/UserInfoUpdateReq.java | 16 +
.../com/realtime/packets/AnswerPacket.java | 18 +
.../realtime/packets/AutoSoftwarePacket.java | 23 +
.../java/com/realtime/packets/CallPacket.java | 18 +
.../com/realtime/packets/ConnectPacket.java | 16 +
.../com/realtime/packets/FilePackets.java | 18 +
.../com/realtime/packets/GroupPacket.java | 22 +
.../com/realtime/packets/GroupSendPacket.java | 21 +
.../realtime/packets/InventGroupPacket.java | 21 +
.../com/realtime/packets/PingPongPacket.java | 15 +
.../com/realtime/packets/RealTimePacket.java | 20 +
.../realtime/packets/RemoveGroupPacket.java | 21 +
.../com/realtime/packets/SendMsgPackets.java | 31 +
.../realtime/packets/SystemNoticePackets.java | 17 +
.../packets/basePackets/BasePackets.java | 24 +
.../com/realtime/packets/command/Command.java | 25 +
.../packets/resp/GroupResponsePacket.java | 18 +
.../realtime/packets/server/NettyServer.java | 47 ++
.../server/handler/ConnectMessageHandler.java | 59 ++
.../server/handler/ExceptionHandler.java | 34 +
.../server/handler/GroupMessageHandler.java | 48 ++
.../server/handler/InventGroupHandler.java | 60 ++
.../server/handler/JoinGroupHandler.java | 58 ++
.../server/handler/MessageSocketHandler.java | 78 +++
.../server/handler/PingPongHartHandler.java | 41 ++
.../server/handler/PrivateMessageHandler.java | 51 ++
.../handler/RealTimeTransferHandler.java | 44 ++
.../server/handler/RemoveGroupHandler.java | 46 ++
.../server/handler/SocketChannelHandler.java | 69 ++
.../handler/SystemNoticeMessageHandler.java | 18 +
.../packets/strategy/PackStrategy.java | 12 +
.../packets/strategy/PacketService.java | 12 +
.../impl/AutoSoftwareStrategyImpl.java | 24 +
.../impl/ConnectPackStrategyImpl.java | 26 +
.../impl/GroupJoinPackStrategyImpl.java | 24 +
.../impl/GroupSendPackStrategyImpl.java | 26 +
.../strategy/impl/InventStrategyImpl.java | 27 +
.../strategy/impl/PacketServiceImpl.java | 35 ++
.../impl/PingPongPackStrategyImpl.java | 24 +
.../impl/PrivatePackStrategyImpl.java | 26 +
.../impl/RealTimePackStrategyImpl.java | 24 +
.../strategy/impl/RemoveStrategyImpl.java | 27 +
.../realtime/service/BaiduAuthService.java | 46 ++
.../com/realtime/service/BaiduTtsService.java | 94 +++
.../com/realtime/service/ChatListService.java | 28 +
.../realtime/service/DoubaoVoiceService.java | 105 ++++
.../com/realtime/service/FileService.java | 18 +
.../service/FriendRelationshipService.java | 22 +
.../realtime/service/GroupListService.java | 33 +
.../realtime/service/GroupMemberService.java | 32 +
.../realtime/service/GroupMessageService.java | 23 +
.../com/realtime/service/MessageService.java | 30 +
.../service/RealTimeVoiceService.java | 18 +
.../service/impl/ChatListServiceImpl.java | 147 +++++
.../service/impl/ChatServiceImpl.java | 589 ++++++++++++++++++
.../service/impl/FileServiceImpl.java | 89 +++
.../impl/FriendRelationshipServiceImpl.java | 79 +++
.../service/impl/GroupListServiceImpl.java | 123 ++++
.../service/impl/GroupMemberServiceImpl.java | 76 +++
.../service/impl/GroupMessageServiceImpl.java | 26 +
.../service/impl/MessageServiceImpl.java | 43 ++
.../impl/RealTimeVoiceServiceImpl.java | 250 ++++++++
.../com/realtime/sysconst/RTASRClient.java | 377 +++++++++++
.../java/com/realtime/sysconst/Result.java | 61 ++
.../sysconst/enumConst/ResultEnum.java | 30 +
.../java/com/realtime/utils/Attributes.java | 9 +
.../realtime/utils/Base64ToMultipartFile.java | 89 +++
.../utils/InputStreamMultipartFile.java | 66 ++
.../java/com/realtime/utils/SessionUtils.java | 74 +++
.../vo/ChatFriendRelationshipInfoVo.java | 21 +
.../java/com/realtime/vo/ChatListInfoVo.java | 19 +
src/main/java/com/realtime/vo/ChatReqVo.java | 9 +
.../java/com/realtime/vo/FriendMessageVo.java | 19 +
.../java/com/realtime/vo/GroupDetailVo.java | 13 +
.../com/realtime/vo/GroupListMessagesVo.java | 13 +
.../java/com/realtime/vo/GroupListVo.java | 15 +
.../com/realtime/vo/GroupMemberListVo.java | 10 +
.../java/com/realtime/vo/MessageInfoVo.java | 22 +
.../java/com/realtime/vo/MessageItemVo.java | 10 +
src/main/java/com/realtime/vo/MessageVo.java | 17 +
src/main/java/com/realtime/vo/UploadVo.java | 16 +
src/main/resources/application.yml | 53 ++
src/main/resources/mappers/ChatListMapper.xml | 38 ++
.../mappers/FriendRelationshipMapper.xml | 24 +
.../resources/mappers/GroupListMapper.xml | 53 ++
.../resources/mappers/GroupMemberMapper.xml | 70 +++
.../resources/mappers/GroupMessageMapper.xml | 25 +
src/main/resources/mappers/MessageMapper.xml | 57 ++
140 files changed, 6032 insertions(+)
create mode 100644 pom.xml
create mode 100644 src/main/docker/Dockerfile
create mode 100644 src/main/java/com/realtime/RealTimeApplication.java
create mode 100644 src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java
create mode 100644 src/main/java/com/realtime/config/BaiduTtsConfig.java
create mode 100644 src/main/java/com/realtime/config/ClientVoiceHandler.java
create mode 100644 src/main/java/com/realtime/config/CorsConfig.java
create mode 100644 src/main/java/com/realtime/config/DoubaoVoiceConfig.java
create mode 100644 src/main/java/com/realtime/config/FileProperties.java
create mode 100644 src/main/java/com/realtime/config/GlobalException.java
create mode 100644 src/main/java/com/realtime/config/MinioComponent.java
create mode 100644 src/main/java/com/realtime/config/MinioConfig.java
create mode 100644 src/main/java/com/realtime/config/MyBatisPlusConfig.java
create mode 100644 src/main/java/com/realtime/config/NettyConfig.java
create mode 100644 src/main/java/com/realtime/config/ProtocolFrameDecoder.java
create mode 100644 src/main/java/com/realtime/config/RtasrConfig.java
create mode 100644 src/main/java/com/realtime/config/WebSocketAnnotationConfig.java
create mode 100644 src/main/java/com/realtime/controller/ChatListController.java
create mode 100644 src/main/java/com/realtime/controller/FileController.java
create mode 100644 src/main/java/com/realtime/controller/FriendshipController.java
create mode 100644 src/main/java/com/realtime/controller/GroupController.java
create mode 100644 src/main/java/com/realtime/controller/MessageController.java
create mode 100644 src/main/java/com/realtime/controller/TtsController.java
create mode 100644 src/main/java/com/realtime/exception/BusinessException.java
create mode 100644 src/main/java/com/realtime/mappers/ChatListMapper.java
create mode 100644 src/main/java/com/realtime/mappers/FriendRelationshipMapper.java
create mode 100644 src/main/java/com/realtime/mappers/GroupListMapper.java
create mode 100644 src/main/java/com/realtime/mappers/GroupMemberMapper.java
create mode 100644 src/main/java/com/realtime/mappers/GroupMessageMapper.java
create mode 100644 src/main/java/com/realtime/mappers/MessageMapper.java
create mode 100644 src/main/java/com/realtime/model/baseModel/BaseQueryModel.java
create mode 100644 src/main/java/com/realtime/model/pojo/ChatList.java
create mode 100644 src/main/java/com/realtime/model/pojo/ChatListSaveReq.java
create mode 100644 src/main/java/com/realtime/model/pojo/FriendRelationship.java
create mode 100644 src/main/java/com/realtime/model/pojo/GroupList.java
create mode 100644 src/main/java/com/realtime/model/pojo/GroupMember.java
create mode 100644 src/main/java/com/realtime/model/pojo/GroupMessage.java
create mode 100644 src/main/java/com/realtime/model/pojo/Message.java
create mode 100644 src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/ChatListPageQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/ChatQueryPageReq.java
create mode 100644 src/main/java/com/realtime/model/query/GroupDetailQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/GroupListQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/LoginQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/MessageQueryReq.java
create mode 100644 src/main/java/com/realtime/model/query/TtsOptionsReq.java
create mode 100644 src/main/java/com/realtime/model/remove/DisbandGroupReq.java
create mode 100644 src/main/java/com/realtime/model/remove/RemoveGroupReq.java
create mode 100644 src/main/java/com/realtime/model/remove/RemovesGroupReq.java
create mode 100644 src/main/java/com/realtime/model/update/GroupInventUpdateReq.java
create mode 100644 src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java
create mode 100644 src/main/java/com/realtime/model/update/UserInfoUpdateReq.java
create mode 100644 src/main/java/com/realtime/packets/AnswerPacket.java
create mode 100644 src/main/java/com/realtime/packets/AutoSoftwarePacket.java
create mode 100644 src/main/java/com/realtime/packets/CallPacket.java
create mode 100644 src/main/java/com/realtime/packets/ConnectPacket.java
create mode 100644 src/main/java/com/realtime/packets/FilePackets.java
create mode 100644 src/main/java/com/realtime/packets/GroupPacket.java
create mode 100644 src/main/java/com/realtime/packets/GroupSendPacket.java
create mode 100644 src/main/java/com/realtime/packets/InventGroupPacket.java
create mode 100644 src/main/java/com/realtime/packets/PingPongPacket.java
create mode 100644 src/main/java/com/realtime/packets/RealTimePacket.java
create mode 100644 src/main/java/com/realtime/packets/RemoveGroupPacket.java
create mode 100644 src/main/java/com/realtime/packets/SendMsgPackets.java
create mode 100644 src/main/java/com/realtime/packets/SystemNoticePackets.java
create mode 100644 src/main/java/com/realtime/packets/basePackets/BasePackets.java
create mode 100644 src/main/java/com/realtime/packets/command/Command.java
create mode 100644 src/main/java/com/realtime/packets/resp/GroupResponsePacket.java
create mode 100644 src/main/java/com/realtime/packets/server/NettyServer.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java
create mode 100644 src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java
create mode 100644 src/main/java/com/realtime/packets/strategy/PackStrategy.java
create mode 100644 src/main/java/com/realtime/packets/strategy/PacketService.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java
create mode 100644 src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java
create mode 100644 src/main/java/com/realtime/service/BaiduAuthService.java
create mode 100644 src/main/java/com/realtime/service/BaiduTtsService.java
create mode 100644 src/main/java/com/realtime/service/ChatListService.java
create mode 100644 src/main/java/com/realtime/service/DoubaoVoiceService.java
create mode 100644 src/main/java/com/realtime/service/FileService.java
create mode 100644 src/main/java/com/realtime/service/FriendRelationshipService.java
create mode 100644 src/main/java/com/realtime/service/GroupListService.java
create mode 100644 src/main/java/com/realtime/service/GroupMemberService.java
create mode 100644 src/main/java/com/realtime/service/GroupMessageService.java
create mode 100644 src/main/java/com/realtime/service/MessageService.java
create mode 100644 src/main/java/com/realtime/service/RealTimeVoiceService.java
create mode 100644 src/main/java/com/realtime/service/impl/ChatListServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/ChatServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/FileServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/GroupListServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/MessageServiceImpl.java
create mode 100644 src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java
create mode 100644 src/main/java/com/realtime/sysconst/RTASRClient.java
create mode 100644 src/main/java/com/realtime/sysconst/Result.java
create mode 100644 src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java
create mode 100644 src/main/java/com/realtime/utils/Attributes.java
create mode 100644 src/main/java/com/realtime/utils/Base64ToMultipartFile.java
create mode 100644 src/main/java/com/realtime/utils/InputStreamMultipartFile.java
create mode 100644 src/main/java/com/realtime/utils/SessionUtils.java
create mode 100644 src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java
create mode 100644 src/main/java/com/realtime/vo/ChatListInfoVo.java
create mode 100644 src/main/java/com/realtime/vo/ChatReqVo.java
create mode 100644 src/main/java/com/realtime/vo/FriendMessageVo.java
create mode 100644 src/main/java/com/realtime/vo/GroupDetailVo.java
create mode 100644 src/main/java/com/realtime/vo/GroupListMessagesVo.java
create mode 100644 src/main/java/com/realtime/vo/GroupListVo.java
create mode 100644 src/main/java/com/realtime/vo/GroupMemberListVo.java
create mode 100644 src/main/java/com/realtime/vo/MessageInfoVo.java
create mode 100644 src/main/java/com/realtime/vo/MessageItemVo.java
create mode 100644 src/main/java/com/realtime/vo/MessageVo.java
create mode 100644 src/main/java/com/realtime/vo/UploadVo.java
create mode 100644 src/main/resources/application.yml
create mode 100644 src/main/resources/mappers/ChatListMapper.xml
create mode 100644 src/main/resources/mappers/FriendRelationshipMapper.xml
create mode 100644 src/main/resources/mappers/GroupListMapper.xml
create mode 100644 src/main/resources/mappers/GroupMemberMapper.xml
create mode 100644 src/main/resources/mappers/GroupMessageMapper.xml
create mode 100644 src/main/resources/mappers/MessageMapper.xml
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..c073769
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,207 @@
+
+
+ 4.0.0
+ com.realTime
+ real-time-application
+ 0.0.1-SNAPSHOT
+ real-time-application
+ real-time-application
+
+ 17
+ UTF-8
+ UTF-8
+ 3.0.2
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+
+ commons-fileupload
+ commons-fileupload
+ 1.5
+
+
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
+
+ org.json
+ json
+ 20231013
+
+
+
+ org.java-websocket
+ Java-WebSocket
+ 1.5.3
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.14
+
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+ 3.0.2
+
+
+
+ org.bytedeco
+ javacv-platform
+ 1.5.9
+
+
+ mysql
+ mysql-connector-java
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ com.alibaba
+ druid-spring-boot-3-starter
+ 1.2.23
+
+
+
+ io.netty
+ netty-all
+
+
+
+ io.swagger.core.v3
+ swagger-annotations
+ 2.2.25
+
+
+
+ io.swagger.core.v3
+ swagger-annotations-jakarta
+ 2.2.28
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ 3.5.10.1
+
+
+
+ com.baomidou
+ mybatis-plus-jsqlparser
+ 3.5.10.1
+
+
+
+ cn.hutool
+ hutool-all
+ 5.8.40
+
+
+
+ io.minio
+ minio
+ 8.5.13
+
+
+
+ com.google.zxing
+ core
+ 3.4.1
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.58
+
+
+
+
+ com.google.zxing
+ javase
+ 3.3.3
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+ 1.18.40
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ 17
+ 17
+ UTF-8
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.1.0
+
+ com.realtime.RealTimeApplication
+ false
+
+
+
+ repackage
+
+ repackage
+
+
+
+
+
+
+
+
diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile
new file mode 100644
index 0000000..7602896
--- /dev/null
+++ b/src/main/docker/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:21-jre
+VOLUME /tmp
+COPY real.jar real.jar
+ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/real.jar"]
diff --git a/src/main/java/com/realtime/RealTimeApplication.java b/src/main/java/com/realtime/RealTimeApplication.java
new file mode 100644
index 0000000..7b26005
--- /dev/null
+++ b/src/main/java/com/realtime/RealTimeApplication.java
@@ -0,0 +1,26 @@
+package com.realtime;
+
+import com.realtime.packets.server.NettyServer;
+import lombok.RequiredArgsConstructor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.realtime.mappers")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class RealTimeApplication implements CommandLineRunner {
+
+ private final NettyServer nettyServer;
+
+ public static void main(String[] args) {
+ SpringApplication.run(RealTimeApplication.class, args);
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ nettyServer.run();
+ }
+}
diff --git a/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java b/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java
new file mode 100644
index 0000000..b7901b7
--- /dev/null
+++ b/src/main/java/com/realtime/config/AnnotationBinaryWebSocket.java
@@ -0,0 +1,77 @@
+package com.realtime.config;
+
+import com.realtime.sysconst.RTASRClient;
+import com.realtime.utils.Base64ToMultipartFile;
+import jakarta.websocket.*;
+import jakarta.websocket.server.ServerEndpoint;
+import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+@Component
+@ServerEndpoint("/binary")
+
+public class AnnotationBinaryWebSocket {
+
+ private static final Logger logger = LoggerFactory.getLogger(AnnotationBinaryWebSocket.class);
+
+ @OnOpen
+ public void onOpen(Session session) {
+ logger.info("注解方式 - WebSocket 连接建立: {}", session.getId());
+ }
+
+ @OnMessage(maxMessageSize = 10485760) // 10MB限制
+ public void onBinaryMessage(byte[] data, Session session) {
+ logger.info("注解方式 - 收到二进制数据, 大小: {} bytes", data.length);
+
+ // 处理数据
+ processData(session, data);
+
+ // 发送响应
+ sendResponse(session, data);
+ }
+
+ @OnMessage
+ public void onTextMessage(String message, Session session) {
+ logger.info("注解方式 - 收到文本消息: {}", message);
+ }
+
+ @OnError
+ public void onError(Session session, Throwable error) {
+ logger.error("注解方式 - WebSocket 错误: {}", session.getId(), error);
+ }
+
+ @OnClose
+ public void onClose(Session session, CloseReason closeReason) {
+ logger.info("注解方式 - WebSocket 连接关闭: {}, 原因: {}",
+ session.getId(), closeReason.getReasonPhrase());
+ }
+
+ private void processData(Session session, byte[] data) {
+ // 数据处理逻辑
+
+ }
+
+ private void sendResponse(Session session, byte[] data) {
+ try {
+ MultipartFile convert = Base64ToMultipartFile.convert(data, UUID.randomUUID() + ".pcm");
+ RTASRClient client = new RTASRClient("5d899195","4c428332836cd9481be4127c941f4167", "ZjFiMWViMGY0NDA4ODNkNDgxYzg0Yzg3", "",convert.getInputStream(),session);
+ client.connect();
+ boolean b = client.sendAudio();
+ // 发送处理结果
+ ByteBuffer buffer = ByteBuffer.wrap(("已接收 " + data.length + " bytes").getBytes());
+
+ } catch (IOException e) {
+ logger.error("发送响应失败", e);
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/config/BaiduTtsConfig.java b/src/main/java/com/realtime/config/BaiduTtsConfig.java
new file mode 100644
index 0000000..34af0ea
--- /dev/null
+++ b/src/main/java/com/realtime/config/BaiduTtsConfig.java
@@ -0,0 +1,15 @@
+
+package com.realtime.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = "baidu.tts")
+@Data
+public class BaiduTtsConfig {
+ private String appId;
+ private String apiKey;
+ private String secretKey;
+}
diff --git a/src/main/java/com/realtime/config/ClientVoiceHandler.java b/src/main/java/com/realtime/config/ClientVoiceHandler.java
new file mode 100644
index 0000000..97380d1
--- /dev/null
+++ b/src/main/java/com/realtime/config/ClientVoiceHandler.java
@@ -0,0 +1,90 @@
+package com.realtime.config;
+
+import com.realtime.service.DoubaoVoiceService;
+import lombok.extern.slf4j.Slf4j;
+import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.FFmpegFrameRecorder;
+import org.bytedeco.javacv.Frame;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.BinaryMessage;
+import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.socket.WebSocketSession;
+import org.springframework.web.socket.handler.BinaryWebSocketHandler;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+@Slf4j
+@Component
+public class ClientVoiceHandler extends BinaryWebSocketHandler {
+ private final DoubaoVoiceService doubaoVoiceService;
+
+ public ClientVoiceHandler(DoubaoVoiceService doubaoVoiceService) {
+ this.doubaoVoiceService = doubaoVoiceService;
+ }
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ // 客户端会话
+ // 建立与豆包 API 的连接
+
+ System.out.println(session);
+ doubaoVoiceService.connect(session);
+ }
+
+ @Override
+ protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
+ System.out.println("2");
+ // 接收客户端的音频数据(如 PCM 片段)
+ byte[] audioData = message.getPayload().array();
+ // 预处理:确保格式符合豆包 API 要求(如采样率、位深)
+ byte[] processedData = preprocessAudio(audioData);
+ // 发送给豆包 API
+ doubaoVoiceService.sendAudio(processedData);
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+ // 关闭与豆包 API 的连接
+ doubaoVoiceService.close();
+ }
+
+ private byte[] preprocessAudio(byte[] audioData) {
+ if (audioData == null || audioData.length == 0) {
+ log.warn("接收到空的音频数据,跳过处理");
+ return new byte[0]; // 返回空数组,避免后续错误
+ }
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(new ByteArrayInputStream(audioData));
+ FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputStream, 1)) {
+
+ grabber.start();
+ // 打印输入音频信息(调试用)
+ log.debug("输入音频格式:{},采样率:{},声道:{}",
+ grabber.getFormat(), grabber.getSampleRate(), grabber.getAudioChannels());
+
+ recorder.setFormat("s16le");
+ recorder.setSampleRate(16000);
+ recorder.setAudioChannels(1);
+ recorder.start();
+
+ Frame frame;
+ int frameCount = 0;
+ while ((frame = grabber.grab()) != null) {
+ recorder.record(frame);
+ frameCount++;
+ }
+ log.debug("成功处理 {} 帧音频", frameCount);
+
+ recorder.stop();
+ grabber.stop();
+ return outputStream.toByteArray();
+
+ } catch (Exception e) {
+ log.error("音频预处理失败", e);
+ return new byte[0];
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/config/CorsConfig.java b/src/main/java/com/realtime/config/CorsConfig.java
new file mode 100644
index 0000000..1f6e94a
--- /dev/null
+++ b/src/main/java/com/realtime/config/CorsConfig.java
@@ -0,0 +1,24 @@
+package com.realtime.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+@Configuration
+public class CorsConfig {
+
+
+ @Bean
+ CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration config = new CorsConfiguration();
+ config.setAllowCredentials(true);
+ config.addAllowedOriginPattern("*");
+ config.addAllowedHeader("*");
+ config.addAllowedMethod("*");
+ source.registerCorsConfiguration("/**", config);
+ return new CorsFilter(source);
+ }
+}
diff --git a/src/main/java/com/realtime/config/DoubaoVoiceConfig.java b/src/main/java/com/realtime/config/DoubaoVoiceConfig.java
new file mode 100644
index 0000000..65a9789
--- /dev/null
+++ b/src/main/java/com/realtime/config/DoubaoVoiceConfig.java
@@ -0,0 +1,14 @@
+package com.realtime.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "doubao.voice")
+public class DoubaoVoiceConfig {
+ private String appId;
+ private String apiKey; // 豆包 API Key
+ private String accessToken; // 访问令牌
+ private String websocketUrl; // 豆包实时语音接口的 WebSocket 地址(如 wss://api.doubao.com/voice/realtime)
+}
diff --git a/src/main/java/com/realtime/config/FileProperties.java b/src/main/java/com/realtime/config/FileProperties.java
new file mode 100644
index 0000000..6a1b4dd
--- /dev/null
+++ b/src/main/java/com/realtime/config/FileProperties.java
@@ -0,0 +1,17 @@
+package com.realtime.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "file")
+public class FileProperties {
+ private int picMaxSize;
+ private int picMaxCount;
+ private String picAllowedFormats;
+ private String region;
+ private String allowedFormats;
+}
+
diff --git a/src/main/java/com/realtime/config/GlobalException.java b/src/main/java/com/realtime/config/GlobalException.java
new file mode 100644
index 0000000..ad3c355
--- /dev/null
+++ b/src/main/java/com/realtime/config/GlobalException.java
@@ -0,0 +1,27 @@
+package com.realtime.config;
+
+
+import com.realtime.exception.BusinessException;
+import com.realtime.sysconst.Result;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalException {
+
+ @ExceptionHandler(BusinessException.class)
+ public Result handle(BusinessException e) {
+ return Result.systemError(e.getMessage(),e.getCode());
+ }
+
+ /**
+ * 兜底异常
+ * @param e 异常
+ * @return 异常类型
+ */
+ @ExceptionHandler(Exception.class)
+ public Result exceptionHandler(Exception e) {
+ return Result.fail(e.getMessage());
+ }
+
+}
diff --git a/src/main/java/com/realtime/config/MinioComponent.java b/src/main/java/com/realtime/config/MinioComponent.java
new file mode 100644
index 0000000..ad33473
--- /dev/null
+++ b/src/main/java/com/realtime/config/MinioComponent.java
@@ -0,0 +1,25 @@
+package com.realtime.config;
+
+import io.minio.MinioClient;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class MinioComponent {
+
+ private final MinioConfig minioConfig;
+
+ @Bean
+ public MinioClient minioClient() {
+ return MinioClient.builder()
+ .endpoint(minioConfig.getEndpoint())
+ .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey())
+ .build();
+ }
+
+}
diff --git a/src/main/java/com/realtime/config/MinioConfig.java b/src/main/java/com/realtime/config/MinioConfig.java
new file mode 100644
index 0000000..1ab843c
--- /dev/null
+++ b/src/main/java/com/realtime/config/MinioConfig.java
@@ -0,0 +1,25 @@
+package com.realtime.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Data
+public class MinioConfig {
+
+ @Value("${minio.endpoint}")
+ private String endpoint;
+
+ @Value("${minio.access-key}")
+ private String accessKey;
+
+ @Value("${minio.secret-key}")
+ private String secretKey;
+
+ @Value("${minio.bucket-name}")
+ private String bucketName;
+
+
+}
diff --git a/src/main/java/com/realtime/config/MyBatisPlusConfig.java b/src/main/java/com/realtime/config/MyBatisPlusConfig.java
new file mode 100644
index 0000000..186fce6
--- /dev/null
+++ b/src/main/java/com/realtime/config/MyBatisPlusConfig.java
@@ -0,0 +1,21 @@
+package com.realtime.config;
+
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MyBatisPlusConfig {
+ /**
+ * 分页插件
+ */
+ @Bean
+ public MybatisPlusInterceptor mybatisPlusInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+ return interceptor;
+ }
+}
diff --git a/src/main/java/com/realtime/config/NettyConfig.java b/src/main/java/com/realtime/config/NettyConfig.java
new file mode 100644
index 0000000..0c96541
--- /dev/null
+++ b/src/main/java/com/realtime/config/NettyConfig.java
@@ -0,0 +1,12 @@
+package com.realtime.config;
+
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class NettyConfig {
+ public final static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+}
diff --git a/src/main/java/com/realtime/config/ProtocolFrameDecoder.java b/src/main/java/com/realtime/config/ProtocolFrameDecoder.java
new file mode 100644
index 0000000..f64c8db
--- /dev/null
+++ b/src/main/java/com/realtime/config/ProtocolFrameDecoder.java
@@ -0,0 +1,14 @@
+package com.realtime.config;
+
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+
+public class ProtocolFrameDecoder extends LengthFieldBasedFrameDecoder {
+
+ public ProtocolFrameDecoder() {
+ this(1024, 12, 4, 0, 0);
+ }
+
+ public ProtocolFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
+ super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
+ }
+}
diff --git a/src/main/java/com/realtime/config/RtasrConfig.java b/src/main/java/com/realtime/config/RtasrConfig.java
new file mode 100644
index 0000000..1062a76
--- /dev/null
+++ b/src/main/java/com/realtime/config/RtasrConfig.java
@@ -0,0 +1,20 @@
+package com.realtime.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "rtsa")
+public class RtasrConfig {
+ private String appId;
+ private String accessKeyId;
+ private String accessKeySecret;
+ private String baseWsUrl;
+ private String audioEncode;
+ private String lang;
+ private Integer samplerate;
+ private Integer audioFameSize;
+ private Integer frameIntervalMs;
+}
diff --git a/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java b/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java
new file mode 100644
index 0000000..e241881
--- /dev/null
+++ b/src/main/java/com/realtime/config/WebSocketAnnotationConfig.java
@@ -0,0 +1,23 @@
+package com.realtime.config;
+
+import org.springframework.context.annotation.Bean;
+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;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+@Configuration
+@EnableWebSocket
+public class WebSocketAnnotationConfig implements WebSocketConfigurer {
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ // 空实现,因为使用 @ServerEndpoint
+ }
+
+ @Bean
+ public ServerEndpointExporter serverEndpointExporter() {
+ return new ServerEndpointExporter();
+ }
+}
diff --git a/src/main/java/com/realtime/controller/ChatListController.java b/src/main/java/com/realtime/controller/ChatListController.java
new file mode 100644
index 0000000..b503ffa
--- /dev/null
+++ b/src/main/java/com/realtime/controller/ChatListController.java
@@ -0,0 +1,47 @@
+package com.realtime.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.ChatList;
+import com.realtime.model.query.ChatListPageQueryReq;
+import com.realtime.service.ChatListService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatListInfoVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/chatList")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class ChatListController {
+
+ private final ChatListService chatListService;
+
+ @PostMapping("/getChatFriend")
+ Result> getChatFriend(@RequestBody ChatListPageQueryReq chatListPageQueryReq){
+ return chatListService.getChatList(chatListPageQueryReq);
+ }
+
+ @PostMapping("/save")
+ Result saveChatList(@RequestBody List chatList){
+ return chatListService.saveSignChatList(chatList);
+ }
+
+ @PostMapping("/delete")
+ Result deleteChatList(@RequestBody ChatList ids){
+ return chatListService.deleteSignChatList(ids);
+ }
+
+ @PostMapping("/update")
+ Result updateChatList(@RequestBody List chatList){
+ return chatListService.updateChatListFName(chatList);
+ }
+}
diff --git a/src/main/java/com/realtime/controller/FileController.java b/src/main/java/com/realtime/controller/FileController.java
new file mode 100644
index 0000000..71f0e25
--- /dev/null
+++ b/src/main/java/com/realtime/controller/FileController.java
@@ -0,0 +1,35 @@
+package com.realtime.controller;
+
+
+
+import com.realtime.service.FileService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.UploadVo;
+import io.minio.errors.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+@Slf4j
+@RestController
+@RequestMapping("/file")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class FileController {
+
+ private final FileService fileService;
+
+ @PostMapping("/upload")
+ Result upload(@RequestPart("file") MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
+ return fileService.uploadFile(file);
+ }
+
+}
diff --git a/src/main/java/com/realtime/controller/FriendshipController.java b/src/main/java/com/realtime/controller/FriendshipController.java
new file mode 100644
index 0000000..56c9bfa
--- /dev/null
+++ b/src/main/java/com/realtime/controller/FriendshipController.java
@@ -0,0 +1,43 @@
+package com.realtime.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.FriendRelationship;
+import com.realtime.model.query.ChatFriendRelationshipQueryReq;
+import com.realtime.service.FriendRelationshipService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatFriendRelationshipInfoVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/friendship")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class FriendshipController {
+
+ private final FriendRelationshipService friendRelationshipService;
+
+ @PostMapping("/getFriendship")
+ Result> selectByPhone(@RequestBody ChatFriendRelationshipQueryReq req){
+ return friendRelationshipService.selectByPhone(req);
+ }
+
+ @PostMapping("/saveShip")
+ Result saveShip(@RequestBody FriendRelationship req){
+ return friendRelationshipService.saveShip(req);
+ }
+
+ @PostMapping("/remove")
+ Result remove(@RequestBody List ids){
+ return friendRelationshipService.removeIds(ids);
+ }
+
+}
diff --git a/src/main/java/com/realtime/controller/GroupController.java b/src/main/java/com/realtime/controller/GroupController.java
new file mode 100644
index 0000000..ce420d0
--- /dev/null
+++ b/src/main/java/com/realtime/controller/GroupController.java
@@ -0,0 +1,88 @@
+package com.realtime.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.google.zxing.WriterException;
+import com.realtime.model.pojo.GroupMember;
+import com.realtime.model.query.GroupDetailQueryReq;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.model.query.GroupMemberListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.remove.RemoveGroupReq;
+import com.realtime.model.remove.RemovesGroupReq;
+import com.realtime.model.update.GroupInventUpdateReq;
+import com.realtime.service.GroupListService;
+import com.realtime.service.GroupMemberService;
+import com.realtime.service.GroupMessageService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.List;
+
+@Slf4j
+@RestController
+@RequestMapping("/group")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class GroupController {
+
+ private final GroupListService groupListService;
+
+ private final GroupMessageService groupMessageService;
+
+ private final GroupMemberService groupMemberService;
+
+ @PostMapping("/getGroup")
+ Result> getGroup(@RequestBody GroupListQueryReq groupListQueryReq) {
+ return groupListService.getGroup(groupListQueryReq);
+ }
+
+ @PostMapping("/getGroupList")
+ Result> getGroupList(@RequestBody GroupListQueryReq req) {
+ return groupMessageService.getGroupList(req);
+ }
+
+ @PostMapping("/getGroupMemberList")
+ Result> getGroupMemberList(@RequestBody GroupMemberListQueryReq req) {
+ return groupMemberService.getMemberList(req);
+ }
+
+ @PostMapping("/getGroupDetail")
+ Result getGroupDetail(@RequestBody GroupDetailQueryReq queryReq) throws IOException, WriterException {
+ return groupListService.getGroupDetail(queryReq);
+ }
+
+ @PostMapping("/updateInvent")
+ Result updateInvent(@RequestBody GroupInventUpdateReq groupInventUpdateReq) {
+ return groupListService.updateInvent(groupInventUpdateReq);
+ }
+
+ @PostMapping("/inventFriend")
+ Result> getAllByGroupIdAndMemberId(@RequestBody GroupMemberListQueryReq queryReq) {
+ return groupMemberService.getAllByGroupIdAndMemberId(queryReq);
+ }
+
+ @PostMapping("/remove")
+ Result remove(@RequestBody RemovesGroupReq ids) {
+ return groupMemberService.removeMembersByIds(ids);
+ }
+
+ @PostMapping("/saveInvent")
+ Result saveInvent(@RequestBody List groupMembers,@RequestParam("launchContactId")String launchContactId) {
+ return groupMemberService.saveInvent(groupMembers,launchContactId);
+ }
+
+ @PostMapping("/disband")
+ Result disband(@RequestBody DisbandGroupReq disbandGroupReq) {
+ return groupListService.disband(disbandGroupReq);
+ }
+
+ @PostMapping("/quit")
+ Result quit(@RequestBody RemoveGroupReq removeGroupReq) {
+ return groupMemberService.quit(removeGroupReq);
+ }
+}
diff --git a/src/main/java/com/realtime/controller/MessageController.java b/src/main/java/com/realtime/controller/MessageController.java
new file mode 100644
index 0000000..db5ba61
--- /dev/null
+++ b/src/main/java/com/realtime/controller/MessageController.java
@@ -0,0 +1,38 @@
+package com.realtime.controller;
+
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.query.ChatQueryPageReq;
+import com.realtime.model.query.MessageQueryReq;
+import com.realtime.service.MessageService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.FriendMessageVo;
+import com.realtime.vo.MessageVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@RestController
+@RequestMapping("/message")
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class MessageController {
+
+ private final MessageService messageService;
+
+ @PostMapping("/list")
+ Result> getList(@RequestBody MessageQueryReq messageQueryReq){
+ return messageService.getList(messageQueryReq);
+ }
+ @PostMapping("/getFriendChatList")
+ Result> getFriendChatList(@RequestBody MessageQueryReq messageQueryReq){
+ return messageService.getFriendChatList(messageQueryReq);
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/controller/TtsController.java b/src/main/java/com/realtime/controller/TtsController.java
new file mode 100644
index 0000000..abc766f
--- /dev/null
+++ b/src/main/java/com/realtime/controller/TtsController.java
@@ -0,0 +1,84 @@
+
+package com.realtime.controller;
+
+import com.realtime.exception.BusinessException;
+import com.realtime.model.query.TtsOptionsReq;
+import com.realtime.service.BaiduTtsService;
+import com.realtime.service.FileService;
+import com.realtime.sysconst.Result;
+import com.realtime.utils.InputStreamMultipartFile;
+import com.realtime.vo.UploadVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.ByteArrayInputStream;
+import java.util.UUID;
+
+@Slf4j
+@RestController
+@RequestMapping("/tts")
+@RequiredArgsConstructor(onConstructor_ = {@Autowired})
+public class TtsController {
+
+ private final BaiduTtsService ttsService;
+
+ private final FileService fileService;
+
+ /**
+ * 文本转语音,返回音频流
+ */
+ @GetMapping("/speech")
+ public Result textToSpeech(@RequestParam("text") String text,
+ @RequestParam(defaultValue = "0",value = "per") int per,
+ @RequestParam(defaultValue = "5",value = "speed") int speed) {
+ try {
+ TtsOptionsReq options = TtsOptionsReq.builder()
+ .per(per)
+ .speed(speed)
+ .build();
+
+ byte[] audioData = ttsService.textToSpeech(text, options);
+
+ if (audioData == null) {
+ throw new BusinessException("转换异常");
+ }
+
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(audioData);
+
+ InputStreamMultipartFile speech = new InputStreamMultipartFile(UUID.randomUUID().toString(), "speech.mp3", "audio/mp3", byteArrayInputStream);
+
+ return fileService.uploadFile(speech);
+ } catch (Exception e) {
+ throw new BusinessException(e.getMessage());
+ }
+ }
+
+ /**
+ * 文本转语音并下载
+ */
+ @PostMapping("/download")
+ public ResponseEntity downloadSpeech(@RequestParam String text) {
+ try {
+ byte[] audioData = ttsService.textToSpeech(text, TtsOptionsReq.defaultOptions());
+
+ if (audioData == null) {
+ return ResponseEntity.badRequest().build();
+ }
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+ headers.setContentDispositionFormData("attachment", "speech.mp3");
+
+ return ResponseEntity.ok()
+ .headers(headers)
+ .body(audioData);
+ } catch (Exception e) {
+ return ResponseEntity.internalServerError().build();
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/exception/BusinessException.java b/src/main/java/com/realtime/exception/BusinessException.java
new file mode 100644
index 0000000..38d8e45
--- /dev/null
+++ b/src/main/java/com/realtime/exception/BusinessException.java
@@ -0,0 +1,22 @@
+package com.realtime.exception;
+
+
+import com.realtime.sysconst.enumConst.ResultEnum;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class BusinessException extends RuntimeException {
+ private Integer code;
+ private ResultEnum result;
+
+ public BusinessException(ResultEnum result) {
+ super(result.getMsg());
+ this.code = result.getCode();
+ }
+
+ public BusinessException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/com/realtime/mappers/ChatListMapper.java b/src/main/java/com/realtime/mappers/ChatListMapper.java
new file mode 100644
index 0000000..8c9550f
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/ChatListMapper.java
@@ -0,0 +1,22 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.ChatList;
+import com.realtime.model.query.ChatListPageQueryReq;
+import com.realtime.vo.ChatListInfoVo;
+import org.apache.ibatis.annotations.Param;
+
+public interface ChatListMapper extends BaseMapper {
+
+ String getMachineIdBySenderId(@Param("id") String senderId);
+
+ IPage getChatList(@Param("reqPage") IPage page, @Param("req") ChatListPageQueryReq chatListPageQueryReq);
+
+ void deleteFriend(@Param("id") String id,@Param("receiver") String receiver);
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java b/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java
new file mode 100644
index 0000000..600c62d
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/FriendRelationshipMapper.java
@@ -0,0 +1,18 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.FriendRelationship;
+import com.realtime.model.query.ChatFriendRelationshipQueryReq;
+import com.realtime.vo.ChatFriendRelationshipInfoVo;
+import org.apache.ibatis.annotations.Param;
+
+public interface FriendRelationshipMapper extends BaseMapper {
+
+
+ IPage selectByPhone(@Param("page") IPage page, @Param("req") ChatFriendRelationshipQueryReq req);
+
+ void updateStateById(@Param("id") Long friendRelationshipId);
+
+}
diff --git a/src/main/java/com/realtime/mappers/GroupListMapper.java b/src/main/java/com/realtime/mappers/GroupListMapper.java
new file mode 100644
index 0000000..2a21519
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/GroupListMapper.java
@@ -0,0 +1,30 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.GroupList;
+import com.realtime.model.query.GroupDetailQueryReq;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.update.GroupInventUpdateReq;
+import com.realtime.vo.GroupDetailVo;
+import com.realtime.vo.GroupListVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface GroupListMapper extends BaseMapper {
+
+ IPage getGroup(@Param("reqpage")IPage iPage, @Param("req") GroupListQueryReq loginIdAsLong);
+
+ GroupDetailVo getGroupDetail(@Param("req") GroupDetailQueryReq queryReq);
+
+ void updateInvent(@Param("req") GroupInventUpdateReq groupInventUpdateReq);
+
+ int isOwner(@Param("req") DisbandGroupReq disbandGroupReq);
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/mappers/GroupMemberMapper.java b/src/main/java/com/realtime/mappers/GroupMemberMapper.java
new file mode 100644
index 0000000..db17287
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/GroupMemberMapper.java
@@ -0,0 +1,34 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.GroupMember;
+import com.realtime.model.query.GroupMemberListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.remove.RemoveGroupReq;
+import com.realtime.model.remove.RemovesGroupReq;
+import com.realtime.vo.ChatListInfoVo;
+import com.realtime.vo.GroupMemberListVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface GroupMemberMapper extends BaseMapper {
+
+ IPage getMemberList(@Param("page") IPage queryReqIPage, @Param("req") GroupMemberListQueryReq queryReq);
+
+ IPage getAllByGroupIdAndMemberId(@Param("page") IPage queryReqIPage, @Param("req") GroupMemberListQueryReq queryReq);
+
+ void quit(RemoveGroupReq removeGroupReq);
+
+ void removeByGroupId(@Param("req") DisbandGroupReq disbandGroupReq);
+
+ void removesByGroupPhoneAndGroupId(@Param("req") RemovesGroupReq ids);
+
+ List getByGroupContactId(@Param("groupContactId")String groupContactId);
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/mappers/GroupMessageMapper.java b/src/main/java/com/realtime/mappers/GroupMessageMapper.java
new file mode 100644
index 0000000..9ba7d33
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/GroupMessageMapper.java
@@ -0,0 +1,18 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.GroupMessage;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.vo.GroupListMessagesVo;
+import org.apache.ibatis.annotations.Param;
+
+public interface GroupMessageMapper extends BaseMapper {
+
+ IPage getGroupList(@Param("page") IPage req, @Param("req") GroupListQueryReq req1);
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/mappers/MessageMapper.java b/src/main/java/com/realtime/mappers/MessageMapper.java
new file mode 100644
index 0000000..326f9be
--- /dev/null
+++ b/src/main/java/com/realtime/mappers/MessageMapper.java
@@ -0,0 +1,24 @@
+package com.realtime.mappers;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.pojo.Message;
+import com.realtime.model.query.MessageQueryReq;
+import com.realtime.vo.FriendMessageVo;
+import com.realtime.vo.MessageItemVo;
+import com.realtime.vo.MessageVo;
+import org.apache.ibatis.annotations.Param;
+
+public interface MessageMapper extends BaseMapper {
+
+ IPage getMsgList(@Param("req") IPage messageQueryReqIPage, @Param("req") MessageQueryReq messageQueryReq);
+
+ IPage getFriendMsgList(@Param("page") IPage messageQueryReqIPage, @Param("req") MessageQueryReq messageQueryReq);
+
+ MessageItemVo selectLastContent(@Param("sessionId") Long sessionId);
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java b/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java
new file mode 100644
index 0000000..d6ae6e1
--- /dev/null
+++ b/src/main/java/com/realtime/model/baseModel/BaseQueryModel.java
@@ -0,0 +1,13 @@
+package com.realtime.model.baseModel;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class BaseQueryModel extends Page {
+ private Long id;
+ private String contactId;
+}
diff --git a/src/main/java/com/realtime/model/pojo/ChatList.java b/src/main/java/com/realtime/model/pojo/ChatList.java
new file mode 100644
index 0000000..8b212fe
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/ChatList.java
@@ -0,0 +1,47 @@
+package com.realtime.model.pojo;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+
+@Data
+public class ChatList implements Serializable {
+ @TableId(type = IdType.AUTO)
+ private Long id;
+ /**
+ * 好友昵称
+ */
+ private String friendNickName;
+ /**
+ * 发送者用户电话
+ */
+ private String sender;
+ /**
+ * 接受者Id
+ */
+ private String receiver;
+ /**
+ * 是否将好友置顶
+ */
+ private Integer isTop;
+ /**
+ * 会话Id
+ */
+ private Long sessionId;
+ /**
+ * 用户是不可以删除助手的 只有用户与用户之间可以删除 1 = 可以 0 = 不可以
+ */
+ private Integer isDelete;
+ private LocalDateTime createdTime;
+
+ @TableField(exist = false)
+ private Long friendRelationshipId;
+
+
+}
diff --git a/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java b/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java
new file mode 100644
index 0000000..df88404
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/ChatListSaveReq.java
@@ -0,0 +1,11 @@
+package com.realtime.model.pojo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ChatListSaveReq implements Serializable {
+ private ChatList chatList;
+ private ChatList newChatList;
+}
diff --git a/src/main/java/com/realtime/model/pojo/FriendRelationship.java b/src/main/java/com/realtime/model/pojo/FriendRelationship.java
new file mode 100644
index 0000000..8cd31e2
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/FriendRelationship.java
@@ -0,0 +1,37 @@
+package com.realtime.model.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+public class FriendRelationship implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ private String sendId;
+ /**
+ * 发起添加好友的时间
+ */
+ private LocalDateTime createdTime;
+ /**
+ * 0 = 未通过 1 = 通过好友
+ */
+ private Integer state;
+
+ private String friendNickName;
+ /**
+ * 这个是被申请加好友的一方
+ */
+ private String recipientId;
+ /**
+ * 写入到chat_list的session_id
+ */
+ private Long sessionId = System.currentTimeMillis();
+
+}
diff --git a/src/main/java/com/realtime/model/pojo/GroupList.java b/src/main/java/com/realtime/model/pojo/GroupList.java
new file mode 100644
index 0000000..d09d3ce
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/GroupList.java
@@ -0,0 +1,48 @@
+package com.realtime.model.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+public class GroupList implements Serializable {
+ @TableId(type = IdType.INPUT)
+ private Long id;
+
+ /**
+ *
+ */
+ private String name;
+
+ /**
+ * 创建者
+ */
+ private String creator;
+
+ /**
+ *
+ */
+ private LocalDateTime createdTime;
+
+ /**
+ * 群图片
+ */
+ private String picture;
+
+ /**
+ * 固定值
+ */
+ private Integer type;
+
+ /**
+ * 是否需要邀请才能加入 1 = 是 0 = 否
+ */
+ private Integer isInvent;
+
+
+ private Integer owner;
+
+}
diff --git a/src/main/java/com/realtime/model/pojo/GroupMember.java b/src/main/java/com/realtime/model/pojo/GroupMember.java
new file mode 100644
index 0000000..4f7519b
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/GroupMember.java
@@ -0,0 +1,31 @@
+package com.realtime.model.pojo;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+public class GroupMember implements Serializable {
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ *
+ */
+ private Long groupId;
+
+ /**
+ * 成员电话号码
+ */
+ private String groupContactId;
+
+ /**
+ * 加入时间
+ */
+ private LocalDateTime createdTime;
+
+
+}
diff --git a/src/main/java/com/realtime/model/pojo/GroupMessage.java b/src/main/java/com/realtime/model/pojo/GroupMessage.java
new file mode 100644
index 0000000..77cedc6
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/GroupMessage.java
@@ -0,0 +1,63 @@
+package com.realtime.model.pojo;
+
+
+
+
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.realtime.packets.GroupSendPacket;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+
+public class GroupMessage implements Serializable {
+ /**
+ *
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 消息内容
+ */
+ private String message;
+
+ /**
+ * 群Id
+ */
+ private Long groupId;
+
+ /**
+ * 发送者Id
+ */
+ private String sender;
+
+ /**
+ *
+ */
+ private Long createTime;
+
+ /**
+ * 0消息 1 =文件/文件
+ */
+ private Integer messageType;
+
+ private String contentJson;
+
+ public GroupMessage(GroupSendPacket groupMessage) {
+ this.createTime = System.currentTimeMillis();
+ this.message = groupMessage.getMessage();
+ this.groupId = groupMessage.getGroupId();
+ this.sender = groupMessage.getSender();
+
+ this.messageType = Integer.valueOf(groupMessage.getMessageType());
+ if (this.messageType == 1) {
+ this.contentJson = JSON.toJSONString(groupMessage.getUploadVos());
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/model/pojo/Message.java b/src/main/java/com/realtime/model/pojo/Message.java
new file mode 100644
index 0000000..ec7b805
--- /dev/null
+++ b/src/main/java/com/realtime/model/pojo/Message.java
@@ -0,0 +1,64 @@
+package com.realtime.model.pojo;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.realtime.packets.SendMsgPackets;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Message {
+ /**
+ *
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 发送者手机号
+ */
+ private String sender;
+
+ /**
+ * 接受者id
+ */
+ private String receiver;
+
+ /**
+ * 消息类型(0:文字;1:图片;2:文件)
+ */
+ private String messageType;
+
+ /**
+ * 内容或url
+ */
+ private String content;
+
+ private Long sessionId;
+
+ /**
+ * 发送时间
+ */
+ private Long createTime;
+
+ private String contentJson;
+
+ public Message(SendMsgPackets params) {
+ this.sender = params.getSender();
+ this.receiver = params.getReceiver();
+ this.createTime = System.currentTimeMillis();
+ this.messageType = String.valueOf(params.getContentType());
+ this.content = params.getMessage();
+ this.sessionId = params.getSessionId();
+ this.contentJson = JSONObject.toJSONString(params.getUploadVos());
+ }
+
+}
diff --git a/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java b/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java
new file mode 100644
index 0000000..7874dcc
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/ChatFriendRelationshipQueryReq.java
@@ -0,0 +1,12 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ChatFriendRelationshipQueryReq extends BaseQueryModel {
+ private String sendId;
+}
diff --git a/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java b/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java
new file mode 100644
index 0000000..9a751de
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/ChatListPageQueryReq.java
@@ -0,0 +1,12 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ChatListPageQueryReq extends BaseQueryModel {
+ private String sendId;
+}
diff --git a/src/main/java/com/realtime/model/query/ChatQueryPageReq.java b/src/main/java/com/realtime/model/query/ChatQueryPageReq.java
new file mode 100644
index 0000000..ff5d9e4
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/ChatQueryPageReq.java
@@ -0,0 +1,13 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+public class ChatQueryPageReq extends BaseQueryModel {
+}
diff --git a/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java b/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java
new file mode 100644
index 0000000..9dcea0e
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/GroupDetailQueryReq.java
@@ -0,0 +1,12 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupDetailQueryReq extends BaseQueryModel {
+ private Long groupId;
+}
diff --git a/src/main/java/com/realtime/model/query/GroupListQueryReq.java b/src/main/java/com/realtime/model/query/GroupListQueryReq.java
new file mode 100644
index 0000000..f1b2637
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/GroupListQueryReq.java
@@ -0,0 +1,14 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupListQueryReq extends BaseQueryModel {
+ private Long groupId;
+ private Long beginTime;
+ private Long endTime;
+}
diff --git a/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java b/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java
new file mode 100644
index 0000000..fbdeafc
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/GroupMemberListQueryReq.java
@@ -0,0 +1,16 @@
+package com.realtime.model.query;
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupMemberListQueryReq extends BaseQueryModel {
+ private Long groupId;
+ private String name;
+ private LocalDateTime beginTime;
+ private LocalDateTime endTime;
+}
diff --git a/src/main/java/com/realtime/model/query/LoginQueryReq.java b/src/main/java/com/realtime/model/query/LoginQueryReq.java
new file mode 100644
index 0000000..e65ffa9
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/LoginQueryReq.java
@@ -0,0 +1,11 @@
+package com.realtime.model.query;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class LoginQueryReq implements Serializable {
+ private Long phone;
+ private String password;
+}
diff --git a/src/main/java/com/realtime/model/query/MessageQueryReq.java b/src/main/java/com/realtime/model/query/MessageQueryReq.java
new file mode 100644
index 0000000..a32f410
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/MessageQueryReq.java
@@ -0,0 +1,18 @@
+package com.realtime.model.query;
+
+
+import com.realtime.model.baseModel.BaseQueryModel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class MessageQueryReq extends BaseQueryModel {
+ private Long taskId;
+ private Long acceptId;
+ private Long sessionId;
+ private Long beginTime;
+ private Long endTime;
+}
diff --git a/src/main/java/com/realtime/model/query/TtsOptionsReq.java b/src/main/java/com/realtime/model/query/TtsOptionsReq.java
new file mode 100644
index 0000000..6543eda
--- /dev/null
+++ b/src/main/java/com/realtime/model/query/TtsOptionsReq.java
@@ -0,0 +1,50 @@
+package com.realtime.model.query;
+
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class TtsOptionsReq {
+ /**
+ * 语言
+ */
+ @Builder.Default
+ private String lang = "zh";
+
+ /**
+ * 语速,0-15,默认为5
+ */
+ @Builder.Default
+ private int speed = 5;
+
+ /**
+ * 音调,0-15,默认为5
+ */
+ @Builder.Default
+ private int pitch = 5;
+
+ /**
+ * 音量,0-15,默认为5
+ */
+ @Builder.Default
+ private int volume = 5;
+
+ /**
+ * 发音人选择
+ * 0-女声,1-男声,3-情感合成-度逍遥,4-情感合成-度丫丫
+ */
+ @Builder.Default
+ private int per = 4100;
+
+ /**
+ * 音频格式
+ * 3:mp3(默认) 4:pcm-16k 5:pcm-8k 6:wav
+ */
+ @Builder.Default
+ private String aue = "3";
+
+ public static TtsOptionsReq defaultOptions() {
+ return TtsOptionsReq.builder().build();
+ }
+}
diff --git a/src/main/java/com/realtime/model/remove/DisbandGroupReq.java b/src/main/java/com/realtime/model/remove/DisbandGroupReq.java
new file mode 100644
index 0000000..944addd
--- /dev/null
+++ b/src/main/java/com/realtime/model/remove/DisbandGroupReq.java
@@ -0,0 +1,9 @@
+package com.realtime.model.remove;
+
+import lombok.Data;
+
+@Data
+public class DisbandGroupReq {
+ private Long groupId;
+ private String groupContactId;
+}
diff --git a/src/main/java/com/realtime/model/remove/RemoveGroupReq.java b/src/main/java/com/realtime/model/remove/RemoveGroupReq.java
new file mode 100644
index 0000000..114aaec
--- /dev/null
+++ b/src/main/java/com/realtime/model/remove/RemoveGroupReq.java
@@ -0,0 +1,9 @@
+package com.realtime.model.remove;
+
+import lombok.Data;
+
+@Data
+public class RemoveGroupReq {
+ private Long groupId;
+ private String groupContactId;
+}
diff --git a/src/main/java/com/realtime/model/remove/RemovesGroupReq.java b/src/main/java/com/realtime/model/remove/RemovesGroupReq.java
new file mode 100644
index 0000000..2612af4
--- /dev/null
+++ b/src/main/java/com/realtime/model/remove/RemovesGroupReq.java
@@ -0,0 +1,11 @@
+package com.realtime.model.remove;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class RemovesGroupReq {
+ private Long groupId;
+ private List groupContactId;
+}
diff --git a/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java b/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java
new file mode 100644
index 0000000..c516c18
--- /dev/null
+++ b/src/main/java/com/realtime/model/update/GroupInventUpdateReq.java
@@ -0,0 +1,9 @@
+package com.realtime.model.update;
+
+import lombok.Data;
+
+@Data
+public class GroupInventUpdateReq {
+ private Long groupId;
+ private Integer invent;
+}
diff --git a/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java b/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java
new file mode 100644
index 0000000..6f66674
--- /dev/null
+++ b/src/main/java/com/realtime/model/update/UpdateUserPasswordReq.java
@@ -0,0 +1,13 @@
+package com.realtime.model.update;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class UpdateUserPasswordReq implements Serializable {
+ private String code;
+ private String password;
+ private Long phone;
+ private String type;
+}
diff --git a/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java b/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java
new file mode 100644
index 0000000..6badcaf
--- /dev/null
+++ b/src/main/java/com/realtime/model/update/UserInfoUpdateReq.java
@@ -0,0 +1,16 @@
+package com.realtime.model.update;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class UserInfoUpdateReq implements Serializable {
+ private Long id;
+ private Long phone;
+ private String nickName;
+ private String avatar;
+ private String occupation;
+ private String region;
+ private Integer sex;
+}
diff --git a/src/main/java/com/realtime/packets/AnswerPacket.java b/src/main/java/com/realtime/packets/AnswerPacket.java
new file mode 100644
index 0000000..730bd38
--- /dev/null
+++ b/src/main/java/com/realtime/packets/AnswerPacket.java
@@ -0,0 +1,18 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class AnswerPacket extends BasePackets {
+ private String sdp;
+ private String type; // answer
+ @Override
+ public Byte getCommand() {
+ return Command.ANSWER;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/AutoSoftwarePacket.java b/src/main/java/com/realtime/packets/AutoSoftwarePacket.java
new file mode 100644
index 0000000..723faf5
--- /dev/null
+++ b/src/main/java/com/realtime/packets/AutoSoftwarePacket.java
@@ -0,0 +1,23 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class AutoSoftwarePacket extends BasePackets {
+ private String url;
+ private String body;
+ private String method;
+ private String commandLine;
+
+ @Override
+ public Byte getCommand() {
+ return Command.SOFT_CALL_MSG;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/CallPacket.java b/src/main/java/com/realtime/packets/CallPacket.java
new file mode 100644
index 0000000..c7dcfe0
--- /dev/null
+++ b/src/main/java/com/realtime/packets/CallPacket.java
@@ -0,0 +1,18 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class CallPacket extends BasePackets {
+ private String sdp;
+ private String type; // "call", "leave", "offer", "answer", "candidate", "hangup"
+ @Override
+ public Byte getCommand() {
+ return Command.CALL_LING;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/ConnectPacket.java b/src/main/java/com/realtime/packets/ConnectPacket.java
new file mode 100644
index 0000000..ceff12f
--- /dev/null
+++ b/src/main/java/com/realtime/packets/ConnectPacket.java
@@ -0,0 +1,16 @@
+package com.realtime.packets;
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class ConnectPacket extends BasePackets {
+
+ @Override
+ public Byte getCommand() {
+ return Command.REGISTER;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/FilePackets.java b/src/main/java/com/realtime/packets/FilePackets.java
new file mode 100644
index 0000000..9cbf7bf
--- /dev/null
+++ b/src/main/java/com/realtime/packets/FilePackets.java
@@ -0,0 +1,18 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FilePackets extends BasePackets {
+ private String fileName;
+ private String filePath;
+
+ @Override
+ public Byte getCommand() {
+ return -1;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/GroupPacket.java b/src/main/java/com/realtime/packets/GroupPacket.java
new file mode 100644
index 0000000..3e45a15
--- /dev/null
+++ b/src/main/java/com/realtime/packets/GroupPacket.java
@@ -0,0 +1,22 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupPacket extends BasePackets {
+ private List userIds;
+ private Integer type = 2;
+ private String groupName;
+
+ @Override
+ public Byte getCommand() {
+ return Command.CREATE_GROUP;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/GroupSendPacket.java b/src/main/java/com/realtime/packets/GroupSendPacket.java
new file mode 100644
index 0000000..b22692d
--- /dev/null
+++ b/src/main/java/com/realtime/packets/GroupSendPacket.java
@@ -0,0 +1,21 @@
+package com.realtime.packets;
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.vo.UploadVo;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class GroupSendPacket extends BasePackets {
+ private Long groupId;
+ private Integer type = 2;
+ private List uploadVos;
+ @Override
+ public Byte getCommand() {
+ return Command.GROUP_MESSAGE;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/InventGroupPacket.java b/src/main/java/com/realtime/packets/InventGroupPacket.java
new file mode 100644
index 0000000..fa2a021
--- /dev/null
+++ b/src/main/java/com/realtime/packets/InventGroupPacket.java
@@ -0,0 +1,21 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class InventGroupPacket extends BasePackets {
+ private List userIds;
+ private Long groupId;
+
+ @Override
+ public Byte getCommand() {
+ return Command.INVENT_GROUP;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/PingPongPacket.java b/src/main/java/com/realtime/packets/PingPongPacket.java
new file mode 100644
index 0000000..f166714
--- /dev/null
+++ b/src/main/java/com/realtime/packets/PingPongPacket.java
@@ -0,0 +1,15 @@
+package com.realtime.packets;
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class PingPongPacket extends BasePackets {
+ @Override
+ public Byte getCommand() {
+ return Command.PING_PONG;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/RealTimePacket.java b/src/main/java/com/realtime/packets/RealTimePacket.java
new file mode 100644
index 0000000..a8f3bf9
--- /dev/null
+++ b/src/main/java/com/realtime/packets/RealTimePacket.java
@@ -0,0 +1,20 @@
+package com.realtime.packets;
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import io.netty.handler.codec.http.HttpObject;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class RealTimePacket extends BasePackets {
+ private String httpObject;
+
+ private String end;
+ @Override
+ public Byte getCommand() {
+ return Command.REAL_TIME_VOICE;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/RemoveGroupPacket.java b/src/main/java/com/realtime/packets/RemoveGroupPacket.java
new file mode 100644
index 0000000..7dde391
--- /dev/null
+++ b/src/main/java/com/realtime/packets/RemoveGroupPacket.java
@@ -0,0 +1,21 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class RemoveGroupPacket extends BasePackets {
+ private List userIds;
+ private Long groupId;
+
+ @Override
+ public Byte getCommand() {
+ return Command.REMOVE_GROUP;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/SendMsgPackets.java b/src/main/java/com/realtime/packets/SendMsgPackets.java
new file mode 100644
index 0000000..7e9a6f3
--- /dev/null
+++ b/src/main/java/com/realtime/packets/SendMsgPackets.java
@@ -0,0 +1,31 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.vo.UploadVo;
+import io.minio.messages.Upload;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SendMsgPackets extends BasePackets {
+ private FilePackets filePackets;
+ private Long sessionId;
+ private Integer contentType;
+ private String friendNickName; //朋友给我的昵称
+ private String friendName;// 我给朋友的昵称
+ private String toAvatar;
+ private Integer unRead = 1;//规定一条
+ private List uploadVos;
+ private Integer type = 1;
+
+
+ @Override
+ public Byte getCommand() {
+ return Command.SINGLE_MESSAGE;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/SystemNoticePackets.java b/src/main/java/com/realtime/packets/SystemNoticePackets.java
new file mode 100644
index 0000000..88813ba
--- /dev/null
+++ b/src/main/java/com/realtime/packets/SystemNoticePackets.java
@@ -0,0 +1,17 @@
+package com.realtime.packets;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SystemNoticePackets extends BasePackets {
+
+ @Override
+ public Byte getCommand() {
+ return Command.SYS_NOTICE;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/basePackets/BasePackets.java b/src/main/java/com/realtime/packets/basePackets/BasePackets.java
new file mode 100644
index 0000000..552842b
--- /dev/null
+++ b/src/main/java/com/realtime/packets/basePackets/BasePackets.java
@@ -0,0 +1,24 @@
+package com.realtime.packets.basePackets;
+
+import io.netty.handler.codec.http.HttpObject;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public abstract class BasePackets implements Serializable {
+ private Byte version = 1;
+ private String sender;
+ private String receiver;
+ private Long groupId = System.currentTimeMillis();
+ private String nickName;
+ private String avatar;
+ private String messageType;
+ private String message;
+ private HttpObject audioByte;
+ private Long createTime = System.currentTimeMillis();
+ private Boolean isNoticeBar = Boolean.FALSE; // 是否需要显示到手机通知栏
+ private Boolean callBackMessage = Boolean.FALSE; //是否需要回执消息
+
+ public abstract Byte getCommand();
+}
diff --git a/src/main/java/com/realtime/packets/command/Command.java b/src/main/java/com/realtime/packets/command/Command.java
new file mode 100644
index 0000000..ac29f6d
--- /dev/null
+++ b/src/main/java/com/realtime/packets/command/Command.java
@@ -0,0 +1,25 @@
+package com.realtime.packets.command;
+
+public interface Command {
+ Byte SELF_RESPONSE = 0; //自己发送的消息确认
+ Byte SINGLE_MESSAGE = 1; //私聊消息
+ Byte MESSAGE_RESPONSE = 2; //私聊响应
+ Byte CREATE_GROUP = 3; //创建群
+ Byte CREATE_GROUP_RESPONSE = 4; //创建群响应
+ Byte LOGIN_REQUEST = 5; //登录请求
+ Byte LOGIN_RESPONSE = 6; // 登录响应
+ Byte REGISTER = 7; //注册请求
+ Byte INVENT_GROUP = 8; //邀请好友加入群聊
+ Byte GROUP_MESSAGE = 9; //发送群消息
+ Byte REMOVE_GROUP = 10; //移除群成员
+ Byte HEARTBEAT_REQUEST = 11; //心跳消息请求
+ Byte HEARTBEAT_RESPONSE = 12; //心跳消息恢复
+ Byte RED_PACK_CREATED = 13; //红包发起
+ Byte JOIN_GROUP = 14; //加入群
+ Byte CALL_LING = 15;// 语音通话发起
+ Byte ANSWER = 16;
+ Byte SYS_NOTICE = 20; //系统消息
+ Byte PING_PONG = 21;
+ Byte REAL_TIME_VOICE = 22;
+ Byte SOFT_CALL_MSG = 23;
+}
diff --git a/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java b/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java
new file mode 100644
index 0000000..54abad4
--- /dev/null
+++ b/src/main/java/com/realtime/packets/resp/GroupResponsePacket.java
@@ -0,0 +1,18 @@
+package com.realtime.packets.resp;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class GroupResponsePacket {
+ private Long groupId;
+ private Integer groupSize;
+ private boolean success = Boolean.TRUE;
+}
diff --git a/src/main/java/com/realtime/packets/server/NettyServer.java b/src/main/java/com/realtime/packets/server/NettyServer.java
new file mode 100644
index 0000000..8eece41
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/NettyServer.java
@@ -0,0 +1,47 @@
+package com.realtime.packets.server;
+
+
+import com.realtime.packets.server.handler.SocketChannelHandler;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor
+public class NettyServer {
+ private final EventLoopGroup bossGroup = new NioEventLoopGroup(8);
+ private final EventLoopGroup workGroup = new NioEventLoopGroup();
+ private final SocketChannelHandler myWebSocketChannelHandler;
+ private final AtomicReference port = new AtomicReference<>(88);
+
+ public void run() {
+ try {
+ ServerBootstrap bootstrap = new ServerBootstrap();
+ bootstrap.group(bossGroup, workGroup).option(ChannelOption.SO_BACKLOG, 1024)
+ .channel(NioServerSocketChannel.class)
+ .option(ChannelOption.SO_BACKLOG, 1024)
+ .childOption(ChannelOption.SO_KEEPALIVE, true)
+ .childOption(ChannelOption.TCP_NODELAY, true)
+ .childHandler(myWebSocketChannelHandler);
+ Channel ch = bootstrap.bind(port.get()).sync().channel();
+ ch.closeFuture().sync();
+ } catch (Exception e) {
+ log.error("异常{}", e.getMessage());
+ } finally {
+ bossGroup.shutdownGracefully();
+ workGroup.shutdownGracefully();
+ }
+ }
+
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java
new file mode 100644
index 0000000..9972541
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/ConnectMessageHandler.java
@@ -0,0 +1,59 @@
+package com.realtime.packets.server.handler;
+
+
+import com.realtime.packets.ConnectPacket;
+import com.realtime.service.GroupMemberService;
+import com.realtime.utils.SessionUtils;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class ConnectMessageHandler extends SimpleChannelInboundHandler {
+
+ private final GroupMemberService groupMemberService;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, ConnectPacket connectPacket) throws Exception {
+ SessionUtils.bindChannel(connectPacket, channelHandlerContext.channel());
+ connectGroup(channelHandlerContext, connectPacket);
+ if (SessionUtils.hasLogin(channelHandlerContext.channel())) {
+ System.out.println(channelHandlerContext.channel());
+ log.info("{}用户已登录", connectPacket.getSender());
+ }
+ }
+
+ // 重连到群组
+ void connectGroup(ChannelHandlerContext ctx, ConnectPacket connectPacket) {
+ List byGroupContactId = groupMemberService.getByGroupContactId(connectPacket.getSender());
+ if (!byGroupContactId.isEmpty()) {
+ byGroupContactId.forEach(item -> {
+ ChannelGroup channelGroup = SessionUtils.getChannelGroup(item);
+ if (channelGroup == null) {
+ ChannelGroup channels = new DefaultChannelGroup(ctx.executor());
+ SessionUtils.bindChannelGroup(item, channels);
+ Channel channel = SessionUtils.getChannel(connectPacket.getSender());
+ channels.add(channel);
+ } else {
+ Channel channel = SessionUtils.getChannel(connectPacket.getSender());
+ boolean contains = channelGroup.contains(channel);
+ if (!contains) {
+ channelGroup.add(channel);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java b/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java
new file mode 100644
index 0000000..59f629d
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/ExceptionHandler.java
@@ -0,0 +1,34 @@
+package com.realtime.packets.server.handler;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelDuplexHandler;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.extern.slf4j.Slf4j;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+@Slf4j
+@Sharable
+public class ExceptionHandler extends ChannelDuplexHandler {
+
+ private final Map map = new ConcurrentHashMap<>();
+
+ public static final ExceptionHandler INSTANCE_EXCEPTION = new ExceptionHandler();
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ if (cause instanceof RuntimeException) {
+ ByteBuf byteBuf = ctx.alloc().buffer();
+ map.put("errorCode",-10000);
+ map.put("errorMessage",cause.getMessage());
+ byteBuf.writeBytes(map.toString().getBytes(StandardCharsets.UTF_8));
+ ctx.channel().writeAndFlush(new TextWebSocketFrame(byteBuf));
+ }
+ }
+}
+
diff --git a/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java
new file mode 100644
index 0000000..8c51390
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/GroupMessageHandler.java
@@ -0,0 +1,48 @@
+package com.realtime.packets.server.handler;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.model.pojo.GroupMessage;
+import com.realtime.packets.GroupSendPacket;
+import com.realtime.service.GroupMessageService;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+
+public class GroupMessageHandler extends SimpleChannelInboundHandler {
+
+ private final GroupMessageService groupMessageService;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, GroupSendPacket groupSendPacket) throws Exception {
+ ChannelGroup group = SessionUtils.getChannelGroup(groupSendPacket.getGroupId());
+ ByteBuf buff = getBuff(channelHandlerContext, groupSendPacket);
+ assert group != null;
+ group.writeAndFlush(new TextWebSocketFrame(buff));
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, GroupSendPacket groupSendPacket) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ byte[] bytes = JSONObject.toJSONString(groupSendPacket).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ groupMessageService.save(new GroupMessage(groupSendPacket));
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java
new file mode 100644
index 0000000..1165735
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/InventGroupHandler.java
@@ -0,0 +1,60 @@
+package com.realtime.packets.server.handler;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.InventGroupPacket;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class InventGroupHandler extends SimpleChannelInboundHandler {
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, InventGroupPacket inventGroupPacket) {
+ Long groupId = inventGroupPacket.getGroupId();
+ if (SessionUtils.getChannelGroup(groupId) == null) {
+ ChannelGroup channels = new DefaultChannelGroup(channelHandlerContext.executor());
+ SessionUtils.bindChannelGroup(groupId, channels);
+ inventGroupPacket.getUserIds().forEach(item -> {
+ Channel userChannel = SessionUtils.getChannel(item);
+ if (userChannel != null) {
+ channels.add(userChannel);
+ }
+ });
+ ByteBuf buff = getBuff(channelHandlerContext, inventGroupPacket);
+ channels.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8)));
+ } else {
+ ChannelGroup channelGroup = SessionUtils.getChannelGroup(groupId);
+ inventGroupPacket.getUserIds().forEach(item -> {
+ Channel userChannel = SessionUtils.getChannel(item);
+ if (userChannel != null) {
+ channelGroup.add(userChannel);
+ }
+ });
+ ByteBuf buff = getBuff(channelHandlerContext, inventGroupPacket);
+ channelGroup.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8)));
+ }
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, InventGroupPacket inventGroupPacket) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ byte[] bytes = JSONObject.toJSONString(inventGroupPacket).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java
new file mode 100644
index 0000000..e039652
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/JoinGroupHandler.java
@@ -0,0 +1,58 @@
+package com.realtime.packets.server.handler;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.GroupPacket;
+import com.realtime.service.GroupListService;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class JoinGroupHandler extends SimpleChannelInboundHandler {
+
+ private final GroupListService groupListService;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, GroupPacket groupPacket) throws Exception {
+ ChannelGroup channels = new DefaultChannelGroup(channelHandlerContext.executor());
+ Long groupId = groupPacket.getGroupId();
+ SessionUtils.bindChannelGroup(groupPacket.getGroupId(), channels);
+ groupPacket.getUserIds().add(groupPacket.getSender());//把自己添加到群聊
+ groupPacket.getUserIds().forEach(item -> {
+ Channel userChannel = SessionUtils.getChannel(item);
+ if (userChannel != null) {
+ channels.add(userChannel);
+ }
+ });
+ System.out.println(channels.size()+"人");
+ ByteBuf buff = getBuff(channelHandlerContext, channels, groupId, groupPacket);
+ channels.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8)));
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, ChannelGroup channels, Long groupId, GroupPacket groupPacket) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ groupPacket.setGroupId(groupId);
+ byte[] bytes = JSONObject.toJSONString(groupPacket).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ groupListService.saveGroupList(groupPacket, groupId);
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java b/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java
new file mode 100644
index 0000000..b6d5f23
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/MessageSocketHandler.java
@@ -0,0 +1,78 @@
+package com.realtime.packets.server.handler;
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.config.NettyConfig;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.strategy.PacketService;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Service
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class MessageSocketHandler extends SimpleChannelInboundHandler {
+
+ private final PacketService packetService;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame binaryWebSocketFrame) throws Exception {
+ dealWithMessage(channelHandlerContext, binaryWebSocketFrame);
+ }
+
+ private void dealWithMessage(ChannelHandlerContext context, WebSocketFrame webSocketFrame) {
+ if (webSocketFrame instanceof CloseWebSocketFrame) {
+ context.channel().close();
+ }
+
+ if (webSocketFrame instanceof PingWebSocketFrame) {
+ context.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain()));
+ }
+
+ ByteBuf byteBuf = webSocketFrame.content();
+ String content = byteBuf.toString(StandardCharsets.UTF_8);
+ JSONObject dataObject = JSONObject.parseObject(content);
+ JSONObject body = dataObject.getJSONObject("body");
+ BasePackets basePackets = packetService.getCurrent(body);
+ if (basePackets.getCallBackMessage()) {
+ TextWebSocketFrame tws = new TextWebSocketFrame(String.valueOf(JSONObject.toJSONString(basePackets)));
+ context.channel().writeAndFlush(tws);
+ }
+
+ context.fireChannelRead(basePackets);
+ }
+
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ NettyConfig.group.add(ctx.channel());
+ }
+
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ NettyConfig.group.remove(ctx.channel());
+ }
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) {
+ ctx.flush();
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+// ctx.close();
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java b/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java
new file mode 100644
index 0000000..cb5a4fd
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/PingPongHartHandler.java
@@ -0,0 +1,41 @@
+package com.realtime.packets.server.handler;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.PingPongPacket;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+public class PingPongHartHandler extends SimpleChannelInboundHandler {
+
+ private final AtomicInteger times = new AtomicInteger(10);
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, PingPongPacket pingPongPacket) throws Exception {
+ Channel channel = SessionUtils.getChannel(pingPongPacket.getSender());
+ ByteBuf buff = getBuff(channelHandlerContext, pingPongPacket);
+ assert channel != null;
+ channel.writeAndFlush(new TextWebSocketFrame(buff));
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, PingPongPacket pingPongPacket) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ pingPongPacket.setMessage("pong");
+ byte[] bytes = JSONObject.toJSONString(pingPongPacket).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java
new file mode 100644
index 0000000..e6d247a
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/PrivateMessageHandler.java
@@ -0,0 +1,51 @@
+package com.realtime.packets.server.handler;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.mappers.MessageMapper;
+import com.realtime.model.pojo.Message;
+import com.realtime.packets.SendMsgPackets;
+import com.realtime.service.MessageService;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class PrivateMessageHandler extends SimpleChannelInboundHandler {
+
+ private final MessageMapper messageMapper;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, SendMsgPackets sendMsgPackets) throws Exception {
+
+ messageMapper.insert(new Message(sendMsgPackets));
+ Channel chanel = SessionUtils.getChannel(sendMsgPackets.getReceiver());
+ ByteBuf buff = getBuff(channelHandlerContext, sendMsgPackets);
+ Objects.requireNonNull(chanel).writeAndFlush(new TextWebSocketFrame(buff));
+ System.out.println("发送私聊消息");
+
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, SendMsgPackets sendMsgPackets) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ byte[] bytes = JSONObject.toJSONString(sendMsgPackets).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java b/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java
new file mode 100644
index 0000000..fed0328
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/RealTimeTransferHandler.java
@@ -0,0 +1,44 @@
+package com.realtime.packets.server.handler;
+
+
+
+import com.realtime.config.RtasrConfig;
+
+import com.realtime.packets.RealTimePacket;
+
+import com.realtime.sysconst.RTASRClient;
+import com.realtime.utils.Base64ToMultipartFile;
+
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class RealTimeTransferHandler extends SimpleChannelInboundHandler {
+
+// private final RealTimeVoiceService realTimeVoiceService;
+//
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, RealTimePacket realTimePacket) throws Exception {
+
+
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java b/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java
new file mode 100644
index 0000000..ef001dd
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/RemoveGroupHandler.java
@@ -0,0 +1,46 @@
+package com.realtime.packets.server.handler;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.RemoveGroupPacket;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Component
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class RemoveGroupHandler extends SimpleChannelInboundHandler {
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, RemoveGroupPacket removeGroupPacket) {
+ Long groupId = removeGroupPacket.getGroupId();
+ ChannelGroup channelGroup = SessionUtils.getChannelGroup(groupId);
+ removeGroupPacket.getUserIds().forEach(userId -> {
+ Channel channel = SessionUtils.getChannel(userId);
+ assert channelGroup != null;
+ channelGroup.remove(channel);
+ });
+ ByteBuf buff = getBuff(channelHandlerContext, removeGroupPacket);
+ assert channelGroup != null;
+ channelGroup.writeAndFlush(new TextWebSocketFrame(buff.toString(StandardCharsets.UTF_8)));
+ }
+
+ ByteBuf getBuff(ChannelHandlerContext channelHandlerContext, RemoveGroupPacket removeGroupPacket) {
+ ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
+ byte[] bytes = JSONObject.toJSONString(removeGroupPacket).getBytes(StandardCharsets.UTF_8);
+ byteBuf.writeBytes(bytes);
+ return byteBuf;
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java b/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java
new file mode 100644
index 0000000..1d7dfcd
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/SocketChannelHandler.java
@@ -0,0 +1,69 @@
+package com.realtime.packets.server.handler;
+
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.*;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.stream.ChunkedWriteHandler;
+import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.CharsetUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import static com.realtime.packets.server.handler.ExceptionHandler.INSTANCE_EXCEPTION;
+
+@Slf4j
+@Service
+@ChannelHandler.Sharable
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class SocketChannelHandler extends ChannelInitializer {
+
+ private final MessageSocketHandler myWebSocketHandler;
+
+ private final GroupMessageHandler groupMessageHandler;
+
+ private final ConnectMessageHandler connectMessageHandler;
+
+ private final JoinGroupHandler joinGroupHandler;
+
+ private final PrivateMessageHandler privateMessageHandler;
+
+ private final PingPongHartHandler pingPongHartHandler;
+
+ private final InventGroupHandler inventGroupHandler;
+
+ private final RealTimeTransferHandler realTimeTransferHandler;
+
+ @Override
+ protected void initChannel(SocketChannel socketChannel) throws Exception {
+ int maxFrameSize = 10 * 1024 * 1024;
+ socketChannel.pipeline()
+ .addLast("http-codec", new HttpServerCodec())
+ .addLast("http-chunked", new ChunkedWriteHandler())
+ .addLast(new WebSocketServerProtocolHandler("/ws", null,true, maxFrameSize))
+ .addLast()
+ .addLast(new StringDecoder(CharsetUtil.UTF_8))
+ .addLast(new StringEncoder(CharsetUtil.UTF_8))
+ .addLast("myWebSocketHandler", myWebSocketHandler)
+ .addLast("groupMessageHandler", groupMessageHandler)
+ .addLast("connectHandler", connectMessageHandler)
+ .addLast("joinGroupHandler", joinGroupHandler)
+ .addLast("privateMessageHandler", privateMessageHandler)
+ .addLast("inventGroupHandler", inventGroupHandler)
+ .addLast("pingPongHartHandler", pingPongHartHandler)
+ .addLast("realTimeTransferHandler", realTimeTransferHandler)
+// .addLast(new IdleStateHandler(10,0,0))
+ .addLast("selfException", INSTANCE_EXCEPTION);
+
+
+
+ }
+}
diff --git a/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java b/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java
new file mode 100644
index 0000000..ddad730
--- /dev/null
+++ b/src/main/java/com/realtime/packets/server/handler/SystemNoticeMessageHandler.java
@@ -0,0 +1,18 @@
+package com.realtime.packets.server.handler;
+
+
+import com.realtime.packets.SystemNoticePackets;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@ChannelHandler.Sharable
+public class SystemNoticeMessageHandler extends SimpleChannelInboundHandler {
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, SystemNoticePackets msg) throws Exception {
+
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/PackStrategy.java b/src/main/java/com/realtime/packets/strategy/PackStrategy.java
new file mode 100644
index 0000000..54d83d9
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/PackStrategy.java
@@ -0,0 +1,12 @@
+package com.realtime.packets.strategy;
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.basePackets.BasePackets;
+
+public interface PackStrategy {
+ boolean getCurrent(Byte commandLine);
+
+ BasePackets getCurrentPacket(JSONObject jsonObject);
+}
diff --git a/src/main/java/com/realtime/packets/strategy/PacketService.java b/src/main/java/com/realtime/packets/strategy/PacketService.java
new file mode 100644
index 0000000..273c1e5
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/PacketService.java
@@ -0,0 +1,12 @@
+package com.realtime.packets.strategy;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.basePackets.BasePackets;
+
+public interface PacketService {
+
+ BasePackets getCurrent(JSONObject jsonObject);
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java
new file mode 100644
index 0000000..13c4240
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/AutoSoftwareStrategyImpl.java
@@ -0,0 +1,24 @@
+package com.realtime.packets.strategy.impl;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.AutoSoftwarePacket;
+import com.realtime.packets.ConnectPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class AutoSoftwareStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.SOFT_CALL_MSG.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), AutoSoftwarePacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java
new file mode 100644
index 0000000..19de994
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/ConnectPackStrategyImpl.java
@@ -0,0 +1,26 @@
+package com.realtime.packets.strategy.impl;
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.ConnectPacket;
+import com.realtime.packets.SendMsgPackets;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class ConnectPackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.REGISTER.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), ConnectPacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java
new file mode 100644
index 0000000..899f834
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/GroupJoinPackStrategyImpl.java
@@ -0,0 +1,24 @@
+package com.realtime.packets.strategy.impl;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.GroupPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class GroupJoinPackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.CREATE_GROUP.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), GroupPacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java
new file mode 100644
index 0000000..510d571
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/GroupSendPackStrategyImpl.java
@@ -0,0 +1,26 @@
+package com.realtime.packets.strategy.impl;
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.GroupSendPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class GroupSendPackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.GROUP_MESSAGE.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+
+ return JSONObject.parseObject(jsonObject.toString(), GroupSendPacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java
new file mode 100644
index 0000000..92a08ce
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/InventStrategyImpl.java
@@ -0,0 +1,27 @@
+package com.realtime.packets.strategy.impl;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.InventGroupPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class InventStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.INVENT_GROUP.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), InventGroupPacket.class);
+
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java
new file mode 100644
index 0000000..ed1b82a
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/PacketServiceImpl.java
@@ -0,0 +1,35 @@
+package com.realtime.packets.strategy.impl;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.exception.BusinessException;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.strategy.PackStrategy;
+import com.realtime.packets.strategy.PacketService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class PacketServiceImpl implements PacketService {
+
+ private final List packStrategies;
+ @Override
+ public BasePackets getCurrent(JSONObject jsonObject) {
+ Byte command = jsonObject.getByte("command");
+ return getCurrent(command).getCurrentPacket(jsonObject);
+ }
+
+ private PackStrategy getCurrent(Byte commandLine) {
+ long size = packStrategies.stream().filter(item -> item.getCurrent(commandLine)).count();
+ if (size <= 0) {
+ throw new BusinessException("没有可用的频道!!");
+ }
+ return packStrategies.stream().filter(item -> item.getCurrent(commandLine)).toList().get(0);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java
new file mode 100644
index 0000000..d9508f7
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/PingPongPackStrategyImpl.java
@@ -0,0 +1,24 @@
+package com.realtime.packets.strategy.impl;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.PingPongPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class PingPongPackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.PING_PONG.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), PingPongPacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java
new file mode 100644
index 0000000..f9dfcf8
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/PrivatePackStrategyImpl.java
@@ -0,0 +1,26 @@
+package com.realtime.packets.strategy.impl;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.SendMsgPackets;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class PrivatePackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.SINGLE_MESSAGE.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), SendMsgPackets.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java
new file mode 100644
index 0000000..39bcaa6
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/RealTimePackStrategyImpl.java
@@ -0,0 +1,24 @@
+package com.realtime.packets.strategy.impl;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.RealTimePacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class RealTimePackStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.REAL_TIME_VOICE.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), RealTimePacket.class);
+ }
+}
diff --git a/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java b/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java
new file mode 100644
index 0000000..e0bb182
--- /dev/null
+++ b/src/main/java/com/realtime/packets/strategy/impl/RemoveStrategyImpl.java
@@ -0,0 +1,27 @@
+package com.realtime.packets.strategy.impl;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.packets.RemoveGroupPacket;
+import com.realtime.packets.basePackets.BasePackets;
+import com.realtime.packets.command.Command;
+import com.realtime.packets.strategy.PackStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class RemoveStrategyImpl implements PackStrategy {
+ @Override
+ public boolean getCurrent(Byte commandLine) {
+ return Command.REMOVE_GROUP.equals(commandLine);
+ }
+
+ @Override
+ public BasePackets getCurrentPacket(JSONObject jsonObject) {
+ return JSONObject.parseObject(jsonObject.toString(), RemoveGroupPacket.class);
+
+ }
+}
diff --git a/src/main/java/com/realtime/service/BaiduAuthService.java b/src/main/java/com/realtime/service/BaiduAuthService.java
new file mode 100644
index 0000000..8e4b9bc
--- /dev/null
+++ b/src/main/java/com/realtime/service/BaiduAuthService.java
@@ -0,0 +1,46 @@
+package com.realtime.service;
+
+
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.realtime.config.BaiduTtsConfig;
+import lombok.RequiredArgsConstructor;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+public class BaiduAuthService {
+
+
+ private final BaiduTtsConfig ttsConfig;
+
+ /**
+ * 获取百度语音合成访问令牌
+ */
+ public String getAccessToken() {
+ String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
+ String getAccessTokenUrl = authHost
+ + "grant_type=client_credentials"
+ + "&client_id=" + ttsConfig.getApiKey()
+ + "&client_secret=" + ttsConfig.getSecretKey();
+
+ try {
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+ HttpGet get = new HttpGet(getAccessTokenUrl);
+ HttpResponse response = httpClient.execute(get);
+ String result = EntityUtils.toString(response.getEntity());
+
+ JSONObject jsonObject = JSONObject.parseObject(result);
+ return jsonObject.getString("access_token");
+ } catch (Exception e) {
+ throw new RuntimeException("获取百度语音合成Token失败", e);
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/service/BaiduTtsService.java b/src/main/java/com/realtime/service/BaiduTtsService.java
new file mode 100644
index 0000000..92dfd64
--- /dev/null
+++ b/src/main/java/com/realtime/service/BaiduTtsService.java
@@ -0,0 +1,94 @@
+package com.realtime.service;
+
+
+import com.google.common.io.Files;
+import com.realtime.model.query.TtsOptionsReq;
+import lombok.RequiredArgsConstructor;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Autowired})
+public class BaiduTtsService {
+
+ private static final String TTS_URL = "http://tsn.baidu.com/text2audio";
+
+ private final BaiduAuthService authService;
+
+ /**
+ * 文本转语音
+ * @param text 要转换的文本
+ * @param options 合成参数
+ * @return 音频字节数组
+ */
+ public byte[] textToSpeech(String text, TtsOptionsReq options) {
+ try {
+ String accessToken = authService.getAccessToken();
+
+ Map params = new HashMap<>();
+ params.put("tex", URLEncoder.encode(text, StandardCharsets.UTF_8));
+ params.put("tok", accessToken);
+ params.put("cuid", UUID.randomUUID().toString().replaceAll("-", ""));
+ params.put("ctp", "1");
+ params.put("lan", options.getLang());
+ params.put("spd", String.valueOf(options.getSpeed()));
+ params.put("pit", String.valueOf(options.getPitch()));
+ params.put("vol", String.valueOf(options.getVolume()));
+ params.put("per", String.valueOf(options.getPer()));
+ params.put("aue", options.getAue());
+
+ return postForm(params);
+ } catch (Exception e) {
+ throw new RuntimeException("语音合成失败", e);
+ }
+ }
+
+ /**
+ * 发送POST请求
+ */
+ private byte[] postForm(Map params) throws Exception {
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+ HttpPost post = new HttpPost(BaiduTtsService.TTS_URL);
+
+ // 设置表单参数
+ List paramList = new ArrayList<>();
+ for (Map.Entry param : params.entrySet()) {
+ paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
+ }
+ post.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8"));
+
+ // 执行请求
+ HttpResponse response = httpClient.execute(post);
+ HttpEntity entity = response.getEntity();
+
+ if (entity != null) {
+ return EntityUtils.toByteArray(entity);
+ }
+ return null;
+ }
+
+ /**
+ * 文本转语音并保存为文件
+ */
+ public void textToSpeechFile(String text, TtsOptionsReq options, String filePath) throws IOException {
+ byte[] audioData = textToSpeech(text, options);
+ if (audioData != null) {
+ Files.write(audioData,new File(filePath));
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/service/ChatListService.java b/src/main/java/com/realtime/service/ChatListService.java
new file mode 100644
index 0000000..cd47b8a
--- /dev/null
+++ b/src/main/java/com/realtime/service/ChatListService.java
@@ -0,0 +1,28 @@
+package com.realtime.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.realtime.model.pojo.ChatList;
+import com.realtime.model.query.ChatListPageQueryReq;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatListInfoVo;
+
+import java.util.List;
+
+public interface ChatListService extends IService {
+
+
+ void saveChatList(ChatList chatList);
+
+ String getMachineIdBySenderId(String senderId);
+
+ Result> getChatList(ChatListPageQueryReq chatListPageQueryReq);
+
+ Result saveSignChatList(List chatList);
+
+ Result updateChatListFName(List chatList);
+
+
+ Result deleteSignChatList(ChatList ids);
+}
diff --git a/src/main/java/com/realtime/service/DoubaoVoiceService.java b/src/main/java/com/realtime/service/DoubaoVoiceService.java
new file mode 100644
index 0000000..749fc32
--- /dev/null
+++ b/src/main/java/com/realtime/service/DoubaoVoiceService.java
@@ -0,0 +1,105 @@
+package com.realtime.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.realtime.config.DoubaoVoiceConfig;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import okio.ByteString;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+import org.springframework.web.socket.BinaryMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+@Slf4j
+@Service
+public class DoubaoVoiceService {
+ private final DoubaoVoiceConfig config;
+ private final OkHttpClient okHttpClient;
+ private WebSocket doubaoWebSocket; // 与豆包 API 的 WebSocket 连接
+
+ public DoubaoVoiceService(DoubaoVoiceConfig config) {
+ this.config = config;
+ this.okHttpClient = new OkHttpClient.Builder()
+ .readTimeout(0, TimeUnit.MILLISECONDS) // 实时流禁用超时
+ .build();
+ }
+
+ /**
+ * 建立与豆包实时语音接口的 WebSocket 连接
+ * @param clientSession 客户端的 WebSocket 会话(用于将结果返回给客户端)
+ */
+ public void connect(WebSocketSession clientSession) {
+
+ Request request = new Request.Builder()
+ .addHeader("X-Api-App-ID",config.getAppId())
+ .addHeader("X-Api-Access-Key",config.getAccessToken())
+ .addHeader("X-Api-Resource-Id","volc.speech.dialog").addHeader("X-Api-App-Key",config.getApiKey())
+ .url("wss://openspeech.bytedance.com/api/v3/realtime/dialogue")
+ .build();
+
+ // 连接豆包 API 并处理回调
+ doubaoWebSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
+ @Override
+ public void onOpen(@NotNull WebSocket webSocket, @NotNull Response response) {
+ // 连接成功:可发送初始化参数(如语音类型、采样率)
+ sendInitParams(webSocket);
+ }
+
+ @Override
+ public void onMessage(@NotNull WebSocket webSocket, ByteString bytes) {
+ // 接收豆包返回的实时结果(如识别文本、合成语音)
+ try {
+ // 将结果转发给客户端
+ clientSession.sendMessage(new BinaryMessage(bytes.toByteArray()));
+ } catch (IOException e) {
+ log.error("转发结果到客户端失败", e);
+ }
+ }
+
+ @Override
+ public void onFailure(WebSocket webSocket, Throwable t, Response response) {
+ System.out.println(t.getMessage());
+ log.error("豆包 WebSocket 连接失败", t);
+ }
+ });
+ }
+
+ /**
+ * 向豆包 API 发送音频数据(实时流)
+ */
+ public void sendAudio(byte[] audioData) {
+ if (doubaoWebSocket != null) {
+ doubaoWebSocket.send(ByteString.of(audioData));
+ }
+ }
+
+ /**
+ * 发送初始化参数(根据豆包 API 要求)
+ */
+ private void sendInitParams(WebSocket webSocket) {
+ Map params = new HashMap<>();
+ params.put("action", "init");
+ params.put("format", "pcm"); // 音频格式
+ params.put("sample_rate", 16000); // 采样率
+ params.put("mode", "realtime"); // 实时模式
+ try {
+ webSocket.send(new ObjectMapper().writeValueAsString(params));
+ } catch (JsonProcessingException e) {
+ log.error("发送初始化参数失败", e);
+ }
+ }
+
+ /**
+ * 关闭连接
+ */
+ public void close() {
+ if (doubaoWebSocket != null) {
+ doubaoWebSocket.close(1000, "正常关闭");
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/service/FileService.java b/src/main/java/com/realtime/service/FileService.java
new file mode 100644
index 0000000..bf4f603
--- /dev/null
+++ b/src/main/java/com/realtime/service/FileService.java
@@ -0,0 +1,18 @@
+package com.realtime.service;
+
+
+
+import com.realtime.sysconst.Result;
+import com.realtime.vo.UploadVo;
+import io.minio.errors.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public interface FileService {
+
+ Result uploadFile(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException;
+
+}
diff --git a/src/main/java/com/realtime/service/FriendRelationshipService.java b/src/main/java/com/realtime/service/FriendRelationshipService.java
new file mode 100644
index 0000000..4f7d253
--- /dev/null
+++ b/src/main/java/com/realtime/service/FriendRelationshipService.java
@@ -0,0 +1,22 @@
+package com.realtime.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.realtime.model.pojo.FriendRelationship;
+import com.realtime.model.query.ChatFriendRelationshipQueryReq;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatFriendRelationshipInfoVo;
+
+import java.util.List;
+
+public interface FriendRelationshipService extends IService {
+
+ Result> selectByPhone(ChatFriendRelationshipQueryReq req);
+
+ Result saveShip(FriendRelationship friendRelationship);
+
+ void updateStateById(Long friendRelationshipId);
+
+ Result removeIds(List ids);
+}
diff --git a/src/main/java/com/realtime/service/GroupListService.java b/src/main/java/com/realtime/service/GroupListService.java
new file mode 100644
index 0000000..45083fe
--- /dev/null
+++ b/src/main/java/com/realtime/service/GroupListService.java
@@ -0,0 +1,33 @@
+package com.realtime.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.google.zxing.WriterException;
+import com.realtime.model.pojo.GroupList;
+import com.realtime.model.query.GroupDetailQueryReq;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.update.GroupInventUpdateReq;
+import com.realtime.packets.GroupPacket;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.GroupDetailVo;
+import com.realtime.vo.GroupListVo;
+
+import java.io.IOException;
+import java.util.List;
+
+public interface GroupListService extends IService {
+
+ void saveGroupList(GroupPacket groupPacket, Long groupId);
+
+ Result> getGroup(GroupListQueryReq groupDetailQueryReq);
+
+ Result getGroupDetail(GroupDetailQueryReq queryReq) throws WriterException, IOException, WriterException;
+
+
+ Result updateInvent(GroupInventUpdateReq groupInventUpdateReq);
+
+ Result disband(DisbandGroupReq disbandGroupReq);
+
+}
diff --git a/src/main/java/com/realtime/service/GroupMemberService.java b/src/main/java/com/realtime/service/GroupMemberService.java
new file mode 100644
index 0000000..0c684b4
--- /dev/null
+++ b/src/main/java/com/realtime/service/GroupMemberService.java
@@ -0,0 +1,32 @@
+package com.realtime.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.realtime.model.pojo.GroupMember;
+import com.realtime.model.query.GroupMemberListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.remove.RemoveGroupReq;
+import com.realtime.model.remove.RemovesGroupReq;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatListInfoVo;
+import com.realtime.vo.GroupMemberListVo;
+
+import java.util.List;
+
+public interface GroupMemberService extends IService {
+
+ Result> getMemberList(GroupMemberListQueryReq queryReq);
+
+ Result> getAllByGroupIdAndMemberId(GroupMemberListQueryReq queryReq);
+
+ Result saveInvent(List groupMembers, String launchContactId);
+
+ Result quit(RemoveGroupReq removeGroupReq);
+
+ void removeByGroupId(DisbandGroupReq disbandGroupReq);
+
+ Result removeMembersByIds(RemovesGroupReq removesGroupReq);
+
+ List getByGroupContactId(String groupContactId);
+}
diff --git a/src/main/java/com/realtime/service/GroupMessageService.java b/src/main/java/com/realtime/service/GroupMessageService.java
new file mode 100644
index 0000000..7d994c6
--- /dev/null
+++ b/src/main/java/com/realtime/service/GroupMessageService.java
@@ -0,0 +1,23 @@
+package com.realtime.service;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.realtime.model.pojo.GroupMessage;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.GroupListMessagesVo;
+
+import java.util.List;
+
+public interface GroupMessageService extends IService {
+
+ Result> getGroupList(GroupListQueryReq req);
+
+ default Result removeMembersByIds(List ids) {
+ removeByIds(ids);
+ return Result.success("ok");
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/service/MessageService.java b/src/main/java/com/realtime/service/MessageService.java
new file mode 100644
index 0000000..6d7f37c
--- /dev/null
+++ b/src/main/java/com/realtime/service/MessageService.java
@@ -0,0 +1,30 @@
+package com.realtime.service;
+
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.model.query.ChatQueryPageReq;
+import com.realtime.model.query.MessageQueryReq;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.FriendMessageVo;
+import com.realtime.vo.MessageInfoVo;
+import com.realtime.vo.MessageVo;
+import io.netty.channel.ChannelHandlerContext;
+
+public interface MessageService {
+
+
+ /**
+ * 获取聊天记录
+ * @param messageQueryReq 请求参数
+ * @return 结果
+ */
+ Result> getList(MessageQueryReq messageQueryReq);
+
+ /****
+ * 获取所有和我聊过天的好友
+ * @param messageQueryReq
+ * @return
+ */
+ Result> getFriendChatList(MessageQueryReq messageQueryReq);
+}
diff --git a/src/main/java/com/realtime/service/RealTimeVoiceService.java b/src/main/java/com/realtime/service/RealTimeVoiceService.java
new file mode 100644
index 0000000..9dabe58
--- /dev/null
+++ b/src/main/java/com/realtime/service/RealTimeVoiceService.java
@@ -0,0 +1,18 @@
+package com.realtime.service;
+
+
+import com.realtime.packets.RealTimePacket;
+import org.json.JSONObject;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+
+public interface RealTimeVoiceService {
+ void connect() throws RuntimeException, URISyntaxException;
+
+
+ void sendAudio(RealTimePacket relativePacket) throws RuntimeException, URISyntaxException;
+}
diff --git a/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java b/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java
new file mode 100644
index 0000000..2dff14b
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/ChatListServiceImpl.java
@@ -0,0 +1,147 @@
+package com.realtime.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.realtime.mappers.ChatListMapper;
+import com.realtime.model.pojo.ChatList;
+import com.realtime.model.pojo.FriendRelationship;
+import com.realtime.model.query.ChatListPageQueryReq;
+import com.realtime.service.ChatListService;
+import com.realtime.service.FriendRelationshipService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatListInfoVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class ChatListServiceImpl extends ServiceImpl
+ implements ChatListService {
+
+ private final FriendRelationshipService friendRelationshipService;
+
+ /**
+ * @param chatList
+ * @return
+ */
+ @Override
+ public void saveChatList(ChatList chatList) {
+ long sessionId = System.currentTimeMillis();
+ chatList.setSessionId(sessionId);
+ chatList.setIsDelete(0);
+ ChatList newChatList = new ChatList();
+ newChatList.setSessionId(sessionId);
+ newChatList.setReceiver(chatList.getSender());
+ newChatList.setSender(chatList.getReceiver());
+ newChatList.setIsDelete(0);
+ newChatList.setFriendNickName("我的助手");
+ baseMapper.insert(chatList);
+ baseMapper.insert(newChatList);
+ }
+
+ /**
+ * @param senderId 用户号码
+ * @return 返回机器人的虚拟电话号码
+ */
+ @Override
+ public String getMachineIdBySenderId(String senderId) {
+ return baseMapper.getMachineIdBySenderId(senderId);
+ }
+
+ /**
+ * 查询自己的的好友
+ *
+ * @param chatListPageQueryReq 请求参数
+ * @return 结果
+ */
+ @Override
+ public Result> getChatList(ChatListPageQueryReq chatListPageQueryReq) {
+ return Result.success(baseMapper.getChatList(chatListPageQueryReq, chatListPageQueryReq));
+ }
+
+ /**
+ * 保存好友
+ *
+ * @param chatList 请求参数
+ * @return 结果
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Result saveSignChatList(List chatList) {
+ Long friendRelationshipId = chatList.get(0).getFriendRelationshipId();
+ chatList.get(1).setFriendNickName(friendRelationshipService.getById(friendRelationshipId).getFriendNickName());
+ this.saveBatch(chatList);
+ friendRelationshipService.updateStateById(friendRelationshipId);
+ return Result.success("添加成功");
+ }
+
+ //@Override
+ //public Result updateChatListFName(List chatList) {
+ // return null;
+ //}
+
+// @Override
+// public Result deleteSignChatList(ChatList chatList) {
+// List i = baseMapper.selectList(new LambdaQueryWrapper().eq(ChatList::getSessionId, chatList.getSessionId()));
+// if(i.size() < 2){
+// return Result.fail("删除失败: 非好友");
+// }
+// if(i.get(0).getIsDelete() == 0){
+// return Result.fail("不可删除");
+// }
+// baseMapper.delete(new LambdaQueryWrapper().eq(ChatList::getSessionId, chatList.getSessionId()));
+// friendRelationshipService.remove(new LambdaQueryWrapper().eq(FriendRelationship::getSessionId, chatList.getSessionId()));
+// return Result.success("删除成功");
+// }
+ /**
+ * @param chatList
+ * @return
+ */
+ @Override
+ public Result updateChatListFName(List chatList) {
+ // 遍历传入的chatList
+ for (ChatList chat : chatList) {
+ // 根据receiver和sessionId查询聊天列表
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+ queryWrapper.eq("receiver", chat.getReceiver())
+ .eq("session_id", chat.getSessionId());
+
+ ChatList existingChat = this.getOne(queryWrapper);
+ System.out.println(existingChat);
+ if (existingChat != null) {
+ // 判断是否是"我的助手",如果是,不进行修改
+ if ("我的助手".equals(existingChat.getFriendNickName())) {
+ // 如果是"我的助手",跳过此记录
+ continue;
+ } else {
+ // 如果不是"我的助手",修改friendNickName
+ existingChat.setFriendNickName(chat.getFriendNickName());
+ System.out.println(existingChat.getFriendNickName());
+ this.updateById(existingChat); // 更新数据库中的数据
+ }
+ }
+ }
+ return Result.success("更新完成");
+ }
+
+ @Override
+ public Result deleteSignChatList(ChatList ids) {
+ baseMapper.deleteFriend(ids.getSender(), ids.getReceiver());
+ baseMapper.deleteFriend(ids.getReceiver(),ids.getSender());
+ return Result.success("ok");
+ }
+
+
+}
+
+
+
diff --git a/src/main/java/com/realtime/service/impl/ChatServiceImpl.java b/src/main/java/com/realtime/service/impl/ChatServiceImpl.java
new file mode 100644
index 0000000..cd07786
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/ChatServiceImpl.java
@@ -0,0 +1,589 @@
+///*
+// * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
+// *
+// * Licensed under the GNU Affero General Public License, Version 3 (the "License");
+// * you may not use this file except in compliance with the License.
+// * You may obtain a copy of the License at
+// *
+// * https://www.gnu.org/licenses/agpl-3.0.html
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// */
+//
+//package com.realtime.service.impl;
+//
+//
+//import com.chat.config.OssProperties;
+//import com.chat.constants.FileConstant;
+//import com.chat.constants.RoleEnum;
+//import com.chat.endpoint.DoBaoAiService;
+//import com.chat.model.pojo.AigcMessage;
+//import com.chat.model.pojo.AigcOss;
+//import com.chat.model.query.ChatReq;
+//import com.chat.model.query.ChatRes;
+//import com.chat.model.query.ImageR;
+//import com.chat.service.AigcMessageService;
+//import com.chat.service.ChatService;
+//import com.chat.service.LangChatService;
+//import com.chat.service.UserService;
+//import com.chat.utils.HttpUtil;
+//import com.chat.utils.OssFileUtil;
+//import com.chat.utils.ServletUtil;
+//import com.chat.utils.StreamEmitter;
+//import dev.langchain4j.data.image.Image;
+//import dev.langchain4j.model.output.Response;
+//import dev.langchain4j.model.output.TokenUsage;
+//import lombok.AllArgsConstructor;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.beans.BeanUtils;
+//import org.springframework.stereotype.Service;
+//
+//import java.io.BufferedReader;
+//import java.io.IOException;
+//import java.io.InputStreamReader;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.util.List;
+//import java.util.Objects;
+//import java.util.concurrent.ExecutorService;
+//import java.util.concurrent.Executors;
+//
+///**
+// * @author tycoding
+// * @since 2024/1/4
+// */
+//@Slf4j
+//@Service
+//@AllArgsConstructor
+//public class ChatServiceImpl implements ChatService {
+//
+// private final LangChatService langChatService;
+// private final AigcMessageService aigcMessageService;
+// private final DoBaoAiService doBaoAiService;
+// private final UserService userService;
+// private final OssProperties ossProperties;
+// private final OssFileUtil ossFileUtil;
+//
+// private final String addText = "add_text";
+// private final String addFile = "add_file";
+//
+// private final String fileHandleUrl = "http://127.0.0.1:5001/convert/word-to-markdown";
+//
+// @Override
+// public void chat(ChatReq req, ExecutorService executorService) {
+// if(req.getUrl() != null){
+// gradioChat(req, executorService, addFile, req.getUrl(), req.getMessage());
+// }else {
+// gradioChat(req, executorService, addText, req.getMessage());
+// }
+// }
+//
+// @Override
+// public void chat(ChatReq req) {
+// StreamEmitter emitter = req.getEmitter();
+// long startTime = System.currentTimeMillis();
+// StringBuilder text = new StringBuilder();
+//
+//
+// // save user message
+// req.setRole(RoleEnum.USER.getName());
+// saveMessage(req, 0, 0);
+//
+// //if(req.getType() == 0){
+// // chatFileWord(req);
+// // return;
+// //}
+// if(req.getType() == 2 || req.getType() == 0){
+// emitter.complete();
+// return;
+// }
+//
+// try {
+// if (req.getUrl() != null && !req.getUrl().isEmpty()){
+// doBaoAiService.chatFile(req);
+// }
+// else if(Objects.equals(req.getModelName(), "AI对话")){
+// doBaoAiService.chat(req);
+// }
+// else {
+// langChatService
+// .chat(req)
+// .onNext(e -> {
+// StringBuilder append = text.append(e);
+// emitter.send(new ChatRes(e));
+// })
+// .onComplete((e) -> {
+// TokenUsage tokenUsage = e.tokenUsage();
+// ChatRes res = new ChatRes(tokenUsage.totalTokenCount(), startTime);
+// emitter.send(res);
+// emitter.complete();
+//
+// // save assistant message
+// req.setMessage(text.toString());
+// req.setRole(RoleEnum.ASSISTANT.getName());
+// req.setType(1);
+// saveMessage(req, tokenUsage.inputTokenCount(), tokenUsage.outputTokenCount());
+// })
+// .onError((e) -> {
+// emitter.error(e.getMessage());
+// throw new RuntimeException(e.getMessage());
+// })
+// .start();
+// }
+// } catch (Exception e) {
+// e.printStackTrace();
+// emitter.error(e.getMessage());
+// throw new RuntimeException(e.getMessage());
+// }
+// }
+//
+// private void chatFileWord(ChatReq req) {
+// StreamEmitter emitter = req.getEmitter();
+// long startTime = System.currentTimeMillis();
+//
+// JSONObject jsonObject = HttpUtil.builder()
+// .url("http://127.0.0.1:5001/convert/word-to-markdown")
+// .addParam("ossUrl", req.getMessage())
+// .addParam("userId", req.getUserId())
+// .post(true)
+// .sync();
+// if(req.getEmitter() != null){
+// if(jsonObject.getString("status").equals("success")){
+// emitter.send(new ChatRes(jsonObject.getJSONObject("result").getString("content")));
+// req.setMessage(jsonObject.getJSONObject("result").getString("content"));
+// req.setRole(RoleEnum.ASSISTANT.getName());
+// req.setType(1);
+// saveMessage(req, 0, 0);
+// }else {
+// emitter.send(new ChatRes(jsonObject.getString("message")));
+// req.setMessage(jsonObject.getString("message"));
+// req.setRole(RoleEnum.ASSISTANT.getName());
+// req.setType(1);
+// saveMessage(req, 0, 0);
+// }
+//
+// }
+// ChatRes res = new ChatRes(0, startTime);
+// emitter.send(res);
+// emitter.complete();
+// }
+//
+// private void saveMessage(ChatReq req, Integer inputToken, Integer outputToken) {
+// if (req.getConversationId() != null) {
+// AigcMessage message = new AigcMessage();
+// BeanUtils.copyProperties(req, message);
+// message.setIp(ServletUtil.getIpAddr());
+// message.setPromptTokens(inputToken);
+// message.setTokens(outputToken);
+// aigcMessageService.addMessage(message);
+// }
+// }
+//
+// @Override
+// public String text(ChatReq req) {
+// String text;
+// try {
+// text = langChatService.text(req);
+// } catch (Exception e) {
+// e.printStackTrace();
+// throw new RuntimeException(e.getMessage());
+// }
+// return text;
+// }
+//
+// @Override
+// public AigcOss image(ImageR req) {
+// Response res = langChatService.image(req);
+//
+// String path = res.content().url().toString();
+// AigcOss oss = new AigcOss();
+// oss.setUrl(path);
+// return oss;
+// }
+//
+// @Override
+// public void saveTaskMessage(ChatReq req) {
+//
+// req.setRole(RoleEnum.USER.getName());
+// saveMessage(req, 0, 0);
+// StreamEmitter emitter = req.getEmitter();
+//// emitter.send(new ChatRes("点击文件进行操作"));
+// emitter.send(new ChatRes(0,0));
+// emitter.complete();
+// }
+//
+// @Override
+// public JSONObject isPdfToDxf(ChatReq req) {
+// JSONObject jsonObject = null;
+// try {
+// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本
+// String pythonPath = getProjectRoot() +
+// (System.getProperty("os.name").toLowerCase().contains("win")
+// ? "\\venv\\Scripts\\python.exe"
+// : "/venv/bin/python");
+// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() +"/scripts/prompt.py");
+// System.out.println(List.of(req.getMessage()));
+// pb.command().add(req.getMessage());
+// // 启动进程
+// Process process = pb.start();
+//
+// // 获取进程的标准输出流
+// BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
+// // 获取进程的错误输出流
+// BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+//
+// String line;
+// // 读取并打印 Python 脚本的标准输出
+// while ((line = stdInput.readLine()) != null) {
+// jsonObject = JSONObject.parseObject(line);
+// }
+//
+// // 读取并打印 Python 脚本的错误输出
+// while ((line = stdError.readLine()) != null) {
+// System.err.println(line);
+// }
+//
+// // 等待进程执行完毕
+// int exitCode = process.waitFor();
+// System.out.println("Exit Code: " + exitCode);
+//
+// } catch (InterruptedException | IOException e) {
+// e.printStackTrace();
+// }
+// if (jsonObject == null) {
+// jsonObject = JSONObject.parseObject("{\"status\": false}");
+// }
+// return jsonObject;
+// }
+//
+// @Override
+// public void pdfToDxf(ChatReq req, ExecutorService executor, JSONObject jsonObject) {
+// StreamEmitter emitter = req.getEmitter();
+// long startTime = System.currentTimeMillis();
+//
+// String userId = String.valueOf(userService.getIdByPhone(Long.parseLong(req.getUserId())));
+// String filePath = FileConstant.UserFilePath + userId + "/" + jsonObject.get("pdf_file");
+// String outFilePath = ossProperties.getEndpoint() + "/" + ossProperties.getBucketName() + "/" + FileConstant.USERTEMPName + userId + "/";
+// String outFileName = jsonObject.getString("dxf_file");
+// // 调用模型
+// String out = "AI异常";
+// JSONObject jsonObject1 = pdfToDxfPy(req.getMessage(), filePath, jsonObject.getString("pdf_file"), outFilePath, outFileName);
+// // 生成文件
+// if(jsonObject1.getBoolean("success")){
+// ossFileUtil.upFile("D://xiazai//"+outFileName, FileConstant.USERTEMPName + userId + "/");
+// out = "操作成功";
+// }
+// // 发送结果
+// emitter.send(new ChatRes(out));
+// // 关闭SSE
+// emitter.send(new ChatRes(0, startTime));
+// emitter.complete();
+//
+// }
+//
+// @Override
+// public void pdfToDxf2(ChatReq req, ExecutorService executor, JSONObject jsonObject) {
+// StreamEmitter emitter = req.getEmitter();
+// long startTime = System.currentTimeMillis();
+// try {
+// String userId = String.valueOf(userService.getIdByPhone(Long.parseLong(req.getUserId())));
+// String filePath = FileConstant.UserFilePath + userId + "/" + jsonObject.get("pdf_file");
+// String outFilePath = ossProperties.getEndpoint() + "/" + ossProperties.getBucketName() + "/" + FileConstant.USERTEMPName + userId + "/";
+// String outFileName = jsonObject.getString("dxf_file");
+// // 调用模型
+// String out = "AI异常";
+// JSONObject jsonObject1 = pdfToDxfPy(req.getMessage(), filePath, jsonObject.getString("pdf_file"), outFilePath, outFileName);
+// // 上传文件
+// if(jsonObject1.getBoolean("success")){
+// ossFileUtil.upFile("D:/xiazai/"+outFileName, FileConstant.USERTEMPPath + userId + "/" + outFileName);
+// out = "操作成功";
+// }
+// // 发送结果
+// emitter.send(new ChatRes(out));
+// // 关闭SSE
+// emitter.send(new ChatRes(0, startTime));
+// }catch (Exception e){
+// emitter.error("AI处理异常");
+// log.error(e.getMessage());
+// }finally {
+// emitter.complete();
+// }
+// }
+//
+// private JSONObject pdfToDxfPy(String message, String filePath,String xiazaiFileneme, String outFilePath, String outFileName) {
+// // 下载文件
+// ossFileUtil.download(filePath, "D:\\xiazai\\" + xiazaiFileneme);
+// JSONObject jsonObject = null;
+// try {
+// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本
+// String pythonPath = getProjectRoot() +
+// (System.getProperty("os.name").toLowerCase().contains("win")
+// ? "\\venv\\Scripts\\python.exe"
+// : "/venv/bin/python");
+// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() +"/scripts/forceTest_agent(2).py");
+// System.out.println(List.of(message));
+// pb.command().add(message);
+// // 启动进程
+// Process process = pb.start();
+//
+// // 获取进程的标准输出流
+// BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
+// // 获取进程的错误输出流
+// BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+//
+// String line;
+// // 读取并打印 Python 脚本的标准输出
+// StringBuilder aimessage = new StringBuilder();
+// boolean foundStart = false;
+// while ((line = stdInput.readLine()) != null) {
+// if (!foundStart) {
+// if (line.trim().startsWith("{")) {
+// foundStart = true;
+// aimessage.append(line);
+// }
+// } else {
+// aimessage.append(line);
+// if (line.trim().endsWith("}")) {
+// break;
+// }
+// }
+// }
+// log.info(String.valueOf(aimessage));
+// jsonObject = JSONObject.parseObject(String.valueOf(aimessage));
+// // 读取并打印 Python 脚本的错误输出
+// while ((line = stdError.readLine()) != null) {
+// System.err.println(line);
+// }
+//
+// // 等待进程执行完毕
+// int exitCode = process.waitFor();
+// System.out.println("Exit Code: " + exitCode);
+//
+// } catch (InterruptedException | IOException e) {
+// e.printStackTrace();
+// }
+// if (jsonObject == null || jsonObject.getBoolean("success") == null) {
+// jsonObject = JSONObject.parseObject("{\"success\": false}");
+// }
+// return jsonObject;
+// }
+//
+// private void gradioChat(ChatReq req, ExecutorService executorService, String pythonFile, String... inputMessage){
+// ExecutorService executor = req.getExecutor() != null ? executorService : Executors.newSingleThreadExecutor();
+//
+// try {
+// StreamEmitter emitter = req.getEmitter();
+// long startTime = System.currentTimeMillis();
+//
+//
+// // save user message
+// req.setRole(RoleEnum.USER.getName());
+// saveMessage(req, 0, 0);
+//
+// if(req.getType() == 2){
+// emitter.complete();
+// return;
+// }
+//
+// String pythonPath = getProjectRoot() +
+// (System.getProperty("os.name").toLowerCase().contains("win")
+// ? "\\venv\\Scripts\\python.exe"
+// : "/venv/bin/python");
+// ProcessBuilder pb1 = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/c20250423/"+ pythonFile +".py");
+// //System.out.println(List.of(inputMessage));
+// pb1.command().addAll(List.of(inputMessage));
+// // 启动进程
+// Process process1 = pb1.start();
+// String line1;
+// StringBuilder aimessage1 = new StringBuilder();
+// // 处理标准输出流
+// try (BufferedReader stdInput = new BufferedReader(
+// new InputStreamReader(process1.getInputStream()))) {
+// while ((line1 = stdInput.readLine()) != null) {
+// aimessage1.append(line1);
+// }
+// }
+// JSONObject jsonObject = doBaoAiService.pdData(String.valueOf(aimessage1));
+// log.info("AI任务对话:{}", jsonObject);
+// if(jsonObject.getString("code").equals("3") && jsonObject.getString("txt").equals("false")){
+// // 调用Python脚本获取AI响应
+// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本
+// // 动态构建Python路径
+// ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/"+ pythonFile +".py");
+// //System.out.println(List.of(inputMessage));
+// pb.command().addAll(List.of(inputMessage));
+// // 启动进程
+// Process process = pb.start();
+// String line;
+// StringBuilder aimessage = new StringBuilder();
+// // 处理标准输出流
+// try (BufferedReader stdInput = new BufferedReader(
+// new InputStreamReader(process.getInputStream()))) {
+// boolean skipFirst = true;
+// String previousLine = "";
+//
+// while ((line = stdInput.readLine()) != null) {
+// // 不要开头
+// if (skipFirst && line.startsWith("Loaded as API: ")) {
+// skipFirst = false;
+// continue;
+// }
+//
+// int startIndex = previousLine.length();
+// if (startIndex < line.length()) {
+// String processedLine = line.replace("\\~n", "\n").replace("\\~r", "\r");;
+// String newPart = processedLine.substring(startIndex);
+// aimessage.append(newPart);
+// // 发送流式响应
+// if (emitter != null) {
+// emitter.send(new ChatRes(newPart));
+// }
+// previousLine = processedLine;
+// }
+//
+// }
+// if (emitter != null) {
+// emitter.send(new ChatRes(0,startTime));
+// }
+// }
+//
+// // 处理错误流
+// try (BufferedReader stdError = new BufferedReader(
+// new InputStreamReader(process.getErrorStream()))) {
+//
+// String errorLine;
+// while ((errorLine = stdError.readLine()) != null) {
+// log.error("Python script error: {}", errorLine);
+// }
+// }
+//
+// // 等待进程结束
+// int exitCode = process.waitFor();
+// if (exitCode != 0) {
+// throw new RuntimeException("Python script exited with code: " + exitCode);
+// }
+//
+// req.setMessage(String.valueOf(aimessage));
+// req.setRole(RoleEnum.ASSISTANT.getName());
+// req.setType(1);
+// saveMessage(req, 0, 0);
+//
+// } else {
+// if (emitter != null) {
+// emitter.send(new ChatRes(jsonObject.getString("txt")));
+// emitter.send(new ChatRes(0,startTime));
+// }
+//
+// req.setMessage(String.valueOf(jsonObject.getString("txt")));
+// req.setRole(RoleEnum.ASSISTANT.getName());
+// req.setType(1);
+// saveMessage(req, 0, 0);
+// }
+//
+//
+// // 处理错误流
+// try (BufferedReader stdError = new BufferedReader(
+// new InputStreamReader(process1.getErrorStream()))) {
+// String errorLine;
+// while ((errorLine = stdError.readLine()) != null) {
+// log.error("Python script error: {}", errorLine);
+// }
+// }
+//
+// // 等待进程结束
+// int exitCode1 = process1.waitFor();
+// if (exitCode1 != 0) {
+// throw new RuntimeException("Python script exited with code: " + exitCode1);
+// }
+//
+//
+// // 调用Python脚本获取AI响应
+// // 创建一个 ProcessBuilder 对象,用于执行 Python 脚本
+// // 动态构建Python路径
+// //ProcessBuilder pb = new ProcessBuilder(pythonPath, getProjectRoot() + "/scripts/c202523/"+ pythonFile +".py");
+// ////System.out.println(List.of(inputMessage));
+// //pb.command().addAll(List.of(inputMessage));
+// //// 启动进程
+// //Process process = pb.start();
+// //String line;
+// //StringBuilder aimessage = new StringBuilder();
+// //// 处理标准输出流
+// //try (BufferedReader stdInput = new BufferedReader(
+// // new InputStreamReader(process.getInputStream()))) {
+// // boolean skipFirst = true;
+// // String previousLine = "";
+// //
+// // while ((line = stdInput.readLine()) != null) {
+// // // 不要开头
+// // if (skipFirst && line.startsWith("Loaded as API: ")) {
+// // skipFirst = false;
+// // continue;
+// // }
+// //
+// // int startIndex = previousLine.length();
+// // if (startIndex < line.length()) {
+// // String processedLine = line.replace("\\~n", "\n").replace("\\~r", "\r");;
+// // String newPart = processedLine.substring(startIndex);
+// // aimessage.append(newPart);
+// // // 发送流式响应
+// // if (emitter != null) {
+// // emitter.send(new ChatRes(newPart));
+// // }
+// // previousLine = processedLine;
+// // }
+// //
+// // }
+// // if (emitter != null) {
+// // emitter.send(new ChatRes(0,startTime));
+// // }
+// //}
+// //
+// //// 处理错误流
+// //try (BufferedReader stdError = new BufferedReader(
+// // new InputStreamReader(process.getErrorStream()))) {
+// //
+// // String errorLine;
+// // while ((errorLine = stdError.readLine()) != null) {
+// // log.error("Python script error: {}", errorLine);
+// // }
+// //}
+// //
+// //// 等待进程结束
+// //int exitCode = process.waitFor();
+// //if (exitCode != 0) {
+// // throw new RuntimeException("Python script exited with code: " + exitCode);
+// //}
+//
+// // 保存AI响应到数据库
+// //req.setMessage(String.valueOf(aimessage));
+// //req.setRole(RoleEnum.ASSISTANT.getName());
+// //req.setType(1);
+// //saveMessage(req, 0, 0);
+//
+//
+// // 7. 完成流式响应
+// if (req.getEmitter() != null) {
+// req.getEmitter().complete();
+// }
+// } catch (Exception e) {
+// log.error("Chat processing failed", e);
+// if (req.getEmitter() != null) {
+// req.getEmitter().error(e.getMessage());
+// }
+// } finally {
+// if (req.getExecutor() != null) {
+// executor.shutdown();
+// }
+// }
+// }
+//
+// // 获取项目根目录路径
+// private static String getProjectRoot() {
+// Path currentPath = Paths.get("").toAbsolutePath();
+// return currentPath.toString();
+// }
+//}
diff --git a/src/main/java/com/realtime/service/impl/FileServiceImpl.java b/src/main/java/com/realtime/service/impl/FileServiceImpl.java
new file mode 100644
index 0000000..46bfb80
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/FileServiceImpl.java
@@ -0,0 +1,89 @@
+package com.realtime.service.impl;
+
+
+import cn.hutool.core.codec.Base64;
+import com.realtime.config.FileProperties;
+import com.realtime.config.MinioComponent;
+import com.realtime.config.MinioConfig;
+import com.realtime.exception.BusinessException;
+import com.realtime.service.FileService;
+import com.realtime.sysconst.Result;
+import com.realtime.sysconst.enumConst.ResultEnum;
+import com.realtime.vo.UploadVo;
+import io.minio.MinioClient;
+import io.minio.PutObjectArgs;
+import io.minio.errors.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class FileServiceImpl implements FileService {
+
+ private final MinioConfig minioConfig;
+
+ private final MinioClient minioClient;
+
+ private final FileProperties fileProperties;
+
+ @Override
+ public Result uploadFile(MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
+ if (file.isEmpty()) throw new BusinessException(ResultEnum.FILE_NOT_NULL);
+ List allowedFormats = Arrays.asList(fileProperties.getAllowedFormats().split(","));
+ String fileName = Objects.requireNonNull(file.getOriginalFilename()).toLowerCase();
+ String fileSuffix = fileName.substring(fileName.lastIndexOf('.') + 1);
+ if (!allowedFormats.contains(fileSuffix)) {
+ throw new BusinessException(ResultEnum.FILE_FORMAT_ERROR);
+ }
+
+ UploadVo vo = generateFileName(file,fileSuffix);
+ InputStream inputStream = file.getInputStream();
+ minioClient.putObject(PutObjectArgs.builder()
+ .bucket(minioConfig.getBucketName())
+ .object(vo.getNewFileName())
+ .stream(inputStream, file.getSize(), -1)
+ .contentType(file.getContentType())
+ .build()
+ );
+ return Result.success(vo);
+ }
+
+
+ private UploadVo generateFileName(MultipartFile file,String fileSuffix) {
+ String originalFilename = file.getOriginalFilename();
+ assert originalFilename != null;
+ UploadVo uploadVo = new UploadVo();
+ String storeFileName = UUID.randomUUID() + "_" + originalFilename;
+ String url = generateFileUrl(storeFileName);
+ uploadVo.setName(originalFilename);
+ uploadVo.setUrl(url);
+ uploadVo.setExtendName(fileSuffix);
+ uploadVo.setNewFileName(storeFileName);
+ uploadVo.setFileSize(BigDecimal.valueOf(file.getSize()).divide(BigDecimal.valueOf(1048576)).setScale(3, RoundingMode.HALF_UP)); // MB
+ uploadVo.setFileNameCode(Base64.encode(originalFilename));
+ return uploadVo;
+
+ }
+
+ private String generateFileUrl(String fileName) {
+ return
+ minioConfig.getEndpoint()+"/real/" + fileName;
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java b/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java
new file mode 100644
index 0000000..38c7875
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/FriendRelationshipServiceImpl.java
@@ -0,0 +1,79 @@
+package com.realtime.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.realtime.exception.BusinessException;
+import com.realtime.mappers.FriendRelationshipMapper;
+import com.realtime.model.pojo.FriendRelationship;
+import com.realtime.model.query.ChatFriendRelationshipQueryReq;
+import com.realtime.service.FriendRelationshipService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.ChatFriendRelationshipInfoVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class FriendRelationshipServiceImpl extends ServiceImpl implements FriendRelationshipService {
+ /**
+ * 获取好友申请
+ * @param req 请求参数
+ * @return 结果
+ */
+ @Override
+ public Result> selectByPhone(ChatFriendRelationshipQueryReq req) {
+ return Result.success(baseMapper.selectByPhone(req,req));
+ }
+
+ /**
+ * 申请添加好友
+ * @param friendRelationship 请求参数
+ * @return 结果
+ */
+ @Override
+ public Result saveShip(FriendRelationship friendRelationship) {
+// if (StpUtil.getLoginIdAsLong() == friendRelationship.getRecipientPhone()){
+// throw new BusinessException(ResultEnum.NOT_ADD_SELF);
+// }
+ Long count = baseMapper.selectCount(
+ new LambdaQueryWrapper()
+ .and(wrapper -> wrapper
+ .eq(FriendRelationship::getSendId, friendRelationship.getSendId())
+ .eq(FriendRelationship::getRecipientId, friendRelationship.getRecipientId())
+ .eq(FriendRelationship::getState,0)
+ )
+ .or(wrapper -> wrapper
+ .eq(FriendRelationship::getSendId, friendRelationship.getRecipientId())
+ .eq(FriendRelationship::getRecipientId, friendRelationship.getSendId())
+ .eq(FriendRelationship::getState,0)
+ )
+ );
+ if (count > 0) {
+ return Result.fail("重复申请");
+ }
+
+ baseMapper.insert(friendRelationship);
+ return Result.success("success");
+ }
+
+ /**
+ * @param friendRelationshipId
+ */
+ @Override
+ public void updateStateById(Long friendRelationshipId) {
+ baseMapper.updateStateById(friendRelationshipId);
+ }
+
+ @Override
+ public Result removeIds(List ids) {
+ removeByIds(ids);
+ return Result.success("ok");
+ }
+}
diff --git a/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java
new file mode 100644
index 0000000..7f5d183
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/GroupListServiceImpl.java
@@ -0,0 +1,123 @@
+package com.realtime.service.impl;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.WriterException;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
+import com.realtime.exception.BusinessException;
+import com.realtime.mappers.GroupListMapper;
+import com.realtime.model.pojo.GroupList;
+import com.realtime.model.pojo.GroupMember;
+import com.realtime.model.query.GroupDetailQueryReq;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.update.GroupInventUpdateReq;
+import com.realtime.packets.GroupPacket;
+import com.realtime.service.GroupListService;
+import com.realtime.service.GroupMemberService;
+import com.realtime.sysconst.Result;
+import com.realtime.utils.SessionUtils;
+import com.realtime.vo.GroupDetailVo;
+import com.realtime.vo.GroupListVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Autowired})
+public class GroupListServiceImpl extends ServiceImpl
+ implements GroupListService {
+
+ private final GroupMemberService groupMemberService;
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void saveGroupList(GroupPacket groupPacket, Long groupId) {
+ GroupList groupList = new GroupList();
+ groupList.setId(groupId);
+ groupList.setCreator(groupPacket.getSender());
+ groupList.setOwner(1);
+ groupList.setName(groupPacket.getGroupName());
+ save(groupList);
+
+ saveMember(groupPacket,groupId);
+ }
+
+ @Override
+ public Result> getGroup(GroupListQueryReq groupListQueryReq) {
+ return Result.success(baseMapper.getGroup(groupListQueryReq,groupListQueryReq));
+ }
+
+ @Override
+ public Result getGroupDetail(GroupDetailQueryReq queryReq) throws IOException, WriterException {
+ String content = "/pages/group/joinGroup?qrCode=" + queryReq.getGroupId(); // 扫描这个内容直接跳转到确认登录界面
+ // 生成二维码图片
+ QRCodeWriter qrCodeWriter = new QRCodeWriter();
+ BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 240, 240);
+ BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
+
+ // 转换为Base64
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", baos);
+ byte[] bytes = baos.toByteArray();
+ String qrcode = "data:image/png;base64,"+ Base64.getEncoder().encodeToString(bytes);
+ GroupDetailVo groupDetail = baseMapper.getGroupDetail(queryReq);
+ groupDetail.setQrCode(qrcode);
+ return Result.success(groupDetail);
+ }
+
+ @Override
+ public Result updateInvent(GroupInventUpdateReq groupInventUpdateReq) {
+ baseMapper.updateInvent(groupInventUpdateReq);
+ return Result.success(null);
+ }
+
+ @Override
+ public Result disband(DisbandGroupReq disbandGroupReq) {
+// long loginIdAsLong = StpUtil.getLoginIdAsLong();
+// disbandGroupReq.setPhone(loginIdAsLong);
+// int owner = baseMapper.isOwner(disbandGroupReq);
+// if (owner != 1){
+// throw new BusinessException(NOT_CREATOR);
+// }
+// Objects.requireNonNull(SessionUtils.getChannelGroup(disbandGroupReq.getGroupId())).close().addListener(item->{
+// baseMapper.deleteById(disbandGroupReq.getGroupId());
+// groupMemberService.removeByGroupId(disbandGroupReq);
+// });
+
+ return Result.success("解散成功");
+ }
+
+ void saveMember(GroupPacket groupPacket,Long groupId) {
+ List saveList = new ArrayList<>();
+ groupPacket.getUserIds().forEach(item->{
+ GroupMember groupMember = new GroupMember();
+ groupMember.setGroupId(groupId);
+ groupMember.setGroupContactId(item);
+ saveList.add(groupMember);
+ });
+ groupMemberService.saveBatch(saveList);
+ }
+
+
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java
new file mode 100644
index 0000000..72e38cb
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/GroupMemberServiceImpl.java
@@ -0,0 +1,76 @@
+package com.realtime.service.impl;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.realtime.mappers.GroupMemberMapper;
+import com.realtime.model.pojo.GroupList;
+import com.realtime.model.pojo.GroupMember;
+import com.realtime.model.query.GroupMemberListQueryReq;
+import com.realtime.model.remove.DisbandGroupReq;
+import com.realtime.model.remove.RemoveGroupReq;
+import com.realtime.model.remove.RemovesGroupReq;
+import com.realtime.service.GroupListService;
+import com.realtime.service.GroupMemberService;
+import com.realtime.sysconst.Result;
+import com.realtime.utils.SessionUtils;
+import com.realtime.vo.ChatListInfoVo;
+import com.realtime.vo.GroupMemberListVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class GroupMemberServiceImpl extends ServiceImpl
+ implements GroupMemberService {
+
+ @Override
+ public Result> getMemberList(GroupMemberListQueryReq queryReq) {
+ return Result.success(baseMapper.getMemberList(queryReq, queryReq));
+ }
+
+ @Override
+ public Result> getAllByGroupIdAndMemberId(GroupMemberListQueryReq queryReq) {
+ return Result.success(baseMapper.getAllByGroupIdAndMemberId(queryReq, queryReq));
+ }
+
+ @Override
+ public Result saveInvent(List groupMembers, String launchContactId) {
+ saveBatch(groupMembers);
+ return Result.success("ok");
+ }
+
+ @Override
+ public Result quit(RemoveGroupReq removeGroupReq) {
+ baseMapper.quit(removeGroupReq);
+ SessionUtils.removeChanelByGroup(removeGroupReq.getGroupId(), removeGroupReq.getGroupContactId());
+ return Result.success("ok");
+ }
+
+ @Override
+ public void removeByGroupId(DisbandGroupReq disbandGroupReq) {
+ baseMapper.removeByGroupId(disbandGroupReq);
+ }
+
+ @Override
+ public Result removeMembersByIds(RemovesGroupReq ids) {
+ SessionUtils.removeBatchChannel(ids.getGroupId(), ids.getGroupContactId());
+ baseMapper.removesByGroupPhoneAndGroupId(ids);
+ return Result.success("ok");
+ }
+
+ @Override
+ public List getByGroupContactId(String groupContactId) {
+ return baseMapper.getByGroupContactId(groupContactId);
+ }
+
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java b/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java
new file mode 100644
index 0000000..0a736fe
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/GroupMessageServiceImpl.java
@@ -0,0 +1,26 @@
+package com.realtime.service.impl;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.realtime.mappers.GroupMessageMapper;
+import com.realtime.model.pojo.GroupMessage;
+import com.realtime.model.query.GroupListQueryReq;
+import com.realtime.service.GroupMessageService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.GroupListMessagesVo;
+import org.springframework.stereotype.Service;
+
+@Service
+public class GroupMessageServiceImpl extends ServiceImpl
+ implements GroupMessageService {
+
+ @Override
+ public Result> getGroupList(GroupListQueryReq req) {
+ return Result.success(baseMapper.getGroupList(req,req));
+ }
+}
+
+
+
+
diff --git a/src/main/java/com/realtime/service/impl/MessageServiceImpl.java b/src/main/java/com/realtime/service/impl/MessageServiceImpl.java
new file mode 100644
index 0000000..514ca8d
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/MessageServiceImpl.java
@@ -0,0 +1,43 @@
+package com.realtime.service.impl;
+
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.realtime.exception.BusinessException;
+import com.realtime.mappers.MessageMapper;
+import com.realtime.model.query.ChatQueryPageReq;
+import com.realtime.model.query.MessageQueryReq;
+import com.realtime.service.MessageService;
+import com.realtime.sysconst.Result;
+import com.realtime.vo.FriendMessageVo;
+import com.realtime.vo.MessageInfoVo;
+import com.realtime.vo.MessageVo;
+import io.netty.channel.ChannelHandlerContext;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class MessageServiceImpl implements MessageService {
+
+ private final MessageMapper mapper;
+
+
+
+ @Override
+ public Result> getList(MessageQueryReq messageQueryReq) {
+ return Result.success(mapper.getMsgList(messageQueryReq,messageQueryReq));
+ }
+
+
+ @Override
+ public Result> getFriendChatList(MessageQueryReq messageQueryReq) {
+ return Result.success(mapper.getFriendMsgList(messageQueryReq,messageQueryReq));
+ }
+
+}
diff --git a/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java b/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java
new file mode 100644
index 0000000..8916526
--- /dev/null
+++ b/src/main/java/com/realtime/service/impl/RealTimeVoiceServiceImpl.java
@@ -0,0 +1,250 @@
+//package com.realtime.service.impl;
+//
+//import com.realtime.config.RtasrConfig;
+//import com.realtime.packets.RealTimePacket;
+//import com.realtime.service.RealTimeVoiceService;
+//import lombok.RequiredArgsConstructor;
+//import lombok.extern.slf4j.Slf4j;
+//import org.java_websocket.client.WebSocketClient;
+//import org.java_websocket.handshake.ServerHandshake;
+//import org.json.JSONObject;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Service;
+//
+//import javax.crypto.Mac;
+//import javax.crypto.spec.SecretKeySpec;
+//import java.io.*;
+//import java.net.URI;
+//import java.net.URISyntaxException;
+//import java.net.URLEncoder;
+//import java.nio.charset.StandardCharsets;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.text.SimpleDateFormat;
+//import java.util.*;
+//
+//@Slf4j
+//@Service
+//@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+//public class RealTimeVoiceServiceImpl implements RealTimeVoiceService {
+//
+// private final RtasrConfig config;
+//
+// private String sessionId;
+//
+// private WebSocketClient webSocketClient;
+//
+// @Override
+// public void connect() throws RuntimeException, URISyntaxException {
+// Map authParams = generateAuthParams();
+// String paramsStr = buildParamsString(authParams);
+// String fullWsUrl = config.getBaseWsUrl() + "?" + paramsStr;
+// System.out.println("【连接信息】完整URL:" + fullWsUrl);
+// webSocketClient = new WebSocketClient(new URI(fullWsUrl)) {
+// @Override
+// public void onOpen(ServerHandshake handshakedata) {
+// System.out.println(handshakedata);
+// // 等待服务端初始化
+// try {
+// Thread.sleep(1200);
+// } catch (InterruptedException e) {
+// Thread.currentThread().interrupt();
+// }
+// }
+//
+// @Override
+// public void onMessage(String message) {
+// System.out.println(message);
+// try {
+// // 使用org.json解析JSON消息
+// JSONObject json = new JSONObject(message);
+// System.out.println("【接收消息】" + json.toString());
+//
+// // 处理会话ID
+// if ("action".equals(json.optString("msg_type"))) {
+// JSONObject data = json.optJSONObject("data");
+// if (data != null && data.has("sessionId")) {
+// sessionId = data.getString("sessionId");
+// System.out.println("【会话信息】已获取sessionId:" + sessionId);
+// }
+// }
+// } catch (Exception e) {
+// int maxLength = Math.min(50, message.length());
+// System.out.println("【接收异常】非JSON文本消息:" + message.substring(0, maxLength) + "...");
+// }
+// }
+//
+// @Override
+// public void onClose(int code, String reason, boolean remote) {
+//
+// System.out.println("【连接关闭】代码:" + code + ",原因:" + reason);
+// }
+//
+// @Override
+// public void onError(Exception ex) {
+// System.err.println("【WebSocket错误】" + ex.getMessage());
+// ex.printStackTrace();
+// }
+// };
+// }
+//
+// @Override
+// public void sendAudio(RealTimePacket relativePacket) throws RuntimeException, URISyntaxException {
+// try (FileInputStream fis = convertBytesToFileInputStream(relativePacket.getAudioByte(),UUID.randomUUID().toString(),".pcm")) {
+//
+//
+//
+// // 发送音频帧
+// byte[] buffer = new byte[config.getAudioFameSize()];
+// int bytesRead;
+// int frameIndex = 0;
+// Long startTime = null;
+//
+// while ((bytesRead = fis.read(buffer)) != -1) {
+// // 处理实际读取的字节数(最后一帧可能不足AUDIO_FRAME_SIZE)
+// byte[] frameData = bytesRead == config.getAudioFameSize() ? buffer : Arrays.copyOf(buffer, bytesRead);
+//
+// // 记录起始时间
+// if (startTime == null) {
+// startTime = System.currentTimeMillis();
+// System.out.println("【发送开始】起始时间:" + startTime + "ms(基准时间)");
+// }
+//
+// // 计算理论发送时间
+// long expectedSendTime = startTime + ((long) frameIndex * config.getFrameIntervalMs());
+// long currentTime = System.currentTimeMillis();
+// long timeDiff = expectedSendTime - currentTime;
+//
+// // 动态调整休眠时间
+// if (timeDiff > 1) { // 大于1ms才休眠
+// try {
+// Thread.sleep(timeDiff);
+// } catch (InterruptedException e) {
+// Thread.currentThread().interrupt();
+//
+// }
+// }
+// System.out.println(webSocketClient);
+//
+// System.out.println(frameData);
+// // 发送音频帧(二进制消息)
+// webSocketClient.send(frameData);
+//
+// // 打印节奏控制日志(每10帧)
+// if (frameIndex % 10 == 0) {
+// long actualSendTime = System.currentTimeMillis();
+// System.out.printf("【节奏控制】帧%d | 理论时间:%dms | 实际时间:%dms | 误差:%.1fms%n", frameIndex, expectedSendTime, actualSendTime, (actualSendTime - expectedSendTime) * 1.0);
+// }
+//
+// frameIndex++;
+// }
+//
+// System.out.println("【发送完成】所有音频帧发送完毕(共" + frameIndex + "帧)");
+//
+// // 发送结束标记(使用org.json构建JSON)
+// JSONObject endMsg = new JSONObject();
+// endMsg.put("end", true);
+// if (sessionId != null && !sessionId.isEmpty()) {
+// endMsg.put("sessionId", sessionId);
+// }
+// String endMsgStr = endMsg.toString();
+// webSocketClient.send(endMsgStr);
+// System.out.println("【发送结束】已发送标准JSON结束标记:" + endMsgStr);
+//
+//
+// } catch (FileNotFoundException e) {
+//// System.err.println("【发送失败】音频文件不存在:" + audioPath);
+// e.printStackTrace();
+// } catch (IOException e) {
+// System.err.println("【发送异常】文件读取错误:" + e.getMessage());
+// e.printStackTrace();
+// }
+//
+//
+// }
+//
+// private Map generateAuthParams() {
+// Map params = new TreeMap<>(); // TreeMap保证字典序排序
+//
+// // 固定参数
+// params.put("audio_encode", config.getAudioEncode());
+// params.put("lang", config.getLang());
+// params.put("samplerate", config.getLang());
+//
+// // 动态参数
+// params.put("accessKeyId", config.getAccessKeyId());
+// params.put("appId", config.getAppId());
+// params.put("uuid", UUID.randomUUID().toString().replaceAll("-", ""));
+// params.put("utc", getUtcTime());
+//
+// // 计算签名
+// String signature = calculateSignature(params);
+// params.put("signature", signature);
+//
+// return params;
+// }
+//
+// private String getUtcTime() {
+// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+// sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+// return sdf.format(new Date());
+// }
+//
+// private String calculateSignature(Map params) {
+// try {
+// // 构建基础字符串
+// StringBuilder baseStr = new StringBuilder();
+// boolean first = true;
+// for (Map.Entry entry : params.entrySet()) {
+// String key = entry.getKey();
+// String value = entry.getValue();
+//
+// // 跳过signature参数
+// if ("signature".equals(key)) continue;
+// // 过滤空值
+// if (value == null || value.trim().isEmpty()) continue;
+//
+// if (!first) {
+// baseStr.append("&");
+// }
+// baseStr.append(URLEncoder.encode(key, StandardCharsets.UTF_8)).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8));
+// first = false;
+// }
+//
+// // HMAC-SHA1计算
+// Mac mac = Mac.getInstance("HmacSHA1");
+// SecretKeySpec keySpec = new SecretKeySpec(config.getAccessKeyId().getBytes(StandardCharsets.UTF_8), "HmacSHA1");
+// mac.init(keySpec);
+// byte[] signBytes = mac.doFinal(baseStr.toString().getBytes(StandardCharsets.UTF_8));
+//
+// // Base64编码
+// return Base64.getEncoder().encodeToString(signBytes);
+// } catch (Exception e) {
+// throw new RuntimeException("计算签名失败", e);
+// }
+// }
+//
+// private String buildParamsString(Map params) {
+// StringBuilder sb = new StringBuilder();
+// boolean first = true;
+// for (Map.Entry entry : params.entrySet()) {
+// if (!first) {
+// sb.append("&");
+// }
+// sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
+// first = false;
+// }
+// return sb.toString();
+// }
+//
+// public static FileInputStream convertBytesToFileInputStream(byte[] data,
+// String prefix,
+// String suffix) throws IOException {
+// Path tempFile = Files.createTempFile(prefix, suffix);
+// Files.write(tempFile, data);
+//
+// return new FileInputStream(tempFile.toFile());
+// }
+//
+//
+//}
diff --git a/src/main/java/com/realtime/sysconst/RTASRClient.java b/src/main/java/com/realtime/sysconst/RTASRClient.java
new file mode 100644
index 0000000..9a5dc10
--- /dev/null
+++ b/src/main/java/com/realtime/sysconst/RTASRClient.java
@@ -0,0 +1,377 @@
+package com.realtime.sysconst;
+
+import com.realtime.packets.RealTimePacket;
+import com.realtime.utils.SessionUtils;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import jakarta.websocket.Session;
+import lombok.Data;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.URI;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Data
+public class RTASRClient {
+ // 配置参数
+ private static final String AUDIO_ENCODE = "pcm_s16le";
+ private static final String LANG = "autodialect";
+ private static final String SAMPLERATE = "16000";
+ private static final int AUDIO_FRAME_SIZE = 1280; // 每帧字节数
+ private static final int FRAME_INTERVAL_MS = 40; // 帧间隔(毫秒)
+ private static final Logger log = LoggerFactory.getLogger(RTASRClient.class);
+
+
+ // 客户端参数
+ private final String appId;
+ private final String accessKeyId;
+ private final InputStream inputStream;
+ private final String accessKeySecret;
+ private final String audioPath;
+ private final Session realTimePacket;
+ private final String baseWsUrl = "wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1";
+
+ // 状态变量
+ private WebSocketClient webSocketClient;
+ private final AtomicBoolean isConnected = new AtomicBoolean(false);
+ private final AtomicBoolean isSendingAudio = new AtomicBoolean(false);
+ private String sessionId;
+ private long audioFileSize = 0;
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ public RTASRClient(String appId, String accessKeyId, String accessKeySecret, String audioPath, InputStream inputStream, Session realTimePacket) {
+ this.appId = appId;
+ this.accessKeyId = accessKeyId;
+ this.accessKeySecret = accessKeySecret;
+ this.audioPath = audioPath;
+ this.inputStream = inputStream;
+ this.realTimePacket = realTimePacket;
+ }
+
+ /**
+ * 获取音频文件大小
+ */
+ private long getAudioFileSize() {
+ try {
+ return this.inputStream.available();
+ } catch (Exception _e) {
+ log.info(_e.getMessage());
+ }
+ return 0;
+ }
+
+ /**
+ * 生成鉴权参数并建立WebSocket连接
+ */
+ public boolean connect() {
+ try {
+ // 生成鉴权参数
+ Map authParams = generateAuthParams();
+ String paramsStr = buildParamsString(authParams);
+ String fullWsUrl = baseWsUrl + "?" + paramsStr;
+ System.out.println("【连接信息】完整URL:" + fullWsUrl);
+
+ // 创建WebSocket客户端
+ webSocketClient = new WebSocketClient(new URI(fullWsUrl)) {
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ isConnected.set(true);
+ System.out.println("【连接成功】WebSocket握手完成,等待服务端就绪(1.5秒)...");
+
+ // 启动接收消息处理线程
+ executor.submit(() -> receiveMessages());
+
+ // 等待服务端初始化
+ try {
+ Thread.sleep(1500);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public void onMessage(String message) {
+ try {
+ // 使用org.json解析JSON消息
+ JSONObject json = new JSONObject(message);
+ System.out.println("【接收消息】" + json.toString());
+
+ // 处理会话ID
+ if ("action".equals(json.optString("msg_type"))) {
+ JSONObject data = json.optJSONObject("data");
+ if (data != null && data.has("sessionId")) {
+ sessionId = data.getString("sessionId");
+ System.out.println("【会话信息】已获取sessionId:" + sessionId);
+ }
+ }
+ realTimePacket.getBasicRemote().sendText(message);
+ } catch (Exception e) {
+ int maxLength = Math.min(50, message.length());
+ System.out.println("【接收异常】非JSON文本消息:" + message.substring(0, maxLength) + "...");
+ }
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ isConnected.set(false);
+ System.out.println("【连接关闭】代码:" + code + ",原因:" + reason);
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ System.err.println("【WebSocket错误】" + ex.getMessage());
+ ex.printStackTrace();
+ }
+ };
+
+ // 连接服务器
+ webSocketClient.connectBlocking(15, TimeUnit.SECONDS);
+ return isConnected.get();
+ } catch (Exception e) {
+ System.err.println("【连接失败】" + e.getMessage());
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 接收并处理服务端消息
+ */
+ private void receiveMessages() {
+ while (isConnected.get() && webSocketClient != null) {
+ try {
+ // 等待消息(通过onMessage回调处理)
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ break;
+ } catch (Exception e) {
+ System.err.println("【接收异常】" + e.getMessage());
+ e.printStackTrace();
+ close();
+ break;
+ }
+ }
+ System.out.println("【接收线程】连接已关闭,退出接收循环");
+ }
+
+ /**
+ * 发送音频文件(带精确节奏控制)
+ */
+ public boolean sendAudio() throws IOException {
+ if (!isConnected.get() || webSocketClient == null || isSendingAudio.get()) {
+ System.out.println("【发送失败】WebSocket未连接或已有发送任务");
+ return false;
+ }
+
+ isSendingAudio.set(true);
+ audioFileSize = getAudioFileSize();
+ try (InputStream fis = this.getInputStream()) {
+ System.out.println(fis.available());
+ // 计算总帧数和预估时长
+ long totalFrames = audioFileSize / AUDIO_FRAME_SIZE;
+ long remainingBytes = audioFileSize % AUDIO_FRAME_SIZE;
+ if (remainingBytes > 0) {
+ totalFrames++;
+ }
+ double estimatedDuration = (totalFrames * FRAME_INTERVAL_MS) / 1000.0;
+ System.out.printf("【发送配置】音频文件大小:%d字节 | 总帧数:%d | 预估时长:%.1f秒%n", audioFileSize, totalFrames, estimatedDuration);
+ System.out.printf("【发送配置】每%dms发送%d字节,严格控制节奏%n", FRAME_INTERVAL_MS, AUDIO_FRAME_SIZE);
+
+ // 发送音频帧
+ byte[] buffer = new byte[AUDIO_FRAME_SIZE];
+ int bytesRead;
+ int frameIndex = 0;
+ Long startTime = null;
+
+ while ((bytesRead = fis.read(buffer)) != -1) {
+ // 处理实际读取的字节数(最后一帧可能不足AUDIO_FRAME_SIZE)
+ byte[] frameData = bytesRead == AUDIO_FRAME_SIZE ? buffer : Arrays.copyOf(buffer, bytesRead);
+
+ // 记录起始时间
+ if (startTime == null) {
+ startTime = System.currentTimeMillis();
+ System.out.println("【发送开始】起始时间:" + startTime + "ms(基准时间)");
+ }
+
+ // 计算理论发送时间
+ long expectedSendTime = startTime + (frameIndex * FRAME_INTERVAL_MS);
+ long currentTime = System.currentTimeMillis();
+ long timeDiff = expectedSendTime - currentTime;
+
+ // 动态调整休眠时间
+ if (timeDiff > 1) { // 大于1ms才休眠
+ try {
+ Thread.sleep(timeDiff);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ // 发送音频帧(二进制消息)
+ webSocketClient.send(frameData);
+
+ // 打印节奏控制日志(每10帧)
+ if (frameIndex % 10 == 0) {
+ long actualSendTime = System.currentTimeMillis();
+ System.out.printf("【节奏控制】帧%d | 理论时间:%dms | 实际时间:%dms | 误差:%.1fms%n", frameIndex, expectedSendTime, actualSendTime, (actualSendTime - expectedSendTime) * 1.0);
+ }
+
+ frameIndex++;
+ }
+
+ System.out.println("【发送完成】所有音频帧发送完毕(共" + frameIndex + "帧)");
+
+ // 发送结束标记(使用org.json构建JSON)
+ JSONObject endMsg = new JSONObject();
+ endMsg.put("end", true);
+ if (sessionId != null && !sessionId.isEmpty()) {
+ endMsg.put("sessionId", sessionId);
+ }
+ String endMsgStr = endMsg.toString();
+ webSocketClient.send(endMsgStr);
+ System.out.println("【发送结束】已发送标准JSON结束标记:" + endMsgStr);
+
+ return false;
+ } catch (FileNotFoundException e) {
+ System.err.println("【发送失败】音频文件不存在:" + audioPath);
+ e.printStackTrace();
+ } catch (IOException e) {
+ System.err.println("【发送异常】文件读取错误:" + e.getMessage());
+ e.printStackTrace();
+ } finally {
+ isSendingAudio.set(false);
+ }
+ return false;
+ }
+
+ /**
+ * 生成鉴权参数
+ */
+ private Map generateAuthParams() {
+ Map params = new TreeMap<>(); // TreeMap保证字典序排序
+
+ // 固定参数
+ params.put("audio_encode", AUDIO_ENCODE);
+ params.put("lang", LANG);
+ params.put("samplerate", SAMPLERATE);
+
+ // 动态参数
+ params.put("accessKeyId", accessKeyId);
+ params.put("appId", appId);
+ params.put("uuid", UUID.randomUUID().toString().replaceAll("-", ""));
+ params.put("utc", getUtcTime());
+
+ // 计算签名
+ String signature = calculateSignature(params);
+ params.put("signature", signature);
+
+ return params;
+ }
+
+ /**
+ * 生成UTC时间字符串(yyyy-MM-dd'T'HH:mm:ss+0800)
+ */
+ private String getUtcTime() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+ sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+ return sdf.format(new Date());
+ }
+
+ /**
+ * 计算HMAC-SHA1签名
+ */
+ private String calculateSignature(Map params) {
+ try {
+ // 构建基础字符串
+ StringBuilder baseStr = new StringBuilder();
+ boolean first = true;
+ for (Map.Entry entry : params.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+
+ // 跳过signature参数
+ if ("signature".equals(key)) continue;
+ // 过滤空值
+ if (value == null || value.trim().isEmpty()) continue;
+
+ if (!first) {
+ baseStr.append("&");
+ }
+ baseStr.append(URLEncoder.encode(key, StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(value, StandardCharsets.UTF_8.name()));
+ first = false;
+ }
+
+ // HMAC-SHA1计算
+ Mac mac = Mac.getInstance("HmacSHA1");
+ SecretKeySpec keySpec = new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
+ mac.init(keySpec);
+ byte[] signBytes = mac.doFinal(baseStr.toString().getBytes(StandardCharsets.UTF_8));
+
+ // Base64编码
+ return Base64.getEncoder().encodeToString(signBytes);
+ } catch (Exception e) {
+ throw new RuntimeException("计算签名失败", e);
+ }
+ }
+
+ /**
+ * 构建参数字符串
+ */
+ private String buildParamsString(Map params) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (Map.Entry entry : params.entrySet()) {
+ if (!first) {
+ sb.append("&");
+ }
+ try {
+ sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
+ } catch (UnsupportedEncodingException e) {
+ // UTF-8编码总是支持的
+ e.printStackTrace();
+ }
+ first = false;
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 关闭连接
+ */
+ public void close() {
+ if (isConnected.get() && webSocketClient != null) {
+ isConnected.set(false);
+ webSocketClient.close();
+ System.out.println("【连接关闭】WebSocket已安全关闭");
+ } else {
+ System.out.println("【连接关闭】WebSocket已断开或未初始化");
+ }
+ executor.shutdown();
+ try {
+ if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
+ executor.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ executor.shutdownNow();
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/sysconst/Result.java b/src/main/java/com/realtime/sysconst/Result.java
new file mode 100644
index 0000000..6902533
--- /dev/null
+++ b/src/main/java/com/realtime/sysconst/Result.java
@@ -0,0 +1,61 @@
+package com.realtime.sysconst;
+
+import lombok.Data;
+
+@Data
+public class Result {
+ private Integer code;
+ private String msg;
+ private T data;
+ private String token;
+ private Long timestamp = System.currentTimeMillis();
+
+
+ public static Result success(T data) {
+ Result result = new Result<>();
+ result.setCode(0);
+ result.setMsg("成功");
+ result.setData(data);
+ return result;
+ }
+
+ public static Result success(T data,String token) {
+ Result result = new Result<>();
+ result.setCode(0);
+ result.setMsg("成功");
+ result.setToken(token);
+ result.setData(data);
+ return result;
+ }
+
+
+ public static Result fail(String msg) {
+ Result result = new Result<>();
+ result.setCode(-1);
+ result.setMsg(msg);
+ result.setData(null);
+ return result;
+ }
+
+ public static Result notAuth(String msg) {
+ Result result = new Result<>();
+ result.setCode(-2);
+ result.setMsg(msg);
+ result.setData(null);
+ return result;
+ }
+
+ public static Result systemError(String msg) {
+ return notAuth(msg);
+ }
+
+ public static Result systemError(String msg,Integer code) {
+ Result result = new Result<>();
+ result.setCode(code);
+ result.setMsg(msg);
+ result.setData(null);
+ return result;
+ }
+
+
+}
diff --git a/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java b/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java
new file mode 100644
index 0000000..a1f1e2d
--- /dev/null
+++ b/src/main/java/com/realtime/sysconst/enumConst/ResultEnum.java
@@ -0,0 +1,30 @@
+package com.realtime.sysconst.enumConst;
+
+import lombok.Getter;
+
+@Getter
+public enum ResultEnum {
+ SYSTEM_ERROR("系统异常",500),
+ FILE_NOT_NULL("请上传文件", -8),
+ FILE_FORMAT_ERROR("文件格式不正确", -9),
+ LOGIN_DISABLE("账户状态异常",-10),
+ PARAMETER_ERROR("参数异常",-11),
+ PERMISSION_INSUFFICIENT("权限不足", -12),
+ SEND_ERROR("请稍后发送", -13),
+ MSG_CODE_ERROR("验证码错误", -4),
+ ACCOUNT_ERROR_OR_PASSWORD_ERROR("用户名或密码错误",-15),
+ ACCOUNT_NOT_EXITS("账户不存在",-16),
+ CUSTOMER_NOT_EXITS("该客户不存在",-17),
+ MANAGER_NOT_EXITS("该领导不存在",-18),
+ ASSIGNEE_NOT_EXITS("该负责人不存在",-19),
+ DATABASE_EXITS("动态数据库已存在",-20);
+
+ private final String msg;
+ private final Integer code;
+
+ ResultEnum(String msg, Integer code) {
+ this.msg = msg;
+ this.code = code;
+ }
+
+}
diff --git a/src/main/java/com/realtime/utils/Attributes.java b/src/main/java/com/realtime/utils/Attributes.java
new file mode 100644
index 0000000..4702914
--- /dev/null
+++ b/src/main/java/com/realtime/utils/Attributes.java
@@ -0,0 +1,9 @@
+package com.realtime.utils;
+
+
+import com.realtime.packets.basePackets.BasePackets;
+import io.netty.util.AttributeKey;
+
+public interface Attributes {
+ AttributeKey SESSION = AttributeKey.newInstance("session");
+}
diff --git a/src/main/java/com/realtime/utils/Base64ToMultipartFile.java b/src/main/java/com/realtime/utils/Base64ToMultipartFile.java
new file mode 100644
index 0000000..091524a
--- /dev/null
+++ b/src/main/java/com/realtime/utils/Base64ToMultipartFile.java
@@ -0,0 +1,89 @@
+package com.realtime.utils;
+
+import org.jetbrains.annotations.NotNull;
+import org.springframework.web.multipart.MultipartFile;
+import java.io.*;
+
+public class Base64ToMultipartFile {
+
+ public static MultipartFile convert(byte[] byteData , String filename) {
+ final byte[] bytes = byteData;
+
+ return new MultipartFile() {
+ @NotNull
+ @Override
+ public String getName() {
+ return "file";
+ }
+
+ @Override
+ public String getOriginalFilename() {
+ return filename;
+ }
+
+ @Override
+ public String getContentType() {
+ return getContentTypeFromFilename(filename);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return bytes.length == 0;
+ }
+
+ @Override
+ public long getSize() {
+ return bytes.length;
+ }
+
+ @NotNull
+ @Override
+ public byte[] getBytes() throws IOException {
+ return bytes;
+ }
+
+ @NotNull
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ @Override
+ public void transferTo(@NotNull File dest) throws IOException, IllegalStateException {
+ try (FileOutputStream fos = new FileOutputStream(dest)) {
+ fos.write(bytes);
+ }
+ }
+ };
+ }
+
+ private static String getContentTypeFromFilename(String filename) {
+ if (filename == null) {
+ return "application/octet-stream";
+ }
+
+ String lowerCaseFilename = filename.toLowerCase();
+
+ if (lowerCaseFilename.endsWith(".jpg") || lowerCaseFilename.endsWith(".jpeg")) {
+ return "image/jpeg";
+ } else if (lowerCaseFilename.endsWith(".png")) {
+ return "image/png";
+ } else if (lowerCaseFilename.endsWith(".gif")) {
+ return "image/gif";
+ } else if (lowerCaseFilename.endsWith(".pdf")) {
+ return "application/pdf";
+ } else if (lowerCaseFilename.endsWith(".txt")) {
+ return "text/plain";
+ } else if (lowerCaseFilename.endsWith(".doc")) {
+ return "application/msword";
+ } else if (lowerCaseFilename.endsWith(".docx")) {
+ return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+ } else if (lowerCaseFilename.endsWith(".xls")) {
+ return "application/vnd.ms-excel";
+ } else if (lowerCaseFilename.endsWith(".xlsx")) {
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+ }
+
+ return "application/octet-stream";
+ }
+}
diff --git a/src/main/java/com/realtime/utils/InputStreamMultipartFile.java b/src/main/java/com/realtime/utils/InputStreamMultipartFile.java
new file mode 100644
index 0000000..1de75e5
--- /dev/null
+++ b/src/main/java/com/realtime/utils/InputStreamMultipartFile.java
@@ -0,0 +1,66 @@
+package com.realtime.utils;
+
+import org.jetbrains.annotations.NotNull;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.*;
+
+public class InputStreamMultipartFile implements MultipartFile {
+
+ private final String name;
+ private final String originalFilename;
+ private final String contentType;
+ private final byte[] content;
+
+ public InputStreamMultipartFile(String name, String originalFilename,
+ String contentType, InputStream inputStream) throws IOException {
+ this.name = name;
+ this.originalFilename = originalFilename;
+ this.contentType = contentType;
+ this.content = FileCopyUtils.copyToByteArray(inputStream);
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public String getOriginalFilename() {
+ return this.originalFilename;
+ }
+
+ @Override
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.content.length == 0;
+ }
+
+ @Override
+ public long getSize() {
+ return this.content.length;
+ }
+
+ @NotNull
+ @Override
+ public byte[] getBytes() throws IOException {
+ return this.content;
+ }
+
+ @NotNull
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(this.content);
+ }
+
+ @Override
+ public void transferTo(@NotNull File dest) throws IOException, IllegalStateException {
+ FileCopyUtils.copy(this.content, dest);
+ }
+}
diff --git a/src/main/java/com/realtime/utils/SessionUtils.java b/src/main/java/com/realtime/utils/SessionUtils.java
new file mode 100644
index 0000000..a6782d7
--- /dev/null
+++ b/src/main/java/com/realtime/utils/SessionUtils.java
@@ -0,0 +1,74 @@
+package com.realtime.utils;
+
+import com.realtime.packets.basePackets.BasePackets;
+import io.netty.channel.Channel;
+import io.netty.channel.group.ChannelGroup;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SessionUtils {
+
+ public static final Map userIdChannelMap = new ConcurrentHashMap<>();
+
+ /**
+ * groupId ---> channelgroup 群聊ID和群聊ChannelGroup映射
+ */
+ public static final Map sessionUser = new ConcurrentHashMap<>();
+
+ private static final Map groupIdChannelGroupMap = new ConcurrentHashMap<>();
+
+ public static void bindChannel(BasePackets user, Channel channel) {
+ userIdChannelMap.put(user.getSender(), channel);
+ sessionUser.put(user.getSender(), user);
+ channel.attr(Attributes.SESSION).set(user);
+ }
+
+ public static void unbind(Channel channel) {
+ if (hasLogin(channel)) {
+ userIdChannelMap.remove(getUser(channel).getSender());
+ channel.attr(Attributes.SESSION).set(null);
+ }
+ }
+
+ public static boolean hasLogin(Channel channel) {
+ return channel.hasAttr(Attributes.SESSION);
+ }
+
+ public static BasePackets getUser(Channel channel) {
+ return channel.attr(Attributes.SESSION).get();
+ }
+
+ public static Channel getChannel(String userId) {
+ return userIdChannelMap.get(userId) == null ? null : userIdChannelMap.get(userId);
+ }
+
+ public static void bindChannelGroup(Long groupId, ChannelGroup channelGroup) {
+ groupIdChannelGroupMap.put(groupId, channelGroup);
+ }
+
+ public static ChannelGroup getChannelGroup(Long groupId) {
+ return groupIdChannelGroupMap.get(groupId) == null ? null : groupIdChannelGroupMap.get(groupId);
+ }
+
+ public static void removeChanelByGroup(Long groupId, String phone) {
+ Channel channel = getChannel(phone);
+ if (channel != null) {
+ ChannelGroup channelGroup = getChannelGroup(groupId);
+ if (channelGroup != null) {
+ channelGroup.remove(channel);
+ }
+ }
+ }
+
+ public static void removeBatchChannel(Long groupId, List phone) {
+ ChannelGroup channelGroup = getChannelGroup(groupId);
+ if (channelGroup != null) {
+ phone.forEach(item -> {
+ Channel channel = getChannel(item);
+ channelGroup.remove(channel);
+ });
+ }
+ }
+}
diff --git a/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java b/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java
new file mode 100644
index 0000000..c64ac5e
--- /dev/null
+++ b/src/main/java/com/realtime/vo/ChatFriendRelationshipInfoVo.java
@@ -0,0 +1,21 @@
+package com.realtime.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+public class ChatFriendRelationshipInfoVo implements Serializable {
+ private Long id;
+ private Long sessionId;
+ private Integer state;
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createdTime;
+ private String sendId;
+ private String recipientId;
+ private String friendNickName;
+}
diff --git a/src/main/java/com/realtime/vo/ChatListInfoVo.java b/src/main/java/com/realtime/vo/ChatListInfoVo.java
new file mode 100644
index 0000000..4e79de3
--- /dev/null
+++ b/src/main/java/com/realtime/vo/ChatListInfoVo.java
@@ -0,0 +1,19 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ChatListInfoVo implements Serializable {
+ private Long id;
+ private String sender;
+ private String receiver;
+ private String avatar;
+ private String nickName;
+ private String friendNickName;
+ private Long sessionId;
+ private Integer isDelete;
+ private Boolean exits;
+ private Integer type;
+}
diff --git a/src/main/java/com/realtime/vo/ChatReqVo.java b/src/main/java/com/realtime/vo/ChatReqVo.java
new file mode 100644
index 0000000..5120ebe
--- /dev/null
+++ b/src/main/java/com/realtime/vo/ChatReqVo.java
@@ -0,0 +1,9 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+@Data
+public class ChatReqVo {
+ private String txt;
+ private String fileId;
+}
diff --git a/src/main/java/com/realtime/vo/FriendMessageVo.java b/src/main/java/com/realtime/vo/FriendMessageVo.java
new file mode 100644
index 0000000..d7f6871
--- /dev/null
+++ b/src/main/java/com/realtime/vo/FriendMessageVo.java
@@ -0,0 +1,19 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class FriendMessageVo implements Serializable {
+ private Long id;
+ private String sender;
+ private String receiver;
+ private String avatar;
+ private MessageItemVo item;
+ private String friendNickName;
+ private Long sessionId;
+ private String nickName;
+ private String friendName; // 好友给我备注的昵称
+ private String contentJson;
+}
diff --git a/src/main/java/com/realtime/vo/GroupDetailVo.java b/src/main/java/com/realtime/vo/GroupDetailVo.java
new file mode 100644
index 0000000..2aa7040
--- /dev/null
+++ b/src/main/java/com/realtime/vo/GroupDetailVo.java
@@ -0,0 +1,13 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+@Data
+public class GroupDetailVo {
+ private Long id;
+ private String name;
+ private Boolean owner;
+ private Integer isInvent;
+ private String creator;
+ private String qrCode;
+}
diff --git a/src/main/java/com/realtime/vo/GroupListMessagesVo.java b/src/main/java/com/realtime/vo/GroupListMessagesVo.java
new file mode 100644
index 0000000..8c18b27
--- /dev/null
+++ b/src/main/java/com/realtime/vo/GroupListMessagesVo.java
@@ -0,0 +1,13 @@
+package com.realtime.vo;
+import lombok.Data;
+
+@Data
+public class GroupListMessagesVo {
+ private Long id;
+ private String message;
+ private Integer messageType;
+ private Long groupId;
+ private Long createTime;
+ private String contentJson;
+ private String sender;
+}
diff --git a/src/main/java/com/realtime/vo/GroupListVo.java b/src/main/java/com/realtime/vo/GroupListVo.java
new file mode 100644
index 0000000..09e1f00
--- /dev/null
+++ b/src/main/java/com/realtime/vo/GroupListVo.java
@@ -0,0 +1,15 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class GroupListVo {
+ private Long id;
+ private String name;
+ private String picture;
+ private Integer type;
+ private String content;
+ private LocalDateTime createTime;
+}
diff --git a/src/main/java/com/realtime/vo/GroupMemberListVo.java b/src/main/java/com/realtime/vo/GroupMemberListVo.java
new file mode 100644
index 0000000..5791b06
--- /dev/null
+++ b/src/main/java/com/realtime/vo/GroupMemberListVo.java
@@ -0,0 +1,10 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+@Data
+public class GroupMemberListVo {
+ private Long id;
+ private String groupContactId;
+ private Long groupId;
+}
diff --git a/src/main/java/com/realtime/vo/MessageInfoVo.java b/src/main/java/com/realtime/vo/MessageInfoVo.java
new file mode 100644
index 0000000..e00e6c5
--- /dev/null
+++ b/src/main/java/com/realtime/vo/MessageInfoVo.java
@@ -0,0 +1,22 @@
+package com.realtime.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+public class MessageInfoVo implements Serializable {
+
+ private String avatar;
+ private String nickName;
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createTime;;
+ private String message;
+ private String role;
+ private String ip;
+ private Integer type;
+}
diff --git a/src/main/java/com/realtime/vo/MessageItemVo.java b/src/main/java/com/realtime/vo/MessageItemVo.java
new file mode 100644
index 0000000..618ddb4
--- /dev/null
+++ b/src/main/java/com/realtime/vo/MessageItemVo.java
@@ -0,0 +1,10 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+@Data
+public class MessageItemVo {
+ private String content;
+ private Integer type;
+ private Long createTime;
+}
diff --git a/src/main/java/com/realtime/vo/MessageVo.java b/src/main/java/com/realtime/vo/MessageVo.java
new file mode 100644
index 0000000..43f2a30
--- /dev/null
+++ b/src/main/java/com/realtime/vo/MessageVo.java
@@ -0,0 +1,17 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MessageVo implements Serializable {
+ private String sender;
+ private String receiver;
+ private String content;
+ private Long taskId;
+ private String avatar;
+ private Long createTime;
+ private String messageType;
+ private String contentJson;
+}
diff --git a/src/main/java/com/realtime/vo/UploadVo.java b/src/main/java/com/realtime/vo/UploadVo.java
new file mode 100644
index 0000000..737fd0c
--- /dev/null
+++ b/src/main/java/com/realtime/vo/UploadVo.java
@@ -0,0 +1,16 @@
+package com.realtime.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class UploadVo implements Serializable {
+ private BigDecimal fileSize;
+ private String url;
+ private String newFileName;
+ private String name;
+ private String extendName;
+ private String fileNameCode;
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..17518e4
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,53 @@
+server:
+ port: 70
+ servlet:
+ context-path: /api
+minio:
+ endpoint: https://database.yuxindazhineng.com
+ access-key: yuxinda_admin
+ secret-key: yuxinda_admin01
+ bucket-name: real
+file:
+ picMaxSize: 104857600 # 100MB
+ picMaxCount: 1
+ picAllowedFormats: png,jpg
+ allowedFormats: doc,docx,xls,xlsx,ppt,pptx,txt,jpg,jpeg,png,gif,svg,mp3,mp4,zip,rar,exe,dmg,apk,md
+spring:
+ servlet:
+ multipart:
+ max-request-size: 100MB
+ max-file-size: 100MB
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://8.134.75.237:3309/real_time?serverTimezone=Asia/Shanghai
+ username: root
+ password: zhengfei_2024
+ type: com.alibaba.druid.pool.DruidDataSource
+mybatis-plus:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ map-underscore-to-camel-case: true
+ auto-mapping-unknown-column-behavior: warning
+ mapper-locations: classpath*:/mappers/**/*.xml
+ type-aliases-package: com.realtime.vo
+baidu:
+ tts:
+ app-id: 118182863
+ api-key: WemzV9uFIDTad8s0VeCxfrf9
+ secret-key: kRr1OrebrE1kWPn1B02ECbGK5yCCKEdJ
+doubao:
+ voice:
+ app-id: 9478107274
+ api-key: FADK4NWToP_0oSbPr__4qSENvCsPN795
+ access-token: HQ6ZJzTG3MmceyZDuZZSZQYQUrfiewdZ
+ websocket-url: wss://openspeech.bytedance.com/api/v3/realtime/dialogue
+rtsa:
+ appId: 5d899195
+ accessKeyId: 4c428332836cd9481be4127c941f4167
+ accessKeySecret: ZjFiMWViMGY0NDA4ODNkNDgxYzg0Yzg3
+ baseWsUrl: wss://office-api-ast-dx.iflyaisol.com/ast/communicate/v1
+ audioEncode: pcm_s16le
+ lang: autodialect
+ samplerate: 16000
+ audioFameSize: 1280
+ frameIntervalMs: 40
diff --git a/src/main/resources/mappers/ChatListMapper.xml b/src/main/resources/mappers/ChatListMapper.xml
new file mode 100644
index 0000000..df8318a
--- /dev/null
+++ b/src/main/resources/mappers/ChatListMapper.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+ id
+ ,friend_nick_name,sender,receiver,is_top,session_id,
+ is_delete,created_time
+
+
+
+ delete from chat_list lt where lt.sender = #{id} and lt.receiver = #{receiver}
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/mappers/FriendRelationshipMapper.xml b/src/main/resources/mappers/FriendRelationshipMapper.xml
new file mode 100644
index 0000000..d62a828
--- /dev/null
+++ b/src/main/resources/mappers/FriendRelationshipMapper.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ update friend_relationship
+ set state = 1
+ where id = #{id}
+
+
+
diff --git a/src/main/resources/mappers/GroupListMapper.xml b/src/main/resources/mappers/GroupListMapper.xml
new file mode 100644
index 0000000..05687a4
--- /dev/null
+++ b/src/main/resources/mappers/GroupListMapper.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ id
+ ,name,creator,
+ created_time,picture,type,
+ is_invent
+
+
+
+
+
+
+
+ update group_list
+ set is_invent = #{req.invent}
+ where id = #{req.groupId}
+
+
+
+
+
+
diff --git a/src/main/resources/mappers/GroupMemberMapper.xml b/src/main/resources/mappers/GroupMemberMapper.xml
new file mode 100644
index 0000000..430310e
--- /dev/null
+++ b/src/main/resources/mappers/GroupMemberMapper.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+ id
+ ,group_id,group_contact_id,
+ created_time
+
+
+
+
+
+
+
+
+ delete
+ from group_member grp
+ where grp.group_id = #{groupId}
+ and grp.group_contact_id = #{groupContactId}
+
+
+
+ delete
+ from group_member grp
+ where grp.group_id = #{req.groupId}
+
+
+
+ delete from group_member grp where grp.group_contact_id in
+
+ #{item}
+
+ and grp.group_id = #{req.groupId}
+
+
+
diff --git a/src/main/resources/mappers/GroupMessageMapper.xml b/src/main/resources/mappers/GroupMessageMapper.xml
new file mode 100644
index 0000000..1398d7d
--- /dev/null
+++ b/src/main/resources/mappers/GroupMessageMapper.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ id
+ ,message,group_id,
+ sender,create_time,message_type
+
+
+
+
diff --git a/src/main/resources/mappers/MessageMapper.xml b/src/main/resources/mappers/MessageMapper.xml
new file mode 100644
index 0000000..e227a74
--- /dev/null
+++ b/src/main/resources/mappers/MessageMapper.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+ id
+ , sender, receiver, session_id, message_type, content, create_time
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+