diff --git a/.gitignore b/.gitignore index 6e07688..083aa4a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,10 @@ /im-server/src/main/resources/logback-prod.xml /im-commom/im-commom.iml /im-uniapp/node_modules/ -/im-ui/package-lock.json +/im-web/package-lock.json /im-uniapp/unpackage/ /im-uniapp/hybrid/ /im-uniapp/package-lock.json -/im-ui/src/components/rtc/LocalVideo.vue -/im-ui/src/components/rtc/RemoteVideo.vue -/im-ui/src/components/rtc/RtcGroupAcceptor.vue +/im-web/src/components/rtc/LocalVideo.vue +/im-web/src/components/rtc/RemoteVideo.vue +/im-web/src/components/rtc/RtcGroupAcceptor.vue diff --git a/README.md b/README.md index 032bf40..4ac5a63 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ 1. 盒子IM是一个仿微信实现的网页版聊天软件,不依赖任何第三方收费组件。 -1. 支持私聊、群聊、离线消息、发送语音、图片、文件、emoji表情等功能 -1. 支持音视频通话(基于webrtc实现,需要ssl证书) +1. 支持私聊、群聊、离线消息、发送语音、图片、文件、已读未读、群@等功能 +1. 支持单人、多人音视频通话(基于原生webrtc实现,需要ssl证书) +1. uniapp端兼容app、h5、微信小程序,可与web端同时在线,并保持消息同步 1. 后端采用springboot+netty实现,网页端使用vue,移动端使用uniapp 1. 服务器支持集群化部署,每个im-server仅处理自身连接用户的消息 @@ -16,13 +17,11 @@ #### 近期更新 -发布2.0版本,本次更新加入了uniapp移动端: +发布3.0版本: -- 支持移动端和web端同时在线,多端消息同步 -- 目前已兼容h5、微信小程序,安卓和IOS -- 聊天窗口加入已读未读显示 -- 群聊加入@功能 -- 界面风格升级,表情包更新、生成文字头像等 +- 后台管理端上线,后台管理代码仓库地址:https://gitee.com/bluexsx/box-im-admin +- 框架和组件版本全面升级: jdk17、springboot3.3、node18等 +- 部分界面,功能、性能优化 #### 在线体验 @@ -37,27 +36,18 @@ ![输入图片说明](%E6%88%AA%E5%9B%BE/h5%E4%BA%8C%E7%BB%B4%E7%A0%81.png) -微信小程序: - -![输入图片说明](%E6%88%AA%E5%9B%BE/wx%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BA%8C%E7%BB%B4%E7%A0%81.jpg) - - -#### 相关项目 - -一位网友的开源项目,基于盒子IM接口开发的仿QQ客户端,有兴趣的小伙伴可以也关注一下: - -https://gitee.com/zyzyteam/crim +由于微信小程序每次发布审核过于严苛和繁琐,暂时不再提供体验环境,但uniapp端依然会继续兼容小程序 #### 项目结构 -| 模块 | 功能 | -|-------------|------------| -| im-platform | 与页面进行交互,处理业务请求 | -| im-server | 推送聊天消息| -| im-client | 消息推送sdk| -| im-common | 公共包 | -| im-ui | web页面 | -| im-uniapp | app页面 | +| 模块 | 功能 | +|-------------|----------------------------------| +| im-platform | 业务平台服务,负责处理来自用户的业务请求(http) | +| im-server | 消息推送服务,不依赖业务,负责将消息推送给用户(ws) | +| im-client | 消息推送sdk, 任何服务均可集成此sdk与im-server通信 | +| im-common | 公共包 | +| im-ui | web页面 | +| im-uniapp | uniapp页面 | #### 消息推送方案 ![输入图片说明](%E6%88%AA%E5%9B%BE/%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E9%9B%86%E7%BE%A4%E5%8C%96.jpg) @@ -69,12 +59,12 @@ https://gitee.com/zyzyteam/crim #### 本地快速部署 1.安装运行环境 -- 安装node:v14.16.0 -- 安装jdk:1.8 -- 安装maven:3.6.3 -- 安装mysql:5.7,密码分别为root/root,运行sql脚本(脚本在im-platfrom的resources/db目录) -- 安装redis:5.0 -- 安装minio,命令端口使用9001,并创建一个名为"box-im"的bucket,并设置访问权限为公开 +- 安装node:v18.19.0 +- 安装jdk:17 +- 安装maven:3.9.6 +- 安装mysql:8.0,账号密码分别为root/root,创建名为im_platform的数据库,运行db/im_platfrom.sql脚本 +- 安装redis:6.2 +- 安装minio:RELEASE.2024-xx,使用默认账号、密码、端口 2.启动后端服务 ``` @@ -85,161 +75,37 @@ java -jar ./im-server/target/im-server.jar 3.启动前端web ``` -cd im-ui +cd im-web npm install npm run serve ``` 访问 http://localhost:8080 - 4.启动uniapp-h5 将im-uniapp目录导入HBuilderX,点击菜单"运行"->"开发环境-h5" 访问 http://localhost:5173 -#### 快速接入 -消息推送的请求代码已经封装在im-client包中,对于需要接入im-server的小伙伴,可以按照下面的教程快速的将IM功能集成到自己的项目中。 - -注意服务器端和前端都需要接入,服务器端发送消息,前端接收消息。 - -4.1 服务器端接入 - -引入pom文件 -``` - - com.bx - im-client - 2.0.0 - -``` -内容使用了redis进行通信,所以要配置redis地址: - -``` -spring: - redis: - host: 127.0.0.1 - port: 6379 -``` - -直接把IMClient通过@Autowire导进来就可以发送消息了,IMClient 只有2个接口: -``` -public class IMClient { - - /** - * 发送私聊消息 - * - * @param message 私有消息 - */ - public void sendPrivateMessage(IMPrivateMessage message); - - /** - * 发送群聊消息(发送结果通过MessageListener接收) - * - * @param message 群聊消息 - */ - public void sendGroupMessage(IMGroupMessage message); -} -``` - -发送私聊消息(群聊也是类似的方式): -``` - @Autowired - private IMClient imClient; - - public void sendMessage(){ - IMPrivateMessage sendMessage = new IMPrivateMessage<>(); - // 发送方的id和终端类型 - sendMessage.setSender(new IMUserInfo(1L, IMTerminalType.APP.code())); - // 对方的id - sendMessage.setRecvId(2L); - // 推送给对方所有终端 - sendMessage.setRecvTerminals(IMTerminalType.codes()); - // 同时推送给自己的其他类型终端 - sendMessage.setSendToSelf(true); - // 需要回推发送结果,将在IMListener接收发送结果 - sendMessage.setSendResult(true); - // 推送的内容 - sendMessage.setData(msgInfo); - // 推送消息 - imClient.sendPrivateMessage(sendMessage); -} - -``` -监听发送结果: -1.编写消息监听类,实现MessageListener,并加上@IMListener -2.发送消息时指定sendResult为true -``` -@Slf4j -@IMListener(type = IMListenerType.ALL) -public class PrivateMessageListener implements MessageListener { - - @Override - public void process(IMSendResult result){ - PrivateMessageVO messageInfo = result.getData(); - if(result.getCode().equals(IMSendCode.SUCCESS.code())){ - log.info("消息发送成功,消息id:{},发送者:{},接收者:{},终端:{}",messageInfo.getId(),result.getSender().getId(),result.getReceiver().getId(),result.getReceiver().getTerminal()); - } - } -} -``` - -4.2 前端接入 -首先将im-ui/src/api/wssocket.js拷贝到自己的项目。 - -接入代码如下: -``` -import * as wsApi from './api/wssocket'; - -let wsUrl = 'ws://localhost:8878/im' -let token = "您的token"; -wsApi.connect(wsUrl,token); -wsApi.onConnect(() => { - // 连接打开 - console.log("连接成功"); -}); -wsApi.onMessage((cmd,msgInfo) => { - if (cmd == 2) { - // 异地登录,强制下线 - console.log("您已在其他地方登陆,将被强制下线"); - } else if (cmd == 3) { - // 私聊消息 - console.log(msgInfo); - } else if (cmd == 4) { - // 群聊消息 - console.log(msgInfo); - } -}) -wsApi.onClose((e) => { - if (e.code != 3000) { - console.log("意外断开,进行重连"); - wsApi.reconnect(wsUrl,token); - }else{ - console.log("主动断开"); - } -}); -``` - - #### 界面截图 私聊: -![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%A7%81%E8%81%8A.jpg) +![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%A7%81%E8%81%8A.png) 群聊: -![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E8%81%8A1.jpg) - -![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E8%81%8A2.jpg) +![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E8%81%8A.png) +群通话: +![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E8%A7%86%E9%A2%91.png) 好友列表: -![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E5%A5%BD%E5%8F%8B%E5%88%97%E8%A1%A8.jpg) +![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E5%A5%BD%E5%8F%8B%E5%88%97%E8%A1%A8.png) -群聊列表: -![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E8%81%8A%E5%88%97%E8%A1%A8.jpg) +群列表: +![输入图片说明](%E6%88%AA%E5%9B%BE/web/%E7%BE%A4%E5%88%97%E8%A1%A8.png) -微信小程序: -![输入图片说明](%E6%88%AA%E5%9B%BE/wx-mp/%E8%81%8A%E5%A4%A9.jpg) +移动端APP: +![输入图片说明](%E6%88%AA%E5%9B%BE/app/1.jpg) -![输入图片说明](%E6%88%AA%E5%9B%BE/wx-mp/%E5%85%B6%E4%BB%96.jpg) +![输入图片说明](%E6%88%AA%E5%9B%BE/app/2.jpg) #### 加入交流群 1群目前已满员,扫码进入2群: diff --git a/im-platform/src/main/resources/db/db.sql b/db/im-platform.sql similarity index 71% rename from im-platform/src/main/resources/db/db.sql rename to db/im-platform.sql index 1ea4b86..d90976f 100644 --- a/im-platform/src/main/resources/db/db.sql +++ b/db/im-platform.sql @@ -1,19 +1,20 @@ -use `box-im`; create table `im_user`( `id` bigint not null auto_increment primary key comment 'id', `user_name` varchar(255) not null comment '用户名', `nick_name` varchar(255) not null comment '用户昵称', `head_image` varchar(255) default '' comment '用户头像', `head_image_thumb` varchar(255) default '' comment '用户头像缩略图', - `password` varchar(255) not null comment '密码(明文)', + `password` varchar(255) not null comment '密码', `sex` tinyint(1) default 0 comment '性别 0:男 1:女', + `is_banned` tinyint(1) default 0 comment '是否被封禁 0:否 1:是', + `reason` varchar(255) default '' comment '被封禁原因', `type` smallint default 1 comment '用户类型 1:普通用户 2:审核账户', `signature` varchar(1024) default '' comment '个性签名', `last_login_time` datetime DEFAULT null comment '最后登录时间', `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间', unique key `idx_user_name`(user_name), key `idx_nick_name`(nick_name) -) ENGINE=InnoDB CHARSET=utf8mb3 comment '用户'; +) ENGINE=InnoDB CHARSET=utf8mb4 comment '用户'; create table `im_friend`( `id` bigint not null auto_increment primary key comment 'id', @@ -24,18 +25,18 @@ create table `im_friend`( `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间', key `idx_user_id` (`user_id`), key `idx_friend_id` (`friend_id`) -) ENGINE=InnoDB CHARSET=utf8mb3 comment '好友'; +) ENGINE=InnoDB CHARSET=utf8mb4 comment '好友'; create table `im_private_message`( `id` bigint not null auto_increment primary key comment 'id', `send_id` bigint not null comment '发送用户id', `recv_id` bigint not null comment '接收用户id', `content` text comment '发送内容', - `type` tinyint(1) NOT NULL comment '消息类型 0:文字 1:图片 2:文件 3:语音 10:系统提示', - `status` tinyint(1) NOT NULL comment '状态 0:未读 1:已读 2:撤回', + `type` tinyint(1) NOT NULL comment '消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 21:提示', + `status` tinyint(1) NOT NULL comment '状态 0:未读 1:已读 2:撤回 3:已读', `send_time` datetime DEFAULT CURRENT_TIMESTAMP comment '发送时间', key `idx_send_recv_id` (`send_id`,`recv_id`) -)ENGINE=InnoDB CHARSET=utf8mb3 comment '私聊消息'; +)ENGINE=InnoDB CHARSET=utf8mb4 comment '私聊消息'; create table `im_group`( @@ -45,24 +46,26 @@ create table `im_group`( `head_image` varchar(255) default '' comment '群头像', `head_image_thumb` varchar(255) default '' comment '群头像缩略图', `notice` varchar(1024) default '' comment '群公告', - `remark` varchar(255) default '' comment '群备注', + `is_banned` tinyint(1) default 0 comment '是否被封禁 0:否 1:是', + `reason` varchar(255) default '' comment '被封禁原因', `deleted` tinyint(1) default 0 comment '是否已删除', `created_time` datetime default CURRENT_TIMESTAMP comment '创建时间' -)ENGINE=InnoDB CHARSET=utf8mb3 comment '群'; +)ENGINE=InnoDB CHARSET=utf8mb4 comment '群'; create table `im_group_member`( `id` bigint not null auto_increment primary key comment 'id', `group_id` bigint not null comment '群id', `user_id` bigint not null comment '用户id', - `alias_name` varchar(255) DEFAULT '' comment '组内显示名称', + `user_nick_name` varchar(255) DEFAULT '' comment '用户昵称', + `remark_nick_name` varchar(255) DEFAULT '' comment '显示昵称备注', `head_image` varchar(255) DEFAULT '' comment '用户头像', - `remark` varchar(255) DEFAULT '' comment '备注', + `remark_group_name` varchar(255) DEFAULT '' comment '显示群名备注', `quit` tinyint(1) DEFAULT 0 comment '是否已退出', `quit_time` datetime DEFAULT NULL comment '退出时间', `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间', key `idx_group_id`(`group_id`), key `idx_user_id`(`user_id`) -)ENGINE=InnoDB CHARSET=utf8mb3 comment '群成员'; +)ENGINE=InnoDB CHARSET=utf8mb4 comment '群成员'; create table `im_group_message`( `id` bigint not null auto_increment primary key comment 'id', @@ -74,8 +77,16 @@ create table `im_group_message`( `at_user_ids` varchar(1024) comment '被@的用户id列表,逗号分隔', `receipt` tinyint DEFAULT 0 comment '是否回执消息', `receipt_ok` tinyint DEFAULT 0 comment '回执消息是否完成', - `type` tinyint(1) NOT NULL comment '消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10:系统提示' , - `status` tinyint(1) DEFAULT 0 comment '状态 0:未发出 1:已送达 2:撤回 3:已读', + `type` tinyint(1) NOT NULL comment '消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 21:提示' , + `status` tinyint(1) DEFAULT 0 comment '状态 0:未发出 2:撤回 ', `send_time` datetime DEFAULT CURRENT_TIMESTAMP comment '发送时间', key `idx_group_id` (group_id) -)ENGINE=InnoDB CHARSET=utf8mb3 comment '群消息'; +)ENGINE=InnoDB CHARSET=utf8mb4 comment '群消息'; + +create table `im_sensitive_word`( + `id` bigint not null auto_increment primary key comment 'id', + `content` varchar(64) not null comment '敏感词内容', + `enabled` tinyint DEFAULT 0 COMMENT '是否启用 0:未启用 1:启用', + `creator` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' +)ENGINE=InnoDB CHARSET=utf8mb4 comment '敏感词'; \ No newline at end of file diff --git a/im-client/pom.xml b/im-client/pom.xml index 320a3cb..4634ec7 100644 --- a/im-client/pom.xml +++ b/im-client/pom.xml @@ -5,7 +5,7 @@ box-im com.bx - 2.0.0 + 3.0.0 4.0.0 @@ -15,12 +15,7 @@ com.bx im-commom - 2.0.0 - - - - org.springframework.boot - spring-boot-starter-data-redis + 3.0.0 \ No newline at end of file diff --git a/im-client/src/main/java/com/bx/imclient/IMAutoConfiguration.java b/im-client/src/main/java/com/bx/imclient/IMAutoConfiguration.java index 9f8fa84..445cb45 100644 --- a/im-client/src/main/java/com/bx/imclient/IMAutoConfiguration.java +++ b/im-client/src/main/java/com/bx/imclient/IMAutoConfiguration.java @@ -7,7 +7,7 @@ import org.springframework.context.annotation.Configuration; @Slf4j @Configuration -@ComponentScan("com.bx.imclient") +@ComponentScan(basePackages = "com.bx.imclient,com.bx.imcommon") public class IMAutoConfiguration { } diff --git a/im-client/src/main/java/com/bx/imclient/IMClient.java b/im-client/src/main/java/com/bx/imclient/IMClient.java index e94f0b8..e13518e 100644 --- a/im-client/src/main/java/com/bx/imclient/IMClient.java +++ b/im-client/src/main/java/com/bx/imclient/IMClient.java @@ -4,6 +4,7 @@ import com.bx.imclient.sender.IMSender; import com.bx.imcommon.enums.IMTerminalType; import com.bx.imcommon.model.IMGroupMessage; import com.bx.imcommon.model.IMPrivateMessage; +import com.bx.imcommon.model.IMSystemMessage; import lombok.AllArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -46,6 +47,16 @@ public class IMClient { return imSender.getOnlineTerminal(userIds); } + /** + * 发送系统消息(发送结果通过MessageListener接收) + * + * @param message 私有消息 + */ + public void sendSystemMessage(IMSystemMessage message){ + imSender.sendSystemMessage(message); + } + + /** * 发送私聊消息(发送结果通过MessageListener接收) * @@ -65,4 +76,6 @@ public class IMClient { } + + } diff --git a/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java b/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java deleted file mode 100644 index 5ef996c..0000000 --- a/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bx.imclient.config; - -import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration("IMRedisConfig") -public class RedisConfig { - - @Bean("IMRedisTemplate") - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate(); - redisTemplate.setConnectionFactory(redisConnectionFactory); - // 设置值(value)的序列化采用FastJsonRedisSerializer - redisTemplate.setValueSerializer(fastJsonRedisSerializer()); - redisTemplate.setHashValueSerializer(fastJsonRedisSerializer()); - // 设置键(key)的序列化采用StringRedisSerializer。 - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashKeySerializer(new StringRedisSerializer()); - redisTemplate.afterPropertiesSet(); - return redisTemplate; - } - - public FastJsonRedisSerializer fastJsonRedisSerializer(){ - return new FastJsonRedisSerializer<>(Object.class); - } - -} diff --git a/im-client/src/main/java/com/bx/imclient/sender/IMSender.java b/im-client/src/main/java/com/bx/imclient/sender/IMSender.java index 1e0a7f6..61d0a4d 100644 --- a/im-client/src/main/java/com/bx/imclient/sender/IMSender.java +++ b/im-client/src/main/java/com/bx/imclient/sender/IMSender.java @@ -8,33 +8,86 @@ import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; import com.bx.imcommon.enums.IMTerminalType; import com.bx.imcommon.model.*; +import com.bx.imcommon.mq.RedisMQTemplate; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import javax.annotation.Resource; import java.util.*; @Service @RequiredArgsConstructor public class IMSender { - @Resource(name="IMRedisTemplate") - private RedisTemplate redisTemplate; + @Autowired + private RedisMQTemplate redisMQTemplate; @Value("${spring.application.name}") private String appName; private final MessageListenerMulticaster listenerMulticaster; + + public void sendSystemMessage(IMSystemMessage message){ + // 根据群聊每个成员所连的IM-server,进行分组 + Map sendMap = new HashMap<>(); + for (Integer terminal : message.getRecvTerminals()) { + message.getRecvIds().forEach(id -> { + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString()); + sendMap.put(key,new IMUserInfo(id, terminal)); + }); + } + // 批量拉取 + List serverIds = redisMQTemplate.opsForValue().multiGet(sendMap.keySet()); + // 格式:map<服务器id,list<接收方>> + Map> serverMap = new HashMap<>(); + List offLineUsers = new LinkedList<>(); + int idx = 0; + for (Map.Entry entry : sendMap.entrySet()) { + Integer serverId = (Integer)serverIds.get(idx++); + if (!Objects.isNull(serverId)) { + List list = serverMap.computeIfAbsent(serverId, o -> new LinkedList<>()); + list.add(entry.getValue()); + } else { + // 加入离线列表 + offLineUsers.add(entry.getValue()); + } + } + // 逐个server发送 + for (Map.Entry> entry : serverMap.entrySet()) { + IMRecvInfo recvInfo = new IMRecvInfo(); + recvInfo.setCmd(IMCmdType.SYSTEM_MESSAGE.code()); + recvInfo.setReceivers(new LinkedList<>(entry.getValue())); + recvInfo.setServiceName(appName); + recvInfo.setSendResult(message.getSendResult()); + recvInfo.setData(message.getData()); + // 推送至队列 + String key = String.join(":", IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE, entry.getKey().toString()); + redisMQTemplate.opsForList().rightPush(key, recvInfo); + } + // 对离线用户回复消息状态 + if(message.getSendResult() && !offLineUsers.isEmpty()){ + List results = new LinkedList<>(); + for (IMUserInfo offLineUser : offLineUsers) { + IMSendResult result = new IMSendResult(); + result.setReceiver(offLineUser); + result.setCode(IMSendCode.NOT_ONLINE.code()); + result.setData(message.getData()); + results.add(result); + } + listenerMulticaster.multicast(IMListenerType.SYSTEM_MESSAGE, results); + } + } + + public void sendPrivateMessage(IMPrivateMessage message) { List results = new LinkedList<>(); if(!Objects.isNull(message.getRecvId())){ for (Integer terminal : message.getRecvTerminals()) { // 获取对方连接的channelId String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getRecvId().toString(), terminal.toString()); - Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + Integer serverId = (Integer)redisMQTemplate.opsForValue().get(key); // 如果对方在线,将数据存储至redis,等待拉取推送 if (serverId != null) { String sendKey = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, serverId.toString()); @@ -45,7 +98,7 @@ public class IMSender { recvInfo.setSender(message.getSender()); recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getRecvId(), terminal))); recvInfo.setData(message.getData()); - redisTemplate.opsForList().rightPush(sendKey, recvInfo); + redisMQTemplate.opsForList().rightPush(sendKey, recvInfo); } else { IMSendResult result = new IMSendResult(); result.setSender(message.getSender()); @@ -65,7 +118,7 @@ public class IMSender { } // 获取终端连接的channelId String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getSender().getId().toString(), terminal.toString()); - Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + Integer serverId = (Integer)redisMQTemplate.opsForValue().get(key); // 如果终端在线,将数据存储至redis,等待拉取推送 if (serverId != null) { String sendKey = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, serverId.toString()); @@ -76,7 +129,7 @@ public class IMSender { recvInfo.setSender(message.getSender()); recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getSender().getId(), terminal))); recvInfo.setData(message.getData()); - redisTemplate.opsForList().rightPush(sendKey, recvInfo); + redisMQTemplate.opsForList().rightPush(sendKey, recvInfo); } } } @@ -84,10 +137,10 @@ public class IMSender { if(message.getSendResult() && !results.isEmpty()){ listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, results); } + } public void sendGroupMessage(IMGroupMessage message) { - // 根据群聊每个成员所连的IM-server,进行分组 Map sendMap = new HashMap<>(); for (Integer terminal : message.getRecvTerminals()) { @@ -97,14 +150,14 @@ public class IMSender { }); } // 批量拉取 - List serverIds = redisTemplate.opsForValue().multiGet(sendMap.keySet()); + List serverIds = redisMQTemplate.opsForValue().multiGet(sendMap.keySet()); // 格式:map<服务器id,list<接收方>> Map> serverMap = new HashMap<>(); List offLineUsers = new LinkedList<>(); int idx = 0; for (Map.Entry entry : sendMap.entrySet()) { Integer serverId = (Integer)serverIds.get(idx++); - if (serverId != null) { + if (!Objects.isNull(serverId)) { List list = serverMap.computeIfAbsent(serverId, o -> new LinkedList<>()); list.add(entry.getValue()); } else { @@ -123,7 +176,7 @@ public class IMSender { recvInfo.setData(message.getData()); // 推送至队列 String key = String.join(":", IMRedisKey.IM_MESSAGE_GROUP_QUEUE, entry.getKey().toString()); - redisTemplate.opsForList().rightPush(key, recvInfo); + redisMQTemplate.opsForList().rightPush(key, recvInfo); } // 推送给自己的其他终端 @@ -134,9 +187,9 @@ public class IMSender { } // 获取终端连接的channelId String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getSender().getId().toString(), terminal.toString()); - Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + Integer serverId = (Integer)redisMQTemplate.opsForValue().get(key); // 如果终端在线,将数据存储至redis,等待拉取推送 - if (serverId != null) { + if (!Objects.isNull(serverId)) { IMRecvInfo recvInfo = new IMRecvInfo(); recvInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); recvInfo.setSender(message.getSender()); @@ -145,7 +198,7 @@ public class IMSender { recvInfo.setSendResult(false); recvInfo.setData(message.getData()); String sendKey = String.join(":", IMRedisKey.IM_MESSAGE_GROUP_QUEUE, serverId.toString()); - redisTemplate.opsForList().rightPush(sendKey, recvInfo); + redisMQTemplate.opsForList().rightPush(sendKey, recvInfo); } } } @@ -178,7 +231,7 @@ public class IMSender { } } // 批量拉取 - List serverIds = redisTemplate.opsForValue().multiGet(userMap.keySet()); + List serverIds = redisMQTemplate.opsForValue().multiGet(userMap.keySet()); int idx = 0; Map> onlineMap = new HashMap<>(); for (Map.Entry entry : userMap.entrySet()) { @@ -195,7 +248,7 @@ public class IMSender { public Boolean isOnline(Long userId) { String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*"); - return !Objects.requireNonNull(redisTemplate.keys(key)).isEmpty(); + return !Objects.requireNonNull(redisMQTemplate.keys(key)).isEmpty(); } public List getOnlineUser(List userIds){ diff --git a/im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java b/im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java index 154f2f3..346cfab 100644 --- a/im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java @@ -1,44 +1,21 @@ package com.bx.imclient.task; -import com.bx.imcommon.util.ThreadPoolExecutorFactory; -import lombok.SneakyThrows; +import cn.hutool.core.util.StrUtil; +import com.bx.imcommon.mq.RedisMQConsumer; import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.CommandLineRunner; - -import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; +import org.springframework.beans.factory.annotation.Value; @Slf4j -public abstract class AbstractMessageResultTask implements CommandLineRunner { +public abstract class AbstractMessageResultTask extends RedisMQConsumer { - private static final ExecutorService EXECUTOR_SERVICE = ThreadPoolExecutorFactory.getThreadPoolExecutor(); + @Value("${spring.application.name}") + private String appName; @Override - public void run(String... args) { - // 初始化定时器 - EXECUTOR_SERVICE.execute(new Runnable() { - @SneakyThrows - @Override - public void run() { - try { - pullMessage(); - } catch (Exception e) { - log.error("任务调度异常", e); - } - if (!EXECUTOR_SERVICE.isShutdown()) { - Thread.sleep(100); - EXECUTOR_SERVICE.execute(this); - } - } - }); + public String generateKey() { + return StrUtil.join(":", super.generateKey(), appName); } - @PreDestroy - public void destroy() { - log.info("{}线程任务关闭", this.getClass().getSimpleName()); - EXECUTOR_SERVICE.shutdown(); - } - public abstract void pullMessage() throws InterruptedException; } diff --git a/im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java b/im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java index 400220d..c8be7e2 100644 --- a/im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java @@ -1,59 +1,27 @@ package com.bx.imclient.task; -import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSONObject; import com.bx.imclient.listener.MessageListenerMulticaster; import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.model.IMSendResult; +import com.bx.imcommon.mq.RedisMQListener; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import javax.annotation.Resource; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; @Component @RequiredArgsConstructor -public class GroupMessageResultResultTask extends AbstractMessageResultTask { - - @Resource(name = "IMRedisTemplate") - private RedisTemplate redisTemplate; - - @Value("${spring.application.name}") - private String appName; - - @Value("${im.result.batch:100}") - private int batchSize; +@RedisMQListener(queue = IMRedisKey.IM_RESULT_GROUP_QUEUE, batchSize = 100) +public class GroupMessageResultResultTask extends AbstractMessageResultTask { private final MessageListenerMulticaster listenerMulticaster; @Override - public void pullMessage() { - List results; - do { - results = loadBatch(); - if(!results.isEmpty()){ - listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE, results); - } - } while (results.size() >= batchSize); + public void onMessage(List results) { + listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE, results); } - List loadBatch() { - String key = StrUtil.join(":", IMRedisKey.IM_RESULT_GROUP_QUEUE, appName); - //这个接口redis6.2以上才支持 - //List list = redisTemplate.opsForList().leftPop(key, batchSize); - List results = new LinkedList<>(); - JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - while (!Objects.isNull(jsonObject) && results.size() < batchSize) { - results.add(jsonObject.toJavaObject(IMSendResult.class)); - jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - } - return results; - } } diff --git a/im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java b/im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java index 2451db1..38e5ac1 100644 --- a/im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java @@ -1,60 +1,26 @@ package com.bx.imclient.task; -import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSONObject; import com.bx.imclient.listener.MessageListenerMulticaster; import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.model.IMSendResult; +import com.bx.imcommon.mq.RedisMQListener; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import javax.annotation.Resource; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; -@Slf4j + @Component @RequiredArgsConstructor -public class PrivateMessageResultResultTask extends AbstractMessageResultTask { - - @Resource(name = "IMRedisTemplate") - private RedisTemplate redisTemplate; - - @Value("${spring.application.name}") - private String appName; - - @Value("${im.result.batch:100}") - private int batchSize; +@RedisMQListener(queue = IMRedisKey.IM_RESULT_PRIVATE_QUEUE, batchSize = 100) +public class PrivateMessageResultResultTask extends AbstractMessageResultTask { private final MessageListenerMulticaster listenerMulticaster; @Override - public void pullMessage() { - List results; - do { - results = loadBatch(); - if(!results.isEmpty()){ - listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, results); - } - } while (results.size() >= batchSize); - } - - List loadBatch() { - String key = StrUtil.join(":", IMRedisKey.IM_RESULT_PRIVATE_QUEUE, appName); - //这个接口redis6.2以上才支持 - //List list = redisTemplate.opsForList().leftPop(key, batchSize); - List results = new LinkedList<>(); - JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - while (!Objects.isNull(jsonObject) && results.size() < batchSize) { - results.add(jsonObject.toJavaObject(IMSendResult.class)); - jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - } - return results; + public void onMessage(List results) { + listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, results); } } diff --git a/im-client/src/main/java/com/bx/imclient/task/SystemMessageResultResultTask.java b/im-client/src/main/java/com/bx/imclient/task/SystemMessageResultResultTask.java new file mode 100644 index 0000000..a42ca94 --- /dev/null +++ b/im-client/src/main/java/com/bx/imclient/task/SystemMessageResultResultTask.java @@ -0,0 +1,25 @@ +package com.bx.imclient.task; + +import com.bx.imclient.listener.MessageListenerMulticaster; +import com.bx.imcommon.contant.IMRedisKey; +import com.bx.imcommon.enums.IMListenerType; +import com.bx.imcommon.model.IMSendResult; +import com.bx.imcommon.mq.RedisMQListener; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@RequiredArgsConstructor +@RedisMQListener(queue = IMRedisKey.IM_RESULT_SYSTEM_QUEUE, batchSize = 100) +public class SystemMessageResultResultTask extends AbstractMessageResultTask { + + private final MessageListenerMulticaster listenerMulticaster; + + @Override + public void onMessage(List results) { + listenerMulticaster.multicast(IMListenerType.SYSTEM_MESSAGE, results); + } + +} diff --git a/im-client/src/main/resources/META-INF/spring.factories b/im-client/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 801458e..0000000 --- a/im-client/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -com.bx.imclient.IMAutoConfiguration \ No newline at end of file diff --git a/im-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/im-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fe31de9 --- /dev/null +++ b/im-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.bx.imclient.IMAutoConfiguration \ No newline at end of file diff --git a/im-commom/pom.xml b/im-commom/pom.xml index 43fb929..92599d1 100644 --- a/im-commom/pom.xml +++ b/im-commom/pom.xml @@ -5,16 +5,11 @@ box-im com.bx - 2.0.0 + 3.0.0 4.0.0 im-commom - - - 8 - 8 - - + jar org.projectlombok @@ -39,15 +34,9 @@ org.springframework spring-beans - - org.apache.velocity - velocity - ${velocity.version} - com.fasterxml.jackson.datatype jackson-datatype-joda - 2.9.10 org.springframework @@ -63,7 +52,11 @@ org.slf4j slf4j-api - 1.7.36 + + + + org.springframework.boot + spring-boot-starter-data-redis \ No newline at end of file diff --git a/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java b/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java index eccbac8..a7a8bf3 100644 --- a/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java +++ b/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java @@ -2,7 +2,6 @@ package com.bx.imcommon.contant; public final class IMRedisKey { - private IMRedisKey() {} /** * im-server最大id,从0开始递增 @@ -13,13 +12,22 @@ public final class IMRedisKey { */ public static final String IM_USER_SERVER_ID = "im:user:server_id"; /** - * 未读私聊消息队列 + * 系统消息队列 + */ + public static final String IM_MESSAGE_SYSTEM_QUEUE = "im:message:system"; + /** + * 私聊消息队列 */ public static final String IM_MESSAGE_PRIVATE_QUEUE = "im:message:private"; /** - * 未读群聊消息队列 + * 群聊消息队列 */ public static final String IM_MESSAGE_GROUP_QUEUE = "im:message:group"; + + /** + * 系统消息发送结果队列 + */ + public static final String IM_RESULT_SYSTEM_QUEUE = "im:result:system"; /** * 私聊消息发送结果队列 */ diff --git a/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java b/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java index c302aa1..a6731ec 100644 --- a/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java +++ b/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java @@ -24,7 +24,11 @@ public enum IMCmdType { /** * 群发消息 */ - GROUP_MESSAGE(4, "群发消息"); + GROUP_MESSAGE(4, "群发消息"), + /** + * 系统消息 + */ + SYSTEM_MESSAGE(5,"系统消息"); private final Integer code; diff --git a/im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java b/im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java index 0448d2d..5dbb1b2 100644 --- a/im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java +++ b/im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java @@ -15,7 +15,13 @@ public enum IMListenerType { /** * 群聊消息 */ - GROUP_MESSAGE(2, "群聊消息"); + GROUP_MESSAGE(2, "群聊消息"), + /** + * 系统消息 + */ + SYSTEM_MESSAGE(3, "群聊消息"); + + private final Integer code; diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java b/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java index 206c882..e33b540 100644 --- a/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java @@ -26,7 +26,7 @@ public class IMPrivateMessage { private List recvTerminals = IMTerminalType.codes(); /** - * 是否发送给自己的其他终端,默认true + * 是否同步消息给自己的其他终端,默认true */ private Boolean sendToSelf = true; diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java b/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java index c0354b9..9f4688c 100644 --- a/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java @@ -16,7 +16,7 @@ public class IMSendResult { private IMUserInfo receiver; /** - * 发送状态 IMCmdType + * 发送状态编码 IMSendCode */ private Integer code; diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMSystemMessage.java b/im-commom/src/main/java/com/bx/imcommon/model/IMSystemMessage.java new file mode 100644 index 0000000..2241cb5 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMSystemMessage.java @@ -0,0 +1,34 @@ +package com.bx.imcommon.model; + +import com.bx.imcommon.enums.IMTerminalType; +import lombok.Data; + +import java.util.LinkedList; +import java.util.List; + +@Data +public class IMSystemMessage { + + + /** + * 接收者id列表,为空表示向所有在线用户广播 + */ + private List recvIds = new LinkedList<>(); + + /** + * 接收者终端类型,默认全部 + */ + private List recvTerminals = IMTerminalType.codes(); + + /** + * 是否需要回推发送结果,默认true + */ + private Boolean sendResult = true; + + /** + * 消息内容 + */ + private T data; + + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConfig.java b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConfig.java new file mode 100644 index 0000000..99c5074 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConfig.java @@ -0,0 +1,32 @@ +package com.bx.imcommon.mq; + +import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.StringRedisSerializer; + + +@Configuration +public class RedisMQConfig { + + @Bean + public RedisMQTemplate redisMQTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisMQTemplate redisMQTemplate = new RedisMQTemplate(); + redisMQTemplate.setConnectionFactory(redisConnectionFactory); + // 设置值(value)的序列化采用FastJsonRedisSerializer + redisMQTemplate.setValueSerializer(fastJsonRedisSerializer()); + redisMQTemplate.setHashValueSerializer(fastJsonRedisSerializer()); + // 设置键(key)的序列化采用StringRedisSerializer。 + redisMQTemplate.setKeySerializer(new StringRedisSerializer()); + redisMQTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisMQTemplate.afterPropertiesSet(); + return redisMQTemplate; + } + + @Bean + public FastJsonRedisSerializer fastJsonRedisSerializer(){ + return new FastJsonRedisSerializer<>(Object.class); + } + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConsumer.java b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConsumer.java new file mode 100644 index 0000000..cd997fd --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConsumer.java @@ -0,0 +1,35 @@ +package com.bx.imcommon.mq; + +import java.util.List; + +/** + * redis 队列消费者抽象类 + */ +public abstract class RedisMQConsumer { + + /** + * 消费消息回调(单条) + */ + public void onMessage(T data){} + + /** + * 消费消息回调(批量) + */ + public void onMessage(List datas){} + + /** + * 生成redis队列完整key + */ + public String generateKey(){ + // 默认队列名就是redis的key + RedisMQListener annotation = this.getClass().getAnnotation(RedisMQListener.class); + return annotation.queue(); + } + + /** + * 队列是否就绪,返回true才会开始消费 + */ + public Boolean isReady(){ + return true; + } +} diff --git a/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQListener.java b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQListener.java new file mode 100644 index 0000000..eb5fd1e --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQListener.java @@ -0,0 +1,29 @@ +package com.bx.imcommon.mq; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * redis 队列消费监听注解 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface RedisMQListener { + + /** + * 队列,也是redis的key + */ + String queue(); + + /** + * 一次性拉取的数据数量 + */ + int batchSize() default 1; + + /** + * 拉取间隔周期,单位:ms + */ + int period() default 100; +} diff --git a/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQPullTask.java b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQPullTask.java new file mode 100644 index 0000000..353dcaf --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQPullTask.java @@ -0,0 +1,114 @@ +package com.bx.imcommon.mq; + +import com.alibaba.fastjson.JSONObject; +import com.bx.imcommon.util.ThreadPoolExecutorFactory; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * reids 队列拉取定时任务 + * + * @author: Blue + * @date: 2024-07-15 + * @version: 1.0 + */ +@Slf4j +@Component +public class RedisMQPullTask implements CommandLineRunner { + + private static final ScheduledThreadPoolExecutor EXECUTOR = ThreadPoolExecutorFactory.getThreadPoolExecutor(); + + @Autowired(required = false) + private List consumers = Collections.emptyList(); + + @Autowired + private RedisMQTemplate redisMQTemplate; + + @Override + public void run(String... args) { + consumers.forEach((consumer -> { + // 注解参数 + RedisMQListener annotation = consumer.getClass().getAnnotation(RedisMQListener.class); + String queue = annotation.queue(); + int batchSize = annotation.batchSize(); + int period = annotation.period(); + // 获取泛型类型 + Type superClass = consumer.getClass().getGenericSuperclass(); + Type type = ((ParameterizedType)superClass).getActualTypeArguments()[0]; + EXECUTOR.execute(new Runnable() { + @Override + public void run() { + List datas = new LinkedList<>(); + try { + if(redisMQTemplate.isClose()){ + return; + } + if (consumer.isReady()) { + String key = consumer.generateKey(); + // 拉取一个批次的数据 + List objects = pullBatch(key, batchSize); + for (Object obj : objects) { + if (obj instanceof JSONObject) { + JSONObject jsonObject = (JSONObject)obj; + Object data = jsonObject.toJavaObject(type); + consumer.onMessage(data); + datas.add(data); + } + } + if (!datas.isEmpty()) { + consumer.onMessage(datas); + } + } + } catch (Exception e) { + log.error("数据消费异常,队列:{}", queue, e); + return; + } + // 继续消费数据 + if (!EXECUTOR.isShutdown()) { + if (datas.size() < batchSize) { + // 数据已经消费完,等待下一个周期继续拉取 + EXECUTOR.schedule(this, period, TimeUnit.MICROSECONDS); + } else { + // 数据没有消费完,直接开启下一个消费周期 + EXECUTOR.execute(this); + } + } + } + }); + })); + } + + private List pullBatch(String key, Integer batchSize) { + List objects = new LinkedList<>(); + if (redisMQTemplate.isSupportBatchPull()) { + // 版本大于6.2,支持批量拉取 + objects = redisMQTemplate.opsForList().leftPop(key, batchSize); + } else { + // 版本小于6.2,只能逐条拉取 + Object obj = redisMQTemplate.opsForList().leftPop(key); + while (!Objects.isNull(obj) && objects.size() < batchSize) { + objects.add(obj); + obj = redisMQTemplate.opsForList().leftPop(key); + } + } + return objects; + } + + @PreDestroy + public void destory() { + log.info("消费线程停止..."); + ThreadPoolExecutorFactory.shutDown(); + } +} diff --git a/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQTemplate.java b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQTemplate.java new file mode 100644 index 0000000..c98a036 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/mq/RedisMQTemplate.java @@ -0,0 +1,52 @@ +package com.bx.imcommon.mq; + +import org.apache.logging.log4j.util.Strings; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Objects; +import java.util.Properties; + +/** + * @author: Blue + * @date: 2024-07-16 + * @version: 1.0 + */ +public class RedisMQTemplate extends RedisTemplate { + + private String version = Strings.EMPTY; + + public String getVersion() { + if (version.isEmpty()) { + RedisConnection redisConnection = this.getConnectionFactory().getConnection(); + Properties properties = redisConnection.info(); + version = properties.getProperty("redis_version"); + } + return version; + } + + /** + * 是否支持批量拉取,redis版本大于6.2支持批量拉取 + * @return + */ + Boolean isSupportBatchPull() { + String version = getVersion(); + String[] arr = version.split("\\."); + if (arr.length < 2) { + return false; + } + Integer firVersion = Integer.valueOf(arr[0]); + Integer secVersion = Integer.valueOf(arr[1]); + return firVersion > 6 || (firVersion == 6 && secVersion >= 2); + } + + + Boolean isClose(){ + try { + return getConnectionFactory().getConnection().isClosed(); + }catch (Exception e){ + return true; + } + } +} diff --git a/im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java b/im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java index 503fb4d..46d77b3 100644 --- a/im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java +++ b/im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java @@ -2,9 +2,8 @@ package com.bx.imcommon.util; import lombok.extern.slf4j.Slf4j; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; /** * 创建单例线程池 @@ -38,7 +37,7 @@ public final class ThreadPoolExecutorFactory { /** * 线程池对象 */ - private static volatile ThreadPoolExecutor threadPoolExecutor = null; + private static volatile ScheduledThreadPoolExecutor threadPoolExecutor = null; /** * 构造方法私有化 @@ -49,34 +48,20 @@ public final class ThreadPoolExecutorFactory { } } - /** - * 重写readResolve方法 - */ - private Object readResolve() { - //重写readResolve方法,防止序列化破坏单例 - return ThreadPoolExecutorFactory.getThreadPoolExecutor(); - } /** * 双检锁创建线程安全的单例 */ - public static ThreadPoolExecutor getThreadPoolExecutor() { + public static ScheduledThreadPoolExecutor getThreadPoolExecutor() { if (null == threadPoolExecutor) { synchronized (ThreadPoolExecutorFactory.class) { if (null == threadPoolExecutor) { - threadPoolExecutor = new ThreadPoolExecutor( - //核心线程数 - CORE_POOL_SIZE, - //最大线程数,包含临时线程 - MAX_IMUM_POOL_SIZE, - //临时线程的存活时间 - KEEP_ALIVE_TIME, - //时间单位(毫秒) - TimeUnit.MILLISECONDS, - //等待队列 - new LinkedBlockingQueue<>(QUEUE_SIZE), - //拒绝策略 - new ThreadPoolExecutor.CallerRunsPolicy()); + threadPoolExecutor = new ScheduledThreadPoolExecutor( + //核心线程数 + CORE_POOL_SIZE, + //拒绝策略 + new ThreadPoolExecutor.CallerRunsPolicy() + ); } } } @@ -86,13 +71,13 @@ public final class ThreadPoolExecutorFactory { /** * 关闭线程池 */ - public void shutDown() { + public static void shutDown() { if (threadPoolExecutor != null) { threadPoolExecutor.shutdown(); } } - public void execute(Runnable runnable) { + public static void execute(Runnable runnable) { if (runnable == null) { return; } diff --git a/im-docker-compose/README.md b/im-docker-compose/README.md deleted file mode 100644 index a658ac7..0000000 --- a/im-docker-compose/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# docker 构建和部署指南 - -## 配置 - -请配置以下文件的挂载目录、端口号、环境变量、账户信息等。 - -- box-im/im-docker-compose/im-coturn/docker-compose.yml -- box-im/im-docker-compose/im-service/docker-compose.yml -- box-im/im-docker-compose/im-coturn/im-platform.env -- box-im/im-docker-compose/im-coturn/im-server.env - -## 构建 - -可以在部署的目标服务器上在下面两个目录下构建出 im-server 和 im-platform 的 docker images. - -- box-im/im-server/Dockerfile -- box-im/im-platform/Dockerfile - -## 部署 - -在部署的目标服务器上通过 docker-compose 启动所有容器, - -```bash -docker-compose -f im-docker-compose/im-coturn/docker-compose.yml up -d -docker-compose -f im-docker-compose/im-service/docker-compose.yml up -d -``` diff --git a/im-docker-compose/im-coturn/docker-compose.yml b/im-docker-compose/im-coturn/docker-compose.yml deleted file mode 100644 index 7be5ce8..0000000 --- a/im-docker-compose/im-coturn/docker-compose.yml +++ /dev/null @@ -1,27 +0,0 @@ - -version: "3" - -services: - im-coturn: - container_name: im-coturn - image: coturn/coturn:4.6.2-alpine - command: turnserver -v -a -c /etc/coturn/conf/coturn.conf - restart: always - ports: - - PORT_COTURN_LISTEN_OS:3478 - - PORT_COTURN_LISTEN_OS:3478/udp - - PORT_COTURN_LISTEN_TLS_OS:5349 - - PORT_COTURN_LISTEN_TLS_OS:5349/udp - - PORT_COTURN_RELAY_BEGIN_OS-PORT_COTURN_RELAY_END_OS:PORT_COTURN_RELAY_BEGIN_OS-PORT_COTURN_RELAY_END_OS/udp - # network_mode: "host" - environment: - - DETECT_EXTERNAL_IP=yes - - DETECT_RELAY_IP=yes - volumes: - - deploydir/docker_volumes_data/coturn/conf:/etc/coturn/conf - - deploydir/docker_volumes_data/coturn/certs:/etc/coturn/ssl - - deploydir/docker_volumes_data/coturn/log:/var/log/coturn/ -networks: - default: - external: - name: turn-network diff --git a/im-docker-compose/im-service/docker-compose.yml b/im-docker-compose/im-service/docker-compose.yml deleted file mode 100644 index 51e5e90..0000000 --- a/im-docker-compose/im-service/docker-compose.yml +++ /dev/null @@ -1,99 +0,0 @@ - -version: "3" - -services: - im-mysql: - container_name: im-mysql - image: mysql:5.7 - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - - TZ=Asia/Shanghai - - MYSQL_ROOT_PASSWORD=MYSQL_ROOT_USER_PASSWORD - - MYSQL_ROOT_HOST=% - - MYSQL_IM_USERNAME=MYSQL_USERNAME - - MYSQL_IM_PASSWORD=MYSQL_PASSWORD - volumes: - - deploydir/docker_volumes_data/mysql/data:/var/lib/mysql - - deploydir/docker_volumes_data/mysql/mysql.conf.d:/etc/mysql/mysql.conf.d - - im-redis: - container_name: im-redis - image: redis:6-alpine - command: redis-server --requirepass REDIS_PASSWORD --appendonly yes --appendfsync everysec --auto-aof-rewrite-percentage 100 --auto-aof-rewrite-min-size 100mb - restart: always - # ports: - # - "127.0.0.1:6379:6379" - volumes: - - deploydir/docker_volumes_data/redis/data:/data - - im-minio: - container_name: im-minio - image: bitnami/minio:2024 - restart: always - # ports: - # - 9001:9001 - # - 9002:9002 - privileged: true - environment: - - MINIO_SKIP_CLIENT=yes - - MINIO_API_PORT_NUMBER=9001 - - MINIO_CONSOLE_PORT_NUMBER=9002 - # - MINIO_OPTS="--console-address :9002 --address :9001" - # - MINIO_DOMAIN=im_minio:9001 - - MINIO_DATA_DIR=/data/minio - - MINIO_ROOT_USER=MINIO_USERNAME - - MINIO_ROOT_PASSWORD=MINIO_PASSWORD - volumes: - - deploydir/docker_volumes_data/minio/data:/data/minio - - im-nginx: - container_name: im-nginx - image: openresty/openresty:1.21.4.1-0-alpine - restart: always - ports: - - PORT_NGINX_HTTP_OS:80 - - PORT_NGINX_HTTPS_OS:443 - - PORT_NGINX_WSS_OS:81 - depends_on: - im-platform: - condition: service_started - im-server: - condition: service_started - volumes: - - deploydir/docker_volumes_data/nginx/data/conf:/etc/nginx ## configs - - deploydir/docker_volumes_data/nginx/data/certs:/etc/certs ## cert files - - deploydir/docker_volumes_data/nginx/data/web:/usr/share/nginx ## web - - im-platform: - container_name: im-platform - image: im-platform:latest - restart: always - depends_on: - im-mysql: - condition: service_started - im-redis: - condition: service_started - im-minio: - condition: service_started - env_file: - - im-platform.env - - im-server: - container_name: im-server - image: im-server:latest - restart: always - depends_on: - im-mysql: - condition: service_started - im-redis: - condition: service_started - im-minio: - condition: service_started - env_file: - - im-server.env -networks: - default: - external: - name: im-network - diff --git a/im-docker-compose/im-service/im-platform.env b/im-docker-compose/im-service/im-platform.env deleted file mode 100644 index 5438781..0000000 --- a/im-docker-compose/im-service/im-platform.env +++ /dev/null @@ -1,28 +0,0 @@ -spring_datasource_username=MYSQL_USERNAME -spring_datasource_password=MYSQL_PASSWORD -spring_redis_password=REDIS_PASSWORD - -spring_datasource_url=jdbc:mysql://im-mysql:3306/box-im?useSSL=false&useUnicode=true&characterEncoding=utf-8 -spring_datasource_password=MYSQL_PASSWORD -spring_redis_host=im-redis -spring_redis_port=6379 -spring_redis_password=REDIS_PASSWORD - -minio_accessKey=MINIO_USERNAME -minio_secretKey=MINIO_PASSWORD -minio_public=https://IM_DOMAIN:PORT_NGINX_HTTPS_EXTERNAL/file -minio_endpoint=http://im-minio:9001 - -ICE_SERVER_1_URL=TURN_DOMAIN:PORT_COTURN_LISTEN_EXTERNAL -ICE_SERVER_1_USERNAME=TURN_USERNAME -ICE_SERVER_1_CREDENTIAL=TURN_PASSWORD - -ICE_SERVER_2_URL=TURN_DOMAIN:PORT_COTURN_LISTEN_EXTERNAL -ICE_SERVER_2_USERNAME=TURN_USERNAME -ICE_SERVER_2_CREDENTIAL=TURN_PASSWORD - -jwt_accessToken_secret=JWT_ACCESSTOKEN_SECRET -jwt_accessToken_expireIn=JWT_ACCESSTOKEN_EXPIREDIN -jwt_refreshToken_secret=JWT_REFRESHTOKEN_SECRET -jwt_refreshToken_expireIn=JWT_REFRESHTOKEN_EXPIREDIN - diff --git a/im-docker-compose/im-service/im-server.env b/im-docker-compose/im-service/im-server.env deleted file mode 100644 index 6a9f063..0000000 --- a/im-docker-compose/im-service/im-server.env +++ /dev/null @@ -1,4 +0,0 @@ -spring_redis_host=im-redis -spring_redis_port=6379 -spring_redis_password=REDIS_PASSWORD -jwt_accessToken_secret=JWT_ACCESSTOKEN_SECRET diff --git a/im-platform/pom.xml b/im-platform/pom.xml index 16e987c..65ef8ab 100644 --- a/im-platform/pom.xml +++ b/im-platform/pom.xml @@ -5,22 +5,16 @@ box-im com.bx - 2.0.0 + 3.0.0 4.0.0 - im-platform - com.bx im-client - 2.0.0 - - - org.springframework.boot - spring-boot + 3.0.0 org.springframework.boot @@ -29,41 +23,38 @@ com.baomidou mybatis-plus-boot-starter + + + org.mybatis + mybatis-spring + + + + + org.mybatis + mybatis-spring + ${mybatis.spring.version} com.alibaba druid - mysql - mysql-connector-java + com.mysql + mysql-connector-j org.springframework.boot spring-boot-starter-jdbc - - io.springfox - springfox-swagger2 - ${swagger.version} - - - io.springfox - springfox-swagger-ui - ${swagger.version} - org.aspectj aspectjweaver - - - org.springframework.boot - spring-boot-starter-data-redis - - org.springframework.boot - spring-boot-starter-security + org.springframework.security + spring-security-crypto + 6.3.1 org.springframework.session @@ -77,27 +68,7 @@ io.minio minio - 8.4.3 - - - com.squareup.okhttp3 - okhttp - - - org.jetbrains.kotlin - kotlin-stdlib - - - - - com.squareup.okhttp3 - okhttp - 4.9.0 - - - org.jetbrains.kotlin - kotlin-stdlib - 1.3.70 + ${minio.version} @@ -112,18 +83,21 @@ org.redisson - redisson - 3.17.3 + redisson-spring-boot-starter + ${redisson.version} + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} - ${project.artifactId} org.springframework.boot spring-boot-maven-plugin - 2.0.3.RELEASE diff --git a/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java b/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java index e2aabee..2b8a91c 100644 --- a/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java +++ b/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java @@ -1,27 +1,18 @@ package com.bx.implatform; -import cn.hutool.core.util.StrUtil; -import com.bx.implatform.contant.RedisKey; import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.data.redis.core.RedisTemplate; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; + @Slf4j @EnableAspectJAutoProxy(exposeProxy = true) @MapperScan(basePackages = {"com.bx.implatform.mapper"}) -@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})// 禁用secrity +@SpringBootApplication public class IMPlatformApp { public static void main(String[] args) { diff --git a/im-platform/src/main/java/com/bx/implatform/annotation/OnlineCheck.java b/im-platform/src/main/java/com/bx/implatform/annotation/OnlineCheck.java index f616002..4baec54 100644 --- a/im-platform/src/main/java/com/bx/implatform/annotation/OnlineCheck.java +++ b/im-platform/src/main/java/com/bx/implatform/annotation/OnlineCheck.java @@ -4,7 +4,6 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.concurrent.TimeUnit; /** * 在线校验,标注此注解的接口用户必须保持长连接,否则将抛异常 diff --git a/im-platform/src/main/java/com/bx/implatform/aspect/OnlineCheckAspect.java b/im-platform/src/main/java/com/bx/implatform/aspect/OnlineCheckAspect.java index b81124c..a9be97e 100644 --- a/im-platform/src/main/java/com/bx/implatform/aspect/OnlineCheckAspect.java +++ b/im-platform/src/main/java/com/bx/implatform/aspect/OnlineCheckAspect.java @@ -1,8 +1,6 @@ package com.bx.implatform.aspect; -import cn.hutool.core.util.StrUtil; import com.bx.imclient.IMClient; -import com.bx.implatform.annotation.RedisLock; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; @@ -11,13 +9,8 @@ import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.reflect.MethodSignature; -import org.redisson.api.RLock; -import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; - /** * @author: blue * @date: 2024-06-16 diff --git a/im-platform/src/main/java/com/bx/implatform/aspect/RedisLockAspect.java b/im-platform/src/main/java/com/bx/implatform/aspect/RedisLockAspect.java index 0cd5586..dc5c6b5 100644 --- a/im-platform/src/main/java/com/bx/implatform/aspect/RedisLockAspect.java +++ b/im-platform/src/main/java/com/bx/implatform/aspect/RedisLockAspect.java @@ -8,8 +8,6 @@ import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; -import org.redisson.Redisson; -import org.redisson.RedissonLock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.core.DefaultParameterNameDiscoverer; diff --git a/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java b/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java index 4ee1d19..2dee3c9 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java @@ -19,13 +19,10 @@ public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(xssInterceptor) - .addPathPatterns("/**") - .excludePathPatterns("/error"); - registry.addInterceptor(authInterceptor) - .addPathPatterns("/**") - .excludePathPatterns("/login", "/logout", "/register", "/refreshToken", - "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"); + registry.addInterceptor(xssInterceptor).addPathPatterns("/**").excludePathPatterns("/error"); + registry.addInterceptor(authInterceptor).addPathPatterns("/**") + .excludePathPatterns("/login", "/logout", "/register", "/refreshToken", "/swagger/**", "/v3/api-docs/**", + "/swagger-resources/**", "/swagger-ui.html", "/swagger-ui/**", "/doc.html"); } @Bean diff --git a/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java b/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java index 14922b0..d74e656 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java @@ -1,18 +1,17 @@ package com.bx.implatform.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import jakarta.annotation.Resource; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.interceptor.CacheErrorHandler; -import org.springframework.cache.interceptor.CacheResolver; -import org.springframework.cache.interceptor.SimpleCacheErrorHandler; -import org.springframework.cache.interceptor.SimpleCacheResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @@ -24,9 +23,7 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; -import javax.annotation.Resource; import java.time.Duration; -import java.util.Objects; @EnableCaching @Configuration @@ -40,7 +37,6 @@ public class RedisConfig extends CachingConfigurerSupport { public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); - // 设置值(value)的序列化采用jackson2JsonRedisSerializer redisTemplate.setValueSerializer(jackson2JsonRedisSerializer()); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer()); @@ -51,42 +47,28 @@ public class RedisConfig extends CachingConfigurerSupport { return redisTemplate; } + + + @Bean + public CacheManager cacheManager() { + // 设置redis缓存管理器 + RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(600)) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer())); + return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build(); + } + + @Bean public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer() { - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 解决jackson2无法反序列化LocalDateTime的问题 om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); + om.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略空值 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); - jackson2JsonRedisSerializer.setObjectMapper(om); - return jackson2JsonRedisSerializer; - } - - - @Bean - @Override - public CacheResolver cacheResolver() { - return new SimpleCacheResolver(Objects.requireNonNull(cacheManager())); - } - - @Bean - @Override - public CacheErrorHandler errorHandler() { - // 用于捕获从Cache中进行CRUD时的异常的回调处理器。 - return new SimpleCacheErrorHandler(); - } - - @Bean - @Override - public CacheManager cacheManager() { - // 设置redis缓存管理器 - RedisCacheConfiguration cacheConfiguration = - RedisCacheConfiguration.defaultCacheConfig() - .disableCachingNullValues() - .entryTtl(Duration.ofMinutes(10)) - .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer())); - return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build(); + //忽略无效字段 + om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return new Jackson2JsonRedisSerializer<>(om, Object.class); } } diff --git a/im-platform/src/main/java/com/bx/implatform/config/RedissonConfig.java b/im-platform/src/main/java/com/bx/implatform/config/RedissonConfig.java index 7dc1c92..f3203a0 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/RedissonConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/RedissonConfig.java @@ -6,11 +6,8 @@ import org.redisson.api.RedissonClient; import org.redisson.client.codec.StringCodec; import org.redisson.config.Config; import org.redisson.config.SingleServerConfig; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; /** * @author: Blue @@ -18,9 +15,9 @@ import org.springframework.context.annotation.Configuration; * @version: 1.0 */ -@Configuration -@ConditionalOnClass(Config.class) -@EnableConfigurationProperties(RedisProperties.class) +//@Configuration +//@ConditionalOnClass(Config.class) +//@EnableConfigurationProperties(RedisProperties.class) public class RedissonConfig { @Bean diff --git a/im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java b/im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java index 3410b08..3b2ae2a 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java @@ -1,41 +1,38 @@ package com.bx.implatform.config; -import io.swagger.annotations.ApiOperation; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springdoc.core.models.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.ApiInfoBuilder; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.ApiInfo; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration -@EnableSwagger2 public class SwaggerConfig { @Bean - public Docket createRestApi() { - - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .select() - //这里采用包含注解的方式来确定要显示的接口 - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) - //这里采用包扫描的方式来确定要显示的接口 - .paths(PathSelectors.any()) - .build(); - + public GroupedOpenApi userApi() { + String[] paths = {"/**"}; + String[] packagedToMatch = {"com.bx"}; + return GroupedOpenApi.builder().group("IM-Platform") + .pathsToMatch(paths) + .packagesToScan(packagedToMatch).build(); } - private ApiInfo apiInfo() { - return new ApiInfoBuilder() - .title("IM Platform doc") - .description("盒子IM API文档") - .termsOfServiceUrl("http://8.134.92.70/") - .version("1.0") - .build(); + @Bean + public OpenAPI customOpenAPI() { + Contact contact = new Contact(); + contact.setName("Blue"); + return new OpenAPI().info(new Info() + .title("盒子IM接口文档") + .description("盒子IM业务平台服务") + .contact(contact) + .version("3.0") + .termsOfService("https://www.boxim.online") + .license(new License().name("MIT") + .url("https://www.boxim.online"))); } } diff --git a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java index 6d23dfc..08e4125 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java @@ -2,20 +2,21 @@ package com.bx.implatform.contant; public final class Constant { - private Constant() { - } - + /** + * 系统用户id + */ + public static final Long SYS_USER_ID = 0L; /** * 最大图片上传大小 */ - public static final long MAX_IMAGE_SIZE = 20 * 1024 * 1024; + public static final Long MAX_IMAGE_SIZE = 20 * 1024 * 1024L; /** * 最大上传文件大小 */ - public static final long MAX_FILE_SIZE = 20 * 1024 * 1024; + public static final Long MAX_FILE_SIZE = 20 * 1024 * 1024L; /** * 群聊最大人数 */ - public static final long MAX_GROUP_MEMBER = 500; + public static final Long MAX_GROUP_MEMBER = 500L; } diff --git a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java index 026e3c9..17ddd9f 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java @@ -18,31 +18,38 @@ public final class RedisKey { * webrtc 群通话 */ public static final String IM_WEBRTC_GROUP_SESSION = "im:webrtc:group:session"; + + /** + * 用户被封禁消息队列 + */ + public static final String IM_QUEUE_USER_BANNED = "im:queue:user:banned"; + + /** + * 群聊被封禁消息队列 + */ + public static final String IM_QUEUE_GROUP_BANNED = "im:queue:group:banned"; + /** - * 缓存前缀 + * 群聊解封消息队列 */ - public static final String IM_CACHE = "im:cache:"; + public static final String IM_QUEUE_GROUP_UNBAN = "im:queue:group:unban"; + + /** * 缓存是否好友:bool */ - public static final String IM_CACHE_FRIEND = IM_CACHE + "friend"; + public static final String IM_CACHE_FRIEND = "im:cache:friend"; /** * 缓存群聊信息 */ - public static final String IM_CACHE_GROUP = IM_CACHE + "group"; + public static final String IM_CACHE_GROUP = "im:cache:group"; /** * 缓存群聊成员id */ - public static final String IM_CACHE_GROUP_MEMBER_ID = IM_CACHE + "group_member_ids"; - - /** - * 分布式锁前缀 - */ - public static final String IM_LOCK = "im:lock:"; - + public static final String IM_CACHE_GROUP_MEMBER_ID = "im:cache:group_member_ids"; /** * 分布式锁前缀 */ - public static final String IM_LOCK_RTC_GROUP = IM_LOCK + "rtc:group"; + public static final String IM_LOCK_RTC_GROUP = "im:lock:rtc:group"; } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/FileController.java b/im-platform/src/main/java/com/bx/implatform/controller/FileController.java index 204f639..ddf9236 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/FileController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/FileController.java @@ -4,33 +4,34 @@ import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.thirdparty.FileService; import com.bx.implatform.vo.UploadImageVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @Slf4j @RestController -@Api(tags = "文件上传") +@Tag(name = "文件上传") @RequiredArgsConstructor public class FileController { private final FileService fileService; - @ApiOperation(value = "上传图片", notes = "上传图片,上传后返回原图和缩略图的url") + @Operation(summary = "上传图片", description = "上传图片,上传后返回原图和缩略图的url") @PostMapping("/image/upload") - public Result uploadImage(MultipartFile file) { + public Result uploadImage(@RequestParam("file") MultipartFile file) { return ResultUtils.success(fileService.uploadImage(file)); } @CrossOrigin - @ApiOperation(value = "上传文件", notes = "上传文件,上传后返回文件url") + @Operation(summary = "上传文件", description = "上传文件,上传后返回文件url") @PostMapping("/file/upload") - public Result uploadFile(MultipartFile file) { + public Result uploadFile(@RequestParam("file") MultipartFile file) { return ResultUtils.success(fileService.uploadFile(file), ""); } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java index 3ded8bd..e66be74 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java @@ -3,29 +3,29 @@ package com.bx.implatform.controller; import com.bx.implatform.entity.Friend; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IFriendService; +import com.bx.implatform.service.FriendService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.vo.FriendVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; import java.util.List; import java.util.stream.Collectors; -@Api(tags = "好友") +@Tag(name = "好友") @RestController @RequestMapping("/friend") @RequiredArgsConstructor public class FriendController { - private final IFriendService friendService; + private final FriendService friendService; @GetMapping("/list") - @ApiOperation(value = "好友列表", notes = "获取好友列表") + @Operation(summary = "好友列表", description = "获取好友列表") public Result> findFriends() { List friends = friendService.findFriendByUserId(SessionContext.getSession().getUserId()); List vos = friends.stream().map(f -> { @@ -40,28 +40,28 @@ public class FriendController { @PostMapping("/add") - @ApiOperation(value = "添加好友", notes = "双方建立好友关系") - public Result addFriend(@NotEmpty(message = "好友id不可为空") @RequestParam("friendId") Long friendId) { + @Operation(summary = "添加好友", description = "双方建立好友关系") + public Result addFriend(@NotNull(message = "好友id不可为空") @RequestParam Long friendId) { friendService.addFriend(friendId); return ResultUtils.success(); } @GetMapping("/find/{friendId}") - @ApiOperation(value = "查找好友信息", notes = "查找好友信息") - public Result findFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId) { + @Operation(summary = "查找好友信息", description = "查找好友信息") + public Result findFriend(@NotNull(message = "好友id不可为空") @PathVariable Long friendId) { return ResultUtils.success(friendService.findFriend(friendId)); } @DeleteMapping("/delete/{friendId}") - @ApiOperation(value = "删除好友", notes = "解除好友关系") - public Result delFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId) { + @Operation(summary = "删除好友", description = "解除好友关系") + public Result delFriend(@NotNull(message = "好友id不可为空") @PathVariable Long friendId) { friendService.delFriend(friendId); return ResultUtils.success(); } @PutMapping("/update") - @ApiOperation(value = "更新好友信息", notes = "更新好友头像或昵称") + @Operation(summary = "更新好友信息", description = "更新好友头像或昵称") public Result modifyFriend(@Valid @RequestBody FriendVO vo) { friendService.update(vo); return ResultUtils.success(); diff --git a/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java b/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java index a76b451..7f29c23 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java @@ -2,82 +2,83 @@ package com.bx.implatform.controller; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IGroupService; +import com.bx.implatform.service.GroupService; import com.bx.implatform.vo.GroupInviteVO; import com.bx.implatform.vo.GroupMemberVO; import com.bx.implatform.vo.GroupVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.util.List; -@Api(tags = "群聊") +@Tag(name = "群聊") @RestController @RequestMapping("/group") @RequiredArgsConstructor public class GroupController { - private final IGroupService groupService; + private final GroupService groupService; - @ApiOperation(value = "创建群聊", notes = "创建群聊") + @Operation(summary = "创建群聊", description = "创建群聊") @PostMapping("/create") public Result createGroup(@Valid @RequestBody GroupVO vo) { return ResultUtils.success(groupService.createGroup(vo)); } - @ApiOperation(value = "修改群聊信息", notes = "修改群聊信息") + @Operation(summary = "修改群聊信息", description = "修改群聊信息") @PutMapping("/modify") public Result modifyGroup(@Valid @RequestBody GroupVO vo) { return ResultUtils.success(groupService.modifyGroup(vo)); } - @ApiOperation(value = "解散群聊", notes = "解散群聊") + @Operation(summary = "解散群聊", description = "解散群聊") @DeleteMapping("/delete/{groupId}") public Result deleteGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { groupService.deleteGroup(groupId); return ResultUtils.success(); } - @ApiOperation(value = "查询群聊", notes = "查询单个群聊信息") + @Operation(summary = "查询群聊", description = "查询单个群聊信息") @GetMapping("/find/{groupId}") public Result findGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { return ResultUtils.success(groupService.findById(groupId)); } - @ApiOperation(value = "查询群聊列表", notes = "查询群聊列表") + @Operation(summary = "查询群聊列表", description = "查询群聊列表") @GetMapping("/list") public Result> findGroups() { return ResultUtils.success(groupService.findGroups()); } - @ApiOperation(value = "邀请进群", notes = "邀请好友进群") + @Operation(summary = "邀请进群", description = "邀请好友进群") @PostMapping("/invite") public Result invite(@Valid @RequestBody GroupInviteVO vo) { groupService.invite(vo); return ResultUtils.success(); } - @ApiOperation(value = "查询群聊成员", notes = "查询群聊成员") + @Operation(summary = "查询群聊成员", description = "查询群聊成员") @GetMapping("/members/{groupId}") - public Result> findGroupMembers(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { + public Result> findGroupMembers( + @NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { return ResultUtils.success(groupService.findGroupMembers(groupId)); } - @ApiOperation(value = "退出群聊", notes = "退出群聊") + @Operation(summary = "退出群聊", description = "退出群聊") @DeleteMapping("/quit/{groupId}") public Result quitGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) { groupService.quitGroup(groupId); return ResultUtils.success(); } - @ApiOperation(value = "踢出群聊", notes = "将用户踢出群聊") + @Operation(summary = "踢出群聊", description = "将用户踢出群聊") @DeleteMapping("/kick/{groupId}") public Result kickGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId, - @NotNull(message = "用户id不能为空") @RequestParam Long userId) { + @NotNull(message = "用户id不能为空") @RequestParam Long userId) { groupService.kickGroup(groupId, userId); return ResultUtils.success(); } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java b/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java index c9df96c..007a3de 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java @@ -3,63 +3,64 @@ package com.bx.implatform.controller; import com.bx.implatform.dto.GroupMessageDTO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IGroupMessageService; +import com.bx.implatform.service.GroupMessageService; import com.bx.implatform.vo.GroupMessageVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.util.List; -@Api(tags = "群聊消息") +@Tag(name = "群聊消息") @RestController @RequestMapping("/message/group") @RequiredArgsConstructor public class GroupMessageController { - private final IGroupMessageService groupMessageService; + private final GroupMessageService groupMessageService; @PostMapping("/send") - @ApiOperation(value = "发送群聊消息", notes = "发送群聊消息") - public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo) { + @Operation(summary = "发送群聊消息", description = "发送群聊消息") + public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo) { return ResultUtils.success(groupMessageService.sendMessage(vo)); } @DeleteMapping("/recall/{id}") - @ApiOperation(value = "撤回消息", notes = "撤回群聊消息") + @Operation(summary = "撤回消息", description = "撤回群聊消息") public Result recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) { groupMessageService.recallMessage(id); return ResultUtils.success(); } @GetMapping("/pullOfflineMessage") - @ApiOperation(value = "拉取离线消息", notes = "拉取离线消息,消息将通过webscoket异步推送") + @Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送") public Result pullOfflineMessage(@RequestParam Long minId) { groupMessageService.pullOfflineMessage(minId); return ResultUtils.success(); } @PutMapping("/readed") - @ApiOperation(value = "消息已读", notes = "将群聊中的消息状态置为已读") + @Operation(summary = "消息已读", description = "将群聊中的消息状态置为已读") public Result readedMessage(@RequestParam Long groupId) { groupMessageService.readedMessage(groupId); return ResultUtils.success(); } @GetMapping("/findReadedUsers") - @ApiOperation(value = "获取已读用户id", notes = "获取消息已读用户列表") - public Result> findReadedUsers(@RequestParam Long groupId,@RequestParam Long messageId) { - return ResultUtils.success(groupMessageService.findReadedUsers(groupId,messageId)); + @Operation(summary = "获取已读用户id", description = "获取消息已读用户列表") + public Result> findReadedUsers(@RequestParam Long groupId, + @RequestParam Long messageId) { + return ResultUtils.success(groupMessageService.findReadedUsers(groupId, messageId)); } @GetMapping("/history") - @ApiOperation(value = "查询聊天记录", notes = "查询聊天记录") + @Operation(summary = "查询聊天记录", description = "查询聊天记录") public Result> recallMessage(@NotNull(message = "群聊id不能为空") @RequestParam Long groupId, - @NotNull(message = "页码不能为空") @RequestParam Long page, - @NotNull(message = "size不能为空") @RequestParam Long size) { + @NotNull(message = "页码不能为空") @RequestParam Long page, + @NotNull(message = "size不能为空") @RequestParam Long size) { return ResultUtils.success(groupMessageService.findHistoryMessage(groupId, page, size)); } } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java index 4a960a1..e889e40 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java @@ -5,47 +5,44 @@ import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.dto.RegisterDTO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IUserService; +import com.bx.implatform.service.UserService; import com.bx.implatform.vo.LoginVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; - -@Api(tags = "用户登录和注册") +@Tag(name = "注册登陆") @RestController @RequiredArgsConstructor public class LoginController { - private final IUserService userService; + private final UserService userService; @PostMapping("/login") - @ApiOperation(value = "用户登陆", notes = "用户登陆") - public Result login(@Valid @RequestBody LoginDTO dto) { + @Operation(summary = "用户登陆", description = "用户登陆") + public Result login(@Valid @RequestBody LoginDTO dto) { LoginVO vo = userService.login(dto); return ResultUtils.success(vo); } - @PutMapping("/refreshToken") - @ApiOperation(value = "刷新token", notes = "用refreshtoken换取新的token") + @Operation(summary = "刷新token", description = "用refreshtoken换取新的token") public Result refreshToken(@RequestHeader("refreshToken") String refreshToken) { LoginVO vo = userService.refreshToken(refreshToken); return ResultUtils.success(vo); } - @PostMapping("/register") - @ApiOperation(value = "用户注册", notes = "用户注册") + @Operation(summary = "用户注册", description = "用户注册") public Result register(@Valid @RequestBody RegisterDTO dto) { userService.register(dto); return ResultUtils.success(); } @PutMapping("/modifyPwd") - @ApiOperation(value = "修改密码", notes = "修改用户密码") + @Operation(summary = "修改密码", description = "修改用户密码") public Result modifyPassword(@Valid @RequestBody ModifyPwdDTO dto) { userService.modifyPassword(dto); return ResultUtils.success(); diff --git a/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java b/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java index 9f99531..622c5dc 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java @@ -3,64 +3,64 @@ package com.bx.implatform.controller; import com.bx.implatform.dto.PrivateMessageDTO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IPrivateMessageService; +import com.bx.implatform.service.PrivateMessageService; import com.bx.implatform.vo.PrivateMessageVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; import java.util.List; -@Api(tags = "私聊消息") +@Tag(name = "私聊消息") @RestController @RequestMapping("/message/private") @RequiredArgsConstructor public class PrivateMessageController { - private final IPrivateMessageService privateMessageService; + private final PrivateMessageService privateMessageService; @PostMapping("/send") - @ApiOperation(value = "发送消息", notes = "发送私聊消息") - public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo) { + @Operation(summary = "发送消息", description = "发送私聊消息") + public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo) { return ResultUtils.success(privateMessageService.sendMessage(vo)); } - @DeleteMapping("/recall/{id}") - @ApiOperation(value = "撤回消息", notes = "撤回私聊消息") + @Operation(summary = "撤回消息", description = "撤回私聊消息") public Result recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) { privateMessageService.recallMessage(id); return ResultUtils.success(); } @GetMapping("/pullOfflineMessage") - @ApiOperation(value = "拉取离线消息", notes = "拉取离线消息,消息将通过webscoket异步推送") + @Operation(summary = "拉取离线消息", description = "拉取离线消息,消息将通过webscoket异步推送") public Result pullOfflineMessage(@RequestParam Long minId) { privateMessageService.pullOfflineMessage(minId); return ResultUtils.success(); } @PutMapping("/readed") - @ApiOperation(value = "消息已读", notes = "将会话中接收的消息状态置为已读") + @Operation(summary = "消息已读", description = "将会话中接收的消息状态置为已读") public Result readedMessage(@RequestParam Long friendId) { privateMessageService.readedMessage(friendId); return ResultUtils.success(); } @GetMapping("/maxReadedId") - @ApiOperation(value = "获取最大已读消息的id",notes="获取某个会话中已读消息的最大id") - public Result getMaxReadedId(@RequestParam Long friendId){ + @Operation(summary = "获取最大已读消息的id", description = "获取某个会话中已读消息的最大id") + public Result getMaxReadedId(@RequestParam Long friendId) { return ResultUtils.success(privateMessageService.getMaxReadedId(friendId)); } @GetMapping("/history") - @ApiOperation(value = "查询聊天记录", notes = "查询聊天记录") - public Result> recallMessage(@NotNull(message = "好友id不能为空") @RequestParam Long friendId, - @NotNull(message = "页码不能为空") @RequestParam Long page, - @NotNull(message = "size不能为空") @RequestParam Long size) { + @Operation(summary = "查询聊天记录", description = "查询聊天记录") + public Result> recallMessage( + @NotNull(message = "好友id不能为空") @RequestParam Long friendId, + @NotNull(message = "页码不能为空") @RequestParam Long page, + @NotNull(message = "size不能为空") @RequestParam Long size) { return ResultUtils.success(privateMessageService.findHistoryMessage(friendId, page, size)); } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/SystemController.java b/im-platform/src/main/java/com/bx/implatform/controller/SystemController.java index d3cd30b..fd6de4d 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/SystemController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/SystemController.java @@ -1,14 +1,15 @@ package com.bx.implatform.controller; import com.bx.implatform.config.WebrtcConfig; -import com.bx.implatform.dto.PrivateMessageDTO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.vo.SystemConfigVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @@ -17,7 +18,7 @@ import org.springframework.web.bind.annotation.*; * @date: 2024-06-10 * @version: 1.0 */ -@Api(tags = "系统相关") +@Tag(name = "系统相关") @RestController @RequestMapping("/system") @RequiredArgsConstructor @@ -26,7 +27,7 @@ public class SystemController { private final WebrtcConfig webrtcConfig; @GetMapping("/config") - @ApiOperation(value = "加载系统配置", notes = "加载系统配置") + @Operation(summary = "加载系统配置", description = "加载系统配置") public Result loadConfig() { return ResultUtils.success(new SystemConfigVO(webrtcConfig)); } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java index 1291db2..9c5af89 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java @@ -3,38 +3,38 @@ package com.bx.implatform.controller; import com.bx.implatform.entity.User; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IUserService; +import com.bx.implatform.service.UserService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; import com.bx.implatform.vo.OnlineTerminalVO; import com.bx.implatform.vo.UserVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; -import javax.validation.constraints.NotEmpty; import java.util.List; -@Api(tags = "用户") +@Tag(name = "用户相关") @RestController @RequestMapping("/user") @RequiredArgsConstructor public class UserController { - private final IUserService userService; + private final UserService userService; @GetMapping("/terminal/online") - @ApiOperation(value = "判断用户哪个终端在线", notes = "返回在线的用户id的终端集合") - public Result> getOnlineTerminal(@NotEmpty @RequestParam("userIds") String userIds) { + @Operation(summary = "判断用户哪个终端在线", description = "返回在线的用户id的终端集合") + public Result> getOnlineTerminal(@NotNull @RequestParam("userIds") String userIds) { return ResultUtils.success(userService.getOnlineTerminals(userIds)); } @GetMapping("/self") - @ApiOperation(value = "获取当前用户信息", notes = "获取当前用户信息") + @Operation(summary = "获取当前用户信息", description = "获取当前用户信息") public Result findSelfInfo() { UserSession session = SessionContext.getSession(); User user = userService.getById(session.getUserId()); @@ -44,21 +44,21 @@ public class UserController { @GetMapping("/find/{id}") - @ApiOperation(value = "查找用户", notes = "根据id查找用户") - public Result findById(@NotEmpty @PathVariable("id") Long id) { + @Operation(summary = "查找用户", description = "根据id查找用户") + public Result findById(@NotNull @PathVariable("id") Long id) { return ResultUtils.success(userService.findUserById(id)); } @PutMapping("/update") - @ApiOperation(value = "修改用户信息", notes = "修改用户信息,仅允许修改登录用户信息") + @Operation(summary = "修改用户信息", description = "修改用户信息,仅允许修改登录用户信息") public Result update(@Valid @RequestBody UserVO vo) { userService.update(vo); return ResultUtils.success(); } @GetMapping("/findByName") - @ApiOperation(value = "查找用户", notes = "根据用户名或昵称查找用户") - public Result> findByName(@RequestParam("name") String name) { + @Operation(summary = "查找用户", description = "根据用户名或昵称查找用户") + public Result> findByName(@RequestParam String name) { return ResultUtils.success(userService.findUserByName(name)); } } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcGroupController.java b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcGroupController.java index c9fb6b7..fb14e07 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcGroupController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcGroupController.java @@ -1,126 +1,124 @@ package com.bx.implatform.controller; -import com.bx.implatform.config.WebrtcConfig; import com.bx.implatform.dto.*; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IWebrtcGroupService; +import com.bx.implatform.service.WebrtcGroupService; import com.bx.implatform.vo.WebrtcGroupInfoVO; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import javax.validation.Valid; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ -@Api(tags = "webrtc视频多人通话") +@Tag(name = "多人通话") @RestController @RequestMapping("/webrtc/group") @RequiredArgsConstructor public class WebrtcGroupController { - private final IWebrtcGroupService webrtcGroupService; + private final WebrtcGroupService webrtcGroupService; - @ApiOperation(httpMethod = "POST", value = "发起群视频通话") + @Operation(summary = "发起群视频通话") @PostMapping("/setup") public Result setup(@Valid @RequestBody WebrtcGroupSetupDTO dto) { webrtcGroupService.setup(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "接受通话") + @Operation(summary = "接受通话") @PostMapping("/accept") - public Result accept(@RequestParam Long groupId) { + public Result accept(@RequestParam("groupId") Long groupId) { webrtcGroupService.accept(groupId); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "拒绝通话") + @Operation(summary = "拒绝通话") @PostMapping("/reject") - public Result reject(@RequestParam Long groupId) { + public Result reject(@RequestParam("groupId") Long groupId) { webrtcGroupService.reject(groupId); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "通话失败") + @Operation(summary = "通话失败") @PostMapping("/failed") public Result failed(@Valid @RequestBody WebrtcGroupFailedDTO dto) { webrtcGroupService.failed(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "进入视频通话") + @Operation(summary = "进入视频通话") @PostMapping("/join") - public Result join(@RequestParam Long groupId) { + public Result join(@RequestParam("groupId") Long groupId) { webrtcGroupService.join(groupId); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "取消通话") + @Operation(summary = "取消通话") @PostMapping("/cancel") - public Result cancel(@RequestParam Long groupId) { + public Result cancel(@RequestParam("groupId") Long groupId) { webrtcGroupService.cancel(groupId); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "离开视频通话") + @Operation(summary = "离开视频通话") @PostMapping("/quit") - public Result quit(@RequestParam Long groupId) { + public Result quit(@RequestParam("groupId") Long groupId) { webrtcGroupService.quit(groupId); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "推送offer信息") + @Operation(summary = "推送offer信息") @PostMapping("/offer") public Result offer(@Valid @RequestBody WebrtcGroupOfferDTO dto) { webrtcGroupService.offer(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "推送answer信息") + @Operation(summary = "推送answer信息") @PostMapping("/answer") public Result answer(@Valid @RequestBody WebrtcGroupAnswerDTO dto) { webrtcGroupService.answer(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "邀请用户进入视频通话") + @Operation(summary = "邀请用户进入视频通话") @PostMapping("/invite") public Result invite(@Valid @RequestBody WebrtcGroupInviteDTO dto) { webrtcGroupService.invite(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "同步candidate") + @Operation(summary = "同步candidate") @PostMapping("/candidate") public Result candidate(@Valid @RequestBody WebrtcGroupCandidateDTO dto) { webrtcGroupService.candidate(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "设备操作") + @Operation(summary = "设备操作") @PostMapping("/device") public Result device(@Valid @RequestBody WebrtcGroupDeviceDTO dto) { webrtcGroupService.device(dto); return ResultUtils.success(); } - @ApiOperation(httpMethod = "GET", value = "获取通话信息") + @Operation(summary = "获取通话信息") @GetMapping("/info") - public Result info(@RequestParam Long groupId) { + public Result info(@RequestParam("groupId") Long groupId) { return ResultUtils.success(webrtcGroupService.info(groupId)); } - @ApiOperation(httpMethod = "POST", value = "获取通话信息") + @Operation(summary = "获取通话信息") @PostMapping("/heartbeat") - public Result heartbeat(@RequestParam Long groupId) { + public Result heartbeat(@RequestParam("groupId") Long groupId) { webrtcGroupService.heartbeat(groupId); return ResultUtils.success(); } - } +} diff --git a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java index 7d583c6..3bf3764 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcPrivateController.java @@ -1,78 +1,74 @@ package com.bx.implatform.controller; import com.bx.implatform.annotation.OnlineCheck; -import com.bx.implatform.config.ICEServer; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.service.IWebrtcPrivateService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; +import com.bx.implatform.service.WebrtcPrivateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import java.util.List; - -@Api(tags = "webrtc视频单人通话") +@Tag(name = "单人通话") @RestController @RequestMapping("/webrtc/private") @RequiredArgsConstructor public class WebrtcPrivateController { - private final IWebrtcPrivateService webrtcPrivateService; + private final WebrtcPrivateService webrtcPrivateService; @OnlineCheck - @ApiOperation(httpMethod = "POST", value = "呼叫视频通话") + @Operation(summary = "呼叫视频通话") @PostMapping("/call") - public Result call(@RequestParam Long uid, @RequestParam(defaultValue = "video") String mode, @RequestBody String offer) { + public Result call(@RequestParam Long uid, @RequestParam(defaultValue = "video") String mode, + @RequestBody String offer) { webrtcPrivateService.call(uid, mode, offer); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "接受视频通话") + @Operation(summary = "接受视频通话") @PostMapping("/accept") public Result accept(@RequestParam Long uid, @RequestBody String answer) { webrtcPrivateService.accept(uid, answer); return ResultUtils.success(); } - - @ApiOperation(httpMethod = "POST", value = "拒绝视频通话") + @Operation(summary = "拒绝视频通话") @PostMapping("/reject") public Result reject(@RequestParam Long uid) { webrtcPrivateService.reject(uid); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "取消呼叫") + @Operation(summary = "取消呼叫") @PostMapping("/cancel") public Result cancel(@RequestParam Long uid) { webrtcPrivateService.cancel(uid); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "呼叫失败") + @Operation(summary = "呼叫失败") @PostMapping("/failed") public Result failed(@RequestParam Long uid, @RequestParam String reason) { webrtcPrivateService.failed(uid, reason); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "挂断") + @Operation(summary = "挂断") @PostMapping("/handup") public Result handup(@RequestParam Long uid) { webrtcPrivateService.handup(uid); return ResultUtils.success(); } - @PostMapping("/candidate") - @ApiOperation(httpMethod = "POST", value = "同步candidate") + @Operation(summary = "同步candidate") public Result candidate(@RequestParam Long uid, @RequestBody String candidate) { webrtcPrivateService.candidate(uid, candidate); return ResultUtils.success(); } - @ApiOperation(httpMethod = "POST", value = "获取通话信息") + @Operation(summary = "获取通话信息") @PostMapping("/heartbeat") public Result heartbeat(@RequestParam Long uid) { webrtcPrivateService.heartbeat(uid); diff --git a/im-platform/src/main/java/com/bx/implatform/dto/GroupBanDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/GroupBanDTO.java new file mode 100644 index 0000000..cbe673d --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/GroupBanDTO.java @@ -0,0 +1,21 @@ +package com.bx.implatform.dto; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author: Blue + * @date: 2024-07-14 + * @version: 1.0 + */ +@Data +@Schema(description = "群组封禁") +public class GroupBanDTO { + + @Schema(description = "群组id") + private Long id; + + @Schema(description = "封禁原因") + private String reason; +} diff --git a/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java index 6af8f38..9f8e2c8 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java @@ -1,36 +1,35 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Data; import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.List; @Data -@ApiModel("群聊消息DTO") +@Schema(description = "群聊消息DTO") public class GroupMessageDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @Length(max = 1024, message = "发送内容长度不得大于1024") @NotEmpty(message = "发送内容不可为空") - @ApiModelProperty(value = "发送内容") + @Schema(description = "发送内容") private String content; @NotNull(message = "消息类型不可为空") - @ApiModelProperty(value = "消息类型") + @Schema(description = "消息类型 0:文字 1:图片 2:文件 3:语音 4:视频") private Integer type; - @ApiModelProperty(value = "是否回执消息") + @Schema(description = "是否回执消息") private Boolean receipt = false; @Size(max = 20, message = "一次最多只能@20个小伙伴哦") - @ApiModelProperty(value = "被@用户列表") + @Schema(description = "被@用户列表") private List atUserIds; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/GroupUnbanDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/GroupUnbanDTO.java new file mode 100644 index 0000000..2ccffa6 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/GroupUnbanDTO.java @@ -0,0 +1,18 @@ +package com.bx.implatform.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author: Blue + * @date: 2024-07-14 + * @version: 1.0 + */ +@Data +@Schema(description = "群组解锁") +public class GroupUnbanDTO { + + @Schema(description = "群组id") + private Long id; + +} diff --git a/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java index 0cdede2..30b240e 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java @@ -1,30 +1,28 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - @Data -@ApiModel("用户登录DTO") +@Schema(description = "用户登录DTO") public class LoginDTO { @Max(value = 2, message = "登录终端类型取值范围:0,2") @Min(value = 0, message = "登录终端类型取值范围:0,2") @NotNull(message = "登录终端类型不可为空") - @ApiModelProperty(value = "登录终端 0:web 1:app 2:pc") + @Schema(description = "登录终端 0:web 1:app 2:pc") private Integer terminal; @NotEmpty(message = "用户名不可为空") - @ApiModelProperty(value = "用户名") + @Schema(description = "用户名") private String userName; @NotEmpty(message = "用户密码不可为空") - @ApiModelProperty(value = "用户密码") + @Schema(description = "用户密码") private String password; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java index 3ba3078..c733493 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java @@ -1,21 +1,19 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Data; -import javax.validation.constraints.NotEmpty; - @Data -@ApiModel("修改密码DTO") +@Schema(description = "修改密码DTO") public class ModifyPwdDTO { @NotEmpty(message = "旧用户密码不可为空") - @ApiModelProperty(value = "旧用户密码") + @Schema(description = "旧用户密码") private String oldPassword; @NotEmpty(message = "新用户密码不可为空") - @ApiModelProperty(value = "新用户密码") + @Schema(description = "新用户密码") private String newPassword; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java index 99cee20..f954f93 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java @@ -1,29 +1,27 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - @Data -@ApiModel("私聊消息DTO") +@Schema(description = "私聊消息DTO") public class PrivateMessageDTO { @NotNull(message = "接收用户id不可为空") - @ApiModelProperty(value = "接收用户id") + @Schema(description = "接收用户id") private Long recvId; @Length(max = 1024, message = "内容长度不得大于1024") @NotEmpty(message = "发送内容不可为空") - @ApiModelProperty(value = "发送内容") + @Schema(description = "发送内容") private String content; @NotNull(message = "消息类型不可为空") - @ApiModelProperty(value = "消息类型") + @Schema(description = "消息类型 0:文字 1:图片 2:文件 3:语音 4:视频") private Integer type; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java index fd33135..f298808 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java @@ -1,29 +1,27 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Data; import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; - @Data -@ApiModel("用户注册DTO") +@Schema(description = "用户注册DTO") public class RegisterDTO { @Length(max = 64, message = "用户名不能大于64字符") @NotEmpty(message = "用户名不可为空") - @ApiModelProperty(value = "用户名") + @Schema(description = "用户名") private String userName; @Length(min = 5, max = 20, message = "密码长度必须在5-20个字符之间") @NotEmpty(message = "用户密码不可为空") - @ApiModelProperty(value = "用户密码") + @Schema(description = "用户密码") private String password; @Length(max = 64, message = "昵称不能大于64字符") @NotEmpty(message = "用户昵称不可为空") - @ApiModelProperty(value = "用户昵称") + @Schema(description = "用户昵称") private String nickName; diff --git a/im-platform/src/main/java/com/bx/implatform/dto/UserBanDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/UserBanDTO.java new file mode 100644 index 0000000..f8953c6 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/UserBanDTO.java @@ -0,0 +1,21 @@ +package com.bx.implatform.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author: Blue + * @date: 2024-07-14 + * @version: 1.0 + */ +@Data +@Schema(description = "用户锁定DTO") +public class UserBanDTO { + + @Schema(description = "用户id") + private Long id; + + @Schema(description = "锁定原因") + private String reason; + +} diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupAnswerDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupAnswerDTO.java index b66e68e..6e96bc0 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupAnswerDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupAnswerDTO.java @@ -1,31 +1,29 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("回复用户连接请求DTO") +@Schema(description = "回复用户连接请求DTO") public class WebrtcGroupAnswerDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @NotNull(message = "用户id不可为空") - @ApiModelProperty(value = "用户id,代表回复谁的连接请求") + @Schema(description = "用户id,代表回复谁的连接请求") private Long userId; @NotEmpty(message = "anwer不可为空") - @ApiModelProperty(value = "用户本地anwer信息") + @Schema(description = "用户本地anwer信息") private String answer; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupCandidateDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupCandidateDTO.java index fd04e94..69d054e 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupCandidateDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupCandidateDTO.java @@ -1,32 +1,29 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.util.List; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("发起群视频通话DTO") +@Schema(description = "发起群视频通话DTO") public class WebrtcGroupCandidateDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @NotNull(message = "用户id不可为空") - @ApiModelProperty(value = "用户id") + @Schema(description = "用户id") private Long userId; @NotEmpty(message = "candidate信息不可为空") - @ApiModelProperty(value = "candidate信息") + @Schema(description = "candidate信息") private String candidate; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java index 5d87b4d..b7e2073 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupDeviceDTO.java @@ -1,29 +1,26 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("用户设备操作DTO") +@Schema(description = "用户设备操作DTO") public class WebrtcGroupDeviceDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; - @ApiModelProperty(value = "是否开启摄像头") + @Schema(description = "是否开启摄像头") private Boolean isCamera; - @ApiModelProperty(value = "是否开启麦克风") + @Schema(description = "是否开启麦克风") private Boolean isMicroPhone; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupFailedDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupFailedDTO.java index 3df2cb9..fa2d5ba 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupFailedDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupFailedDTO.java @@ -1,25 +1,23 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotNull; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("用户通话失败DTO") +@Schema(description = "用户通话失败DTO") public class WebrtcGroupFailedDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; - @ApiModelProperty(value = "失败原因") + @Schema(description = "失败原因") private String reason; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupInviteDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupInviteDTO.java index 7719a39..1c0f894 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupInviteDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupInviteDTO.java @@ -1,12 +1,11 @@ package com.bx.implatform.dto; import com.bx.implatform.session.WebrtcUserInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.List; /** @@ -15,15 +14,15 @@ import java.util.List; * @version: 1.0 */ @Data -@ApiModel("邀请用户进入群视频通话DTO") +@Schema(description = "邀请用户进入群视频通话DTO") public class WebrtcGroupInviteDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @NotEmpty(message = "参与用户信息不可为空") - @ApiModelProperty(value = "参与用户信息") + @Schema(description = "参与用户信息") private List userInfos; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupJoinDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupJoinDTO.java index adbc066..b59adb0 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupJoinDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupJoinDTO.java @@ -1,23 +1,20 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("进入群视频通话DTO") +@Schema(description = "进入群视频通话DTO") public class WebrtcGroupJoinDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupOfferDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupOfferDTO.java index 057fe20..dbe0048 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupOfferDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupOfferDTO.java @@ -1,31 +1,29 @@ package com.bx.implatform.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - /** * @author: Blue * @date: 2024-06-01 * @version: 1.0 */ @Data -@ApiModel("回复用户连接请求DTO") +@Schema(description = "回复用户连接请求DTO") public class WebrtcGroupOfferDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @NotNull(message = "用户id不可为空") - @ApiModelProperty(value = "用户id,代表回复谁的连接请求") + @Schema(description = "用户id,代表回复谁的连接请求") private Long userId; @NotEmpty(message = "offer不可为空") - @ApiModelProperty(value = "用户offer信息") + @Schema(description = "用户offer信息") private String offer; } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupSetupDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupSetupDTO.java index f59989f..724ceec 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupSetupDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/WebrtcGroupSetupDTO.java @@ -1,12 +1,11 @@ package com.bx.implatform.dto; import com.bx.implatform.session.WebrtcUserInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.List; /** @@ -15,15 +14,15 @@ import java.util.List; * @version: 1.0 */ @Data -@ApiModel("发起群视频通话DTO") +@Schema(description = "发起群视频通话DTO") public class WebrtcGroupSetupDTO { @NotNull(message = "群聊id不可为空") - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; @NotEmpty(message = "参与用户信息不可为空") - @ApiModelProperty(value = "参与用户信息") + @Schema(description = "参与用户信息") private List userInfos; } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/Friend.java b/im-platform/src/main/java/com/bx/implatform/entity/Friend.java index 364ffe1..f869b81 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/Friend.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/Friend.java @@ -1,14 +1,9 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; -import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -20,52 +15,39 @@ import java.util.Date; * @since 2022-10-22 */ @Data -@EqualsAndHashCode(callSuper = false) @TableName("im_friend") -public class Friend extends Model { +public class Friend{ - private static final long serialVersionUID = 1L; /** * id */ - @TableId(value = "id", type = IdType.AUTO) + @TableId private Long id; /** * 用户id */ - @TableField("user_id") private Long userId; /** * 好友id */ - @TableField("friend_id") private Long friendId; /** * 用户昵称 */ - @TableField("friend_nick_name") private String friendNickName; /** * 用户头像 */ - @TableField("friend_head_image") private String friendHeadImage; /** * 创建时间 */ - @TableField("created_time") private Date createdTime; - - @Override - protected Serializable pkVal() { - return this.id; - } - } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/Group.java b/im-platform/src/main/java/com/bx/implatform/entity/Group.java index 1f4ba0b..86cdd55 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/Group.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/Group.java @@ -1,14 +1,9 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; -import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -18,64 +13,60 @@ import java.util.Date; * @since 2022-10-31 */ @Data -@EqualsAndHashCode(callSuper = false) @TableName("im_group") -public class Group extends Model { - - private static final long serialVersionUID = 1L; +public class Group { /** * id */ - @TableId(value = "id", type = IdType.AUTO) + @TableId private Long id; /** * 群名字 */ - @TableField("name") private String name; /** * 群主id */ - @TableField("owner_id") private Long ownerId; /** - * 头像 + * 群头像 */ - @TableField("head_image") private String headImage; /** - * 头像缩略图 + * 群头像缩略图 */ - @TableField("head_image_thumb") private String headImageThumb; /** * 群公告 */ - @TableField("notice") private String notice; /** - * 是否已删除 + * 是否被封禁 */ - @TableField("deleted") - private Boolean deleted; + private Boolean isBanned; + + /** + * 被封禁原因 + */ + private String reason; /** * 创建时间 */ - @TableField("created_time") private Date createdTime; + /** + * 是否已删除 + */ + private Boolean deleted; + - @Override - protected Serializable pkVal() { - return this.id; - } } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java b/im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java index a7d362d..38a8e07 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java @@ -1,14 +1,12 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -24,67 +22,59 @@ import java.util.Date; @TableName("im_group_member") public class GroupMember extends Model { - private static final long serialVersionUID = 1L; - /** * id */ - @TableId(value = "id", type = IdType.AUTO) + @TableId private Long id; /** * 群id */ - @TableField("group_id") private Long groupId; /** * 用户id */ - @TableField("user_id") private Long userId; /** - * 群内显示名称 + * 用户昵称 */ - @TableField("alias_name") - private String aliasName; + private String userNickName; /** - * 头像 + * 显示昵称备注 */ - @TableField("head_image") - private String headImage; - + private String remarkNickName; /** - * 备注 + * 用户头像 */ - @TableField("remark") - private String remark; + private String headImage; /** - * 是否已离开群聊 + * 显示群名备注 */ - @TableField("quit") - private Boolean quit; + private String remarkGroupName; /** - * 退群时间 + * 是否已退出 */ - @TableField("quit_time") - private Date quitTime; + private Boolean quit; /** * 创建时间 */ - @TableField("created_time") private Date createdTime; + /** + * 退出时间 + */ + private Date quitTime; - @Override - protected Serializable pkVal() { - return this.id; + public String getShowNickName() { + return StrUtil.isEmpty(remarkNickName) ? userNickName : remarkNickName; } } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java b/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java index ebe02d5..a0ec72e 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/GroupMessage.java @@ -1,14 +1,9 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; -import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -20,87 +15,68 @@ import java.util.Date; * @since 2022-10-31 */ @Data -@EqualsAndHashCode(callSuper = false) -@TableName("im_group_message") -public class GroupMessage extends Model { - private static final long serialVersionUID = 1L; +@TableName("im_group_message") +public class GroupMessage { /** * id */ - @TableId(value = "id", type = IdType.AUTO) + @TableId private Long id; /** * 群id */ - @TableField("group_id") private Long groupId; /** * 发送用户id */ - @TableField("send_id") private Long sendId; /** * 发送用户昵称 */ - @TableField("send_nick_name") private String sendNickName; /** * 接受用户id,为空表示全体发送 */ - @TableField("recv_ids") private String recvIds; /** * @用户列表 */ - @TableField("at_user_ids") private String atUserIds; /** * 发送内容 */ - @TableField("content") private String content; /** * 消息类型 MessageType */ - @TableField("type") private Integer type; /** * 是否回执消息 */ - @TableField("receipt") private Boolean receipt; /** * 回执消息是否完成 */ - @TableField("receipt_ok") private Boolean receiptOk; /** * 状态 MessageStatus */ - @TableField("status") private Integer status; /** * 发送时间 */ - @TableField("send_time") private Date sendTime; - - @Override - protected Serializable pkVal() { - return this.id; - } - } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java b/im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java index 1914d2e..cc605f1 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java @@ -1,14 +1,8 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; -import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -20,59 +14,44 @@ import java.util.Date; * @since 2022-10-01 */ @Data -@EqualsAndHashCode(callSuper = false) @TableName("im_private_message") -public class PrivateMessage extends Model { - - private static final long serialVersionUID = 1L; +public class PrivateMessage { /** * id */ - @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 发送用户id */ - @TableField("send_id") private Long sendId; /** * 接收用户id */ - @TableField("recv_id") private Long recvId; /** * 发送内容 */ - @TableField("content") private String content; /** - * 消息类型 0:文字 1:图片 2:文件 3:语音 10:撤回消息 + * 消息类型 MessageType */ - @TableField("type") private Integer type; /** * 状态 */ - @TableField("status") private Integer status; /** * 发送时间 */ - @TableField("send_time") private Date sendTime; - @Override - protected Serializable pkVal() { - return this.id; - } - } diff --git a/im-platform/src/main/java/com/bx/implatform/entity/SensitiveWord.java b/im-platform/src/main/java/com/bx/implatform/entity/SensitiveWord.java new file mode 100644 index 0000000..8ced7c7 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/entity/SensitiveWord.java @@ -0,0 +1,50 @@ +package com.bx.implatform.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 敏感词 + * + * @author Blue + * @since 1.0.0 2024-07-20 + */ + +@Data +@TableName("im_sensitive_word") +public class SensitiveWord { + /** + * id + */ + @TableId + private Long id; + + /** + * 敏感词内容 + */ + private String content; + + /** + * 是否启用 + */ + private Boolean enabled; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long creator; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + +} \ No newline at end of file diff --git a/im-platform/src/main/java/com/bx/implatform/entity/User.java b/im-platform/src/main/java/com/bx/implatform/entity/User.java index 639b43b..ca292e6 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/User.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/User.java @@ -1,14 +1,9 @@ package com.bx.implatform.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; -import lombok.EqualsAndHashCode; -import java.io.Serializable; import java.util.Date; /** @@ -20,81 +15,73 @@ import java.util.Date; * @since 2022-10-01 */ @Data -@EqualsAndHashCode(callSuper = false) @TableName("im_user") -public class User extends Model { - - private static final long serialVersionUID = 1L; +public class User { /** * id */ - @TableId(value = "id", type = IdType.AUTO) + @TableId private Long id; /** * 用户名 */ - @TableField("user_name") private String userName; /** - * 用户名 + * 用户昵称 */ - @TableField("nick_name") private String nickName; /** - * 性别 + * 用户头像 */ - @TableField("sex") - private Integer sex; + private String headImage; /** - * 头像 + * 用户头像缩略图 */ - @TableField("head_image") - private String headImage; + private String headImageThumb; /** - * 头像缩略图 + * 密码(明文) */ - @TableField("head_image_thumb") - private String headImageThumb; + private String password; /** - * 用户类型 1:普通用户 2:审核专用账户 + * 性别 0:男 1::女 */ - @TableField("type") - private Integer type; + private Integer sex; /** * 个性签名 */ - @TableField("signature") private String signature; + /** - * 密码(明文) + * 账号是否被封禁 */ - @TableField("password") - private String password; + private Boolean isBanned; + + /** + * 账号被封禁原因 + */ + private String reason; /** * 最后登录时间 */ - @TableField("last_login_time") private Date lastLoginTime; /** - * 创建时间 + * 创建时间(注册时间) */ - @TableField("created_time") private Date createdTime; - - @Override - protected Serializable pkVal() { - return this.id; - } + /** + * 账号类型 1:普通用户 2:wx小程序审核账户 + */ + private Integer type; } diff --git a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java index 21537d4..7a69c2c 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java @@ -9,6 +9,7 @@ import lombok.AllArgsConstructor; * 20-29: 提示类消息: 在会话中间显示的提示 * 30-39: UI交互类消息: 显示加载状态等 * 40-49: 操作交互类消息: 语音通话、视频通话消息等 + * 50-60: 后台操作类消息: 用户封禁、群组封禁等 * 100-199: 单人语音通话rtc信令 * 200-299: 多人语音通话rtc信令 * @@ -16,62 +17,22 @@ import lombok.AllArgsConstructor; @AllArgsConstructor public enum MessageType { - /** - * 文字 - */ - TEXT(0, "文字"), - /** - * 图片 - */ - IMAGE(1, "图片"), - /** - * 文件 - */ - FILE(2, "文件"), - /** - * 音频 - */ - AUDIO(3, "音频"), - /** - * 视频 - */ - VIDEO(4, "视频"), - - /** - * 撤回 - */ + TEXT(0, "文字消息"), + IMAGE(1, "图片消息"), + FILE(2, "文件消息"), + AUDIO(3, "语音消息"), + VIDEO(4, "视频消息"), RECALL(10, "撤回"), - /** - * 已读 - */ READED(11, "已读"), - - /** - * 消息已读回执 - */ RECEIPT(12, "消息已读回执"), - /** - * 时间提示 - */ TIP_TIME(20,"时间提示"), - /** - * 文字提示 - */ TIP_TEXT(21,"文字提示"), - /** - * 消息加载标记 - */ - LOADING(30,"加载中"), - - /** - * 语音通话提示 - */ + LOADING(30,"加载中标记"), ACT_RT_VOICE(40,"语音通话"), - /** - * 视频通话提示 - */ ACT_RT_VIDEO(41,"视频通话"), - + USER_BANNED(50,"用户封禁"), + GROUP_BANNED(51,"群聊封禁"), + GROUP_UNBAN(52,"群聊解封"), RTC_CALL_VOICE(100, "语音呼叫"), RTC_CALL_VIDEO(101, "视频呼叫"), RTC_ACCEPT(102, "接受"), diff --git a/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java b/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java index e33a6ff..6872796 100644 --- a/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java +++ b/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java @@ -1,11 +1,11 @@ package com.bx.implatform.filter; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.stereotype.Component; -import javax.servlet.*; -import javax.servlet.annotation.WebFilter; -import javax.servlet.http.HttpServletRequest; import java.io.IOException; @Component diff --git a/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java b/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java index 9101015..1e301a6 100644 --- a/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java +++ b/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java @@ -1,11 +1,11 @@ package com.bx.implatform.filter; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; import org.apache.commons.compress.utils.IOUtils; -import javax.servlet.ReadListener; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; public class CacheHttpServletRequestWrapper extends HttpServletRequestWrapper { diff --git a/im-platform/src/main/java/com/bx/implatform/generator/CodeGenerator.java b/im-platform/src/main/java/com/bx/implatform/generator/CodeGenerator.java deleted file mode 100644 index d0f423f..0000000 --- a/im-platform/src/main/java/com/bx/implatform/generator/CodeGenerator.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bx.implatform.generator; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.core.toolkit.StringPool; -import com.baomidou.mybatisplus.generator.AutoGenerator; -import com.baomidou.mybatisplus.generator.InjectionConfig; -import com.baomidou.mybatisplus.generator.config.*; -import com.baomidou.mybatisplus.generator.config.po.TableInfo; -import com.baomidou.mybatisplus.generator.config.rules.DateType; -import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; -import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine; - -import java.util.ArrayList; -import java.util.List; - - -public class CodeGenerator { - public static void main(String[] args) { - // 代码生成器 - AutoGenerator mpg = new AutoGenerator(); - - // 全局配置 - GlobalConfig gc = new GlobalConfig(); - //生成的代码输出路径,自己根据需要修改 - String projectPath = "d:\\work\\project\\code"; - gc.setOutputDir(projectPath + "/src/main/java"); - gc.setAuthor("blue"); - gc.setOpen(false); - gc.setFileOverride(true); - gc.setActiveRecord(true); - gc.setBaseColumnList(true); - gc.setBaseResultMap(true); - gc.setIdType(IdType.AUTO); - gc.setDateType(DateType.ONLY_DATE); - mpg.setGlobalConfig(gc); - - // 数据源配置 - DataSourceConfig dsc = new DataSourceConfig(); - dsc.setUrl("jdbc:mysql://localhost:3306/box-im?useUnicode=true&characterEncoding=utf-8"); - dsc.setDriverName("com.mysql.jdbc.Driver"); - dsc.setUsername("root"); - dsc.setPassword("root"); - mpg.setDataSource(dsc); - - // 包配置 - PackageConfig pc = new PackageConfig(); - pc.setModuleName(""); - pc.setParent("com.bx"); - mpg.setPackageInfo(pc); - - // 如果模板引擎是 velocity - String templatePath = "/templates/mapper.xml.vm"; - - // 自定义输出配置 - List focList = new ArrayList<>(); - // 自定义配置会被优先输出 - focList.add(new FileOutConfig(templatePath) { - @Override - public String outputFile(TableInfo tableInfo) { - // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! - return projectPath + "/src/main/resources/mapper/" - + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; - } - }); - - // 自定义配置 - InjectionConfig cfg = new InjectionConfig() { - @Override - public void initMap() { - // to do nothing - } - }; - cfg.setFileOutConfigList(focList); - mpg.setCfg(cfg); - - // 配置模板 - TemplateConfig templateConfig = new TemplateConfig(); - templateConfig.setXml(null); - mpg.setTemplate(templateConfig); - - // 策略配置 - StrategyConfig strategy = new StrategyConfig(); - // 下划线转驼峰 - strategy.setNaming(NamingStrategy.underline_to_camel); - strategy.setColumnNaming(NamingStrategy.underline_to_camel); - strategy.setEntityTableFieldAnnotationEnable(true); - strategy.setVersionFieldName("version"); - //逻辑删除的字段 - strategy.setLogicDeleteFieldName("deleted"); - strategy.setEntityLombokModel(true); - strategy.setRestControllerStyle(true); - - - //多张表的时候直接在代码中写表名 - strategy.setInclude("friends"); - strategy.setTablePrefix(""); - mpg.setStrategy(strategy); - - mpg.setTemplateEngine(new VelocityTemplateEngine()); - mpg.execute(); - } -} diff --git a/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java b/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java index d964cd5..3cd0f43 100644 --- a/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java +++ b/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java @@ -7,6 +7,8 @@ import com.bx.implatform.config.JwtProperties; import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.session.UserSession; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -14,9 +16,6 @@ import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - @Slf4j @Component @AllArgsConstructor @@ -38,7 +37,7 @@ public class AuthInterceptor implements HandlerInterceptor { } String strJson = JwtUtil.getInfo(token); UserSession userSession = JSON.parseObject(strJson, UserSession.class); - //验证 token + // 验证 token if (!JwtUtil.checkSign(token, jwtProperties.getAccessTokenSecret())) { log.error("token已失效,用户:{}", userSession.getUserName()); log.error("token:{}", token); diff --git a/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java b/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java index d747176..073b2c4 100644 --- a/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java +++ b/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java @@ -3,14 +3,14 @@ package com.bx.implatform.interceptor; import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.util.XssUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.util.Map; diff --git a/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java index d927b99..25a31f6 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java @@ -5,9 +5,7 @@ import com.bx.imclient.listener.MessageListener; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; import com.bx.imcommon.model.IMSendResult; -import com.bx.implatform.contant.RedisKey; import com.bx.implatform.vo.GroupMessageVO; -import com.bx.implatform.vo.PrivateMessageVO; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; diff --git a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java index 194f469..2a2f44f 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java @@ -9,7 +9,7 @@ import com.bx.imcommon.enums.IMSendCode; import com.bx.imcommon.model.IMSendResult; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; -import com.bx.implatform.service.IPrivateMessageService; +import com.bx.implatform.service.PrivateMessageService; import com.bx.implatform.vo.PrivateMessageVO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -24,7 +24,7 @@ import java.util.Set; public class PrivateMessageListener implements MessageListener { @Lazy @Autowired - private IPrivateMessageService privateMessageService; + private PrivateMessageService privateMessageService; @Override public void process(List> results) { Set messageIds = new HashSet<>(); diff --git a/im-platform/src/main/java/com/bx/implatform/listener/SystemMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/SystemMessageListener.java new file mode 100644 index 0000000..e97474d --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/listener/SystemMessageListener.java @@ -0,0 +1,26 @@ +package com.bx.implatform.listener; + +import com.bx.imclient.annotation.IMListener; +import com.bx.imclient.listener.MessageListener; +import com.bx.imcommon.enums.IMListenerType; +import com.bx.imcommon.enums.IMSendCode; +import com.bx.imcommon.model.IMSendResult; +import com.bx.implatform.vo.SystemMessageVO; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +@Slf4j +@IMListener(type = IMListenerType.SYSTEM_MESSAGE) +public class SystemMessageListener implements MessageListener { + + @Override + public void process(List> results) { + for(IMSendResult result : results){ + SystemMessageVO messageInfo = result.getData(); + if (result.getCode().equals(IMSendCode.SUCCESS.code())) { + log.info("消息送达,消息id:{},接收者:{},终端:{}", messageInfo.getId(), result.getReceiver().getId(), result.getReceiver().getTerminal()); + } + } + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/mapper/SensitiveWordMapper.java b/im-platform/src/main/java/com/bx/implatform/mapper/SensitiveWordMapper.java new file mode 100644 index 0000000..d989801 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/mapper/SensitiveWordMapper.java @@ -0,0 +1,16 @@ +package com.bx.implatform.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.bx.implatform.entity.SensitiveWord; +import org.apache.ibatis.annotations.Mapper; + +/** +* 敏感词 +* +* @author Blue +* @since 1.0.0 2024-07-20 +*/ +@Mapper +public interface SensitiveWordMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java b/im-platform/src/main/java/com/bx/implatform/service/FriendService.java similarity index 95% rename from im-platform/src/main/java/com/bx/implatform/service/IFriendService.java rename to im-platform/src/main/java/com/bx/implatform/service/FriendService.java index 92e7345..4fdf32f 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/FriendService.java @@ -6,7 +6,7 @@ import com.bx.implatform.vo.FriendVO; import java.util.List; -public interface IFriendService extends IService { +public interface FriendService extends IService { /** * 判断用户2是否用户1的好友 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java b/im-platform/src/main/java/com/bx/implatform/service/GroupMemberService.java similarity index 96% rename from im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java rename to im-platform/src/main/java/com/bx/implatform/service/GroupMemberService.java index bfa2440..87ced17 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/GroupMemberService.java @@ -5,7 +5,7 @@ import com.bx.implatform.entity.GroupMember; import java.util.List; -public interface IGroupMemberService extends IService { +public interface GroupMemberService extends IService { /** * 根据群聊id和用户id查询群聊成员 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java b/im-platform/src/main/java/com/bx/implatform/service/GroupMessageService.java similarity index 91% rename from im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java rename to im-platform/src/main/java/com/bx/implatform/service/GroupMessageService.java index 54f9f5e..dc4efda 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/GroupMessageService.java @@ -7,7 +7,7 @@ import com.bx.implatform.vo.GroupMessageVO; import java.util.List; -public interface IGroupMessageService extends IService { +public interface GroupMessageService extends IService { /** * 发送群聊消息(高并发接口,查询mysql接口都要进行缓存) @@ -15,7 +15,7 @@ public interface IGroupMessageService extends IService { * @param dto 群聊消息 * @return 群聊id */ - Long sendMessage(GroupMessageDTO dto); + GroupMessageVO sendMessage(GroupMessageDTO dto); /** * 撤回消息 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java b/im-platform/src/main/java/com/bx/implatform/service/GroupService.java similarity index 94% rename from im-platform/src/main/java/com/bx/implatform/service/IGroupService.java rename to im-platform/src/main/java/com/bx/implatform/service/GroupService.java index 6f58619..fe2f6fa 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/GroupService.java @@ -8,7 +8,7 @@ import com.bx.implatform.vo.GroupVO; import java.util.List; -public interface IGroupService extends IService { +public interface GroupService extends IService { /** * 创建新群聊 @@ -68,7 +68,7 @@ public interface IGroupService extends IService { * @param groupId 群聊id * @return 群聊实体 */ - Group getById(Long groupId); + Group getAndCheckById(Long groupId); /** * 根据id查找群聊 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java b/im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java similarity index 90% rename from im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java rename to im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java index 89669b8..261a5e0 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/PrivateMessageService.java @@ -7,7 +7,7 @@ import com.bx.implatform.vo.PrivateMessageVO; import java.util.List; -public interface IPrivateMessageService extends IService { +public interface PrivateMessageService extends IService { /** * 发送私聊消息(高并发接口,查询mysql接口都要进行缓存) @@ -15,7 +15,7 @@ public interface IPrivateMessageService extends IService { * @param dto 私聊消息 * @return 消息id */ - Long sendMessage(PrivateMessageDTO dto); + PrivateMessageVO sendMessage(PrivateMessageDTO dto); /** diff --git a/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java b/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java new file mode 100644 index 0000000..f6a4b86 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/SensitiveWordService.java @@ -0,0 +1,22 @@ +package com.bx.implatform.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.bx.implatform.dto.LoginDTO; +import com.bx.implatform.dto.ModifyPwdDTO; +import com.bx.implatform.dto.RegisterDTO; +import com.bx.implatform.entity.SensitiveWord; +import com.bx.implatform.entity.User; +import com.bx.implatform.vo.LoginVO; +import com.bx.implatform.vo.OnlineTerminalVO; +import com.bx.implatform.vo.UserVO; + +import java.util.List; + +public interface SensitiveWordService extends IService { + + /** + * 查询所有开启的敏感词 + * @return + */ + List findAllEnabledWords(); +} diff --git a/im-platform/src/main/java/com/bx/implatform/service/IUserService.java b/im-platform/src/main/java/com/bx/implatform/service/UserService.java similarity index 97% rename from im-platform/src/main/java/com/bx/implatform/service/IUserService.java rename to im-platform/src/main/java/com/bx/implatform/service/UserService.java index a24e0c3..37bcc8b 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IUserService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/UserService.java @@ -11,7 +11,7 @@ import com.bx.implatform.vo.UserVO; import java.util.List; -public interface IUserService extends IService { +public interface UserService extends IService { /** * 用户登录 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IWebrtcGroupService.java b/im-platform/src/main/java/com/bx/implatform/service/WebrtcGroupService.java similarity index 94% rename from im-platform/src/main/java/com/bx/implatform/service/IWebrtcGroupService.java rename to im-platform/src/main/java/com/bx/implatform/service/WebrtcGroupService.java index edef9e6..08e6760 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IWebrtcGroupService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/WebrtcGroupService.java @@ -1,10 +1,9 @@ package com.bx.implatform.service; -import com.bx.implatform.config.WebrtcConfig; import com.bx.implatform.dto.*; import com.bx.implatform.vo.WebrtcGroupInfoVO; -public interface IWebrtcGroupService { +public interface WebrtcGroupService { /** * 发起通话 diff --git a/im-platform/src/main/java/com/bx/implatform/service/IWebrtcPrivateService.java b/im-platform/src/main/java/com/bx/implatform/service/WebrtcPrivateService.java similarity index 78% rename from im-platform/src/main/java/com/bx/implatform/service/IWebrtcPrivateService.java rename to im-platform/src/main/java/com/bx/implatform/service/WebrtcPrivateService.java index 04dd4ad..c2f9c3f 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IWebrtcPrivateService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/WebrtcPrivateService.java @@ -1,15 +1,11 @@ package com.bx.implatform.service; -import com.bx.implatform.config.ICEServer; - -import java.util.List; - /** * webrtc 通信服务 * * @author */ -public interface IWebrtcPrivateService { +public interface WebrtcPrivateService { void call(Long uid, String mode,String offer); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java index 20ef491..c67a0d0 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java @@ -7,11 +7,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.Friend; import com.bx.implatform.entity.User; -import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.FriendMapper; import com.bx.implatform.mapper.UserMapper; -import com.bx.implatform.service.IFriendService; +import com.bx.implatform.service.FriendService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.vo.FriendVO; @@ -25,12 +24,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Objects; @Slf4j @Service @RequiredArgsConstructor @CacheConfig(cacheNames = RedisKey.IM_CACHE_FRIEND) -public class FriendServiceImpl extends ServiceImpl implements IFriendService { +public class FriendServiceImpl extends ServiceImpl implements FriendService { private final UserMapper userMapper; @@ -47,7 +47,7 @@ public class FriendServiceImpl extends ServiceImpl impleme public void addFriend(Long friendId) { long userId = SessionContext.getSession().getUserId(); if (friendId.equals(userId)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "不允许添加自己为好友"); + throw new GlobalException("不允许添加自己为好友"); } // 互相绑定好友关系 FriendServiceImpl proxy = (FriendServiceImpl) AopContext.currentProxy(); @@ -87,12 +87,10 @@ public class FriendServiceImpl extends ServiceImpl impleme queryWrapper.lambda() .eq(Friend::getUserId, userId) .eq(Friend::getFriendId, vo.getId()); - Friend f = this.getOne(queryWrapper); - if (f == null) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "对方不是您的好友"); + if (Objects.isNull(f)) { + throw new GlobalException("对方不是您的好友"); } - f.setFriendHeadImage(vo.getHeadImage()); f.setFriendNickName(vo.getNickName()); this.updateById(f); @@ -148,8 +146,8 @@ public class FriendServiceImpl extends ServiceImpl impleme .eq(Friend::getUserId, session.getUserId()) .eq(Friend::getFriendId, friendId); Friend friend = this.getOne(wrapper); - if (friend == null) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "对方不是您的好友"); + if (Objects.isNull(friend)) { + throw new GlobalException("对方不是您的好友"); } FriendVO vo = new FriendVO(); vo.setId(friend.getFriendId()); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java index 592f761..caf4b37 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java @@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.GroupMember; import com.bx.implatform.mapper.GroupMemberMapper; -import com.bx.implatform.service.IGroupMemberService; +import com.bx.implatform.service.GroupMemberService; import com.bx.implatform.util.DateTimeUtils; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; @@ -22,7 +22,7 @@ import java.util.stream.Collectors; @Service @CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER_ID) -public class GroupMemberServiceImpl extends ServiceImpl implements IGroupMemberService { +public class GroupMemberServiceImpl extends ServiceImpl implements GroupMemberService { @CacheEvict(key = "#member.getGroupId()") @Override public boolean save(GroupMember member) { diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index 5a8c45c..7ae8b42 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -21,12 +21,11 @@ import com.bx.implatform.entity.GroupMember; import com.bx.implatform.entity.GroupMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; -import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.GroupMessageMapper; -import com.bx.implatform.service.IGroupMemberService; -import com.bx.implatform.service.IGroupMessageService; -import com.bx.implatform.service.IGroupService; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.GroupMessageService; +import com.bx.implatform.service.GroupService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; @@ -47,27 +46,22 @@ import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor -public class GroupMessageServiceImpl extends ServiceImpl implements IGroupMessageService { - private final IGroupService groupService; - private final IGroupMemberService groupMemberService; +public class GroupMessageServiceImpl extends ServiceImpl implements + GroupMessageService { + private final GroupService groupService; + private final GroupMemberService groupMemberService; private final RedisTemplate redisTemplate; private final IMClient imClient; private final SensitiveFilterUtil sensitiveFilterUtil; @Override - public Long sendMessage(GroupMessageDTO dto) { + public GroupMessageVO sendMessage(GroupMessageDTO dto) { UserSession session = SessionContext.getSession(); - Group group = groupService.getById(dto.getGroupId()); - if (Objects.isNull(group)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊不存在"); - } - if (Boolean.TRUE.equals(group.getDeleted())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊已解散"); - } + Group group = groupService.getAndCheckById(dto.getGroupId()); // 是否在群聊里面 GroupMember member = groupMemberService.findByGroupAndUserId(dto.getGroupId(), session.getUserId()); if (Objects.isNull(member) || member.getQuit()) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法发送消息"); + throw new GlobalException("您已不在群聊里面,无法发送消息"); } // 群聊成员列表 List userIds = groupMemberService.findUserIdsByGroupId(group.getId()); @@ -77,14 +71,15 @@ public class GroupMessageServiceImpl extends ServiceImpl IMConstant.ALLOW_RECALL_SECOND * 1000) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "消息已发送超过5分钟,无法撤回"); + throw new GlobalException("消息已发送超过5分钟,无法撤回"); } // 判断是否在群里 GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(), session.getUserId()); if (Objects.isNull(member) || Boolean.TRUE.equals(member.getQuit())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不在群聊里面,无法撤回消息"); + throw new GlobalException("您已不在群聊里面,无法撤回消息"); } // 修改数据库 msg.setStatus(MessageStatus.RECALL.code()); @@ -125,7 +120,7 @@ public class GroupMessageServiceImpl extends ServiceImpl !session.getUserId().equals(uid)).collect(Collectors.toList()); GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); msgInfo.setType(MessageType.RECALL.code()); - String content = String.format("'%s'撤回了一条消息", member.getAliasName()); + String content = String.format("'%s'撤回了一条消息", member.getShowNickName()); msgInfo.setContent(content); msgInfo.setSendTime(new Date()); @@ -151,7 +146,7 @@ public class GroupMessageServiceImpl extends ServiceImpl members = groupMemberService.findByUserId(session.getUserId()); @@ -164,14 +159,14 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = Wrappers.lambdaQuery(); wrapper.gt(GroupMessage::getId, minId) .gt(GroupMessage::getSendTime, minDate) .in(GroupMessage::getGroupId, groupIds) .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()) - .orderByDesc(GroupMessage::getId).last("limit 1000"); + .orderByDesc(GroupMessage::getId).last("limit 3000"); List messages = this.list(wrapper); // 通过群聊对消息进行分组 Map> messageGroupMap = messages.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId)); @@ -315,12 +310,12 @@ public class GroupMessageServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java index c32de84..955ab54 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java @@ -14,11 +14,13 @@ import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.*; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; -import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.GroupMapper; import com.bx.implatform.mapper.GroupMessageMapper; -import com.bx.implatform.service.*; +import com.bx.implatform.service.FriendService; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.GroupService; +import com.bx.implatform.service.UserService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; @@ -28,7 +30,6 @@ import com.bx.implatform.vo.GroupMessageVO; import com.bx.implatform.vo.GroupVO; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -40,14 +41,14 @@ import java.util.*; import java.util.stream.Collectors; @Slf4j -@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP) @Service @RequiredArgsConstructor -public class GroupServiceImpl extends ServiceImpl implements IGroupService { - private final IUserService userService; - private final IGroupMemberService groupMemberService; +@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP) +public class GroupServiceImpl extends ServiceImpl implements GroupService { + private final UserService userService; + private final GroupMemberService groupMemberService; private final GroupMessageMapper groupMessageMapper; - private final IFriendService friendsService; + private final FriendService friendsService; private final IMClient imClient; private final RedisTemplate redisTemplate; @@ -60,17 +61,17 @@ public class GroupServiceImpl extends ServiceImpl implements group.setOwnerId(user.getId()); this.save(group); // 把群主加入群 - GroupMember groupMember = new GroupMember(); - groupMember.setGroupId(group.getId()); - groupMember.setUserId(user.getId()); - groupMember.setHeadImage(user.getHeadImageThumb()); - groupMember.setAliasName(StringUtils.isEmpty(vo.getAliasName()) ? session.getNickName() : vo.getAliasName()); - groupMember.setRemark(StringUtils.isEmpty(vo.getRemark()) ? group.getName() : vo.getRemark()); - groupMemberService.save(groupMember); - + GroupMember member = new GroupMember(); + member.setGroupId(group.getId()); + member.setUserId(user.getId()); + member.setHeadImage(user.getHeadImageThumb()); + member.setRemarkNickName(vo.getRemarkNickName()); + member.setRemarkGroupName(vo.getRemarkGroupName()); + groupMemberService.save(member); + // 返回 vo.setId(group.getId()); - vo.setAliasName(groupMember.getAliasName()); - vo.setRemark(groupMember.getRemark()); + vo.setShowNickName(StrUtil.isEmpty(vo.getRemarkNickName()) ? member.getUserNickName() : vo.getRemarkNickName()); + vo.setShowGroupName(StrUtil.isEmpty(vo.getRemarkGroupName()) ? group.getName() : vo.getRemarkGroupName()); log.info("创建群聊,群聊id:{},群聊名称:{}", group.getId(), group.getName()); return vo; } @@ -81,20 +82,22 @@ public class GroupServiceImpl extends ServiceImpl implements public GroupVO modifyGroup(GroupVO vo) { UserSession session = SessionContext.getSession(); // 校验是不是群主,只有群主能改信息 - Group group = this.getById(vo.getId()); - // 群主有权修改群基本信息 - if (group.getOwnerId().equals(session.getUserId())) { - group = BeanUtils.copyProperties(vo, Group.class); - this.updateById(group); - } + Group group = this.getAndCheckById(vo.getId()); // 更新成员信息 GroupMember member = groupMemberService.findByGroupAndUserId(vo.getId(), session.getUserId()); if (Objects.isNull(member) || member.getQuit()) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您不是群聊的成员"); + throw new GlobalException("您不是群聊的成员"); } - member.setAliasName(StringUtils.isEmpty(vo.getAliasName()) ? session.getNickName() : vo.getAliasName()); - member.setRemark(StringUtils.isEmpty(vo.getRemark()) ? Objects.requireNonNull(group).getName() : vo.getRemark()); + member.setRemarkNickName(vo.getRemarkNickName()); + member.setRemarkGroupName(vo.getRemarkGroupName()); groupMemberService.updateById(member); + // 群主有权修改群基本信息 + if (group.getOwnerId().equals(session.getUserId())) { + group = BeanUtils.copyProperties(vo, Group.class); + this.updateById(group); + } + vo.setShowNickName(StrUtil.isEmpty(vo.getRemarkNickName()) ? member.getUserNickName() : vo.getRemarkNickName()); + vo.setShowGroupName(StrUtil.isEmpty(vo.getRemarkGroupName()) ? group.getName() : vo.getRemarkGroupName()); log.info("修改群聊,群聊id:{},群聊名称:{}", group.getId(), group.getName()); return vo; } @@ -106,7 +109,7 @@ public class GroupServiceImpl extends ServiceImpl implements UserSession session = SessionContext.getSession(); Group group = this.getById(groupId); if (!group.getOwnerId().equals(session.getUserId())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "只有群主才有权限解除群聊"); + throw new GlobalException("只有群主才有权限解除群聊"); } // 群聊用户id List userIds = groupMemberService.findUserIdsByGroupId(groupId); @@ -119,7 +122,7 @@ public class GroupServiceImpl extends ServiceImpl implements String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId); redisTemplate.delete(key); // 推送解散群聊提示 - this.sendTipMessage(groupId,userIds,String.format("'%s'解散了群聊",session.getNickName())); + this.sendTipMessage(groupId, userIds, String.format("'%s'解散了群聊", session.getNickName())); log.info("删除群聊,群聊id:{},群聊名称:{}", group.getId(), group.getName()); } @@ -128,35 +131,35 @@ public class GroupServiceImpl extends ServiceImpl implements Long userId = SessionContext.getSession().getUserId(); Group group = this.getById(groupId); if (group.getOwnerId().equals(userId)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您是群主,不可退出群聊"); + throw new GlobalException("您是群主,不可退出群聊"); } // 删除群聊成员 groupMemberService.removeByGroupAndUserId(groupId, userId); // 清理已读缓存 String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId); - redisTemplate.opsForHash().delete(key,userId.toString()); + redisTemplate.opsForHash().delete(key, userId.toString()); // 推送退出群聊提示 - this.sendTipMessage(groupId,Arrays.asList(userId),"您已退出群聊"); + this.sendTipMessage(groupId, Arrays.asList(userId), "您已退出群聊"); log.info("退出群聊,群聊id:{},群聊名称:{},用户id:{}", group.getId(), group.getName(), userId); } @Override public void kickGroup(Long groupId, Long userId) { UserSession session = SessionContext.getSession(); - Group group = this.getById(groupId); + Group group = this.getAndCheckById(groupId); if (!group.getOwnerId().equals(session.getUserId())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您不是群主,没有权限踢人"); + throw new GlobalException("您不是群主,没有权限踢人"); } if (userId.equals(session.getUserId())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "亲,不能移除自己哟"); + throw new GlobalException("亲,不能移除自己哟"); } // 删除群聊成员 groupMemberService.removeByGroupAndUserId(groupId, userId); // 清理已读缓存 String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId); - redisTemplate.opsForHash().delete(key,userId.toString()); + redisTemplate.opsForHash().delete(key, userId.toString()); // 推送踢出群聊提示 - this.sendTipMessage(groupId,Arrays.asList(userId),"您已被移出群聊"); + this.sendTipMessage(groupId, Arrays.asList(userId), "您已被移出群聊"); log.info("踢出群聊,群聊id:{},群聊名称:{},用户id:{}", group.getId(), group.getName(), userId); } @@ -165,28 +168,33 @@ public class GroupServiceImpl extends ServiceImpl implements UserSession session = SessionContext.getSession(); Group group = super.getById(groupId); if (Objects.isNull(group)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群组不存在"); + throw new GlobalException("群组不存在"); } GroupMember member = groupMemberService.findByGroupAndUserId(groupId, session.getUserId()); if (Objects.isNull(member)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您未加入群聊"); + throw new GlobalException("您未加入群聊"); } GroupVO vo = BeanUtils.copyProperties(group, GroupVO.class); - vo.setAliasName(member.getAliasName()); - vo.setRemark(member.getRemark()); + vo.setRemarkGroupName(member.getRemarkGroupName()); + vo.setRemarkNickName(member.getRemarkNickName()); + vo.setShowNickName(member.getShowNickName()); + vo.setShowGroupName(StrUtil.isEmpty(vo.getRemarkGroupName()) ? group.getName() : vo.getRemarkGroupName()); vo.setQuit(member.getQuit()); return vo; } @Cacheable(key = "#groupId") @Override - public Group getById(Long groupId) { + public Group getAndCheckById(Long groupId) { Group group = super.getById(groupId); if (Objects.isNull(group)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群组不存在"); + throw new GlobalException("群组不存在"); } if (group.getDeleted()) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群组'" + group.getName() + "'已解散"); + throw new GlobalException("群组'" + group.getName() + "'已解散"); + } + if (group.getIsBanned()) { + throw new GlobalException("群组'" + group.getName() + "'已被封禁,原因:" + group.getReason()); } return group; } @@ -210,8 +218,9 @@ public class GroupServiceImpl extends ServiceImpl implements return groups.stream().map(g -> { GroupVO vo = BeanUtils.copyProperties(g, GroupVO.class); GroupMember member = groupMembers.stream().filter(m -> g.getId().equals(m.getGroupId())).findFirst().get(); - vo.setAliasName(member.getAliasName()); - vo.setRemark(member.getRemark()); + vo.setShowNickName( + StrUtil.isEmpty(vo.getRemarkNickName()) ? session.getNickName() : vo.getRemarkNickName()); + vo.setShowGroupName(StrUtil.isEmpty(vo.getRemarkGroupName()) ? g.getName() : vo.getRemarkGroupName()); vo.setQuit(member.getQuit()); return vo; }).collect(Collectors.toList()); @@ -220,35 +229,33 @@ public class GroupServiceImpl extends ServiceImpl implements @Override public void invite(GroupInviteVO vo) { UserSession session = SessionContext.getSession(); - Group group = this.getById(vo.getGroupId()); - if (Objects.isNull(group)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊不存在"); - } + Group group = this.getAndCheckById(vo.getGroupId()); GroupMember member = groupMemberService.findByGroupAndUserId(vo.getGroupId(), session.getUserId()); if (Objects.isNull(group) || member.getQuit()) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您不在群聊中,邀请失败"); + throw new GlobalException("您不在群聊中,邀请失败"); } // 群聊人数校验 List members = groupMemberService.findByGroupId(vo.getGroupId()); long size = members.stream().filter(m -> !m.getQuit()).count(); if (vo.getFriendIds().size() + size > Constant.MAX_GROUP_MEMBER) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊人数不能大于" + Constant.MAX_GROUP_MEMBER + "人"); + throw new GlobalException("群聊人数不能大于" + Constant.MAX_GROUP_MEMBER + "人"); } // 找出好友信息 List friends = friendsService.findFriendByUserId(session.getUserId()); - List friendsList = vo.getFriendIds().stream().map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get()) - .collect(Collectors.toList()); + List friendsList = vo.getFriendIds().stream() + .map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get()) + .collect(Collectors.toList()); if (friendsList.size() != vo.getFriendIds().size()) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "部分用户不是您的好友,邀请失败"); + throw new GlobalException("部分用户不是您的好友,邀请失败"); } // 批量保存成员数据 List groupMembers = friendsList.stream().map(f -> { - Optional optional = members.stream().filter(m -> m.getUserId().equals(f.getFriendId())).findFirst(); + Optional optional = + members.stream().filter(m -> m.getUserId().equals(f.getFriendId())).findFirst(); GroupMember groupMember = optional.orElseGet(GroupMember::new); groupMember.setGroupId(vo.getGroupId()); groupMember.setUserId(f.getFriendId()); - groupMember.setAliasName(f.getFriendNickName()); - groupMember.setRemark(group.getName()); + groupMember.setUserNickName(f.getFriendNickName()); groupMember.setHeadImage(f.getFriendHeadImage()); groupMember.setCreatedTime(new Date()); groupMember.setQuit(false); @@ -259,25 +266,29 @@ public class GroupServiceImpl extends ServiceImpl implements } // 推送进入群聊消息 List userIds = groupMemberService.findUserIdsByGroupId(vo.getGroupId()); - String memberNames = groupMembers.stream().map(GroupMember::getAliasName).collect(Collectors.joining(",")); - String content = String.format("'%s'邀请'%s'加入了群聊",session.getNickName(), memberNames); - this.sendTipMessage(vo.getGroupId(),userIds,content); - log.info("邀请进入群聊,群聊id:{},群聊名称:{},被邀请用户id:{}", group.getId(), group.getName(), vo.getFriendIds()); + String memberNames = groupMembers.stream().map(GroupMember::getShowNickName).collect(Collectors.joining(",")); + String content = String.format("'%s'邀请'%s'加入了群聊", session.getNickName(), memberNames); + this.sendTipMessage(vo.getGroupId(), userIds, content); + log.info("邀请进入群聊,群聊id:{},群聊名称:{},被邀请用户id:{}", group.getId(), group.getName(), + vo.getFriendIds()); } @Override public List findGroupMembers(Long groupId) { + Group group = getAndCheckById(groupId); List members = groupMemberService.findByGroupId(groupId); List userIds = members.stream().map(GroupMember::getUserId).collect(Collectors.toList()); List onlineUserIds = imClient.getOnlineUser(userIds); return members.stream().map(m -> { GroupMemberVO vo = BeanUtils.copyProperties(m, GroupMemberVO.class); + vo.setShowNickName(m.getShowNickName()); + vo.setShowGroupName(StrUtil.isEmpty(m.getRemarkGroupName()) ? group.getName() : m.getRemarkGroupName()); vo.setOnline(onlineUserIds.contains(m.getUserId())); return vo; }).sorted((m1, m2) -> m2.getOnline().compareTo(m1.getOnline())).collect(Collectors.toList()); } - private void sendTipMessage(Long groupId,List recvIds,String content){ + private void sendTipMessage(Long groupId, List recvIds, String content) { UserSession session = SessionContext.getSession(); // 消息入库 GroupMessage message = new GroupMessage(); @@ -291,14 +302,14 @@ public class GroupServiceImpl extends ServiceImpl implements message.setRecvIds(CommaTextUtils.asText(recvIds)); groupMessageMapper.insert(message); // 推送 - GroupMessageVO msgInfo = BeanUtils.copyProperties(message,GroupMessageVO.class); + GroupMessageVO msgInfo = BeanUtils.copyProperties(message, GroupMessageVO.class); IMGroupMessage sendMessage = new IMGroupMessage<>(); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal())); - if(CollUtil.isEmpty(recvIds)){ + if (CollUtil.isEmpty(recvIds)) { // 为空表示向全体发送 List userIds = groupMemberService.findUserIdsByGroupId(groupId); sendMessage.setRecvIds(userIds); - }else{ + } else { sendMessage.setRecvIds(recvIds); } sendMessage.setData(msgInfo); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index 0e10922..995e97d 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -16,11 +16,10 @@ import com.bx.implatform.entity.Friend; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; -import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.PrivateMessageMapper; -import com.bx.implatform.service.IFriendService; -import com.bx.implatform.service.IPrivateMessageService; +import com.bx.implatform.service.FriendService; +import com.bx.implatform.service.PrivateMessageService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; @@ -38,18 +37,19 @@ import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor -public class PrivateMessageServiceImpl extends ServiceImpl implements IPrivateMessageService { +public class PrivateMessageServiceImpl extends ServiceImpl implements + PrivateMessageService { - private final IFriendService friendService; + private final FriendService friendService; private final IMClient imClient; private final SensitiveFilterUtil sensitiveFilterUtil; @Override - public Long sendMessage(PrivateMessageDTO dto) { + public PrivateMessageVO sendMessage(PrivateMessageDTO dto) { UserSession session = SessionContext.getSession(); Boolean isFriends = friendService.isFriend(session.getUserId(), dto.getRecvId()); if (Boolean.FALSE.equals(isFriends)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不是对方好友,无法发送消息"); + throw new GlobalException("您已不是对方好友,无法发送消息"); } // 保存消息 PrivateMessage msg = BeanUtils.copyProperties(dto, PrivateMessage.class); @@ -57,9 +57,10 @@ public class PrivateMessageServiceImpl extends ServiceImpl sendMessage = new IMPrivateMessage<>(); @@ -70,7 +71,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl IMConstant.ALLOW_RECALL_SECOND * 1000) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "消息已发送超过5分钟,无法撤回"); + throw new GlobalException("消息已发送超过5分钟,无法撤回"); } // 修改消息状态 msg.setStatus(MessageStatus.RECALL.code()); @@ -138,7 +139,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl friends = friendService.findFriendByUserId(session.getUserId()); @@ -152,8 +153,8 @@ public class PrivateMessageServiceImpl extends ServiceImpl friendIds = friends.stream().map(Friend::getFriendId).collect(Collectors.toList()); // 获取当前用户的消息 LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); - // 只能拉取最近1个月的1000条消息 - Date minDate = DateUtils.addMonths(new Date(), -1); + // 只能拉取最近3个月的3000条消息 + Date minDate = DateUtils.addMonths(new Date(), -3); queryWrapper.gt(PrivateMessage::getId, minId) .ge(PrivateMessage::getSendTime, minDate) .ne(PrivateMessage::getStatus, MessageStatus.RECALL.code()) @@ -163,7 +164,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl wp.eq(PrivateMessage::getRecvId, session.getUserId()) .in(PrivateMessage::getSendId, friendIds))) .orderByDesc(PrivateMessage::getId) - .last("limit 1000"); + .last("limit 3000"); List messages = this.list(queryWrapper); // 消息顺序从小到大 CollectionUtil.reverse(messages); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/SensitiveWordServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/SensitiveWordServiceImpl.java new file mode 100644 index 0000000..572e5bd --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/SensitiveWordServiceImpl.java @@ -0,0 +1,30 @@ +package com.bx.implatform.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.bx.implatform.entity.SensitiveWord; +import com.bx.implatform.mapper.SensitiveWordMapper; +import com.bx.implatform.service.SensitiveWordService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SensitiveWordServiceImpl extends ServiceImpl implements + SensitiveWordService { + + @Override + public List findAllEnabledWords() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(SensitiveWord::getEnabled,true); + wrapper.select(SensitiveWord::getContent); + List words = this.list(wrapper); + return words.stream().map(SensitiveWord::getContent).collect(Collectors.toList()); + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java index b10bad4..7ea154b 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java @@ -2,7 +2,7 @@ package com.bx.implatform.service.impl; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; @@ -18,9 +18,9 @@ import com.bx.implatform.entity.User; import com.bx.implatform.enums.ResultCode; import com.bx.implatform.exception.GlobalException; import com.bx.implatform.mapper.UserMapper; -import com.bx.implatform.service.IFriendService; -import com.bx.implatform.service.IGroupMemberService; -import com.bx.implatform.service.IUserService; +import com.bx.implatform.service.FriendService; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.UserService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; @@ -39,19 +39,23 @@ import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor -public class UserServiceImpl extends ServiceImpl implements IUserService { +public class UserServiceImpl extends ServiceImpl implements UserService { private final PasswordEncoder passwordEncoder; - private final IGroupMemberService groupMemberService; - private final IFriendService friendService; + private final GroupMemberService groupMemberService; + private final FriendService friendService; private final JwtProperties jwtProperties; private final IMClient imClient; @Override public LoginVO login(LoginDTO dto) { User user = this.findUserByUserName(dto.getUserName()); - if (null == user) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "用户不存在"); + if (Objects.isNull(user)) { + throw new GlobalException("用户不存在"); + } + if (user.getIsBanned()) { + String tip = String.format("您的账号因'%s'已被管理员封禁,请联系客服!",user.getReason()); + throw new GlobalException(tip); } if (!passwordEncoder.matches(dto.getPassword(), user.getPassword())) { throw new GlobalException(ResultCode.PASSWOR_ERROR); @@ -61,8 +65,10 @@ public class UserServiceImpl extends ServiceImpl implements IU session.setUserId(user.getId()); session.setTerminal(dto.getTerminal()); String strJson = JSON.toJSONString(session); - String accessToken = JwtUtil.sign(user.getId(), strJson, jwtProperties.getAccessTokenExpireIn(), jwtProperties.getAccessTokenSecret()); - String refreshToken = JwtUtil.sign(user.getId(), strJson, jwtProperties.getRefreshTokenExpireIn(), jwtProperties.getRefreshTokenSecret()); + String accessToken = JwtUtil.sign(user.getId(), strJson, jwtProperties.getAccessTokenExpireIn(), + jwtProperties.getAccessTokenSecret()); + String refreshToken = JwtUtil.sign(user.getId(), strJson, jwtProperties.getRefreshTokenExpireIn(), + jwtProperties.getRefreshTokenSecret()); LoginVO vo = new LoginVO(); vo.setAccessToken(accessToken); vo.setAccessTokenExpiresIn(jwtProperties.getAccessTokenExpireIn()); @@ -79,8 +85,18 @@ public class UserServiceImpl extends ServiceImpl implements IU } String strJson = JwtUtil.getInfo(refreshToken); Long userId = JwtUtil.getUserId(refreshToken); - String accessToken = JwtUtil.sign(userId, strJson, jwtProperties.getAccessTokenExpireIn(), jwtProperties.getAccessTokenSecret()); - String newRefreshToken = JwtUtil.sign(userId, strJson, jwtProperties.getRefreshTokenExpireIn(), jwtProperties.getRefreshTokenSecret()); + User user = this.getById(userId); + if (Objects.isNull(user)) { + throw new GlobalException("用户不存在"); + } + if (user.getIsBanned()) { + String tip = String.format("您的账号因'%s'被管理员封禁,请联系客服!",user.getReason()); + throw new GlobalException(tip); + } + String accessToken = + JwtUtil.sign(userId, strJson, jwtProperties.getAccessTokenExpireIn(), jwtProperties.getAccessTokenSecret()); + String newRefreshToken = JwtUtil.sign(userId, strJson, jwtProperties.getRefreshTokenExpireIn(), + jwtProperties.getRefreshTokenSecret()); LoginVO vo = new LoginVO(); vo.setAccessToken(accessToken); vo.setAccessTokenExpiresIn(jwtProperties.getAccessTokenExpireIn()); @@ -92,7 +108,7 @@ public class UserServiceImpl extends ServiceImpl implements IU @Override public void register(RegisterDTO dto) { User user = this.findUserByUserName(dto.getUserName()); - if (null != user) { + if (!Objects.isNull(user)) { throw new GlobalException(ResultCode.USERNAME_ALREADY_REGISTER); } user = BeanUtils.copyProperties(dto, User.class); @@ -125,30 +141,26 @@ public class UserServiceImpl extends ServiceImpl implements IU public void update(UserVO vo) { UserSession session = SessionContext.getSession(); if (!session.getUserId().equals(vo.getId())) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "不允许修改其他用户的信息!"); + throw new GlobalException("不允许修改其他用户的信息!"); } User user = this.getById(vo.getId()); if (Objects.isNull(user)) { - throw new GlobalException(ResultCode.PROGRAM_ERROR, "用户不存在"); + throw new GlobalException("用户不存在"); } - // 更新好友昵称和头像 + if (!user.getNickName().equals(vo.getNickName()) || !user.getHeadImageThumb().equals(vo.getHeadImageThumb())) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(Friend::getFriendId, session.getUserId()); - List friends = friendService.list(queryWrapper); - for (Friend friend : friends) { - friend.setFriendNickName(vo.getNickName()); - friend.setFriendHeadImage(vo.getHeadImageThumb()); - } - friendService.updateBatchById(friends); - } - // 更新群聊中的头像 - if (!user.getHeadImageThumb().equals(vo.getHeadImageThumb())) { - List members = groupMemberService.findByUserId(session.getUserId()); - for (GroupMember member : members) { - member.setHeadImage(vo.getHeadImageThumb()); - } - groupMemberService.updateBatchById(members); + // 更新好友昵称和头像 + LambdaUpdateWrapper wrapper1 = Wrappers.lambdaUpdate(); + wrapper1.eq(Friend::getFriendId, session.getUserId()); + wrapper1.set(Friend::getFriendNickName,vo.getNickName()); + wrapper1.set(Friend::getFriendHeadImage,vo.getHeadImageThumb()); + friendService.update(wrapper1); + // 更新群聊中的昵称和头像 + LambdaUpdateWrapper wrapper2 = Wrappers.lambdaUpdate(); + wrapper2.eq(GroupMember::getUserId, session.getUserId()); + wrapper2.set(GroupMember::getHeadImage,vo.getHeadImageThumb()); + wrapper2.set(GroupMember::getUserNickName,vo.getNickName()); + groupMemberService.update(wrapper2); } // 更新用户信息 user.setNickName(vo.getNickName()); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java index 8851b32..551e162 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcGroupServiceImpl.java @@ -15,9 +15,10 @@ import com.bx.implatform.entity.GroupMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; import com.bx.implatform.exception.GlobalException; -import com.bx.implatform.service.IGroupMemberService; -import com.bx.implatform.service.IGroupMessageService; -import com.bx.implatform.service.IWebrtcGroupService; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.GroupMessageService; +import com.bx.implatform.service.GroupService; +import com.bx.implatform.service.WebrtcGroupService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.session.WebrtcGroupSession; @@ -46,24 +47,21 @@ import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor -public class WebrtcGroupServiceImpl implements IWebrtcGroupService { - - private final IGroupMemberService groupMemberService; - private final IGroupMessageService groupMessageService; +public class WebrtcGroupServiceImpl implements WebrtcGroupService { + private final GroupService groupService; + private final GroupMemberService groupMemberService; + private final GroupMessageService groupMessageService; private final RedisTemplate redisTemplate; private final IMClient imClient; private final UserStateUtils userStateUtils; private final WebrtcConfig webrtcConfig; - @OnlineCheck @RedisLock(prefixKey = RedisKey.IM_LOCK_RTC_GROUP, key = "#dto.groupId") @Override public void setup(WebrtcGroupSetupDTO dto) { UserSession userSession = SessionContext.getSession(); - if(!imClient.isOnline(userSession.getUserId())){ - throw new GlobalException("您已断开连接,请重新登陆"); - } + groupService.getAndCheckById(dto.getGroupId()); if (dto.getUserInfos().size() > webrtcConfig.getMaxChannel()) { throw new GlobalException("最多支持" + webrtcConfig.getMaxChannel() + "人进行通话"); } @@ -72,7 +70,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { throw new GlobalException("部分用户不在群聊中"); } String key = buildWebrtcSessionKey(dto.getGroupId()); - if (redisTemplate.hasKey(key)) { + if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) { throw new GlobalException("该群聊已存在一个通话"); } // 有效用户 @@ -116,11 +114,11 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { } // 向被邀请的用户广播消息,发起呼叫 List recvIds = getRecvIds(userInfos); - sendRtcMessage1(MessageType.RTC_GROUP_SETUP, dto.getGroupId(), recvIds, JSON.toJSONString(userInfos),false); + sendRtcMessage1(MessageType.RTC_GROUP_SETUP, dto.getGroupId(), recvIds, JSON.toJSONString(userInfos), false); // 发送文字提示信息 - WebrtcUserInfo mineInfo = findUserInfo(webrtcSession,userSession.getUserId()); + WebrtcUserInfo mineInfo = findUserInfo(webrtcSession, userSession.getUserId()); String content = mineInfo.getNickName() + " 发起了语音通话"; - sendTipMessage(dto.getGroupId(),content); + sendTipMessage(dto.getGroupId(), content); log.info("发起群通话,userId:{},groupId:{}", userSession.getUserId(), dto.getGroupId()); } @@ -142,7 +140,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { saveWebrtcSession(groupId, webrtcSession); // 广播信令 List recvIds = getRecvIds(webrtcSession.getUserInfos()); - sendRtcMessage1(MessageType.RTC_GROUP_ACCEPT, groupId, recvIds, "",true); + sendRtcMessage1(MessageType.RTC_GROUP_ACCEPT, groupId, recvIds, "", true); log.info("加入群通话,userId:{},groupId:{}", userSession.getUserId(), groupId); } @@ -169,7 +167,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { userStateUtils.setFree(userSession.getUserId()); // 广播消息给的所有用户 List recvIds = getRecvIds(userInfos); - sendRtcMessage1(MessageType.RTC_GROUP_REJECT, groupId, recvIds, "",true); + sendRtcMessage1(MessageType.RTC_GROUP_REJECT, groupId, recvIds, "", true); log.info("拒绝群通话,userId:{},groupId:{}", userSession.getUserId(), groupId); } @@ -198,8 +196,8 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { vo.setUserIds(Arrays.asList(userSession.getUserId())); vo.setReason(dto.getReason()); List recvIds = getRecvIds(userInfos); - sendRtcMessage1(MessageType.RTC_GROUP_FAILED, dto.getGroupId(), recvIds, JSON.toJSONString(vo),false); - log.info("群通话失败,userId:{},groupId:{},原因:{}", userSession.getUserId(), dto.getReason()); + sendRtcMessage1(MessageType.RTC_GROUP_FAILED, dto.getGroupId(), recvIds, JSON.toJSONString(vo), false); + log.info("群通话失败,userId:{},groupId:{},原因:{}", userSession.getUserId(), dto.getGroupId(), dto.getReason()); } @OnlineCheck @@ -216,12 +214,12 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { throw new GlobalException("您不在群里中"); } IMUserInfo mine = findInChatUser(webrtcSession, userSession.getUserId()); - if(!Objects.isNull(mine) && mine.getTerminal() != userSession.getTerminal()){ + if (!Objects.isNull(mine) && mine.getTerminal().equals(userSession.getTerminal())) { throw new GlobalException("已在其他设备加入通话"); } WebrtcUserInfo userInfo = new WebrtcUserInfo(); userInfo.setId(userSession.getUserId()); - userInfo.setNickName(member.getAliasName()); + userInfo.setNickName(member.getShowNickName()); userInfo.setHeadImage(member.getHeadImage()); // 默认是开启麦克风,关闭摄像头 userInfo.setIsCamera(false); @@ -238,7 +236,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { userStateUtils.setBusy(userSession.getUserId()); // 广播信令 List recvIds = getRecvIds(webrtcSession.getUserInfos()); - sendRtcMessage1(MessageType.RTC_GROUP_JOIN, groupId, recvIds, JSON.toJSONString(userInfo),false); + sendRtcMessage1(MessageType.RTC_GROUP_JOIN, groupId, recvIds, JSON.toJSONString(userInfo), false); log.info("加入群通话,userId:{},groupId:{}", userSession.getUserId(), groupId); } @@ -271,8 +269,6 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { } if (!imClient.isOnline(userInfo.getId())) { offlineUserIds.add(userInfo.getId()); -// userStateUtils.setBusy(userInfo.getId()); -// newUserInfos.add(userInfo); } else if (userStateUtils.isBusy(userInfo.getId())) { busyUserIds.add(userInfo.getId()); } else { @@ -301,9 +297,10 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { } // 向被邀请的发起呼叫 List newUserIds = getRecvIds(newUserInfos); - sendRtcMessage1(MessageType.RTC_GROUP_SETUP, dto.getGroupId(), newUserIds, JSON.toJSONString(userInfos),false); + sendRtcMessage1(MessageType.RTC_GROUP_SETUP, dto.getGroupId(), newUserIds, JSON.toJSONString(userInfos), false); // 向已在通话中的用户同步新邀请的用户信息 - sendRtcMessage1(MessageType.RTC_GROUP_INVITE, dto.getGroupId(), userIds, JSON.toJSONString(newUserInfos),false); + sendRtcMessage1(MessageType.RTC_GROUP_INVITE, dto.getGroupId(), userIds, JSON.toJSONString(newUserInfos), + false); log.info("邀请加入群通话,userId:{},groupId:{},邀请用户:{}", userSession.getUserId(), dto.getGroupId(), newUserIds); } @@ -323,9 +320,9 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { webrtcSession.getUserInfos().forEach(user -> userStateUtils.setFree(user.getId())); // 广播消息给的所有用户 List recvIds = getRecvIds(webrtcSession.getUserInfos()); - sendRtcMessage1(MessageType.RTC_GROUP_CANCEL, groupId, recvIds, "",false); + sendRtcMessage1(MessageType.RTC_GROUP_CANCEL, groupId, recvIds, "", false); // 发送文字提示信息 - sendTipMessage(groupId,"通话结束"); + sendTipMessage(groupId, "通话结束"); log.info("发起人取消群通话,userId:{},groupId:{}", userSession.getUserId(), groupId); } @@ -351,9 +348,9 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { webrtcSession.getUserInfos().forEach(user -> userStateUtils.setFree(user.getId())); // 广播给还在呼叫中的用户,取消通话 List recvIds = getRecvIds(webrtcSession.getUserInfos()); - sendRtcMessage1(MessageType.RTC_GROUP_CANCEL, groupId, recvIds, "",false); + sendRtcMessage1(MessageType.RTC_GROUP_CANCEL, groupId, recvIds, "", false); // 发送文字提示信息 - sendTipMessage(groupId,"通话结束"); + sendTipMessage(groupId, "通话结束"); log.info("群通话结束,groupId:{}", groupId); } else { // 更新会话信息 @@ -364,7 +361,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { userStateUtils.setFree(userSession.getUserId()); // 广播信令 List recvIds = getRecvIds(userInfos); - sendRtcMessage1(MessageType.RTC_GROUP_QUIT, groupId, recvIds, "",false); + sendRtcMessage1(MessageType.RTC_GROUP_QUIT, groupId, recvIds, "", false); log.info("用户退出群通话,userId:{},groupId:{}", userSession.getUserId(), groupId); } } @@ -434,7 +431,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { saveWebrtcSession(dto.getGroupId(), webrtcSession); // 广播信令 List recvIds = getRecvIds(webrtcSession.getUserInfos()); - sendRtcMessage1(MessageType.RTC_GROUP_DEVICE, dto.getGroupId(), recvIds, JSON.toJSONString(dto),false); + sendRtcMessage1(MessageType.RTC_GROUP_DEVICE, dto.getGroupId(), recvIds, JSON.toJSONString(dto), false); log.info("设备操作,userId:{},groupId:{},摄像头:{}", userSession.getUserId(), dto.getGroupId(), dto.getIsCamera()); } @@ -458,7 +455,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { GroupMember member = groupMemberService.findByGroupAndUserId(groupId, hostId); host = new WebrtcUserInfo(); host.setId(hostId); - host.setNickName(member.getAliasName()); + host.setNickName(member.getShowNickName()); host.setHeadImage(member.getHeadImage()); } vo.setHost(host); @@ -526,7 +523,8 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { return webrtcSession.getUserInfos().stream().anyMatch(user -> user.getId().equals(userId)); } - private void sendRtcMessage1(MessageType messageType, Long groupId, List recvIds, String content,Boolean sendSelf) { + private void sendRtcMessage1(MessageType messageType, Long groupId, List recvIds, String content, + Boolean sendSelf) { UserSession userSession = SessionContext.getSession(); GroupMessageVO messageInfo = new GroupMessageVO(); messageInfo.setType(messageType.code()); @@ -559,7 +557,7 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { imClient.sendGroupMessage(sendMessage); } - private void sendTipMessage(Long groupId,String content){ + private void sendTipMessage(Long groupId, String content) { UserSession userSession = SessionContext.getSession(); // 群聊成员列表 List userIds = groupMemberService.findUserIdsByGroupId(groupId); @@ -581,5 +579,5 @@ public class WebrtcGroupServiceImpl implements IWebrtcGroupService { sendMessage.setSendResult(false); sendMessage.setData(msgInfo); imClient.sendGroupMessage(sendMessage); - }; + } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java index ac9ca1a..a741e09 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcPrivateServiceImpl.java @@ -9,8 +9,8 @@ import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; import com.bx.implatform.enums.WebrtcMode; import com.bx.implatform.exception.GlobalException; -import com.bx.implatform.service.IPrivateMessageService; -import com.bx.implatform.service.IWebrtcPrivateService; +import com.bx.implatform.service.PrivateMessageService; +import com.bx.implatform.service.WebrtcPrivateService; import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.UserSession; import com.bx.implatform.session.WebrtcPrivateSession; @@ -30,11 +30,11 @@ import java.util.concurrent.TimeUnit; @Slf4j @Service @RequiredArgsConstructor -public class WebrtcPrivateServiceImpl implements IWebrtcPrivateService { +public class WebrtcPrivateServiceImpl implements WebrtcPrivateService { private final IMClient imClient; private final RedisTemplate redisTemplate; - private final IPrivateMessageService privateMessageService; + private final PrivateMessageService privateMessageService; private final UserStateUtils userStateUtils; @Override diff --git a/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java index b727425..8baaaa6 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java @@ -9,6 +9,7 @@ import com.bx.implatform.util.FileUtil; import com.bx.implatform.util.ImageUtil; import com.bx.implatform.util.MinioUtil; import com.bx.implatform.vo.UploadImageVO; +import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -16,7 +17,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import javax.annotation.PostConstruct; import java.io.IOException; import java.util.Objects; diff --git a/im-platform/src/main/java/com/bx/implatform/session/SessionContext.java b/im-platform/src/main/java/com/bx/implatform/session/SessionContext.java index 9577d36..ce61dbb 100644 --- a/im-platform/src/main/java/com/bx/implatform/session/SessionContext.java +++ b/im-platform/src/main/java/com/bx/implatform/session/SessionContext.java @@ -1,10 +1,9 @@ package com.bx.implatform.session; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; - /* * @Description * @Author Blue diff --git a/im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java b/im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java index 5bae898..03c6b2d 100644 --- a/im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java +++ b/im-platform/src/main/java/com/bx/implatform/session/WebrtcUserInfo.java @@ -1,7 +1,6 @@ package com.bx.implatform.session; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; /** @@ -10,20 +9,20 @@ import lombok.Data; * @version: 1.0 */ @Data -@ApiModel("用户信息") +@Schema(description = "用户信息") public class WebrtcUserInfo { - @ApiModelProperty(value = "用户id") + @Schema(description = "用户id") private Long id; - @ApiModelProperty(value = "用户昵称") + @Schema(description = "用户昵称") private String nickName; - @ApiModelProperty(value = "用户头像") + @Schema(description = "用户头像") private String headImage; - @ApiModelProperty(value = "是否开启摄像头") + @Schema(description = "是否开启摄像头") private Boolean isCamera; - @ApiModelProperty(value = "是否开启麦克风") + @Schema(description = "是否开启麦克风") private Boolean isMicroPhone; } diff --git a/im-platform/src/main/java/com/bx/implatform/task/GroupBannedConsumerTask.java b/im-platform/src/main/java/com/bx/implatform/task/GroupBannedConsumerTask.java new file mode 100644 index 0000000..baacfba --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/task/GroupBannedConsumerTask.java @@ -0,0 +1,69 @@ +package com.bx.implatform.task; + +import com.bx.imclient.IMClient; +import com.bx.imcommon.enums.IMTerminalType; +import com.bx.imcommon.model.IMGroupMessage; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.imcommon.mq.RedisMQConsumer; +import com.bx.imcommon.mq.RedisMQListener; +import com.bx.implatform.contant.Constant; +import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.dto.GroupBanDTO; +import com.bx.implatform.entity.GroupMessage; +import com.bx.implatform.enums.MessageStatus; +import com.bx.implatform.enums.MessageType; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.GroupMessageService; +import com.bx.implatform.util.BeanUtils; +import com.bx.implatform.vo.GroupMessageVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * @author: Blue + * @date: 2024-07-15 + * @version: 1.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@RedisMQListener(queue = RedisKey.IM_QUEUE_GROUP_BANNED) +public class GroupBannedConsumerTask extends RedisMQConsumer { + + private final IMClient imClient; + + private final GroupMessageService groupMessageService; + + private final GroupMemberService groupMemberService; + + @Override + public void onMessage(GroupBanDTO dto) { + log.info("群聊被封禁处理,群id:{},原因:{}", dto.getId(), dto.getReason()); + // 群聊成员列表 + List userIds = groupMemberService.findUserIdsByGroupId(dto.getId()); + // 保存消息 + GroupMessage msg = new GroupMessage(); + msg.setGroupId(dto.getId()); + String tip = "本群聊已被管理员封禁,原因:" + dto.getReason(); + msg.setContent(tip); + msg.setSendId(Constant.SYS_USER_ID); + msg.setSendTime(new Date()); + msg.setStatus(MessageStatus.UNSEND.code()); + msg.setSendNickName("系统管理员"); + msg.setType(MessageType.TIP_TEXT.code()); + groupMessageService.save(msg); + // 推送提示语到群聊中 + GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(Constant.SYS_USER_ID, IMTerminalType.PC.code())); + sendMessage.setRecvIds(userIds); + sendMessage.setSendResult(true); + sendMessage.setSendToSelf(false); + sendMessage.setData(msgInfo); + imClient.sendGroupMessage(sendMessage); + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/task/GroupUnbanConsumerTask.java b/im-platform/src/main/java/com/bx/implatform/task/GroupUnbanConsumerTask.java new file mode 100644 index 0000000..a5adda0 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/task/GroupUnbanConsumerTask.java @@ -0,0 +1,68 @@ +package com.bx.implatform.task; + +import com.bx.imclient.IMClient; +import com.bx.imcommon.enums.IMTerminalType; +import com.bx.imcommon.model.IMGroupMessage; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.imcommon.mq.RedisMQConsumer; +import com.bx.imcommon.mq.RedisMQListener; +import com.bx.implatform.contant.Constant; +import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.dto.GroupUnbanDTO; +import com.bx.implatform.entity.GroupMessage; +import com.bx.implatform.enums.MessageStatus; +import com.bx.implatform.enums.MessageType; +import com.bx.implatform.service.GroupMemberService; +import com.bx.implatform.service.GroupMessageService; +import com.bx.implatform.util.BeanUtils; +import com.bx.implatform.vo.GroupMessageVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * @author: Blue + * @date: 2024-07-15 + * @version: 1.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@RedisMQListener(queue = RedisKey.IM_QUEUE_GROUP_UNBAN) +public class GroupUnbanConsumerTask extends RedisMQConsumer { + + private final IMClient imClient; + + private final GroupMessageService groupMessageService; + + private final GroupMemberService groupMemberService; + + @Override + public void onMessage(GroupUnbanDTO dto) { + log.info("群聊解除封禁处理,群id:{}",dto.getId()); + // 群聊成员列表 + List userIds = groupMemberService.findUserIdsByGroupId(dto.getId()); + // 保存消息 + GroupMessage msg = new GroupMessage(); + msg.setGroupId(dto.getId()); + msg.setContent("已解除封禁"); + msg.setSendId(Constant.SYS_USER_ID); + msg.setSendTime(new Date()); + msg.setStatus(MessageStatus.UNSEND.code()); + msg.setSendNickName("系统管理员"); + msg.setType(MessageType.TIP_TEXT.code()); + groupMessageService.save(msg); + // 推送提示语到群聊中 + GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(Constant.SYS_USER_ID, IMTerminalType.PC.code())); + sendMessage.setRecvIds(userIds); + sendMessage.setSendResult(true); + sendMessage.setSendToSelf(false); + sendMessage.setData(msgInfo); + imClient.sendGroupMessage(sendMessage); + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/task/UserBannedConsumerTask.java b/im-platform/src/main/java/com/bx/implatform/task/UserBannedConsumerTask.java new file mode 100644 index 0000000..4b792fb --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/task/UserBannedConsumerTask.java @@ -0,0 +1,42 @@ +package com.bx.implatform.task; + +import com.bx.imclient.IMClient; +import com.bx.imcommon.model.IMSystemMessage; +import com.bx.imcommon.mq.RedisMQConsumer; +import com.bx.imcommon.mq.RedisMQListener; +import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.dto.UserBanDTO; +import com.bx.implatform.enums.MessageType; +import com.bx.implatform.vo.SystemMessageVO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +/** + * @author: Blue + * @date: 2024-07-15 + * @version: 1.0 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@RedisMQListener(queue = RedisKey.IM_QUEUE_USER_BANNED) +public class UserBannedConsumerTask extends RedisMQConsumer { + + private final IMClient imClient; + @Override + public void onMessage(UserBanDTO dto) { + log.info("用户被封禁处理,userId:{},原因:{}",dto.getId(),dto.getReason()); + // 推送消息将用户赶下线 + SystemMessageVO msgInfo = new SystemMessageVO(); + msgInfo.setType(MessageType.USER_BANNED.code()); + msgInfo.setContent(dto.getReason()); + IMSystemMessage sendMessage = new IMSystemMessage<>(); + sendMessage.setRecvIds(Collections.singletonList(dto.getId())); + sendMessage.setData(msgInfo); + sendMessage.setSendResult(true); + imClient.sendSystemMessage(sendMessage); + } +} diff --git a/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java b/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java index 70614df..455ea23 100644 --- a/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java +++ b/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java @@ -13,9 +13,6 @@ import java.util.Date; */ public final class DateTimeUtils extends DateUtils { - private DateTimeUtils() { - } - public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String PARTDATEFORMAT = "yyyyMMdd"; diff --git a/im-platform/src/main/java/com/bx/implatform/util/FileUtil.java b/im-platform/src/main/java/com/bx/implatform/util/FileUtil.java index 5e3a2f9..78d2ab6 100644 --- a/im-platform/src/main/java/com/bx/implatform/util/FileUtil.java +++ b/im-platform/src/main/java/com/bx/implatform/util/FileUtil.java @@ -2,8 +2,6 @@ package com.bx.implatform.util; public final class FileUtil { - private FileUtil() { - } /** * 获取文件后缀 diff --git a/im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java b/im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java index 159dbea..5c08170 100644 --- a/im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java +++ b/im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java @@ -9,9 +9,6 @@ import java.io.ByteArrayOutputStream; @Slf4j public final class ImageUtil { - private ImageUtil() { - } - //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值 private static final Integer ZERO = 0; private static final Integer ONE_ZERO_TWO_FOUR = 1024; diff --git a/im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java b/im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java index bad68c1..0491c14 100644 --- a/im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java +++ b/im-platform/src/main/java/com/bx/implatform/util/SensitiveFilterUtil.java @@ -1,29 +1,30 @@ package com.bx.implatform.util; -import lombok.NoArgsConstructor; +import cn.hutool.core.util.StrUtil; +import com.bx.imcommon.util.ThreadPoolExecutorFactory; +import com.bx.implatform.service.SensitiveWordService; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * 敏感词过滤器——SensitiveFilter * * @author Andrews * @date 2023/12/4 11:12 - * @return null */ @Slf4j @Component -@NoArgsConstructor +@RequiredArgsConstructor public final class SensitiveFilterUtil { /** @@ -36,12 +37,19 @@ public final class SensitiveFilterUtil { */ private static final TrieNode ROOT_NODE = new TrieNode(); + /** + * 线程池 + */ + private static final ScheduledThreadPoolExecutor EXECUTOR_SERVICE = + ThreadPoolExecutorFactory.getThreadPoolExecutor(); + + private final SensitiveWordService sensitiveWordService; + /** * 1、 前缀树 前缀树某一个节点 * * @author NXY * @date 2023/12/4 11:17 - * @return null */ private static class TrieNode { // 关键词结束标识 @@ -79,18 +87,16 @@ public final class SensitiveFilterUtil { */ @PostConstruct public void init() { - try { - // 类加载器 - InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - String keyword; - while ((keyword = reader.readLine()) != null) { - // 添加到前缀树 - this.addKeyword(keyword); - } - } catch (IOException e) { - log.error("加载敏感词文件失败: " + e.getMessage()); - } + // 每120s装载一次敏感词 + EXECUTOR_SERVICE.scheduleAtFixedRate(() -> { + List keywords = sensitiveWordService.findAllEnabledWords(); + keywords.forEach(keyword->{ + if(StrUtil.isNotEmpty(keyword)){ + // 添加到前缀树 + addKeyword(keyword); + } + }); + },0,120, TimeUnit.SECONDS); } /** @@ -189,10 +195,9 @@ public final class SensitiveFilterUtil { /** * 判断是否为符号 ——特殊符号 * - * @param c - * @return boolean * @author NXY * @date 2023/12/4 11:17 + * @return boolean */ private boolean isSymbol(Character c) { // 0x2E80~0x9FFF 是东亚文字范围 diff --git a/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java b/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java index 7a580c1..7b40fb4 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java @@ -1,24 +1,22 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotNull; - @Data -@ApiModel("好友信息VO") +@Schema(description = "好友信息VO") public class FriendVO { @NotNull(message = "好友id不可为空") - @ApiModelProperty(value = "好友id") + @Schema(description = "好友id") private Long id; @NotNull(message = "好友昵称不可为空") - @ApiModelProperty(value = "好友昵称") + @Schema(description = "好友昵称") private String nickName; - @ApiModelProperty(value = "好友头像") + @Schema(description = "好友头像") private String headImage; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupInviteVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupInviteVO.java index 1d1f38d..7c86962 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupInviteVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupInviteVO.java @@ -1,22 +1,21 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; import java.util.List; @Data -@ApiModel("邀请好友进群请求VO") +@Schema(description = "邀请好友进群请求VO") public class GroupInviteVO { @NotNull(message = "群id不可为空") - @ApiModelProperty(value = "群id") + @Schema(description = "群id") private Long groupId; @NotEmpty(message = "群id不可为空") - @ApiModelProperty(value = "好友id列表不可为空") + @Schema(description = "好友id列表不可为空") private List friendIds; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java index f4db9ae..fd2a876 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java @@ -1,29 +1,34 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -@ApiModel("群成员信息VO") +@Schema(description = "群成员信息VO") public class GroupMemberVO { - @ApiModelProperty("用户id") + @Schema(description = "用户id") private Long userId; - @ApiModelProperty("群内显示名称") - private String aliasName; + @Schema(description = "群内显示名称") + private String showNickName; - @ApiModelProperty("头像") + @Schema(description = "群内昵称备注") + private String remarkNickName; + + @Schema(description = "头像") private String headImage; - @ApiModelProperty("是否已退出") + @Schema(description = "是否已退出") private Boolean quit; - @ApiModelProperty(value = "是否在线") + @Schema(description = "是否在线") private Boolean online; - @ApiModelProperty("备注") - private String remark; + @Schema(description = "群名显示名称") + private String showGroupName; + + @Schema(description = "群名备注") + private String remarkGroupName; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java index 377fd8a..ea41bde 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java @@ -2,8 +2,7 @@ package com.bx.implatform.vo; import com.bx.imcommon.serializer.DateToLongSerializer; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.swagger.annotations.ApiModelProperty; -import io.swagger.models.auth.In; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @@ -12,40 +11,40 @@ import java.util.List; @Data public class GroupMessageVO { - @ApiModelProperty(value = "消息id") + @Schema(description = "消息id") private Long id; - @ApiModelProperty(value = "群聊id") + @Schema(description = "群聊id") private Long groupId; - @ApiModelProperty(value = " 发送者id") + @Schema(description = " 发送者id") private Long sendId; - @ApiModelProperty(value = " 发送者昵称") + @Schema(description = " 发送者昵称") private String sendNickName; - @ApiModelProperty(value = "消息内容") + @Schema(description = "消息内容") private String content; - @ApiModelProperty(value = "消息内容类型 具体枚举值由应用层定义") + @Schema(description = "消息内容类型 具体枚举值由应用层定义") private Integer type; - @ApiModelProperty(value = "是否回执消息") + @Schema(description = "是否回执消息") private Boolean receipt; - @ApiModelProperty(value = "回执消息是否完成") + @Schema(description = "回执消息是否完成") private Boolean receiptOk; - @ApiModelProperty(value = "已读消息数量") + @Schema(description = "已读消息数量") private Integer readedCount = 0; - @ApiModelProperty(value = "@用户列表") + @Schema(description = "@用户列表") private List atUserIds; - @ApiModelProperty(value = " 状态") + @Schema(description = " 状态") private Integer status; - @ApiModelProperty(value = "发送时间") + @Schema(description = "发送时间") @JsonSerialize(using = DateToLongSerializer.class) private Date sendTime; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java index cbbbf14..002c4c4 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java @@ -1,50 +1,53 @@ package com.bx.implatform.vo; -import com.baomidou.mybatisplus.annotation.TableField; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; import lombok.Data; import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; - @Data -@ApiModel("群信息VO") +@Schema(description = "群信息VO") public class GroupVO { - @ApiModelProperty(value = "群id") + @Schema(description = "群id") private Long id; @Length(max = 20, message = "群名称长度不能大于20") @NotEmpty(message = "群名称不可为空") - @ApiModelProperty(value = "群名称") + @Schema(description = "群名称") private String name; - @ApiModelProperty(value = "群主id") + @Schema(description = "群主id") private Long ownerId; - @ApiModelProperty(value = "头像") + @Schema(description = "头像") private String headImage; - @ApiModelProperty(value = "头像缩略图") + @Schema(description = "头像缩略图") private String headImageThumb; @Length(max = 1024, message = "群聊显示长度不能大于1024") - @ApiModelProperty(value = "群公告") + @Schema(description = "群公告") private String notice; - @Length(max = 20, message = "群聊显示长度不能大于20") - @ApiModelProperty(value = "用户在群显示昵称") - private String aliasName; + @Length(max = 20, message = "显示昵称长度不能大于20") + @Schema(description = "用户在群显示昵称") + private String remarkNickName; + + @Schema(description = "群内显示名称") + private String showNickName; + + @Schema(description = "群名显示名称") + private String showGroupName; - @Length(max = 20, message = "群聊显示长度不能大于20") - @ApiModelProperty(value = "群聊显示备注") - private String remark; + @Length(max = 20, message = "群备注长度不能大于20") + @Schema(description = "群名备注") + private String remarkGroupName; - @ApiModelProperty(value = "是否已删除") + @Schema(description = "是否已删除") private Boolean deleted; - @ApiModelProperty(value = "是否已退出") + @Schema(description = "是否已退出") private Boolean quit; diff --git a/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java b/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java index 1b765bc..ba9f9a2 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java @@ -1,23 +1,22 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -@ApiModel("用户登录VO") +@Schema(description = "用户登录VO") public class LoginVO { - @ApiModelProperty(value = "每次请求都必须在header中携带accessToken") + @Schema(description = "每次请求都必须在header中携带accessToken") private String accessToken; - @ApiModelProperty(value = "accessToken过期时间(秒)") + @Schema(description = "accessToken过期时间(秒)") private Integer accessTokenExpiresIn; - @ApiModelProperty(value = "accessToken过期后,通过refreshToken换取新的token") + @Schema(description = "accessToken过期后,通过refreshToken换取新的token") private String refreshToken; - @ApiModelProperty(value = "refreshToken过期时间(秒)") + @Schema(description = "refreshToken过期时间(秒)") private Integer refreshTokenExpiresIn; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/OnlineTerminalVO.java b/im-platform/src/main/java/com/bx/implatform/vo/OnlineTerminalVO.java index 67e5413..da40ec6 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/OnlineTerminalVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/OnlineTerminalVO.java @@ -1,6 +1,6 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; @@ -15,10 +15,10 @@ import java.util.List; @AllArgsConstructor public class OnlineTerminalVO { - @ApiModelProperty(value = "用户id") + @Schema(description = "用户id") private Long userId; - @ApiModelProperty(value = "在线终端类型") + @Schema(description = "在线终端类型") private List terminals; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java index c8ea8a5..608e854 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java @@ -2,35 +2,34 @@ package com.bx.implatform.vo; import com.bx.imcommon.serializer.DateToLongSerializer; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.Date; @Data -@ApiModel("私聊消息VO") +@Schema(description = "私聊消息VO") public class PrivateMessageVO { - @ApiModelProperty(value = " 消息id") + @Schema(description = " 消息id") private Long id; - @ApiModelProperty(value = " 发送者id") + @Schema(description = " 发送者id") private Long sendId; - @ApiModelProperty(value = " 接收者id") + @Schema(description = " 接收者id") private Long recvId; - @ApiModelProperty(value = " 发送内容") + @Schema(description = " 发送内容") private String content; - @ApiModelProperty(value = "消息内容类型 IMCmdType") + @Schema(description = "消息内容类型 IMCmdType") private Integer type; - @ApiModelProperty(value = " 状态") + @Schema(description = " 状态") private Integer status; - @ApiModelProperty(value = " 发送时间") + @Schema(description = " 发送时间") @JsonSerialize(using = DateToLongSerializer.class) private Date sendTime; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/SystemConfigVO.java b/im-platform/src/main/java/com/bx/implatform/vo/SystemConfigVO.java index f8e936e..aa92709 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/SystemConfigVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/SystemConfigVO.java @@ -1,8 +1,7 @@ package com.bx.implatform.vo; import com.bx.implatform.config.WebrtcConfig; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; @@ -12,11 +11,11 @@ import lombok.Data; * @version: 1.0 */ @Data -@ApiModel("系统配置VO") +@Schema(description = "系统配置VO") @AllArgsConstructor public class SystemConfigVO { - @ApiModelProperty(value = "webrtc配置") + @Schema(description = "webrtc配置") private WebrtcConfig webrtc; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/SystemMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/SystemMessageVO.java new file mode 100644 index 0000000..d1ee164 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/vo/SystemMessageVO.java @@ -0,0 +1,26 @@ +package com.bx.implatform.vo; + +import com.bx.imcommon.serializer.DateToLongSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Date; + +@Data +@Schema(description = "系统消息VO") +public class SystemMessageVO { + + @Schema(description = " 消息id") + private Long id; + + @Schema(description = " 发送内容") + private String content; + + @Schema(description = "消息内容类型 MessageType") + private Integer type; + + @Schema(description = " 发送时间") + @JsonSerialize(using = DateToLongSerializer.class) + private Date sendTime; +} diff --git a/im-platform/src/main/java/com/bx/implatform/vo/UploadImageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/UploadImageVO.java index 3c63709..f58114f 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/UploadImageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/UploadImageVO.java @@ -1,16 +1,15 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data -@ApiModel("图片上传VO") +@Schema(description = "图片上传VO") public class UploadImageVO { - @ApiModelProperty(value = "原图") + @Schema(description = "原图") private String originUrl; - @ApiModelProperty(value = "缩略图") + @Schema(description = "缩略图") private String thumbUrl; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java b/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java index f44d5aa..ae8345b 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java @@ -1,48 +1,46 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import lombok.Data; import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; - @Data -@ApiModel("用户信息VO") +@Schema(description = "用户信息VO") public class UserVO { @NotNull(message = "用户id不能为空") - @ApiModelProperty(value = "id") + @Schema(description = "id") private Long id; @NotEmpty(message = "用户名不能为空") @Length(max = 64, message = "用户名不能大于64字符") - @ApiModelProperty(value = "用户名") + @Schema(description = "用户名") private String userName; @NotEmpty(message = "用户昵称不能为空") @Length(max = 64, message = "昵称不能大于64字符") - @ApiModelProperty(value = "用户昵称") + @Schema(description = "用户昵称") private String nickName; - @ApiModelProperty(value = "性别") + @Schema(description = "性别") private Integer sex; - @ApiModelProperty(value = "用户类型 1:普通用户 2:审核账户") + @Schema(description = "用户类型 1:普通用户 2:审核账户") private Integer type; @Length(max = 1024, message = "个性签名不能大于1024个字符") - @ApiModelProperty(value = "个性签名") + @Schema(description = "个性签名") private String signature; - @ApiModelProperty(value = "头像") + @Schema(description = "头像") private String headImage; - @ApiModelProperty(value = "头像缩略图") + @Schema(description = "头像缩略图") private String headImageThumb; - @ApiModelProperty(value = "是否在线") + @Schema(description = "是否在线") private Boolean online; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupFailedVO.java b/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupFailedVO.java index 5c7b988..7cd4482 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupFailedVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupFailedVO.java @@ -1,7 +1,6 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @@ -12,12 +11,12 @@ import java.util.List; * @version: 1.0 */ @Data -@ApiModel("用户加入群通话失败VO") +@Schema(description = "用户加入群通话失败VO") public class WebrtcGroupFailedVO { - @ApiModelProperty(value = "失败用户列表") + @Schema(description = "失败用户列表") private List userIds; - @ApiModelProperty(value = "失败原因") + @Schema(description = "失败原因") private String reason; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupInfoVO.java b/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupInfoVO.java index bf27527..7bed11f 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupInfoVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/WebrtcGroupInfoVO.java @@ -1,8 +1,7 @@ package com.bx.implatform.vo; import com.bx.implatform.session.WebrtcUserInfo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @@ -13,16 +12,16 @@ import java.util.List; * @version: 1.0 */ @Data -@ApiModel("群通话信息VO") +@Schema(description = "群通话信息VO") public class WebrtcGroupInfoVO { - @ApiModelProperty(value = "是否在通话中") + @Schema(description = "是否在通话中") private Boolean isChating; - @ApiModelProperty(value = "通话发起人") + @Schema(description = "通话发起人") WebrtcUserInfo host; - @ApiModelProperty(value = "通话用户列表") + @Schema(description = "通话用户列表") private List userInfos; } diff --git a/im-platform/src/main/resources/application-dev.yml b/im-platform/src/main/resources/application-dev.yml new file mode 100644 index 0000000..21e0cee --- /dev/null +++ b/im-platform/src/main/resources/application-dev.yml @@ -0,0 +1,28 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/im_platform?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: root + data: + redis: + host: localhost + port: 6379 + database: 1 + +minio: + endpoint: http://127.0.0.1:9000 #内网地址 + public: http://127.0.0.1:9000 #外网访问地址 + accessKey: minioadmin + secretKey: minioadmin + bucketName: box-im + imagePath: image + filePath: file + videoPath: video + +webrtc: + max-channel: 9 # 多人通话最大通道数量,最大不能超过16,建议值:4,9,16 + iceServers: + - urls: stun:stun.l.google.com:19302 + + diff --git a/im-platform/src/main/resources/application-prod.yml b/im-platform/src/main/resources/application-prod.yml new file mode 100644 index 0000000..cec86c0 --- /dev/null +++ b/im-platform/src/main/resources/application-prod.yml @@ -0,0 +1,32 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/im_platform?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: naQRLdDPbGv2j7PX_ + data: + redis: + host: localhost + port: 6379 + password: PmEpfRjpBnTN6CgW + +minio: + endpoint: http://127.0.0.1:9001 #内网地址 + public: https://www.boxim.online/file #外网访问地址 + accessKey: admin + secretKey: 3fBSt6AkgFuD77D6 + bucketName: box-im + imagePath: image + filePath: file + videoPath: video + +webrtc: + max-channel: 9 # 多人通话最大通道数量,最大不能超过16,建议值:4,9,16 + iceServers: #coturn配置 + - urls: stun:www.boxim.online:3478 + username: admin + credential: UrHHKNvE7nFvBTMV + - urls: turn:www.boxim.online:3478 + username: admin + credential: UrHHKNvE7nFvBTMV + diff --git a/im-platform/src/main/resources/application-test.yml b/im-platform/src/main/resources/application-test.yml new file mode 100644 index 0000000..8b8cc83 --- /dev/null +++ b/im-platform/src/main/resources/application-test.yml @@ -0,0 +1,31 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/im_platform?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true + username: root + password: naQRLdDPbGv2j7PX_ + data: + redis: + host: localhost + port: 6379 + password: PmEpfRjpBnTN6CgW + +minio: + endpoint: http://127.0.0.1:9001 #内网地址 + public: https://www.boxim.online/file #外网访问地址 + accessKey: admin + secretKey: 3fBSt6AkgFuD77D6 + bucketName: box-im + imagePath: image + filePath: file + videoPath: video + +webrtc: + max-channel: 9 # 多人通话最大通道数量,最大不能超过16,建议值:4,9,16 + iceServers: #coturn配置 + - urls: stun:www.boxim.online:3478 + username: admin + credential: UrHHKNvE7nFvBTMV + - urls: turn:www.boxim.online:3478 + username: admin + credential: UrHHKNvE7nFvBTMV diff --git a/im-platform/src/main/resources/application.yml b/im-platform/src/main/resources/application.yml index 8e0cbe8..ae5abb0 100644 --- a/im-platform/src/main/resources/application.yml +++ b/im-platform/src/main/resources/application.yml @@ -1,47 +1,25 @@ server: port: 8888 spring: + profiles: + active: dev # 环境 dev|test|prod application: name: im-platform mvc: pathmatch: matching-strategy: ant_path_matcher - datasource: - driver-class-name: com.mysql.jdbc.Driver - url: jdbc:mysql://localhost:3306/box-im?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true - username: root - password: root - - redis: - host: 127.0.0.1 - port: 6379 - servlet: multipart: max-file-size: 50MB max-request-size: 50MB mybatis-plus: + global-config: + db-config: + id-type: AUTO # ID自增 configuration: - # 是否开启自动驼峰命名规则 - map-underscore-to-camel-case: false + map-underscore-to-camel-case: true #开启自动驼峰命名规则 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - mapper-locations: - - classpath*:mapper/*.xml -minio: - endpoint: http://127.0.0.1:9001 #内网地址 - public: http://127.0.0.1:9001 #外网访问地址 - accessKey: admin - secretKey: 12345678 - bucketName: box-im - imagePath: image - filePath: file - videoPath: video - -webrtc: - max-channel: 9 # 多人通话最大通道数量,最大不能超过16,建议值:4,9,16 - iceServers: - - urls: stun:stun.l.google.com:19302 jwt: accessToken: @@ -51,3 +29,5 @@ jwt: expireIn: 604800 #7天 secret: IKDiqVmn0VFU + + diff --git a/im-platform/src/main/resources/logback.xml b/im-platform/src/main/resources/logback.xml new file mode 100644 index 0000000..a1084bb --- /dev/null +++ b/im-platform/src/main/resources/logback.xml @@ -0,0 +1,48 @@ + + + + + + + + info + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${LOG_PATH}/${APP_NAME}.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${LOG_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/im-platform/src/main/resources/sensitive-words.txt b/im-platform/src/main/resources/sensitive-words.txt deleted file mode 100644 index 59cac85..0000000 --- a/im-platform/src/main/resources/sensitive-words.txt +++ /dev/null @@ -1,3 +0,0 @@ -杀了你 -傻逼 -去死 \ No newline at end of file diff --git a/im-ui/public/logo.png b/im-platform/src/main/resources/static/favicon.ico similarity index 100% rename from im-ui/public/logo.png rename to im-platform/src/main/resources/static/favicon.ico diff --git a/im-server/pom.xml b/im-server/pom.xml index e5d0e78..2e6edbf 100644 --- a/im-server/pom.xml +++ b/im-server/pom.xml @@ -5,7 +5,7 @@ box-im com.bx - 2.0.0 + 3.0.0 4.0.0 @@ -16,31 +16,20 @@ com.bx im-commom - 2.0.0 - - - org.springframework.boot - spring-boot + 3.0.0 io.netty netty-all 4.1.42.Final - - - org.springframework.boot - spring-boot-starter-data-redis - - ${project.artifactId} org.springframework.boot spring-boot-maven-plugin - 2.0.3.RELEASE diff --git a/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java b/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java deleted file mode 100644 index 844cdf5..0000000 --- a/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.bx.imserver.config; - -import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(redisConnectionFactory); - // 设置值(value)的序列化采用FastJsonRedisSerializer - redisTemplate.setValueSerializer(fastJsonRedisSerializer()); - redisTemplate.setHashValueSerializer(fastJsonRedisSerializer()); - // 设置键(key)的序列化采用StringRedisSerializer。 - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashKeySerializer(new StringRedisSerializer()); - redisTemplate.afterPropertiesSet(); - return redisTemplate; - } - - - public FastJsonRedisSerializer fastJsonRedisSerializer() { - return new FastJsonRedisSerializer<>(Object.class); - } - - -} diff --git a/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java b/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java index c498fd1..1498d18 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java +++ b/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java @@ -1,13 +1,13 @@ package com.bx.imserver.netty; import com.bx.imcommon.contant.IMRedisKey; +import jakarta.annotation.PreDestroy; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import javax.annotation.PreDestroy; import java.util.List; @Slf4j @@ -17,7 +17,7 @@ public class IMServerGroup implements CommandLineRunner { public static volatile long serverId = 0; - RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; private final List imServers; @@ -36,7 +36,7 @@ public class IMServerGroup implements CommandLineRunner { } @Override - public void run(String... args) throws Exception { + public void run(String... args) { // 初始化SERVER_ID String key = IMRedisKey.IM_MAX_SERVER_ID; serverId = redisTemplate.opsForValue().increment(key, 1); diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java index eb75f17..6f62d91 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java @@ -13,10 +13,10 @@ import io.netty.channel.ChannelHandlerContext; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.List; +import java.util.Objects; @Slf4j @Component @@ -33,7 +33,7 @@ public class GroupMessageProcessor extends AbstractMessageProcessor for (IMUserInfo receiver : receivers) { try { ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(), receiver.getTerminal()); - if (channelCtx != null) { + if (!Objects.isNull(channelCtx)) { // 推送消息到用户 IMSendInfo sendInfo = new IMSendInfo(); sendInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java index 26803c5..3cae629 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java @@ -15,6 +15,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; +import java.util.Objects; + @Slf4j @Component @RequiredArgsConstructor @@ -26,10 +28,10 @@ public class PrivateMessageProcessor extends AbstractMessageProcessor sendInfo = new IMSendInfo<>(); sendInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code()); diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java b/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java index 72aeb98..117334c 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java @@ -20,6 +20,9 @@ public class ProcessorFactory { case GROUP_MESSAGE: processor = SpringContextHolder.getApplicationContext().getBean(GroupMessageProcessor.class); break; + case SYSTEM_MESSAGE: + processor = SpringContextHolder.getApplicationContext().getBean(SystemMessageProcessor.class); + break; default: break; } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/SystemMessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/SystemMessageProcessor.java new file mode 100644 index 0000000..2020252 --- /dev/null +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/SystemMessageProcessor.java @@ -0,0 +1,65 @@ +package com.bx.imserver.netty.processor; + +import cn.hutool.core.util.StrUtil; +import com.bx.imcommon.contant.IMRedisKey; +import com.bx.imcommon.enums.IMCmdType; +import com.bx.imcommon.enums.IMSendCode; +import com.bx.imcommon.model.IMRecvInfo; +import com.bx.imcommon.model.IMSendInfo; +import com.bx.imcommon.model.IMSendResult; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.imserver.netty.UserChannelCtxMap; +import io.netty.channel.ChannelHandlerContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SystemMessageProcessor extends AbstractMessageProcessor { + + private final RedisTemplate redisTemplate; + + @Override + public void process(IMRecvInfo recvInfo) { + IMUserInfo receiver = recvInfo.getReceivers().get(0); + log.info("接收到系统消息,接收者:{},内容:{}", receiver.getId(), recvInfo.getData()); + try { + ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(), receiver.getTerminal()); + if (!Objects.isNull(channelCtx)) { + // 推送消息到用户 + IMSendInfo sendInfo = new IMSendInfo<>(); + sendInfo.setCmd(IMCmdType.SYSTEM_MESSAGE.code()); + sendInfo.setData(recvInfo.getData()); + channelCtx.channel().writeAndFlush(sendInfo); + // 消息发送成功确认 + sendResult(recvInfo, IMSendCode.SUCCESS); + } else { + // 消息推送失败确认 + sendResult(recvInfo, IMSendCode.NOT_FIND_CHANNEL); + log.error("未找到channel,接收者:{},内容:{}",receiver.getId(), recvInfo.getData()); + } + } catch (Exception e) { + // 消息推送失败确认 + sendResult(recvInfo, IMSendCode.UNKONW_ERROR); + log.error("发送异常,,接收者:{},内容:{}", receiver.getId(), recvInfo.getData(), e); + } + + } + + private void sendResult(IMRecvInfo recvInfo, IMSendCode sendCode) { + if (recvInfo.getSendResult()) { + IMSendResult result = new IMSendResult<>(); + result.setReceiver(recvInfo.getReceivers().get(0)); + result.setCode(sendCode.code()); + result.setData(recvInfo.getData()); + // 推送到结果队列 + String key = StrUtil.join(":",IMRedisKey.IM_RESULT_SYSTEM_QUEUE,recvInfo.getServiceName()); + redisTemplate.opsForList().rightPush(key, result); + } + } +} diff --git a/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java index 6752869..c6b2290 100644 --- a/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java +++ b/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java @@ -1,49 +1,23 @@ package com.bx.imserver.task; -import com.bx.imcommon.util.ThreadPoolExecutorFactory; +import com.bx.imcommon.mq.RedisMQConsumer; import com.bx.imserver.netty.IMServerGroup; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; - -import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; @Slf4j -public abstract class AbstractPullMessageTask implements CommandLineRunner { - - private static final ExecutorService EXECUTOR_SERVICE = ThreadPoolExecutorFactory.getThreadPoolExecutor(); +public abstract class AbstractPullMessageTask extends RedisMQConsumer { @Autowired private IMServerGroup serverGroup; @Override - public void run(String... args) { - EXECUTOR_SERVICE.execute(new Runnable() { - @SneakyThrows - @Override - public void run() { - try { - if (serverGroup.isReady()) { - pullMessage(); - } - } catch (Exception e) { - log.error("任务调度异常", e); - } - if (!EXECUTOR_SERVICE.isShutdown()) { - Thread.sleep(100); - EXECUTOR_SERVICE.execute(this); - } - } - }); + public String generateKey() { + return String.join(":", super.generateKey(), IMServerGroup.serverId + ""); } - @PreDestroy - public void destroy() { - log.info("{}线程任务关闭", this.getClass().getSimpleName()); - EXECUTOR_SERVICE.shutdown(); + @Override + public Boolean isReady() { + return serverGroup.isReady(); } - - public abstract void pullMessage() throws InterruptedException; } diff --git a/im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java index 6d8e83f..2d0db6b 100644 --- a/im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java +++ b/im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java @@ -1,38 +1,25 @@ package com.bx.imserver.task; -import com.alibaba.fastjson.JSONObject; import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.model.IMRecvInfo; -import com.bx.imserver.netty.IMServerGroup; +import com.bx.imcommon.mq.RedisMQListener; import com.bx.imserver.netty.processor.AbstractMessageProcessor; import com.bx.imserver.netty.processor.ProcessorFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import java.util.Objects; - @Slf4j @Component @RequiredArgsConstructor -public class PullGroupMessageTask extends AbstractPullMessageTask { - - private final RedisTemplate redisTemplate; +@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_GROUP_QUEUE, batchSize = 10) +public class PullGroupMessageTask extends AbstractPullMessageTask { @Override - public void pullMessage() { - // 从redis拉取未读消息 - String key = String.join(":", IMRedisKey.IM_MESSAGE_GROUP_QUEUE, IMServerGroup.serverId + ""); - JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - while (!Objects.isNull(jsonObject)) { - IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class); - AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); - processor.process(recvInfo); - // 下一条消息 - jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - } + public void onMessage(IMRecvInfo recvInfo) { + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); + processor.process(recvInfo); } } diff --git a/im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java index 5edd0d6..b9b3545 100644 --- a/im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java +++ b/im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java @@ -1,37 +1,25 @@ package com.bx.imserver.task; -import com.alibaba.fastjson.JSONObject; import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.model.IMRecvInfo; -import com.bx.imserver.netty.IMServerGroup; +import com.bx.imcommon.mq.RedisMQListener; import com.bx.imserver.netty.processor.AbstractMessageProcessor; import com.bx.imserver.netty.processor.ProcessorFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import java.util.Objects; - @Slf4j @Component @RequiredArgsConstructor -public class PullPrivateMessageTask extends AbstractPullMessageTask { - - private final RedisTemplate redisTemplate; +@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, batchSize = 10) +public class PullPrivateMessageTask extends AbstractPullMessageTask { @Override - public void pullMessage() { - // 从redis拉取未读消息 - String key = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, IMServerGroup.serverId + ""); - JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - while (!Objects.isNull(jsonObject)) { - IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class); - AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE); - processor.process(recvInfo); - // 下一条消息 - jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key); - } + public void onMessage(IMRecvInfo recvInfo) { + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE); + processor.process(recvInfo); } + } diff --git a/im-server/src/main/java/com/bx/imserver/task/PullSystemMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/PullSystemMessageTask.java new file mode 100644 index 0000000..c1d6a2b --- /dev/null +++ b/im-server/src/main/java/com/bx/imserver/task/PullSystemMessageTask.java @@ -0,0 +1,28 @@ +package com.bx.imserver.task; + +import com.bx.imcommon.contant.IMRedisKey; +import com.bx.imcommon.enums.IMCmdType; +import com.bx.imcommon.model.IMRecvInfo; +import com.bx.imcommon.mq.RedisMQListener; +import com.bx.imserver.netty.processor.AbstractMessageProcessor; +import com.bx.imserver.netty.processor.ProcessorFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author: Blue + * @date: 2024-07-16 + * @version: 1.0 + */ +@Slf4j +@Component +@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE,batchSize = 10) +public class PullSystemMessageTask extends AbstractPullMessageTask { + + @Override + public void onMessage(IMRecvInfo recvInfo) { + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.SYSTEM_MESSAGE); + processor.process(recvInfo); + } + +} diff --git a/im-server/src/main/resources/application-dev.yml b/im-server/src/main/resources/application-dev.yml new file mode 100644 index 0000000..305d30c --- /dev/null +++ b/im-server/src/main/resources/application-dev.yml @@ -0,0 +1,7 @@ +spring: + data: + redis: + host: 127.0.0.1 + port: 6379 + database: 1 + diff --git a/im-server/src/main/resources/application-prod.yml b/im-server/src/main/resources/application-prod.yml new file mode 100644 index 0000000..79724c4 --- /dev/null +++ b/im-server/src/main/resources/application-prod.yml @@ -0,0 +1,6 @@ +spring: + data: + redis: + host: 127.0.0.1 + port: 6379 + password: PmEpfRjpBnTN6CgW \ No newline at end of file diff --git a/im-server/src/main/resources/application-test.yml b/im-server/src/main/resources/application-test.yml new file mode 100644 index 0000000..79724c4 --- /dev/null +++ b/im-server/src/main/resources/application-test.yml @@ -0,0 +1,6 @@ +spring: + data: + redis: + host: 127.0.0.1 + port: 6379 + password: PmEpfRjpBnTN6CgW \ No newline at end of file diff --git a/im-server/src/main/resources/application.yml b/im-server/src/main/resources/application.yml index 827343d..9b47335 100644 --- a/im-server/src/main/resources/application.yml +++ b/im-server/src/main/resources/application.yml @@ -1,7 +1,8 @@ spring: - redis: - host: 127.0.0.1 - port: 6379 + profiles: + active: dev + application: + name: im-server websocket: enable: true @@ -13,4 +14,4 @@ tcpsocket: jwt: accessToken: - secret: MIIBIjANBgkq # 跟im-platfrom的secret必须一致 \ No newline at end of file + secret: MIIBIjANBgkq # 跟im-platfrom的secret必须一致 diff --git a/im-server/src/main/resources/logback.xml b/im-server/src/main/resources/logback.xml new file mode 100644 index 0000000..ede4d60 --- /dev/null +++ b/im-server/src/main/resources/logback.xml @@ -0,0 +1,48 @@ + + + + + + + + info + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + + ${LOG_PATH}/${APP_NAME}.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + UTF-8 + + + ${LOG_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.%i.log + 100MB + 60 + 20GB + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/im-ui/.gitignore b/im-ui/.gitignore deleted file mode 100644 index 0b0371a..0000000 --- a/im-ui/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -.DS_Store -node_modules -/dist - - -# local env files -.env.local -.env.*.local - -# Log files -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* - -# Editor directories and files -.idea -.vscode -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -# -package-lock.json diff --git a/im-uniapp/.env.js b/im-uniapp/.env.js index 493d3b4..b6b9ff4 100644 --- a/im-uniapp/.env.js +++ b/im-uniapp/.env.js @@ -11,6 +11,6 @@ if(ENV=="DEV"){ } if(ENV=="PROD"){ UNI_APP.BASE_URL = "https://www.boxim.online/api"; - UNI_APP.WS_URL = "wss://www.boxim.online:81/im"; + UNI_APP.WS_URL = "wss://www.boxim.online/im"; } export default UNI_APP \ No newline at end of file diff --git a/im-uniapp/App.vue b/im-uniapp/App.vue index bd7e7d9..98a8802 100644 --- a/im-uniapp/App.vue +++ b/im-uniapp/App.vue @@ -9,12 +9,14 @@ export default { data() { return { + isExit: false, // 是否已退出 audioTip: null, reconnecting: false // 正在重连标志 } }, methods: { init() { + this.isExit = false; // 加载数据 store.dispatch("load").then(() => { // 初始化websocket @@ -30,7 +32,7 @@ wsApi.connect(UNI_APP.WS_URL, loginInfo.accessToken); wsApi.onConnect(() => { // 重连成功提示 - if(this.reconnecting){ + if (this.reconnecting) { this.reconnecting = false; uni.showToast({ title: "已重新连接", @@ -55,15 +57,16 @@ } else if (cmd == 4) { // 群聊消息 this.handleGroupMessage(msgInfo); + } else if (cmd == 5) { + // 系统消息 + this.handleSystemMessage(msgInfo); } }); wsApi.onClose((res) => { console.log("ws断开", res); - // 3099是客户端正常主动关闭 - if (res.code != 3099) { - // 重新连接 - this.reconnectWs(); - } + // 重新连接 + this.reconnectWs(); + }) }, pullPrivateOfflineMessage(minId) { @@ -189,7 +192,17 @@ // 插入群聊消息 this.insertGroupMessage(group, msg); }) - + }, + handleSystemMessage(msg) { + if (msg.type == enums.MESSAGE_TYPE.USER_BANNED) { + // 用户被封禁 + wsApi.close(3099); + uni.showModal({ + content: '您的账号已被管理员封禁,原因:' + msg.content, + showCancel: false, + }) + this.exit(); + } }, insertGroupMessage(group, msg) { // 群视频信令 @@ -224,7 +237,7 @@ let chatInfo = { type: 'GROUP', targetId: group.id, - showName: group.remark, + showName: group.showGroupName, headImage: group.headImageThumb }; // 打开会话 @@ -268,6 +281,7 @@ }, exit() { console.log("exit"); + this.isExit = true; wsApi.close(3099); uni.removeStorageSync("loginInfo"); uni.reLaunch({ @@ -288,6 +302,10 @@ return loginInfo.expireTime < new Date().getTime(); }, reconnectWs() { + // 已退出则不再重连 + if (this.isExit) { + return; + } // 记录标志 this.reconnecting = true; // 重新加载一次个人信息,目的是为了保证网络已经正常且token有效 @@ -302,9 +320,9 @@ wsApi.reconnect(UNI_APP.WS_URL, loginInfo.accessToken); }).catch(() => { // 5s后重试 - setTimeout(()=>{ + setTimeout(() => { this.reconnectWs(); - },5000) + }, 5000) }) }, reloadUserInfo() { @@ -338,11 +356,18 @@ \ No newline at end of file diff --git a/im-uniapp/common/enums.js b/im-uniapp/common/enums.js index 6dddc3b..d6f0c53 100644 --- a/im-uniapp/common/enums.js +++ b/im-uniapp/common/enums.js @@ -13,6 +13,7 @@ const MESSAGE_TYPE = { LOADING:30, ACT_RT_VOICE:40, ACT_RT_VIDEO:41, + USER_BANNED:50, RTC_CALL_VOICE: 100, RTC_CALL_VIDEO: 101, RTC_ACCEPT: 102, diff --git a/im-uniapp/common/recorder-app.js b/im-uniapp/common/recorder-app.js index dce0cbf..e525ef4 100644 --- a/im-uniapp/common/recorder-app.js +++ b/im-uniapp/common/recorder-app.js @@ -39,12 +39,18 @@ let upload = () => { filePath: wavFile.tempFilePath, name: 'file', success: (res) => { - const duration = (new Date().getTime() - startTime.getTime()) / 1000 - const data = { - duration: Math.round(duration), - url: JSON.parse(res.data).data + let r = JSON.parse(res.data); + if (r.code != 200) { + reject(r.message); + } else { + const duration = (new Date().getTime() - startTime.getTime()) / + 1000 + const data = { + duration: Math.round(duration), + url: r.data + } + resolve(data); } - resolve(data); }, fail: (e) => { reject(e); diff --git a/im-uniapp/common/recorder-h5.js b/im-uniapp/common/recorder-h5.js index 1f435ca..b174081 100644 --- a/im-uniapp/common/recorder-h5.js +++ b/im-uniapp/common/recorder-h5.js @@ -33,11 +33,17 @@ let upload = () => { file: file, name: 'file', success: (res) => { - const data = { - duration: parseInt(rc.duration), - url: JSON.parse(res.data).data + let r = JSON.parse(res.data); + if(r.code != 200){ + console.log(res) + reject(r.message); + }else { + const data = { + duration: parseInt(rc.duration), + url: r.data + } + resolve(data); } - resolve(data); }, fail: (e) => { reject(e); diff --git a/im-uniapp/components/chat-at-box/chat-at-box.vue b/im-uniapp/components/chat-at-box/chat-at-box.vue index 51ad5b2..e9f956f 100644 --- a/im-uniapp/components/chat-at-box/chat-at-box.vue +++ b/im-uniapp/components/chat-at-box/chat-at-box.vue @@ -10,21 +10,21 @@ - + - + - - - {{ m.aliasName}} + {{ m.showNickName}} @@ -60,7 +60,7 @@ if(this.ownerId == userId){ this.showMembers.push({ userId:-1, - aliasName: "全体成员" + showNickName: "全体成员" }) } this.members.forEach((m) => { diff --git a/im-uniapp/components/chat-item/chat-item.vue b/im-uniapp/components/chat-item/chat-item.vue index d328e51..db6f955 100644 --- a/im-uniapp/components/chat-item/chat-item.vue +++ b/im-uniapp/components/chat-item/chat-item.vue @@ -1,20 +1,25 @@ @@ -106,36 +111,8 @@ style: "" } } - }, methods: { - onShowMenu(e) { - uni.getSystemInfo({ - success: (res) => { - let touches = e.touches[0]; - let style = ""; - /* 因 非H5端不兼容 style 属性绑定 Object ,所以拼接字符 */ - if (touches.clientY > (res.windowHeight / 2)) { - style = `bottom:${res.windowHeight-touches.clientY}px;`; - } else { - style = `top:${touches.clientY}px;`; - } - if (touches.clientX > (res.windowWidth / 2)) { - style += `right:${res.windowWidth-touches.clientX}px;`; - } else { - style += `left:${touches.clientX}px;`; - } - this.menu.style = style; - // - this.$nextTick(() => { - this.menu.show = true; - }); - } - }) - }, - onHideMenu(){ - this.menu.show = false; - }, onSendFail() { uni.showToast({ title: "该文件已发送失败,目前不支持自动重新发送,建议手动重新发送", @@ -148,11 +125,12 @@ this.innerAudioContext = uni.createInnerAudioContext(); let url = JSON.parse(this.msgInfo.content).url; this.innerAudioContext.src = url; + console.log(url); this.innerAudioContext.onEnded((e) => { console.log('停止') this.audioPlayState = "STOP" }) - this.innerAudioContext.onError((e) =>{ + this.innerAudioContext.onError((e) => { console.log("播放音频出错"); console.log(e) }); @@ -207,7 +185,8 @@ items.push({ key: 'DELETE', name: '删除', - icon: 'trash' + icon: 'trash', + color: '#e64e4e' }); if (this.msgInfo.selfSend && this.msgInfo.id > 0) { items.push({ @@ -225,7 +204,7 @@ } return items; }, - isAction(){ + isAction() { return this.$msgType.isAction(this.msgInfo.type); }, isNormal() { @@ -282,16 +261,16 @@ position: relative; line-height: 60rpx; margin-top: 10rpx; - padding: 10rpx 20rpx; - background-color: white; - border-radius: 10rpx; + padding: 8rpx 20rpx; + background-color: #eee; + border-radius: 20rpx; color: #333; font-size: 30rpx; text-align: left; display: block; word-break: break-all; white-space: pre-line; - box-shadow: 1px 1px 1px #c0c0f0; + &:after { content: ""; @@ -301,7 +280,7 @@ width: 6rpx; height: 6rpx; border-style: solid dashed dashed; - border-color: white transparent transparent; + border-color: #eee transparent transparent; overflow: hidden; border-width: 18rpx; } @@ -460,7 +439,6 @@ margin-left: 10px; background-color: #587ff0; color: #fff; - box-shadow: 1px 1px 1px #ccc; &:after { left: auto; @@ -484,6 +462,7 @@ padding-right: 0; padding-left: 8px; } + .icon-voice-play { transform: rotateY(180deg); } diff --git a/im-uniapp/components/chat-record/chat-record.vue b/im-uniapp/components/chat-record/chat-record.vue index 77de146..ce77c32 100644 --- a/im-uniapp/components/chat-record/chat-record.vue +++ b/im-uniapp/components/chat-record/chat-record.vue @@ -1,10 +1,8 @@