feature: 对接转发消息、通知模块
@@ -731,6 +731,30 @@ CREATE TABLE `im_role` (
|
||||
INSERT INTO `im_role` VALUES (1, '超级管理员', '2024-07-10 11:17:15.089', '2024-07-10 11:17:15.089', 1, 1, NULL, 0);
|
||||
INSERT INTO `im_role` VALUES (2, 'HuLa群聊管理员', '2024-07-10 11:17:15.091', '2024-11-26 12:00:22.452', 1, 1, NULL, 0);
|
||||
|
||||
DROP TABLE IF EXISTS `im_notice`;
|
||||
CREATE TABLE `im_notice` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`event_type` tinyint NOT NULL COMMENT '通知类型:1-好友申请;2-群申请;3-群邀请;5-移除群成员;6-好友被申请;7-被邀请进群',
|
||||
`type` tinyint NOT NULL DEFAULT 1 COMMENT '通知类型 1群聊 2加好友',
|
||||
`sender_id` bigint NOT NULL COMMENT '发起人UID',
|
||||
`receiver_id` bigint NOT NULL COMMENT '接收人UID',
|
||||
`apply_id` bigint NULL DEFAULT NULL COMMENT '申请ID',
|
||||
`operate_id` bigint NOT NULL COMMENT '房间ID',
|
||||
`content` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '0' COMMENT '通知消息 [申请时填写]',
|
||||
`status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '处理状态:0-未处理;1-已同意;2-已拒绝',
|
||||
`is_read` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否已读',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户id',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`create_by` bigint NOT NULL COMMENT '创建人',
|
||||
`update_by` bigint NOT NULL COMMENT '创建人',
|
||||
`is_del` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_receiver_type`(`receiver_id` ASC, `event_type` ASC) USING BTREE,
|
||||
INDEX `idx_sender`(`sender_id` ASC) USING BTREE,
|
||||
INDEX `idx_related`(`apply_id` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 75169527849987 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '统一通知表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for im_room
|
||||
-- ----------------------------
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
NACOS_VERSION=v3.0.2
|
||||
@@ -1,97 +0,0 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
nacos:
|
||||
image: nacos/nacos-server:${NACOS_VERSION}
|
||||
container_name: nacos-standalone-mysql
|
||||
env_file:
|
||||
- ./env/nacos-standalone-mysql.env
|
||||
volumes:
|
||||
- ./nacos/standalone-logs/:/home/nacos/logs
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8848:8848"
|
||||
- "9848:9848"
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
restart: always
|
||||
mysql:
|
||||
container_name: mysql
|
||||
restart: always
|
||||
image: mysql:8.0.30
|
||||
env_file:
|
||||
- ./env/mysql.env
|
||||
volumes:
|
||||
- ./mysql/data:/var/lib/mysql
|
||||
ports:
|
||||
- "13306:3306"
|
||||
healthcheck:
|
||||
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
|
||||
interval: 5s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
redis:
|
||||
image: redis:latest
|
||||
container_name: redis
|
||||
restart: always
|
||||
ports:
|
||||
- '16379:6379'
|
||||
volumes:
|
||||
- ./redis/data:/data
|
||||
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
|
||||
- ./redis/logs:/logs
|
||||
#配置文件启动
|
||||
command: redis-server /usr/local/etc/redis/redis.conf --requirepass luo123456
|
||||
# rocketmq
|
||||
rocketmq-namesrv:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-namesrv
|
||||
ports:
|
||||
- 9876:9876
|
||||
command: sh mqnamesrv
|
||||
volumes:
|
||||
- ./rocketmq/namesrv/logs:/home/rocketmq/logs
|
||||
- ./rocketmq/namesrv/store:/home/rocketmq/store
|
||||
rocketmq-broker:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-broker
|
||||
ports:
|
||||
- 10909:10909
|
||||
- 10911:10911
|
||||
- 10912:10912
|
||||
environment:
|
||||
- NAMESRV_ADDR=rocketmq-namesrv:9876
|
||||
volumes:
|
||||
- ./rocketmq/broker/logs:/home/rocketmq/logs
|
||||
- ./rocketmq/broker/store:/home/rocketmq/store
|
||||
- ./rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
- ./rocketmq/broker/conf/plain_acl.yml:/home/rocketmq/rocketmq-5.3.2/conf/plain_acl.yml
|
||||
depends_on:
|
||||
- rocketmq-namesrv
|
||||
command: sh mqbroker -c /home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
rocketmq-proxy:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-proxy
|
||||
depends_on:
|
||||
- rocketmq-broker
|
||||
- rocketmq-namesrv
|
||||
ports:
|
||||
- 8082:8080
|
||||
- 8081:8081
|
||||
restart: on-failure
|
||||
environment:
|
||||
- NAMESRV_ADDR=rocketmq-namesrv:9876
|
||||
command: sh mqproxy
|
||||
|
||||
jenkins:
|
||||
image: jenkins/jenkins:lts-jdk21
|
||||
container_name: jenkins
|
||||
user: root
|
||||
restart: always
|
||||
ports:
|
||||
- "20000:8080" # Web UI 端口
|
||||
- "50000:50000" # Agent 连接端口
|
||||
volumes:
|
||||
- /home/jenkins/work:/var/jenkins_home # 数据持久化
|
||||
- /var/run/docker.sock:/var/run/docker.sock # 宿主机 Docker 控制
|
||||
- /usr/bin/docker:/usr/bin/docker # 宿主机 Docker 命令
|
||||
12
luohuo-cloud/install/docker/env/mysql.env
vendored
@@ -1,12 +0,0 @@
|
||||
# mysql root 密码
|
||||
MYSQL_ROOT_PASSWORD=123456
|
||||
# 创建nacos 账号和密码
|
||||
MYSQL_DATABASE=nacos
|
||||
MYSQL_USER=nacos
|
||||
MYSQL_PASSWORD=n2SWa3j45a6AdmZE
|
||||
LANG=C.UTF-8
|
||||
# 允许远程访问
|
||||
MYSQL_ROOT_HOST=%
|
||||
# 支持utf8mb4字符集
|
||||
MYSQL_CHARSET=utf8mb4
|
||||
MYSQL_COLLATION=utf8mb4_unicode_ci
|
||||
@@ -1,15 +0,0 @@
|
||||
# 这里要用mysql 的容器名称
|
||||
PREFER_HOST_MODE=mysql
|
||||
MODE=standalone
|
||||
SPRING_DATASOURCE_PLATFORM=mysql
|
||||
MYSQL_SERVICE_HOST=mysql
|
||||
MYSQL_SERVICE_DB_NAME=nacos
|
||||
# 端口配置docker 内部的端口,不用配置宿主机的端口,如果配置宿主机的端口,那么PREFER_HOST_MODE 需要配置host.docker.internal
|
||||
MYSQL_SERVICE_PORT=3306
|
||||
MYSQL_SERVICE_USER=nacos
|
||||
# 密码必须要和mysql中创建的密码一致
|
||||
MYSQL_SERVICE_PASSWORD=n2SWa3j45a6AdmZE
|
||||
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
NACOS_AUTH_IDENTITY_KEY=2222
|
||||
NACOS_AUTH_IDENTITY_VALUE=2xxx
|
||||
NACOS_AUTH_TOKEN=VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=
|
||||
6
luohuo-cloud/install/docker/env/redis.env
vendored
@@ -1,6 +0,0 @@
|
||||
REDIS_PASSWORD="luo123456" # 16位复杂度与mysql业务密码同级
|
||||
REDIS_DATABASES=0 # 默认数据库数量
|
||||
REDIS_MAXMEMORY=2gb # 内存限制
|
||||
REDIS_APPENDONLY=yes # 启用AOF持久化
|
||||
REDIS_PROTECTED_MODE=yes # 保护模式
|
||||
REDIS_RENAME_COMMANDS="FLUSHDB:_,FLUSHALL:_,CONFIG:_" # 禁用危险命令
|
||||
@@ -1,11 +0,0 @@
|
||||
## 📝 修改环境配置
|
||||
|
||||
上传目录下的docker文件夹到服务器/home/docker下面, 需要修改env文件夹rocketmq文件夹里面的配置, 特别是[broker.conf](docker/rocketmq/broker/conf/broker.conf)里面brokerIP1的值
|
||||
|
||||
|
||||
## 🛠️ 启动命令
|
||||
- **仔细阅读**: docker-compose.yml 的内容(redis的密码也在这里面设置的)、./env 文件夹下面的内容,里面包含了账号密码等信息
|
||||
- **打开目录**: 当前文件夹下输入 cmd 回车
|
||||
- **执行命令**: docker-compose up -d
|
||||
- **导入nacos数据库**: [mysql-schema.sql](../mysql-schema.sql)
|
||||
- **导入nacos命名空间数据**: [nacos_config_export_20250816090745.zip](../../nacos/nacos_config_export_20250816090745.zip)
|
||||
@@ -1,105 +0,0 @@
|
||||
#所属集群名字
|
||||
brokerClusterName=DefaultCluster
|
||||
|
||||
# 启用Proxy模式(可选,默认NONE)
|
||||
proxyMode=NONE
|
||||
|
||||
# 启用Controller模式(集群部署需配置)
|
||||
enableControllerMode=false
|
||||
|
||||
#broker名字,注意此处不同的配置文件填写的不一样,如果在broker-a.properties使用:broker-a,
|
||||
#在broker-b.properties使用:broker-b
|
||||
brokerName=broker-a
|
||||
|
||||
#0 表示Master,>0 表示Slave
|
||||
brokerId=0
|
||||
|
||||
#nameServer地址,分号分割
|
||||
#namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
|
||||
namesrvAddr=rocketmq-namesrv:9876
|
||||
|
||||
#启动IP,如果 docker 报 com.alibaba.rocketmq.remoting.exception.RemotingConnectException: connect to <192.168.0.120:10909> failed
|
||||
# 解决方式1 加上一句producer.setVipChannelEnabled(false);,解决方式2 brokerIP1 设置宿主机IP,不要使用docker 内部IP
|
||||
brokerIP1=rocketmq-broker
|
||||
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
|
||||
defaultTopicQueueNums=4
|
||||
|
||||
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭 !!!这里仔细看是false,false,false
|
||||
autoCreateTopicEnable=true
|
||||
enableAutoCreateSystemTopic=true
|
||||
# 必须设置为true(与proxy协调)
|
||||
enableAutoCreateSubscriptionGroup=true
|
||||
|
||||
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
|
||||
autoCreateSubscriptionGroup=true
|
||||
|
||||
#Broker 对外服务的监听端口
|
||||
listenPort=10911
|
||||
|
||||
#此参数控制是否开启密码,不开启可设置false
|
||||
aclEnable=false
|
||||
|
||||
#删除文件时间点,默认凌晨4点
|
||||
deleteWhen=04
|
||||
|
||||
#文件保留时间,默认48小时
|
||||
fileReservedTime=120
|
||||
|
||||
#commitLog每个文件的大小默认1G
|
||||
mappedFileSizeCommitLog=1073741824
|
||||
|
||||
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
|
||||
mappedFileSizeConsumeQueue=300000
|
||||
|
||||
#destroyMapedFileIntervalForcibly=120000
|
||||
#redeleteHangedFileInterval=120000
|
||||
#检测物理文件磁盘空间
|
||||
diskMaxUsedSpaceRatio=88
|
||||
#存储路径
|
||||
storePathRootDir=/home/rocketmq/store
|
||||
#commitLog 存储路径
|
||||
storePathCommitLog=/home/rocketmq/store/commitlog
|
||||
#消费队列存储
|
||||
storePathConsumeQueue=/home/rocketmq/store/consumequeue
|
||||
#消息索引存储路径
|
||||
storePathIndex=/home/rocketmq/store/index
|
||||
#checkpoint 文件存储路径
|
||||
storeCheckpoint=/home/rocketmq/store/checkpoint
|
||||
#abort 文件存储路径
|
||||
abortFile=/home/rocketmq/store/abort
|
||||
#限制的消息大小
|
||||
maxMessageSize=65536
|
||||
|
||||
# 延迟消息配置
|
||||
#timerWheelEnable=false
|
||||
#enableScheduleMessage=false
|
||||
|
||||
# 确保此目录存在且可写
|
||||
#timerStorePath=/home/rocketmq/store/timerwheel
|
||||
#timerFlushIntervalMs=1000
|
||||
#timerPrecisionMs=1000
|
||||
#scheduleMessageServiceThreadPoolNums=4
|
||||
|
||||
#flushCommitLogLeastPages=4
|
||||
#flushConsumeQueueLeastPages=2
|
||||
#flushCommitLogThoroughInterval=10000
|
||||
#flushConsumeQueueThoroughInterval=60000
|
||||
|
||||
#Broker 的角色
|
||||
#- ASYNC_MASTER 异步复制Master
|
||||
#- SYNC_MASTER 同步双写Master
|
||||
#- SLAVE
|
||||
brokerRole=ASYNC_MASTER
|
||||
|
||||
#刷盘方式
|
||||
#- ASYNC_FLUSH 异步刷盘 SYNC_FLUSH 同步刷盘
|
||||
flushDiskType=ASYNC_FLUSH
|
||||
|
||||
# 堆外内存限制(需与 JVM 参数一致)
|
||||
maxDirectMemorySize=1g
|
||||
|
||||
#发消息线程池数量
|
||||
#sendMessageThreadPoolNums=128
|
||||
#拉消息线程池数量
|
||||
#pullMessageThreadPoolNums=128
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
globalWhiteRemoteAddresses:
|
||||
# - 47.100.93.*
|
||||
# - 156.254.120.*
|
||||
|
||||
accounts:
|
||||
- accessKey: RocketMQ
|
||||
secretKey: mq000000
|
||||
whiteRemoteAddress:
|
||||
admin: true
|
||||
defaultTopicPerm: PUB|SUB
|
||||
defaultGroupPerm: PUB|SUB
|
||||
topicPerms:
|
||||
- topicA=DENY
|
||||
- topicB=PUB|SUB
|
||||
- topicC=SUB
|
||||
groupPerms:
|
||||
- groupA=DENY
|
||||
- groupB=PUB|SUB
|
||||
- groupC=SUB
|
||||
|
||||
- accessKey: earthearth
|
||||
secretKey: mq000000
|
||||
whiteRemoteAddress:
|
||||
admin: true
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"rocketMQClusterName": "DefaultCluster"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 65 KiB |
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
set -eo pipefail
|
||||
|
||||
# Check if a custom parameter has been set, otherwise use default values
|
||||
DB_PORT="${DB_PORT:=5432}"
|
||||
SUPERUSER="${SUPERUSER:=postgres}"
|
||||
SUPERUSER_PWD="${SUPERUSER_PWD:=postgres}"
|
||||
|
||||
# Allow to skip Docker if a dockerized Postgres database is already running
|
||||
if [[ -z "${SKIP_DOCKER}" ]]
|
||||
then
|
||||
# if a postgres container is running, print instructions to kill it and exit
|
||||
RUNNING_POSTGRES_CONTAINER=$(docker ps --filter 'name=postgres' --format '{{.ID}}')
|
||||
if [[ -n $RUNNING_POSTGRES_CONTAINER ]]; then
|
||||
echo >&2 "there is a postgres container already running, kill it with"
|
||||
echo >&2 " docker kill ${RUNNING_POSTGRES_CONTAINER}"
|
||||
exit 1
|
||||
fi
|
||||
CONTAINER_NAME="postgres"
|
||||
# Launch postgres using Docker
|
||||
docker run \
|
||||
--env POSTGRES_USER=${SUPERUSER} \
|
||||
--env POSTGRES_PASSWORD=${SUPERUSER_PWD} \
|
||||
--health-cmd="pg_isready -U ${SUPERUSER} || exit 1" \
|
||||
--health-interval=1s \
|
||||
--health-timeout=5s \
|
||||
--health-retries=5 \
|
||||
--publish "${DB_PORT}":5432 \
|
||||
--detach \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
postgres -N 1000
|
||||
# ^ Increased maximum number of connections for testing purposes
|
||||
|
||||
until [ \
|
||||
"$(docker inspect -f "{{.State.Health.Status}}" ${CONTAINER_NAME})" == \
|
||||
"healthy" \
|
||||
]; do
|
||||
>&2 echo "Postgres is still unavailable - sleeping"
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
|
||||
>&2 echo "Postgres is up and running on port ${DB_PORT} - running migrations now!"
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = config_info */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) DEFAULT NULL COMMENT 'group_id',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
`c_desc` varchar(256) DEFAULT NULL COMMENT 'configuration description',
|
||||
`c_use` varchar(64) DEFAULT NULL COMMENT 'configuration usage',
|
||||
`effect` varchar(64) DEFAULT NULL COMMENT '配置生效的描述',
|
||||
`type` varchar(64) DEFAULT NULL COMMENT '配置的类型',
|
||||
`c_schema` text COMMENT '配置的模式',
|
||||
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = config_info since 2.5.0 */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_info_gray` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`src_user` text COMMENT 'src_user',
|
||||
`src_ip` varchar(100) DEFAULT NULL COMMENT 'src_ip',
|
||||
`gmt_create` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_create',
|
||||
`gmt_modified` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'gmt_modified',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`gray_name` varchar(128) NOT NULL COMMENT 'gray_name',
|
||||
`gray_rule` text NOT NULL COMMENT 'gray_rule',
|
||||
`encrypted_data_key` varchar(256) NOT NULL DEFAULT '' COMMENT 'encrypted_data_key',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_configinfogray_datagrouptenantgray` (`data_id`,`group_id`,`tenant_id`,`gray_name`),
|
||||
KEY `idx_dataid_gmt_modified` (`data_id`,`gmt_modified`),
|
||||
KEY `idx_gmt_modified` (`gmt_modified`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='config_info_gray';
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = config_tags_relation */
|
||||
/******************************************/
|
||||
CREATE TABLE `config_tags_relation` (
|
||||
`id` bigint(20) NOT NULL COMMENT 'id',
|
||||
`tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
|
||||
`tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
|
||||
`nid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增长标识',
|
||||
PRIMARY KEY (`nid`),
|
||||
UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
|
||||
KEY `idx_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = group_capacity */
|
||||
/******************************************/
|
||||
CREATE TABLE `group_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
|
||||
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_group_id` (`group_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = his_config_info */
|
||||
/******************************************/
|
||||
CREATE TABLE `his_config_info` (
|
||||
`id` bigint(20) unsigned NOT NULL COMMENT 'id',
|
||||
`nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'nid, 自增标识',
|
||||
`data_id` varchar(255) NOT NULL COMMENT 'data_id',
|
||||
`group_id` varchar(128) NOT NULL COMMENT 'group_id',
|
||||
`app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
|
||||
`content` longtext NOT NULL COMMENT 'content',
|
||||
`md5` varchar(32) DEFAULT NULL COMMENT 'md5',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`src_user` text COMMENT 'source user',
|
||||
`src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
|
||||
`op_type` char(10) DEFAULT NULL COMMENT 'operation type',
|
||||
`tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
|
||||
`encrypted_data_key` varchar(1024) NOT NULL DEFAULT '' COMMENT '密钥',
|
||||
`publish_type` varchar(50) DEFAULT 'formal' COMMENT 'publish type gray or formal',
|
||||
`gray_name` varchar(50) DEFAULT NULL COMMENT 'gray name',
|
||||
`ext_info` longtext DEFAULT NULL COMMENT 'ext info',
|
||||
PRIMARY KEY (`nid`),
|
||||
KEY `idx_gmt_create` (`gmt_create`),
|
||||
KEY `idx_gmt_modified` (`gmt_modified`),
|
||||
KEY `idx_did` (`data_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
|
||||
|
||||
|
||||
/******************************************/
|
||||
/* 表名称 = tenant_capacity */
|
||||
/******************************************/
|
||||
CREATE TABLE `tenant_capacity` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
|
||||
`quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
|
||||
`usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
|
||||
`max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
|
||||
`max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
|
||||
`max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
|
||||
`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
|
||||
|
||||
|
||||
CREATE TABLE `tenant_info` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`kp` varchar(128) NOT NULL COMMENT 'kp',
|
||||
`tenant_id` varchar(128) default '' COMMENT 'tenant_id',
|
||||
`tenant_name` varchar(128) default '' COMMENT 'tenant_name',
|
||||
`tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
|
||||
`create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
|
||||
`gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
|
||||
`gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
|
||||
KEY `idx_tenant_id` (`tenant_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`username` varchar(50) NOT NULL PRIMARY KEY COMMENT 'username',
|
||||
`password` varchar(500) NOT NULL COMMENT 'password',
|
||||
`enabled` boolean NOT NULL COMMENT 'enabled'
|
||||
);
|
||||
|
||||
CREATE TABLE `roles` (
|
||||
`username` varchar(50) NOT NULL COMMENT 'username',
|
||||
`role` varchar(50) NOT NULL COMMENT 'role',
|
||||
UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
|
||||
);
|
||||
|
||||
CREATE TABLE `permissions` (
|
||||
`role` varchar(50) NOT NULL COMMENT 'role',
|
||||
`resource` varchar(128) NOT NULL COMMENT 'resource',
|
||||
`action` varchar(8) NOT NULL COMMENT 'action',
|
||||
UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
|
||||
);
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
services:
|
||||
rocketmq-namesrv:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-namesrv-test
|
||||
networks:
|
||||
- rocketmq-net
|
||||
ports:
|
||||
- 9886:9876
|
||||
command: sh mqnamesrv
|
||||
volumes:
|
||||
- ./rocketmq/namesrv/logs:/home/rocketmq/logs
|
||||
- ./rocketmq/namesrv/store:/home/rocketmq/store
|
||||
|
||||
rocketmq-broker:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-broker-test
|
||||
networks:
|
||||
- rocketmq-net
|
||||
ports:
|
||||
- 11909:10909
|
||||
- 11911:10911
|
||||
- 11912:10912
|
||||
environment:
|
||||
- NAMESRV_ADDR=rocketmq-namesrv:9876
|
||||
volumes:
|
||||
- ./rocketmq/broker/logs:/home/rocketmq/logs
|
||||
- ./rocketmq/broker/store:/home/rocketmq/store
|
||||
- ./rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
- ./rocketmq/broker/conf/plain_acl.yml:/home/rocketmq/rocketmq-5.3.2/conf/plain_acl.yml
|
||||
depends_on:
|
||||
- rocketmq-namesrv
|
||||
command: sh mqbroker -c /home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
rocketmq-proxy:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rocketmq-proxy-test
|
||||
networks:
|
||||
- rocketmq-net
|
||||
depends_on:
|
||||
- rocketmq-broker
|
||||
- rocketmq-namesrv
|
||||
ports:
|
||||
- 8182:8080
|
||||
- 8181:8081
|
||||
restart: on-failure
|
||||
environment:
|
||||
- NAMESRV_ADDR=rocketmq-namesrv:9876
|
||||
command: sh mqproxy
|
||||
|
||||
networks:
|
||||
rocketmq-net:
|
||||
driver: bridge
|
||||
@@ -1,104 +0,0 @@
|
||||
#所属集群名字
|
||||
brokerClusterName=DefaultCluster
|
||||
|
||||
# 启用Proxy模式(可选,默认NONE)
|
||||
proxyMode=NONE
|
||||
|
||||
# 启用Controller模式(集群部署需配置)
|
||||
enableControllerMode=false
|
||||
|
||||
#broker名字,注意此处不同的配置文件填写的不一样,如果在broker-a.properties使用:broker-a,
|
||||
#在broker-b.properties使用:broker-b
|
||||
brokerName=broker-a
|
||||
|
||||
#0 表示Master,>0 表示Slave
|
||||
brokerId=0
|
||||
|
||||
#nameServer地址,分号分割
|
||||
#namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
|
||||
namesrvAddr=rocketmq-namesrv:9876
|
||||
|
||||
#启动IP,如果 docker 报 com.alibaba.rocketmq.remoting.exception.RemotingConnectException: connect to <192.168.0.120:10909> failed
|
||||
# 解决方式1 加上一句producer.setVipChannelEnabled(false);,解决方式2 brokerIP1 设置宿主机IP,不要使用docker 内部IP
|
||||
brokerIP1=192.168.1.37
|
||||
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
|
||||
defaultTopicQueueNums=4
|
||||
|
||||
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭 !!!这里仔细看是false,false,false
|
||||
autoCreateTopicEnable=true
|
||||
enableAutoCreateSystemTopic=true
|
||||
# 必须设置为true(与proxy协调)
|
||||
enableAutoCreateSubscriptionGroup=true
|
||||
|
||||
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
|
||||
autoCreateSubscriptionGroup=true
|
||||
|
||||
#Broker 对外服务的监听端口
|
||||
listenPort=10911
|
||||
|
||||
#此参数控制是否开启密码,不开启可设置false
|
||||
aclEnable=false
|
||||
|
||||
#删除文件时间点,默认凌晨4点
|
||||
deleteWhen=04
|
||||
|
||||
#文件保留时间,默认48小时
|
||||
fileReservedTime=120
|
||||
|
||||
#commitLog每个文件的大小默认1G
|
||||
mappedFileSizeCommitLog=1073741824
|
||||
|
||||
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
|
||||
mappedFileSizeConsumeQueue=300000
|
||||
|
||||
#destroyMapedFileIntervalForcibly=120000
|
||||
#redeleteHangedFileInterval=120000
|
||||
#检测物理文件磁盘空间
|
||||
diskMaxUsedSpaceRatio=88
|
||||
#存储路径
|
||||
storePathRootDir=/home/rocketmq/store
|
||||
#commitLog 存储路径
|
||||
storePathCommitLog=/home/rocketmq/store/commitlog
|
||||
#消费队列存储
|
||||
storePathConsumeQueue=/home/rocketmq/store/consumequeue
|
||||
#消息索引存储路径
|
||||
storePathIndex=/home/rocketmq/store/index
|
||||
#checkpoint 文件存储路径
|
||||
storeCheckpoint=/home/rocketmq/store/checkpoint
|
||||
#abort 文件存储路径
|
||||
abortFile=/home/rocketmq/store/abort
|
||||
#限制的消息大小
|
||||
maxMessageSize=65536
|
||||
|
||||
# 延迟消息配置
|
||||
#timerWheelEnable=false
|
||||
#enableScheduleMessage=false
|
||||
|
||||
# 确保此目录存在且可写
|
||||
#timerStorePath=/home/rocketmq/store/timerwheel
|
||||
#timerFlushIntervalMs=1000
|
||||
#timerPrecisionMs=1000
|
||||
#scheduleMessageServiceThreadPoolNums=4
|
||||
|
||||
#flushCommitLogLeastPages=4
|
||||
#flushConsumeQueueLeastPages=2
|
||||
#flushCommitLogThoroughInterval=10000
|
||||
#flushConsumeQueueThoroughInterval=60000
|
||||
|
||||
#Broker 的角色
|
||||
#- ASYNC_MASTER 异步复制Master
|
||||
#- SYNC_MASTER 同步双写Master
|
||||
#- SLAVE
|
||||
brokerRole=ASYNC_MASTER
|
||||
|
||||
#刷盘方式
|
||||
#- ASYNC_FLUSH 异步刷盘 SYNC_FLUSH 同步刷盘
|
||||
flushDiskType=ASYNC_FLUSH
|
||||
|
||||
# 堆外内存限制(需与 JVM 参数一致)
|
||||
maxDirectMemorySize=1g
|
||||
|
||||
#发消息线程池数量
|
||||
#sendMessageThreadPoolNums=128
|
||||
#拉消息线程池数量
|
||||
#pullMessageThreadPoolNums=128
|
||||
@@ -1,24 +0,0 @@
|
||||
globalWhiteRemoteAddresses:
|
||||
# - 47.100.93.*
|
||||
# - 156.254.120.*
|
||||
|
||||
accounts:
|
||||
- accessKey: RocketMQ
|
||||
secretKey: mq000000
|
||||
whiteRemoteAddress:
|
||||
admin: true
|
||||
defaultTopicPerm: PUB|SUB
|
||||
defaultGroupPerm: PUB|SUB
|
||||
topicPerms:
|
||||
- topicA=DENY
|
||||
- topicB=PUB|SUB
|
||||
- topicC=SUB
|
||||
groupPerms:
|
||||
- groupA=DENY
|
||||
- groupB=PUB|SUB
|
||||
- groupC=SUB
|
||||
|
||||
- accessKey: earthearth
|
||||
secretKey: mq000000
|
||||
whiteRemoteAddress:
|
||||
admin: true
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"rocketMQClusterName": "DefaultCluster"
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
## 📝 修改环境配置
|
||||
|
||||
上传目录下的docker文件夹到服务器/home/docker下面, 需要修改env文件夹rocketmq文件夹里面的配置, 特别是[broker.conf](docker/rocketmq/broker/conf/broker.conf)里面brokerIP1的值
|
||||
|
||||
|
||||
## 🛠️ 启动命令
|
||||
- **提高权限**: sudo chmod -R 777 /home/docker/rocketmq
|
||||
- **开放端口**: 先去你购物服务器的平台里面的安全组里面放行mysql、redis、rocketmq部署的端口,再去1panel或宝塔下面放行
|
||||
- **执行命令**: cd /home/docker & docker-compose up -d
|
||||
- **导入mysql数据库**: install文件夹下面有一个nacos[mysql-schema.sql](mysql-schema.sql)的sql文件,需要导入到数据库里面,不然nacos启动不了
|
||||
- **重试nacos**: 如果还不行就删了nacos的容器,重新执行 docker-compose up -d
|
||||
|
||||
## 🖼️ 效果预览
|
||||

|
||||
|
||||
## 🛠️ 安装项目环境
|
||||
|
||||
- **开放端口**: 安全组里面放行jenkins部署的端口,再去1panel或宝塔下面放行, 我这里配置的是20000
|
||||
- **安装JDK21**: https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz [安装在宿主机]
|
||||
- **安装git、maven**: 我机器自带的git、https://maven.apache.org/download.cgi 下载然后上传解压即可 [安装在宿主机]
|
||||
|
||||
|
||||
## 🛠️ jenkins 环境配置
|
||||
- **查看密码**: docker logs -f jenkins | grep "initialAdminPassword"
|
||||

|
||||
- **进入jenkins**: http://ip:20000,输入上一步查看得到的密码,配置各项基础信息
|
||||
- **安装插件**: 自行选择默认推荐的就行,ant、Gradle等一些没用的插件可以取消勾选
|
||||
- **下载必选jenkins插件**: http://ip:20000/manage/pluginManager/
|
||||
```
|
||||
Git Parameter
|
||||
Git plugin
|
||||
Maven Integration
|
||||
gitee
|
||||
Publish Over SSH
|
||||
```
|
||||
- **系统全局配置**: http://ip:20000/manage/configure 配置环境变量
|
||||
```
|
||||
PATH
|
||||
/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/var/jenkins_home/maven/bin:/root/bin
|
||||
```
|
||||

|
||||
- **系统全局配置**: http://ip:20000/manage/configure 配置项目地址; 添加凭证时必须选giteeAPI, util、cloud两个项目地址都需要配进去,点击测试链接按钮必须返回成功
|
||||

|
||||

|
||||
|
||||
- **系统全局配置**: http://ip:20000/manage/configureTools/ 配置jenkins内部maven; 项目环境中下载的maven解压到 /home/jenkins/work 下面
|
||||

|
||||

|
||||
|
||||
|
||||
## 🛠️ 创建util、cloud项目流水线
|
||||
|
||||
- **创建util**: 输入名称、选择流水线
|
||||

|
||||
- **配置util**: 根据步骤,仔细对比这上面的内容
|
||||

|
||||
- **创建账号凭证**: 这一步创建的账号是username!!!,注意看是你登录gitee的账号密码。不是apikey!
|
||||

|
||||
|
||||
- **创建cloud**: 输入名称、选择流水线
|
||||

|
||||
- **配置cloud**: 根据步骤,仔细对比这上面的内容
|
||||

|
||||
|
||||
## 🛠️ 编译 util、cloud
|
||||
|
||||
- **install util**: 因为cloud依赖 util, 所以先安装util到maven本地仓库
|
||||

|
||||
|
||||
- **install cloud**: 必须等util模块install完成才行,这样cloud模块就可以通过maven本地仓库找到util依赖
|
||||

|
||||
|
||||
## 🛠️ 运行项目
|
||||
- **开放端口**: 10911 [rocketMQ通信用的]
|
||||
- **授权目录**:
|
||||
```
|
||||
chmod 777 /home/docker/rocketmq/broker/logs
|
||||
chmod 777 /home/docker/rocketmq/broker/store
|
||||
chmod 777 /home/docker/rocketmq/namesrv/logs
|
||||
chmod 777 /home/docker/rocketmq/namesrv/store
|
||||
```
|
||||
- **导入数据库**: luohuo_im_01、luohuo_dev
|
||||
- **执行命令**: /bin/bash /home/jenkins/work/workspace/luohuo-cloud/src/main/bin/all-start.sh
|
||||
|
||||

|
||||
|
||||
|
||||
- **注意事项**: 消息推送采用CLUSTERING模式,单个mq只能被一个cloud项目连接,多个cloud可能会导致消息接收不到; 若需要多次连接必须docker再开一个rocketmq的test版本单独连接,直接copy[rocketmqtest](rocketmqtest)目录 docker-compose up -d即可
|
||||
|
||||
|
||||
## 🛠️ 本地视频语音电话
|
||||
- **浏览器输入地址**: chrome://flags/
|
||||
- **搜索关键字**: Insecure origins treated as secure
|
||||
- **开放端口和ip**: http://192.168.1.37:6130,http://192.168.1.24:6130,http://192.168.1.26:6130
|
||||
```
|
||||
@@ -26,6 +26,11 @@ public class RedisKey {
|
||||
*/
|
||||
public static final String FEED_MEDIA = BASE_KEY + "feedMedia";
|
||||
|
||||
/**
|
||||
* 用户徽章
|
||||
*/
|
||||
public static final String USER_ITEM = BASE_KEY + "userItem";
|
||||
|
||||
/**
|
||||
* 朋友圈权限
|
||||
*/
|
||||
@@ -41,6 +46,11 @@ public class RedisKey {
|
||||
*/
|
||||
public static final String USER_INFO_FORMAT = "userInfo:uid_%d";
|
||||
|
||||
/**
|
||||
* 消息缓存
|
||||
*/
|
||||
public static final String ROOM_MSG_FORMAT = "msg:%d";
|
||||
|
||||
/**
|
||||
* 房间详情
|
||||
*/
|
||||
|
||||
@@ -16,12 +16,15 @@ public class GroupInviteMemberEvent extends ApplicationEvent {
|
||||
private final Long roomId;
|
||||
// 消息接收人
|
||||
private final Long uid;
|
||||
// 是否是申请进群
|
||||
private final Boolean applyFor;
|
||||
|
||||
public GroupInviteMemberEvent(Object source, Long roomId, List<Long> memberList, Long uid) {
|
||||
public GroupInviteMemberEvent(Object source, Long roomId, List<Long> memberList, Long uid, Boolean applyFor) {
|
||||
super(source);
|
||||
this.memberList = memberList;
|
||||
this.roomId = roomId;
|
||||
this.uid = uid;
|
||||
this.applyFor = applyFor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class GroupInviteMemberListener {
|
||||
List<Long> uidList = event.getMemberList();
|
||||
Long roomId = event.getRoomId();
|
||||
User user = userCache.get(event.getUid());
|
||||
ChatMessageReq chatMessageReq = RoomAdapter.buildGroupAddMessage(roomId, user, userCache.getBatch(uidList));
|
||||
ChatMessageReq chatMessageReq = RoomAdapter.buildGroupAddMessage(event.getApplyFor(), roomId, user, userCache.getBatch(uidList));
|
||||
chatService.sendMsg(chatMessageReq, user.getId());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.luohuo.flex.im.common.event.listener;
|
||||
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -12,7 +13,6 @@ import com.luohuo.flex.im.domain.entity.ItemConfig;
|
||||
import com.luohuo.flex.im.domain.entity.User;
|
||||
import com.luohuo.flex.im.domain.entity.UserBackpack;
|
||||
import com.luohuo.flex.im.domain.enums.ItemTypeEnum;
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ItemReceiveListener {
|
||||
@EventListener(classes = ItemReceiveEvent.class)
|
||||
public void wear(ItemReceiveEvent event) {
|
||||
UserBackpack userBackpack = event.getUserBackpack();
|
||||
ItemConfig itemConfig = itemCache.getById(userBackpack.getItemId());
|
||||
ItemConfig itemConfig = itemCache.get(userBackpack.getItemId());
|
||||
if (ItemTypeEnum.BADGE.getType().equals(itemConfig.getType())) {
|
||||
User user = userDao.getById(userBackpack.getUid());
|
||||
if (Objects.isNull(user.getItemId())) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.luohuo.flex.im.common.event.listener;
|
||||
|
||||
import com.luohuo.flex.im.common.event.MessageRecallEvent;
|
||||
import com.luohuo.flex.model.entity.dto.ChatMsgRecallDTO;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgPlusCache;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
import com.luohuo.flex.im.core.user.service.adapter.WsAdapter;
|
||||
import com.luohuo.flex.im.core.user.service.impl.PushService;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -22,7 +22,7 @@ import static com.luohuo.flex.im.common.config.ThreadPoolConfig.LUOHUO_EXECUTOR;
|
||||
@Component
|
||||
public class MessageRecallListener {
|
||||
@Resource
|
||||
private MsgPlusCache msgPlusCache;
|
||||
private MsgCache msgCache;
|
||||
@Resource
|
||||
private PushService pushService;
|
||||
|
||||
@@ -31,7 +31,7 @@ public class MessageRecallListener {
|
||||
public void evictMsg(MessageRecallEvent event) {
|
||||
ChatMsgRecallDTO recallDTO = event.getRecallDTO();
|
||||
// msgCache.evictMsg(recallDTO.getMsgId());
|
||||
msgPlusCache.delete(recallDTO.getMsgId());
|
||||
msgCache.delete(recallDTO.getMsgId());
|
||||
}
|
||||
|
||||
@Async(LUOHUO_EXECUTOR)
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package com.luohuo.flex.im.common.event.listener;
|
||||
|
||||
import com.luohuo.flex.im.core.user.dao.NoticeDao;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import com.luohuo.flex.im.common.event.UserApplyEvent;
|
||||
import com.luohuo.flex.im.core.user.dao.UserApplyDao;
|
||||
import com.luohuo.flex.im.domain.entity.UserApply;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
import com.luohuo.flex.im.core.user.service.adapter.WsAdapter;
|
||||
import com.luohuo.flex.im.core.user.service.impl.PushService;
|
||||
|
||||
@@ -22,8 +22,8 @@ import static com.luohuo.flex.im.common.config.ThreadPoolConfig.LUOHUO_EXECUTOR;
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserApplyListener {
|
||||
@Resource
|
||||
private UserApplyDao userApplyDao;
|
||||
@Resource
|
||||
private NoticeDao noticeDao;
|
||||
|
||||
@Resource
|
||||
private PushService pushService;
|
||||
@@ -32,7 +32,7 @@ public class UserApplyListener {
|
||||
@TransactionalEventListener(classes = UserApplyEvent.class, fallbackExecution = true)
|
||||
public void notifyFriend(UserApplyEvent event) {
|
||||
UserApply userApply = event.getUserApply();
|
||||
WSFriendApply resp = userApplyDao.getUnReadCount(userApply.getUid(), userApply.getTargetId());
|
||||
WSNotice resp = noticeDao.getUnReadCount(userApply.getUid(), userApply.getTargetId());
|
||||
pushService.sendPushMsg(WsAdapter.buildApplySend(resp), userApply.getTargetId(), userApply.getUid());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
package com.luohuo.flex.im.core.chat.service;
|
||||
|
||||
import com.luohuo.flex.im.domain.vo.request.*;
|
||||
import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp;
|
||||
import com.luohuo.flex.im.domain.dto.MsgReadInfoDTO;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMemberReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessagePageReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadInfoReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMessageReadResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import jakarta.annotation.Nullable;
|
||||
@@ -31,7 +25,7 @@ public interface ChatService {
|
||||
/**
|
||||
* 获取所有消息
|
||||
*/
|
||||
List<ChatMessageResp> getMsgList(Long lastOptTime, Long receiveUid);
|
||||
List<ChatMessageResp> getMsgList(MsgReq msgReq, Long receiveUid);
|
||||
|
||||
/**
|
||||
* 根据消息获取消息前端展示的物料
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.luohuo.flex.im.domain.vo.request.room.ReadAnnouncementsParam;
|
||||
import com.luohuo.flex.im.domain.vo.request.room.RoomGroupReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.AnnouncementsResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMemberListResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatRoomResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.MemberResp;
|
||||
import com.luohuo.flex.im.domain.vo.req.MergeMessageReq;
|
||||
@@ -182,7 +181,7 @@ public interface RoomAppService {
|
||||
* 合并消息
|
||||
* @return
|
||||
*/
|
||||
ChatMessageResp mergeMessage(Long uid, MergeMessageReq req);
|
||||
void mergeMessage(Long uid, MergeMessageReq req);
|
||||
|
||||
/**
|
||||
* 查询全部群成员
|
||||
@@ -193,7 +192,7 @@ public interface RoomAppService {
|
||||
/**
|
||||
* 解散群聊
|
||||
*/
|
||||
void exitGroup(Long uid, @Valid MemberExitReq request);
|
||||
void exitGroup(Boolean isGroup, Long uid, @Valid MemberExitReq request);
|
||||
|
||||
/**
|
||||
* 添加管理员
|
||||
|
||||
@@ -86,7 +86,7 @@ public class MemberAdapter {
|
||||
return wsBaseResp;
|
||||
}
|
||||
|
||||
public static WsBaseResp<WSMemberChange> buildMemberRemoveWS(Long roomId, Integer totalNun, List<Long> uidList, Integer type) {
|
||||
public static WsBaseResp<WSMemberChange> buildMemberRemoveWS(Long roomId, Integer totalNun, Integer onlineNum, List<Long> uidList, Integer type) {
|
||||
WsBaseResp<WSMemberChange> wsBaseResp = new WsBaseResp<>();
|
||||
wsBaseResp.setType(WSRespTypeEnum.memberChange.getType());
|
||||
WSMemberChange wsMemberChange = new WSMemberChange();
|
||||
@@ -98,6 +98,7 @@ public class MemberAdapter {
|
||||
}).collect(Collectors.toList());
|
||||
wsMemberChange.setUserList(states);
|
||||
wsMemberChange.setTotalNum(totalNun);
|
||||
wsMemberChange.setOnlineNum(onlineNum);
|
||||
wsMemberChange.setRoomId(roomId+"");
|
||||
wsMemberChange.setChangeType(type);
|
||||
wsBaseResp.setData(wsMemberChange);
|
||||
|
||||
@@ -7,20 +7,20 @@ import com.luohuo.flex.im.domain.entity.Announcements;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.domain.entity.MessageMark;
|
||||
import com.luohuo.flex.im.domain.entity.msg.AudioCallMsgDTO;
|
||||
import com.luohuo.flex.im.domain.entity.msg.BodyDTO;
|
||||
import com.luohuo.flex.im.domain.entity.msg.VideoCallMsgDTO;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MergeMsg;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MergeMsgDTO;
|
||||
import com.luohuo.flex.im.domain.entity.msg.NoticeMsgDTO;
|
||||
import com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.ApplyStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.room.UserApplyResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
import com.luohuo.flex.model.enums.MessageMarkTypeEnum;
|
||||
import com.luohuo.flex.im.domain.enums.MessageStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.msg.TextMsgReq;
|
||||
import com.luohuo.flex.im.domain.entity.msg.TextMsgReq;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ReadAnnouncementsResp;
|
||||
import com.luohuo.flex.im.core.chat.service.strategy.msg.AbstractMsgHandler;
|
||||
@@ -164,13 +164,12 @@ public class MessageAdapter {
|
||||
/**
|
||||
* 合并消息
|
||||
*/
|
||||
public static ChatMessageReq buildMergeMsg(Long roomId, List<MergeMsg> messages) {
|
||||
public static ChatMessageReq buildMergeMsg(Long roomId, List<Message> messages) {
|
||||
ChatMessageReq chatMessageReq = new ChatMessageReq();
|
||||
chatMessageReq.setRoomId(roomId);
|
||||
chatMessageReq.setSkip(true);
|
||||
chatMessageReq.setMsgType(MessageTypeEnum.MERGE.getType());
|
||||
MergeMsgDTO mergeMsgDTO = new MergeMsgDTO();
|
||||
mergeMsgDTO.setMessages(messages);
|
||||
chatMessageReq.setBody(mergeMsgDTO);
|
||||
chatMessageReq.setBody(new MergeMsgDTO(messages.stream().map(msg -> new BodyDTO(msg.getFromUid().toString(), msg.getId().toString())).toList()));
|
||||
return chatMessageReq;
|
||||
}
|
||||
|
||||
@@ -206,8 +205,8 @@ public class MessageAdapter {
|
||||
* 邀请用户进群通知
|
||||
* @param resp 通知数据
|
||||
*/
|
||||
public static WsBaseResp<WSFriendApply> buildInviteeUserAddGroupMessage(WSFriendApply resp) {
|
||||
WsBaseResp<WSFriendApply> wsBaseResp = new WsBaseResp<>();
|
||||
public static WsBaseResp<WSNotice> buildInviteeUserAddGroupMessage(WSNotice resp) {
|
||||
WsBaseResp<WSNotice> wsBaseResp = new WsBaseResp<>();
|
||||
wsBaseResp.setType(WSRespTypeEnum.NEW_APPLY.getType());
|
||||
wsBaseResp.setData(resp);
|
||||
return wsBaseResp;
|
||||
|
||||
@@ -61,12 +61,12 @@ public class RoomAdapter {
|
||||
* 创建群的消息
|
||||
* @return
|
||||
*/
|
||||
public static ChatMessageReq buildGroupAddMessage(Long roomId, User inviter, Map<Long, User> member) {
|
||||
public static ChatMessageReq buildGroupAddMessage(Boolean applyFor, Long roomId, User inviter, Map<Long, User> member) {
|
||||
ChatMessageReq chatMessageReq = new ChatMessageReq();
|
||||
chatMessageReq.setRoomId(roomId);
|
||||
chatMessageReq.setMsgType(MessageTypeEnum.SYSTEM.getType());
|
||||
String body = String.format("%s邀请%s加入群聊", inviter.getName(),
|
||||
member.values().stream().map(User::getName).collect(Collectors.joining("、")));
|
||||
String body = applyFor? String.format("%s申请加入群聊", inviter.getName()):
|
||||
String.format("%s邀请%s加入群聊", inviter.getName(), member.values().stream().map(User::getName).collect(Collectors.joining("、")));
|
||||
chatMessageReq.setBody(body);
|
||||
return chatMessageReq;
|
||||
}
|
||||
|
||||
@@ -1,38 +1,44 @@
|
||||
package com.luohuo.flex.im.core.chat.service.cache;
|
||||
|
||||
import com.luohuo.flex.im.common.constant.RedisKey;
|
||||
import com.luohuo.flex.im.common.service.cache.AbstractRedisStringCache;
|
||||
import com.luohuo.flex.im.core.chat.dao.MessageDao;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.core.user.dao.BlackDao;
|
||||
import com.luohuo.flex.im.core.user.dao.RoleDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserDao;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 消息相关缓存
|
||||
* @author nyh
|
||||
*/
|
||||
@Component
|
||||
public class MsgCache {
|
||||
|
||||
@Resource
|
||||
private UserDao userDao;
|
||||
@Resource
|
||||
private BlackDao blackDao;
|
||||
@Resource
|
||||
private RoleDao roleDao;
|
||||
public class MsgCache extends AbstractRedisStringCache<Long, Message> {
|
||||
@Resource
|
||||
private MessageDao messageDao;
|
||||
|
||||
@Cacheable(cacheNames = "luohuo:msg", key = "#msgId", unless = "#result == null")
|
||||
public Message getMsg(Long msgId) {
|
||||
return messageDao.getById(msgId);
|
||||
@Override
|
||||
protected String getKey(Long messageId) {
|
||||
return RedisKey.getKey(RedisKey.ROOM_MSG_FORMAT, messageId);
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = "luohuo:msg", key = "#msgId")
|
||||
public Message evictMsg(Long msgId) {
|
||||
return null;
|
||||
@Override
|
||||
protected Long getExpireSeconds() {
|
||||
return -1L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Long, Message> load(List<Long> messageIds) {
|
||||
return messageDao.listByIds(messageIds)
|
||||
.stream().collect(Collectors.toMap(Message::getId, Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long messageId) {
|
||||
super.delete(messageId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.luohuo.flex.im.core.chat.service.cache;
|
||||
|
||||
import com.luohuo.flex.im.common.service.cache.AbstractRedisStringCache;
|
||||
import com.luohuo.flex.im.core.chat.dao.MessageDao;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 升级消息相关缓存
|
||||
* @author nyh
|
||||
*/
|
||||
@Component
|
||||
public class MsgPlusCache extends AbstractRedisStringCache<Long, Message> {
|
||||
@Resource
|
||||
private MessageDao messageDao;
|
||||
|
||||
@Override
|
||||
protected String getKey(Long messageId) {
|
||||
return "msg" + messageId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getExpireSeconds() {
|
||||
return 3 * 60L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Long, Message> load(List<Long> messageIds) {
|
||||
return messageDao.listByIds(messageIds)
|
||||
.stream().collect(Collectors.toMap(Message::getId, Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Long messageId) {
|
||||
super.delete(messageId);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class RoomGroupCache extends AbstractRedisStringCache<Long, RoomGroup> {
|
||||
/**
|
||||
* 根据群号查询群信息
|
||||
*/
|
||||
@Cacheable(cacheNames = "room", key = "'findGroup'+#account")
|
||||
@Cacheable(cacheNames = "luohuo:room:findGroup", key = "#account")
|
||||
public List<RoomGroup> searchGroup(String account) {
|
||||
return roomGroupDao.searchGroup(account);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class RoomGroupCache extends AbstractRedisStringCache<Long, RoomGroup> {
|
||||
* @param account
|
||||
* @return
|
||||
*/
|
||||
@CacheEvict(cacheNames = "room", key = "'findGroup'+#account")
|
||||
@CacheEvict(cacheNames = "luohuo:room:findGroup", key = "#account")
|
||||
public List<Long> evictGroup(String account) {
|
||||
return null;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class RoomGroupCache extends AbstractRedisStringCache<Long, RoomGroup> {
|
||||
/**
|
||||
* 清除所有群组相关缓存
|
||||
*/
|
||||
@CacheEvict(cacheNames = "room", allEntries = true)
|
||||
@CacheEvict(cacheNames = "luohuo:room:findGroup", allEntries = true)
|
||||
public void evictAllCaches() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
import com.luohuo.flex.im.core.user.dao.UserFriendDao;
|
||||
import com.luohuo.flex.im.domain.entity.*;
|
||||
import com.luohuo.flex.im.domain.enums.*;
|
||||
import com.luohuo.flex.im.domain.vo.request.*;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -26,13 +27,6 @@ import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp;
|
||||
import com.luohuo.flex.im.common.event.MessageSendEvent;
|
||||
import com.luohuo.flex.im.domain.dto.ChatMsgSendDto;
|
||||
import com.luohuo.flex.im.domain.dto.MsgReadInfoDTO;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMemberReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessagePageReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadInfoReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMessageReadResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.core.chat.service.ChatService;
|
||||
@@ -48,7 +42,6 @@ import com.luohuo.flex.im.core.chat.service.strategy.msg.RecallMsgHandler;
|
||||
import com.luohuo.flex.im.core.user.service.RoleService;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -198,25 +191,26 @@ public class ChatServiceImpl implements ChatService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChatMessageResp> getMsgList(Long lastOptTime, Long receiveUid) {
|
||||
// 1. 获取用户所有未屏蔽的聊天室ID列表
|
||||
List<Long> roomIds = getAccessibleRoomIds(receiveUid);
|
||||
if (CollectionUtil.isEmpty(roomIds)) {
|
||||
return Collections.emptyList();
|
||||
public List<ChatMessageResp> getMsgList(MsgReq msgReq, Long receiveUid) {
|
||||
List<Message> messages;
|
||||
if(CollUtil.isEmpty(msgReq.getMsgIds())){
|
||||
// 1. 获取用户所有未屏蔽的聊天室ID列表
|
||||
List<Long> roomIds = getAccessibleRoomIds(receiveUid);
|
||||
if (CollectionUtil.isEmpty(roomIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 2. 计算查询的时间范围(最多15天)
|
||||
LocalDateTime effectiveStartTime = calculateStartTime(msgReq.getLastOptTime());
|
||||
messages = messageDao.list(new LambdaQueryWrapper<Message>().in(Message::getRoomId, roomIds)
|
||||
.between(Message::getCreateTime, effectiveStartTime, LocalDateTime.now()));
|
||||
} else {
|
||||
messages = getMsgByIds(msgReq.getMsgIds());
|
||||
}
|
||||
|
||||
// 2. 批量查询所有房间的最后一条消息ID(用于权限过滤)
|
||||
LambdaQueryWrapper<Message> wrapper = new LambdaQueryWrapper<Message>().in(Message::getRoomId, roomIds);
|
||||
if(ObjectUtil.isNotNull(lastOptTime) && lastOptTime > 0) {
|
||||
wrapper.ge(Message::getCreateTime, TimeUtils.getDateTimeOfTimestamp(lastOptTime)).le(Message::getCreateTime, LocalDateTime.now());
|
||||
}else {
|
||||
wrapper.ge(Message::getCreateTime, LocalDate.now().minusDays(15));
|
||||
}
|
||||
|
||||
List<Message> messages = messageDao.list(wrapper);
|
||||
Map<Long, List<Message>> groupedMessages = messages.stream().collect(Collectors.groupingBy(Message::getRoomId));
|
||||
|
||||
// 4. 转换为响应对象并返回
|
||||
// 3. 转换为响应对象并返回
|
||||
List<ChatMessageResp> baseMessages = new ArrayList<>();
|
||||
for (Long roomId : groupedMessages.keySet()) {
|
||||
baseMessages.addAll(getMsgRespBatch(groupedMessages.get(roomId), receiveUid));
|
||||
@@ -224,6 +218,20 @@ public class ChatServiceImpl implements ChatService {
|
||||
return baseMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算查询的起始时间, 默认最近15天的消息内容
|
||||
*/
|
||||
private LocalDateTime calculateStartTime(Long lastOptTime) {
|
||||
LocalDateTime defaultStartTime = LocalDateTime.now().minusDays(15);
|
||||
|
||||
if (ObjectUtil.isNotNull(lastOptTime) && lastOptTime > 0) {
|
||||
LocalDateTime proposedTime = TimeUtils.getDateTimeOfTimestamp(lastOptTime);
|
||||
return proposedTime.isAfter(defaultStartTime) ? proposedTime : defaultStartTime;
|
||||
}
|
||||
|
||||
return defaultStartTime;
|
||||
}
|
||||
|
||||
private Long getLastMsgId(Long roomId, Long receiveUid) {
|
||||
Room room = roomCache.get(roomId);
|
||||
AssertUtil.isNotEmpty(room, "房间号有误");
|
||||
@@ -241,7 +249,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
AbstractMsgMarkStrategy strategy = MsgMarkFactory.getStrategyNoNull(request.getMarkType());
|
||||
|
||||
// 校验消息
|
||||
Message message = msgCache.getMsg(request.getMsgId());
|
||||
Message message = msgCache.get(request.getMsgId());
|
||||
if (Objects.isNull(message)) {
|
||||
return;
|
||||
}
|
||||
@@ -328,7 +336,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
|
||||
@Override
|
||||
public List<Message> getMsgByIds(List<Long> msgIds) {
|
||||
return messageDao.listByIds(msgIds);
|
||||
return msgCache.getBatch(msgIds).values().stream().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baidu.fsg.uid.UidGenerator;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.luohuo.basic.cache.repository.CachePlusOps;
|
||||
@@ -13,21 +14,24 @@ import com.luohuo.basic.utils.SpringUtils;
|
||||
import com.luohuo.basic.utils.TimeUtils;
|
||||
import com.luohuo.flex.common.cache.PresenceCacheKeyBuilder;
|
||||
import com.luohuo.flex.im.api.PresenceApi;
|
||||
import com.luohuo.flex.im.common.event.GroupInviteMemberEvent;
|
||||
import com.luohuo.flex.im.core.chat.dao.RoomFriendDao;
|
||||
import com.luohuo.flex.im.core.chat.dao.RoomGroupDao;
|
||||
import com.luohuo.flex.im.core.user.dao.NoticeDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserApplyDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserBackpackDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserFriendDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserPrivacyDao;
|
||||
import com.luohuo.flex.im.core.user.service.NoticeService;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import com.luohuo.flex.im.domain.entity.*;
|
||||
import com.luohuo.flex.im.domain.enums.ApplyStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.*;
|
||||
import com.luohuo.flex.im.domain.vo.req.room.UserApplyResp;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.admin.AdminAddReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.admin.AdminRevokeReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.MemberExitReq;
|
||||
import com.luohuo.flex.im.domain.entity.msg.TextMsgReq;
|
||||
import com.luohuo.flex.model.enums.ChatActiveStatusEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.contact.ContactAddReq;
|
||||
import jakarta.validation.Valid;
|
||||
@@ -52,11 +56,6 @@ import com.luohuo.flex.im.core.chat.dao.ContactDao;
|
||||
import com.luohuo.flex.im.core.chat.dao.GroupMemberDao;
|
||||
import com.luohuo.flex.im.core.chat.dao.MessageDao;
|
||||
import com.luohuo.flex.im.domain.dto.RoomBaseInfo;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MergeMsg;
|
||||
import com.luohuo.flex.im.domain.enums.GroupRoleAPPEnum;
|
||||
import com.luohuo.flex.im.domain.enums.GroupRoleEnum;
|
||||
import com.luohuo.flex.im.domain.enums.HotFlagEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMemberReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ContactFriendReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.GroupAddReq;
|
||||
@@ -74,7 +73,6 @@ import com.luohuo.flex.im.domain.vo.request.room.ReadAnnouncementsParam;
|
||||
import com.luohuo.flex.im.domain.vo.request.room.RoomGroupReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.AnnouncementsResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMemberListResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatRoomResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.MemberResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.ReadAnnouncementsResp;
|
||||
@@ -94,7 +92,6 @@ import com.luohuo.flex.im.core.chat.service.cache.RoomGroupCache;
|
||||
import com.luohuo.flex.im.core.chat.service.strategy.msg.AbstractMsgHandler;
|
||||
import com.luohuo.flex.im.core.chat.service.strategy.msg.MsgHandlerFactory;
|
||||
import com.luohuo.flex.im.core.user.dao.UserDao;
|
||||
import com.luohuo.flex.im.domain.enums.RoleTypeEnum;
|
||||
import com.luohuo.flex.model.entity.WsBaseResp;
|
||||
import com.luohuo.flex.im.domain.vo.req.MergeMessageReq;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMemberResp;
|
||||
@@ -122,6 +119,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
private final UserBackpackDao userBackpackDao;
|
||||
private final RoomGroupDao roomGroupDao;
|
||||
private final RoomFriendDao roomFriendDao;
|
||||
private final NoticeDao noticeDao;
|
||||
private final UserApplyDao userApplyDao;
|
||||
private ContactDao contactDao;
|
||||
private RoomCache roomCache;
|
||||
@@ -140,6 +138,8 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
private ChatService chatService;
|
||||
private RoleService roleService;
|
||||
private RoomService roomService;
|
||||
private UidGenerator uidGenerator;
|
||||
private NoticeService noticeService;
|
||||
private GroupMemberCache groupMemberCache;
|
||||
private PushService pushService;
|
||||
private FriendService friendService;
|
||||
@@ -170,7 +170,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
// 分页加载所有群
|
||||
roomGroupDao.list().parallelStream().map(RoomGroup::getRoomId).forEach(this::warmUpGroupMemberCache);
|
||||
List<Long> roomFriendList = roomFriendDao.list().parallelStream().map(RoomFriend::getRoomId).toList();
|
||||
if(CollUtil.isNotEmpty(roomFriendList)) {
|
||||
if (CollUtil.isNotEmpty(roomFriendList)) {
|
||||
friendService.warmUpRoomMemberCache(roomFriendList);
|
||||
}
|
||||
// 分页加载所有用户有多少个群的缓存
|
||||
@@ -225,11 +225,12 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 2. 最后组装会话信息(名称,头像,未读数等)
|
||||
List<ChatRoomResp> result = buildContactResp(contactHashMap, uid, page.getList());
|
||||
return CursorPageBaseResp.init(page, result,0L);
|
||||
return CursorPageBaseResp.init(page, result, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回当前登录用户的全部会话
|
||||
*
|
||||
* @param uid
|
||||
* @return
|
||||
*/
|
||||
@@ -329,6 +330,22 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 5. 增加管理员
|
||||
groupMemberDao.addAdmin(roomGroup.getId(), request.getUidList());
|
||||
|
||||
// 每个被邀请的人都要收到邀请进群的消息
|
||||
setAdminNotice(NoticeTypeEnum.GROUP_SET_ADMIN, uid, request.getUidList(), manageUidList, roomGroup.getName());
|
||||
}
|
||||
|
||||
private void setAdminNotice(NoticeTypeEnum noticeTypeEnum, Long uid, List<Long> uidList, List<Long> manageUidList, String content) {
|
||||
long uuid = uidGenerator.getUid();
|
||||
uidList.stream().filter(id -> !manageUidList.contains(id)).forEach(id -> noticeService.createNotice(
|
||||
RoomTypeEnum.GROUP,
|
||||
noticeTypeEnum,
|
||||
uid,
|
||||
id,
|
||||
uuid,
|
||||
id,
|
||||
content
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,12 +372,13 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 4. 撤销管理员
|
||||
groupMemberDao.revokeAdmin(roomGroup.getId(), request.getUidList());
|
||||
setAdminNotice(NoticeTypeEnum.GROUP_RECALL_ADMIN, uid, request.getUidList(), new ArrayList<>(), roomGroup.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param roomId 房间id
|
||||
* @param roomId 房间id
|
||||
* @param groupId 群聊id
|
||||
* @param uid 当前人员id
|
||||
* @param uid 当前人员id
|
||||
*/
|
||||
@Override
|
||||
public void createSystemFriend(Long roomId, Long groupId, Long uid) {
|
||||
@@ -378,6 +396,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* 分页查询加群申请记录
|
||||
*
|
||||
* @param uid 登录用户id
|
||||
* @param req 分页请求
|
||||
*/
|
||||
@@ -408,14 +427,15 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* 处理用户在线状态
|
||||
*
|
||||
* @param uidList 需要处理的用户
|
||||
* @param roomId 在某个房间处理
|
||||
* @param roomId 在某个房间处理
|
||||
* @return
|
||||
*/
|
||||
// @Async(LUOHUO_EXECUTOR)
|
||||
public void asyncOnline(List<Long> uidList, Long roomId, boolean online) {
|
||||
Set<Long> onlineList = presenceApi.getOnlineUsersList(uidList).getData();
|
||||
if(CollUtil.isEmpty(onlineList)){
|
||||
if (CollUtil.isEmpty(onlineList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -423,7 +443,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
for (Long uid : onlineList) {
|
||||
CacheKey ougKey = PresenceCacheKeyBuilder.onlineUserGroupsKey(uid);
|
||||
|
||||
if(online) {
|
||||
if (online) {
|
||||
// 处理在线的状态
|
||||
cachePlusOps.sAdd(ogmKey, uid);
|
||||
cachePlusOps.sAdd(ougKey, roomId);
|
||||
@@ -437,16 +457,17 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* 校验用户在群里的权限
|
||||
*
|
||||
* @param uid
|
||||
* @return
|
||||
*/
|
||||
public GroupMember verifyGroupPermissions(Long uid, RoomGroup roomGroup) {
|
||||
if(ObjectUtil.isNull(roomGroup)){
|
||||
if (ObjectUtil.isNull(roomGroup)) {
|
||||
throw new RuntimeException("群聊不存在!");
|
||||
}
|
||||
|
||||
GroupMember groupMember = groupMemberDao.getMemberByGroupId(roomGroup.getId(), uid);
|
||||
if(ObjectUtil.isNull(groupMember)){
|
||||
if (ObjectUtil.isNull(groupMember)) {
|
||||
throw new RuntimeException(StrUtil.format("您不是{}的群成员!", roomGroup.getName()));
|
||||
}
|
||||
return groupMember;
|
||||
@@ -454,6 +475,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* 群主,管理员才可以修改
|
||||
*
|
||||
* @param uid
|
||||
* @param request
|
||||
* @return
|
||||
@@ -464,7 +486,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
RoomGroup roomGroup = roomGroupCache.get(request.getId());
|
||||
GroupMember groupMember = verifyGroupPermissions(uid, roomGroup);
|
||||
|
||||
if(GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) {
|
||||
if (GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -474,7 +496,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
Boolean success = roomService.updateRoomInfo(roomGroup);
|
||||
|
||||
// 3.通知群里所有人群信息修改了
|
||||
if(success){
|
||||
if (success) {
|
||||
roomGroupCache.delete(roomGroup.getId());
|
||||
roomGroupCache.evictGroup(roomGroup.getAccount());
|
||||
List<Long> memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId());
|
||||
@@ -490,7 +512,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
GroupMember member = verifyGroupPermissions(uid, roomGroup);
|
||||
|
||||
// 2.修改我的信息
|
||||
boolean equals = member.getMyName().equals(StrUtil.isEmpty(request.getMyName())? "": request.getMyName());
|
||||
boolean equals = member.getMyName().equals(StrUtil.isEmpty(request.getMyName()) ? "" : request.getMyName());
|
||||
boolean success = groupMemberDao.update(null, Wrappers.<GroupMember>lambdaUpdate()
|
||||
.set(GroupMember::getRemark, request.getRemark())
|
||||
.set(GroupMember::getMyName, request.getMyName())
|
||||
@@ -499,7 +521,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
groupMemberCache.evictMemberDetail(roomGroup.getRoomId(), uid);
|
||||
|
||||
// 3.通知群里所有人我的信息改变了
|
||||
if(!equals && success){
|
||||
if (!equals && success) {
|
||||
List<Long> memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId());
|
||||
pushService.sendPushMsg(RoomAdapter.buildMyRoomGroupChangeWS(roomGroup.getRoomId(), uid, request.getMyName()), memberUidList, uid);
|
||||
}
|
||||
@@ -510,7 +532,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
public Boolean setTop(Long uid, ContactTopReq request) {
|
||||
// 1.判断会话我有没有
|
||||
Contact contact = contactDao.get(uid, request.getRoomId());
|
||||
if(ObjectUtil.isNull(contact)){
|
||||
if (ObjectUtil.isNull(contact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -524,7 +546,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
public Boolean pushAnnouncement(Long uid, AnnouncementsParam param) {
|
||||
RoomGroup roomGroup = roomGroupCache.get(param.getRoomId());
|
||||
List<Long> uids = roomService.getGroupUsers(roomGroup.getId(), false);
|
||||
if(CollUtil.isNotEmpty(uids)){
|
||||
if (CollUtil.isNotEmpty(uids)) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Announcements announcements = new Announcements();
|
||||
announcements.setContent(param.getContent());
|
||||
@@ -547,7 +569,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
});
|
||||
// 批量添加未读消息
|
||||
Boolean saved = roomService.saveBatchAnnouncementsRecord(announcementsReadRecordList);
|
||||
if(saved){
|
||||
if (saved) {
|
||||
// 发送公告消息、推送群成员公告内容
|
||||
chatService.sendMsg(MessageAdapter.buildAnnouncementsMsg(param.getRoomId(), announcements), uid);
|
||||
}
|
||||
@@ -560,9 +582,9 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
public Boolean announcementEdit(Long uid, AnnouncementsParam param) {
|
||||
RoomGroup roomGroup = roomGroupCache.get(param.getRoomId());
|
||||
List<Long> uids = roomService.getGroupUsers(roomGroup.getId(), false);
|
||||
if(CollUtil.isNotEmpty(uids)){
|
||||
if (CollUtil.isNotEmpty(uids)) {
|
||||
AnnouncementsResp announcement = roomService.getAnnouncement(param.getId());
|
||||
if(ObjectUtil.isNull(announcement)){
|
||||
if (ObjectUtil.isNull(announcement)) {
|
||||
return false;
|
||||
}
|
||||
Announcements announcements = new Announcements();
|
||||
@@ -572,7 +594,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
announcements.setTop(param.getTop());
|
||||
announcements.setUpdateTime(TimeUtils.now());
|
||||
Boolean edit = roomService.updateAnnouncement(announcements);
|
||||
if(edit){
|
||||
if (edit) {
|
||||
chatService.sendMsg(MessageAdapter.buildAnnouncementsMsg(param.getRoomId(), announcements), uid);
|
||||
}
|
||||
return edit;
|
||||
@@ -590,7 +612,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
// 1.更新已读状态
|
||||
Boolean success = roomService.readAnnouncement(uid, param.getAnnouncementId());
|
||||
|
||||
if(success){
|
||||
if (success) {
|
||||
// 2.刷新最新的已读数量,通知所有人有人对 announcementId 已读了
|
||||
roomAnnouncementsCache.add(param.getAnnouncementId(), uid);
|
||||
|
||||
@@ -610,7 +632,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 3.查询公告已读数量
|
||||
Long count = roomAnnouncementsCache.get(param.getAnnouncementId());
|
||||
if(count < 1){
|
||||
if (count < 1) {
|
||||
count = roomService.getAnnouncementReadCount(param.getAnnouncementId());
|
||||
roomAnnouncementsCache.load(Arrays.asList(param.getAnnouncementId()));
|
||||
}
|
||||
@@ -630,7 +652,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
long count = userBackpackDao.countByUidAndItemId(uid, "HuLa项目贡献者专属徽章");
|
||||
|
||||
if(count == 0 && GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) {
|
||||
if (count == 0 && GroupRoleEnum.MEMBER.getType().equals(groupMember.getRoleId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -646,7 +668,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
public Boolean setNotification(Long uid, ContactNotificationReq request) {
|
||||
// 1. 判断会话我有没有
|
||||
Contact contact = contactDao.get(uid, request.getRoomId());
|
||||
if(ObjectUtil.isNull(contact)){
|
||||
if (ObjectUtil.isNull(contact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -654,20 +676,20 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
contact.setMuteNotification(request.getType());
|
||||
|
||||
// 3.通知所有设备我已经开启/关闭这个房间的免打扰
|
||||
pushService.sendPushMsg(WsAdapter.buildContactNotification(request) , uid, uid);
|
||||
pushService.sendPushMsg(WsAdapter.buildContactNotification(request), uid, uid);
|
||||
return contactDao.updateById(contact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean setShield(Long uid, ContactShieldReq request) {
|
||||
Contact contact = contactDao.get(uid, request.getRoomId());
|
||||
if(ObjectUtil.isNull(contact)){
|
||||
if (ObjectUtil.isNull(contact)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String name;
|
||||
Room room = roomCache.get(request.getRoomId());
|
||||
if(room.getType().equals(RoomTypeEnum.GROUP.getType())){
|
||||
if (room.getType().equals(RoomTypeEnum.GROUP.getType())) {
|
||||
// 1. 把群成员的信息设置为禁止
|
||||
name = roomGroupCache.get(request.getRoomId()).getName();
|
||||
groupMemberDao.setMemberDeFriend(request.getRoomId(), uid, request.getState());
|
||||
@@ -687,30 +709,70 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatMessageResp mergeMessage(Long uid, MergeMessageReq req) {
|
||||
public void mergeMessage(Long uid, MergeMessageReq req) {
|
||||
// 1. 校验人员是否在群里、或者有没有对方的好友
|
||||
Room room = roomCache.get(req.getFromRoomId());
|
||||
if(ObjectUtil.isNull(room)){
|
||||
if (ObjectUtil.isNull(room)) {
|
||||
throw new BizException("房间不存在");
|
||||
}
|
||||
|
||||
if(room.getType().equals(RoomTypeEnum.GROUP.getType())){
|
||||
if (room.getType().equals(RoomTypeEnum.GROUP.getType())) {
|
||||
RoomGroup sourceRoomGroup = roomGroupCache.get(req.getFromRoomId());
|
||||
verifyGroupPermissions(uid, sourceRoomGroup);
|
||||
} else {
|
||||
RoomFriend roomFriend = roomFriendCache.get(req.getFromRoomId());
|
||||
if(ObjectUtil.isNull(roomFriend) || !roomFriend.getUid1().equals(uid) && !roomFriend.getUid1().equals(uid)) {
|
||||
if (ObjectUtil.isNull(roomFriend) || !roomFriend.getUid1().equals(uid) && !roomFriend.getUid1().equals(uid)) {
|
||||
throw new BizException("你们不是好友关系");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 当是转发单条消息的时候
|
||||
List<Message> messagess = chatService.getMsgByIds(req.getMessageIds());
|
||||
List<MergeMsg> msgs = messagess.stream().filter(message -> message.getRoomId().equals(req.getFromRoomId())).map(message -> new MergeMsg(message.getContent(), message.getCreateTime(), userCache.get(message.getFromUid()).getName())).collect(Collectors.toUnmodifiableList());
|
||||
|
||||
// 3. 发布合并消息
|
||||
Long msgId = chatService.sendMsg(MessageAdapter.buildMergeMsg(req.getRoomId(), msgs), uid);
|
||||
return chatService.getMsgResp(msgId, uid);
|
||||
for (Long roomId : req.getRoomIds()) {
|
||||
if (req.getType().equals(MergeTypeEnum.SINGLE.getType())) {
|
||||
messagess.forEach(message -> {
|
||||
ChatMessageReq messageReq = new ChatMessageReq();
|
||||
messageReq.setMsgType(message.getType());
|
||||
messageReq.setRoomId(roomId);
|
||||
// 扩展消息需要另外解析
|
||||
messageReq.setBody(analyze(message));
|
||||
messageReq.setSkip(true);
|
||||
chatService.sendMsg(messageReq, uid);
|
||||
});
|
||||
} else {
|
||||
chatService.sendMsg(MessageAdapter.buildMergeMsg(roomId, messagess), uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析转发的消息
|
||||
*
|
||||
* @param message 数据库里面的消息实体
|
||||
*/
|
||||
private Object analyze(Message message) {
|
||||
return switch (MessageTypeEnum.of(message.getType())) {
|
||||
case TEXT -> {
|
||||
TextMsgReq textMsgReq = new TextMsgReq();
|
||||
textMsgReq.setContent(message.getContent());
|
||||
textMsgReq.setReplyMsgId(message.getReplyMsgId());
|
||||
textMsgReq.setAtUidList(message.getExtra().getAtUidList());
|
||||
yield textMsgReq;
|
||||
}
|
||||
case RECALL -> message.getExtra().getRecall();
|
||||
case IMG -> message.getExtra().getImgMsgDTO();
|
||||
case FILE -> message.getExtra().getFileMsg();
|
||||
case SOUND -> message.getExtra().getSoundMsgDTO();
|
||||
case VIDEO -> message.getExtra().getVideoMsgDTO();
|
||||
case EMOJI -> message.getExtra().getEmojisMsgDTO();
|
||||
case BOT, SYSTEM -> null;
|
||||
case MERGE -> message.getExtra().getMergeMsgDTO();
|
||||
case NOTICE -> message.getExtra().getNoticeMsgDTO();
|
||||
case VIDEO_CALL -> message.getExtra().getVideoCallMsgDTO();
|
||||
case AUDIO_CALL -> message.getExtra().getAudioCallMsgDTO();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -784,18 +846,6 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 7. 群主、管理员永远在前面
|
||||
return chatMemberResps;
|
||||
// return chatMemberResps.stream()
|
||||
// .sorted((m1, m2) -> {
|
||||
// // 群主 > 管理员> 普通成员
|
||||
// int roleCompare = Integer.compare(m1.getRoleId(), m2.getRoleId());
|
||||
//
|
||||
// // 如果是相同角色
|
||||
// if (roleCompare == 0) {
|
||||
// return Integer.compare(m1.getActiveStatus(), m2.getActiveStatus());
|
||||
// }
|
||||
// // 不同角色:管理组始终排在普通组前面
|
||||
// return roleCompare;
|
||||
// }).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -827,11 +877,11 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
// 如果房间人员小于3人 那么直接解散群聊
|
||||
CacheKey membersKey = PresenceCacheKeyBuilder.groupMembersKey(request.getRoomId());
|
||||
Long memberNum = cachePlusOps.sCard(membersKey);
|
||||
if(memberNum <= 3 && self.getRoleId().equals(GroupRoleEnum.LEADER.getType())) {
|
||||
if (memberNum <= 3) {
|
||||
MemberExitReq exitReq = new MemberExitReq();
|
||||
exitReq.setRoomId(request.getRoomId());
|
||||
exitReq.setAccount(roomGroup.getAccount());
|
||||
exitGroup(uid, exitReq);
|
||||
exitGroup(true, uid, exitReq);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -850,12 +900,12 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
AssertUtil.isNotEmpty(member, "用户已经移除");
|
||||
|
||||
// 发送移除事件告知群成员
|
||||
if(transactionTemplate.execute(e -> {
|
||||
if (transactionTemplate.execute(e -> {
|
||||
groupMemberDao.removeById(member.getId());
|
||||
// 1.5 移除会话
|
||||
contactDao.removeByRoomId(room.getId(), Collections.singletonList(request.getUid()));
|
||||
return true;
|
||||
})){
|
||||
})) {
|
||||
// 移除群聊缓存
|
||||
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(request.getUid());
|
||||
cachePlusOps.sRem(membersKey, request.getUid());
|
||||
@@ -864,14 +914,38 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
// 推送状态到前端
|
||||
List<Long> memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId());
|
||||
if(!memberUidList.contains(request.getUid())){
|
||||
if (!memberUidList.contains(request.getUid())) {
|
||||
memberUidList.add(request.getUid());
|
||||
}
|
||||
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), (int) (memberNum - 1), Arrays.asList(member.getUid()), WSMemberChange.CHANGE_TYPE_REMOVE);
|
||||
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), (int) (memberNum - 1), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(member.getUid()), WSMemberChange.CHANGE_TYPE_REMOVE);
|
||||
pushService.sendPushMsg(ws, memberUidList, uid);
|
||||
groupMemberCache.evictMemberList(room.getId());
|
||||
groupMemberCache.evictExceptMemberList(room.getId());
|
||||
groupMemberCache.evictMemberDetail(room.getId(), removedUid);
|
||||
|
||||
long uuid = uidGenerator.getUid();
|
||||
// 保存被删除人的通知
|
||||
noticeService.createNotice(
|
||||
RoomTypeEnum.GROUP,
|
||||
NoticeTypeEnum.GROUP_MEMBER_DELETE,
|
||||
uid,
|
||||
removedUid,
|
||||
uuid,
|
||||
removedUid,
|
||||
roomGroup.getName()
|
||||
);
|
||||
|
||||
// 获取所有管理员
|
||||
List<Long> managerIds = groupMemberDao.getGroupUsers(roomGroup.getId(), true);
|
||||
managerIds.forEach(managerId -> noticeService.createNotice(
|
||||
RoomTypeEnum.GROUP,
|
||||
NoticeTypeEnum.GROUP_MEMBER_DELETE,
|
||||
uid,
|
||||
managerId,
|
||||
uuid,
|
||||
removedUid,
|
||||
roomGroup.getName()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,18 +973,38 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
}
|
||||
|
||||
// 2. 创建邀请记录
|
||||
transactionTemplate.execute(e -> {
|
||||
List<UserApply> invites = validUids.stream().map(inviteeUid -> new UserApply(uid, RoomTypeEnum.GROUP.getType(), roomGroup.getRoomId(), inviteeUid, StrUtil.format("{}邀请你加入{}", userSummaryCache.get(uid).getName(), roomGroup.getName()), ApplyStatusEnum.WAIT_APPROVAL.getCode(), UNREAD.getCode(), 0, false)).collect(Collectors.toList());
|
||||
userApplyDao.saveBatch(invites);
|
||||
return true;
|
||||
});
|
||||
List<UserApply> invites = validUids.stream().map(inviteeUid -> new UserApply(uid, RoomTypeEnum.GROUP.getType(), roomGroup.getRoomId(), inviteeUid, StrUtil.format("{}邀请你加入{}", userSummaryCache.get(uid).getName(), roomGroup.getName()), ApplyStatusEnum.WAIT_APPROVAL.getCode(), UNREAD.getCode(), 0, false)).collect(Collectors.toList());
|
||||
transactionTemplate.execute(e -> userApplyDao.saveBatch(invites));
|
||||
|
||||
// 3. 通知被邀请的人进群
|
||||
validUids.forEach(inviteId -> {
|
||||
SummeryInfoDTO user = userSummaryCache.get(inviteId);
|
||||
if(ObjectUtil.isNotNull(user)){
|
||||
pushService.sendPushMsg(MessageAdapter.buildInviteeUserAddGroupMessage(userApplyDao.getUnReadCount(inviteId, inviteId)), inviteId, uid);
|
||||
// 3. 通知被邀请的人进群, 通知时绑定通知id
|
||||
List<Long> managerIds = groupMemberDao.getGroupUsers(roomGroup.getId(), true);
|
||||
invites.forEach(invite -> {
|
||||
SummeryInfoDTO user = userSummaryCache.get(invite.getTargetId());
|
||||
if (ObjectUtil.isNotNull(user)) {
|
||||
pushService.sendPushMsg(MessageAdapter.buildInviteeUserAddGroupMessage(noticeDao.getUnReadCount(invite.getTargetId(), invite.getTargetId())), invite.getTargetId(), uid);
|
||||
}
|
||||
|
||||
// 每个被邀请的人都要收到邀请进群的消息
|
||||
noticeService.createNotice(
|
||||
RoomTypeEnum.GROUP,
|
||||
NoticeTypeEnum.GROUP_INVITE_ME,
|
||||
uid,
|
||||
invite.getTargetId(),
|
||||
invite.getId(),
|
||||
invite.getTargetId(),
|
||||
roomGroup.getName()
|
||||
);
|
||||
|
||||
// 每个管理员都要收到邀请进群的消息
|
||||
managerIds.forEach(managerId -> noticeService.createNotice(
|
||||
RoomTypeEnum.GROUP,
|
||||
NoticeTypeEnum.GROUP_INVITE,
|
||||
uid,
|
||||
managerId,
|
||||
invite.getId(),
|
||||
invite.getTargetId(),
|
||||
roomGroup.getName()
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -922,7 +1016,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
*/
|
||||
@Override
|
||||
@RedissonLock(prefixKey = "exitGroup:", key = "#request.roomId")
|
||||
public void exitGroup(Long uid, MemberExitReq request) {
|
||||
public void exitGroup(Boolean isGroup, Long uid, MemberExitReq request) {
|
||||
Long roomId = request.getRoomId();
|
||||
// 1. 判断群聊是否存在
|
||||
RoomGroup roomGroup = roomGroupCache.getByRoomId(roomId);
|
||||
@@ -944,14 +1038,20 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
} else {
|
||||
memberUidList = groupMemberCache.getMemberExceptUidList(roomGroup.getRoomId());
|
||||
}
|
||||
CacheKey gKey = PresenceCacheKeyBuilder.groupMembersKey(room.getId());
|
||||
if (isGroup || isLord) {
|
||||
User user = userCache.get(uid);
|
||||
ChatMessageReq messageReq = new ChatMessageReq();
|
||||
messageReq.setBody(StrUtil.format("{}解散了群聊", user.getName()));
|
||||
messageReq.setMsgType(MessageTypeEnum.SYSTEM.getType());
|
||||
chatService.sendMsg(messageReq, uid);
|
||||
|
||||
if (isLord) {
|
||||
// 4.1 删除房间和群并清除缓存
|
||||
transactionTemplate.execute(e -> {
|
||||
boolean isDelRoom = roomService.removeById(roomId);
|
||||
roomGroupCache.removeById(roomGroup.getId());
|
||||
roomGroupCache.evictGroup(roomGroup.getAccount());
|
||||
if(StrUtil.isNotEmpty(request.getAccount())){
|
||||
if (StrUtil.isNotEmpty(request.getAccount())) {
|
||||
roomGroupCache.evictGroup(request.getAccount());
|
||||
}
|
||||
AssertUtil.isTrue(isDelRoom, ResponseEnum.SYSTEM_BUSY.getMsg());
|
||||
@@ -972,12 +1072,20 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
groupMemberCache.evictAllMemberDetails();
|
||||
// 新版解散群聊
|
||||
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(uid);
|
||||
CacheKey gKey = PresenceCacheKeyBuilder.groupMembersKey(room.getId());
|
||||
cachePlusOps.del(uKey, gKey);
|
||||
asyncOnline(memberUidList, room.getId(), false);
|
||||
pushService.sendPushMsg(RoomAdapter.buildGroupDissolution(roomGroup.getRoomId()), memberUidList, uid);
|
||||
// pushService.sendPushMsg(RoomAdapter.buildGroupDissolution(roomGroup.getRoomId()), memberUidList, uid);
|
||||
} else {
|
||||
if(transactionTemplate.execute(e -> {
|
||||
// 如果房间人员小于3人 那么直接解散群聊
|
||||
if (cachePlusOps.sCard(gKey) <= 3) {
|
||||
MemberExitReq exitReq = new MemberExitReq();
|
||||
exitReq.setRoomId(request.getRoomId());
|
||||
exitReq.setAccount(roomGroup.getAccount());
|
||||
exitGroup(true, uid, exitReq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transactionTemplate.execute(e -> {
|
||||
// 4.6 删除会话
|
||||
Boolean isDelContact = contactDao.removeByRoomId(roomId, Collections.singletonList(uid));
|
||||
AssertUtil.isTrue(isDelContact, "会话移除异常");
|
||||
@@ -985,16 +1093,16 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
Boolean isDelGroupMember = groupMemberDao.removeByGroupId(roomGroup.getId(), Collections.singletonList(uid));
|
||||
AssertUtil.isTrue(isDelGroupMember, "群成员移除失败");
|
||||
return true;
|
||||
})){
|
||||
})) {
|
||||
// 新版退出群聊
|
||||
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(uid);
|
||||
CacheKey gKey = PresenceCacheKeyBuilder.groupMembersKey(room.getId());
|
||||
|
||||
cachePlusOps.sRem(gKey, uid);
|
||||
cachePlusOps.sRem(uKey, room.getId());
|
||||
asyncOnline(Arrays.asList(uid), room.getId(), false);
|
||||
|
||||
// 4.8 发送移除事件告知群成员
|
||||
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Arrays.asList(uid), WSMemberChange.CHANGE_TYPE_QUIT);
|
||||
WsBaseResp<WSMemberChange> ws = MemberAdapter.buildMemberRemoveWS(roomGroup.getRoomId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId()))), Arrays.asList(uid), WSMemberChange.CHANGE_TYPE_QUIT);
|
||||
pushService.sendPushMsg(ws, memberUidList, uid);
|
||||
groupMemberCache.evictMemberList(room.getId());
|
||||
groupMemberCache.evictExceptMemberList(room.getId());
|
||||
@@ -1007,20 +1115,20 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
@RedissonLock(prefixKey = "addGroup:", key = "#uid")
|
||||
public Long addGroup(Long uid, GroupAddReq request) {
|
||||
Map<Long, SummeryInfoDTO> userMap = userSummaryCache.getBatch(request.getUidList());
|
||||
AssertUtil.isTrue(userMap.size() > 1,"群聊人数应大于2人");
|
||||
AssertUtil.isTrue(userMap.size() > 1, "群聊人数应大于2人");
|
||||
|
||||
List<Long> uidList = new ArrayList<>(userMap.keySet());
|
||||
AtomicReference<Long> roomIdAtomic = new AtomicReference(0L);
|
||||
|
||||
// 创建群组数据并推送数据到前端
|
||||
if(transactionTemplate.execute(e -> {
|
||||
if (transactionTemplate.execute(e -> {
|
||||
RoomGroup roomGroup = roomService.createGroupRoom(uid, request);
|
||||
// 批量保存群成员
|
||||
List<GroupMember> groupMembers = RoomAdapter.buildGroupMemberBatch(uidList, roomGroup.getId());
|
||||
groupMemberDao.saveBatch(groupMembers);
|
||||
roomIdAtomic.set(roomGroup.getRoomId());
|
||||
return true;
|
||||
})){
|
||||
})) {
|
||||
// 发送邀请加群消息 ==> 触发每个人的会话
|
||||
roomGroupCache.evictAllCaches();
|
||||
// 处理新房间里面所有在线人员
|
||||
@@ -1036,7 +1144,6 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
cachePlusOps.sAdd(PresenceCacheKeyBuilder.userGroupsKey(id), roomIdAtomic.get());
|
||||
});
|
||||
asyncOnline(uidList, roomIdAtomic.get(), true);
|
||||
SpringUtils.publishEvent(new GroupInviteMemberEvent(this, roomIdAtomic.get(), request.getUidList(), uid));
|
||||
SpringUtils.publishEvent(new GroupMemberAddEvent(this, roomIdAtomic.get(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), request.getUidList(), uid));
|
||||
}
|
||||
return roomIdAtomic.get();
|
||||
@@ -1073,8 +1180,8 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* @param contactMap 会话映射
|
||||
* @param uid 当前登录的用户
|
||||
* @param roomIds 所有会话对应的房间
|
||||
* @param uid 当前登录的用户
|
||||
* @param roomIds 所有会话对应的房间
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
@@ -1093,7 +1200,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
Long roomId = room.getRoomId();
|
||||
RoomBaseInfo roomBaseInfo = roomBaseInfoMap.get(roomId);
|
||||
Contact contact = contactMap.get(StrUtil.format("{}_{}", uid, roomId));
|
||||
if(ObjectUtil.isNotNull(contact)){
|
||||
if (ObjectUtil.isNotNull(contact)) {
|
||||
resp.setHide(contact.getHide());
|
||||
resp.setShield(contact.getShield());
|
||||
resp.setMuteNotification(contact.getMuteNotification());
|
||||
@@ -1117,7 +1224,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
resp.setRemark(roomBaseInfo.getRemark());
|
||||
resp.setMyName(roomBaseInfo.getMyName());
|
||||
Message message = msgMap.get(room.getLastMsgId());
|
||||
if(resp.getShield()){
|
||||
if (resp.getShield()) {
|
||||
resp.setText("您已屏蔽该会话");
|
||||
} else {
|
||||
if (Objects.nonNull(message)) {
|
||||
@@ -1128,7 +1235,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
GroupMember messageUser = groupMemberCache.getMemberDetail(roomId, message.getFromUid());
|
||||
if (ObjectUtil.isNotNull(messageUser)) {
|
||||
// 当自己查看时,且最后一条消息是自己发送的,那么显示群备注
|
||||
if (uid.equals(message.getFromUid()) && StrUtil.isNotEmpty(messageUser.getRemark())){
|
||||
if (uid.equals(message.getFromUid()) && StrUtil.isNotEmpty(messageUser.getRemark())) {
|
||||
resp.setRemark(messageUser.getRemark());
|
||||
}
|
||||
}
|
||||
@@ -1156,6 +1263,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
|
||||
/**
|
||||
* 返回房间id与好友的映射
|
||||
*
|
||||
* @param roomIds
|
||||
* @param uid
|
||||
* @return
|
||||
@@ -1204,7 +1312,7 @@ public class RoomAppServiceImpl implements RoomAppService, InitializingBean {
|
||||
roomBaseInfo.setRemark(member.getRemark());
|
||||
roomBaseInfo.setName(roomGroup.getName());
|
||||
roomBaseInfo.setRoleId(member.getRoleId());
|
||||
}else {
|
||||
} else {
|
||||
roomBaseInfo.setName("会话异常");
|
||||
roomBaseInfo.setMyName("会话异常");
|
||||
roomBaseInfo.setRemark("会话异常");
|
||||
|
||||
@@ -15,7 +15,7 @@ import com.luohuo.flex.im.domain.enums.MessageStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.core.chat.service.adapter.MessageAdapter;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgPlusCache;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -26,7 +26,7 @@ public abstract class AbstractMsgHandler<T> {
|
||||
private MessageDao messageDao;
|
||||
|
||||
@Resource
|
||||
private MsgPlusCache msgPlusCache;
|
||||
private MsgCache msgCache;
|
||||
|
||||
@Resource
|
||||
private UserSummaryCache userSummaryCache;
|
||||
@@ -82,7 +82,7 @@ public abstract class AbstractMsgHandler<T> {
|
||||
*/
|
||||
public ReplyMsg replyMsg(Message msg){
|
||||
Optional<Message> reply = Optional.ofNullable(msg.getReplyMsgId())
|
||||
.map(msgPlusCache::get)
|
||||
.map(msgCache::get)
|
||||
.filter(a -> Objects.equals(a.getStatus(), MessageStatusEnum.NORMAL.getStatus()));
|
||||
// TODO 这里的缓存不会立即删除,导致撤回消息后回复的信息还有 (nyh -> 2024-07-14 03:46:34)
|
||||
if (reply.isPresent()) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.luohuo.flex.im.domain.entity.User;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MessageExtra;
|
||||
import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoleTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.msg.TextMsgReq;
|
||||
import com.luohuo.flex.im.domain.entity.msg.TextMsgReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.msg.TextMsgResp;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.luohuo.flex.im.core.chat.service.strategy.msg;
|
||||
|
||||
import com.luohuo.flex.im.core.chat.dao.MessageDao;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserCache;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MergeMsgDTO;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MessageExtra;
|
||||
@@ -8,7 +10,12 @@ import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.luohuo.flex.im.domain.enums.MessageTypeEnum.*;
|
||||
|
||||
/**
|
||||
* 合并消息
|
||||
@@ -17,15 +24,36 @@ import java.util.Optional;
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class MergeMsgHandler extends AbstractMsgHandler<MergeMsgDTO> {
|
||||
private MessageDao messageDao;
|
||||
private MsgCache msgCache;
|
||||
private UserCache userCache;
|
||||
private MessageDao messageDao;
|
||||
|
||||
@Override
|
||||
MessageTypeEnum getMsgTypeEnum() {
|
||||
return MessageTypeEnum.MERGE;
|
||||
return MERGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveMsg(Message message, MergeMsgDTO body) {
|
||||
List<Message> messages = new ArrayList<>(msgCache.getBatch(body.getBody().stream()
|
||||
.limit(3)
|
||||
.map(item -> Long.parseLong(item.getMessageId()))
|
||||
.collect(Collectors.toList())).values());
|
||||
|
||||
List<String> content = messages.stream().map(msg ->
|
||||
userCache.get(msg.getFromUid()).getName() + ": " + switch (msg.getType()) {
|
||||
case MERGE -> "[聊天记录]";
|
||||
case SOUND -> "[语音]";
|
||||
case VIDEO -> "[视频]";
|
||||
case FILE -> "[文件]";
|
||||
case IMG -> "[图片]";
|
||||
case RECALL -> "[消息已撤回]";
|
||||
case EMOJI -> "[表情]";
|
||||
case NOTICE -> "[公告消息]";
|
||||
default -> msg.getContent();
|
||||
}).collect(Collectors.toList());
|
||||
body.setContent(content);
|
||||
|
||||
MessageExtra extra = Optional.ofNullable(message.getExtra()).orElse(new MessageExtra());
|
||||
Message update = new Message();
|
||||
update.setId(message.getId());
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.luohuo.flex.im.core.chat.service.strategy.msg;
|
||||
|
||||
import com.luohuo.basic.utils.SpringUtils;
|
||||
import com.luohuo.basic.utils.TimeUtils;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -13,7 +14,6 @@ import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MessageExtra;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MsgRecall;
|
||||
import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import com.luohuo.flex.im.core.chat.service.cache.MsgCache;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.luohuo.flex.im.core.chat.dao.MessageDao;
|
||||
import com.luohuo.flex.im.domain.entity.Message;
|
||||
import com.luohuo.flex.im.domain.entity.msg.MessageExtra;
|
||||
import com.luohuo.flex.im.domain.enums.MessageTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.request.msg.TextMsgReq;
|
||||
import com.luohuo.flex.im.domain.entity.msg.TextMsgReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.msg.TextMsgResp;
|
||||
import com.luohuo.flex.im.domain.entity.User;
|
||||
import com.luohuo.flex.im.domain.enums.RoleTypeEnum;
|
||||
@@ -65,6 +65,10 @@ public class TextMsgHandler extends AbstractMsgHandler<TextMsgReq> {
|
||||
}
|
||||
}
|
||||
|
||||
private Object reverseFromBean(Objects t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMsg(Message msg, TextMsgReq body) {//插入文本内容
|
||||
MessageExtra extra = Optional.ofNullable(msg.getExtra()).orElse(new MessageExtra());
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.luohuo.flex.im.core.user.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.luohuo.flex.im.core.user.mapper.NoticeMapper;
|
||||
import com.luohuo.flex.im.domain.entity.Notice;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendUnreadDto;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum.READ;
|
||||
import static com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum.UNREAD;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Service
|
||||
public class NoticeDao extends ServiceImpl<NoticeMapper, Notice> {
|
||||
|
||||
public void markAsRead(Long noticeId) {
|
||||
Notice dbNotice = baseMapper.selectById(noticeId);
|
||||
|
||||
Notice notice = new Notice();
|
||||
notice.setId(dbNotice.getId());
|
||||
notice.setIsRead(READ.getCode());
|
||||
baseMapper.updateById(notice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户的通知
|
||||
* @param uid 登录用户
|
||||
* @param onlyUnread 通知状态
|
||||
* @return
|
||||
*/
|
||||
public IPage<Notice> getUserNotices(Long uid, boolean onlyUnread, Page<Notice> page) {
|
||||
return lambdaQuery()
|
||||
.eq(Notice::getReceiverId, uid)
|
||||
.orderByDesc(Notice::getCreateTime)
|
||||
.page(page);
|
||||
}
|
||||
|
||||
public WSNotice getUnReadCount(Long uid, Long receiverId) {
|
||||
List<FriendUnreadDto> unReadCountByTypeMap = baseMapper.getUnReadCountByType(receiverId, UNREAD.getCode());
|
||||
WSNotice wsNotice = new WSNotice();
|
||||
wsNotice.setUid(uid);
|
||||
|
||||
for (FriendUnreadDto friendUnreadDto : unReadCountByTypeMap) {
|
||||
if(friendUnreadDto.getType().equals(RoomTypeEnum.FRIEND.getType())){
|
||||
wsNotice.setUnReadCount4Friend(friendUnreadDto.getCount());
|
||||
} else {
|
||||
wsNotice.setUnReadCount4Group(friendUnreadDto.getCount());
|
||||
}
|
||||
}
|
||||
return wsNotice;
|
||||
}
|
||||
|
||||
public void readNotices(Long uid, List<Long> notices) {
|
||||
lambdaUpdate()
|
||||
.set(Notice::getIsRead, READ.getCode())
|
||||
.eq(Notice::getIsRead, UNREAD.getCode())
|
||||
.in(Notice::getId, notices)
|
||||
.eq(Notice::getReceiverId, uid)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,6 @@ import com.luohuo.flex.im.core.user.mapper.UserApplyMapper;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.CursorPageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendUnreadDto;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@@ -48,54 +46,16 @@ public class UserApplyDao extends ServiceImpl<UserApplyMapper, UserApply> {
|
||||
* @param initiator 方法调用方是否是申请记录发起方
|
||||
* @return {@link UserApply }
|
||||
*/
|
||||
public UserApply getFriendApproving(Long uid, Long targetUid,boolean initiator) {
|
||||
public UserApply getFriendApproving(Long uid, Long targetUid, boolean initiator) {
|
||||
return lambdaQuery().eq(UserApply::getUid, uid)
|
||||
.eq(UserApply::getTargetId, targetUid)
|
||||
.eq(UserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode())
|
||||
.eq(UserApply::getType, RoomTypeEnum.FRIEND.getType())
|
||||
.notIn(initiator,UserApply::getDeleted,ApplyDeletedEnum.applyDeleted())
|
||||
.notIn(!initiator,UserApply::getDeleted,ApplyDeletedEnum.targetDeleted())
|
||||
.notIn(initiator,UserApply::getDeleted, ApplyDeletedEnum.applyDeleted())
|
||||
.notIn(!initiator,UserApply::getDeleted, ApplyDeletedEnum.targetDeleted())
|
||||
.one();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回好友、群聊申请的未读数量
|
||||
* @param targetId
|
||||
* @return
|
||||
*/
|
||||
public WSFriendApply getUnReadCount(Long uid, Long targetId) {
|
||||
List<FriendUnreadDto> unReadCountByTypeMap = baseMapper.getUnReadCountByType(targetId, UNREAD.getCode(), ApplyDeletedEnum.NORMAL.getCode());
|
||||
WSFriendApply wsFriendApply = new WSFriendApply();
|
||||
wsFriendApply.setUid(uid);
|
||||
|
||||
// 构造需要的数据
|
||||
for (FriendUnreadDto friendUnreadDto : unReadCountByTypeMap) {
|
||||
if(friendUnreadDto.getType().equals(RoomTypeEnum.FRIEND.getType())){
|
||||
wsFriendApply.setUnReadCount4Friend(friendUnreadDto.getCount());
|
||||
} else {
|
||||
wsFriendApply.setUnReadCount4Group(friendUnreadDto.getCount());
|
||||
}
|
||||
}
|
||||
return wsFriendApply;
|
||||
}
|
||||
|
||||
public IPage<UserApply> friendApplyPage(Long uid, Page<UserApply> page) {
|
||||
return lambdaQuery()
|
||||
.and(w -> w.eq(UserApply::getTargetId, uid).or().eq(UserApply::getUid, uid))
|
||||
.eq(UserApply::getDeleted,false)
|
||||
.orderByDesc(UserApply::getCreateTime)
|
||||
.page(page);
|
||||
}
|
||||
|
||||
public void readApples(Long uid, List<Long> applyIds) {
|
||||
lambdaUpdate()
|
||||
.set(UserApply::getReadStatus, READ.getCode())
|
||||
.eq(UserApply::getReadStatus, UNREAD.getCode())
|
||||
.in(UserApply::getId, applyIds)
|
||||
.eq(UserApply::getTargetId, uid)
|
||||
.update();
|
||||
}
|
||||
|
||||
public void agree(Long applyId) {
|
||||
lambdaUpdate()
|
||||
.eq(UserApply::getId, applyId)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.luohuo.flex.im.core.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luohuo.flex.im.domain.entity.Notice;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendUnreadDto;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Repository
|
||||
public interface NoticeMapper extends BaseMapper<Notice> {
|
||||
|
||||
List<FriendUnreadDto> getUnReadCountByType(Long receiverId, Integer isRead);
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
package com.luohuo.flex.im.core.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendUnreadDto;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.luohuo.flex.im.domain.entity.UserApply;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 用户申请表 Mapper 接口
|
||||
@@ -18,5 +14,4 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface UserApplyMapper extends BaseMapper<UserApply> {
|
||||
|
||||
List<FriendUnreadDto> getUnReadCountByType(@Param("targetId") Long targetId, @Param("readStatus") Integer readStatus, @Param("normal") Integer normal);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
package com.luohuo.flex.im.core.user.service;
|
||||
|
||||
import com.luohuo.flex.im.domain.entity.UserApply;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.req.friend.FriendApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.RoomApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.ApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.GroupApplyHandleReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendApplyResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
/**
|
||||
@@ -50,21 +46,6 @@ public interface ApplyService {
|
||||
*/
|
||||
void handlerApply(Long uid, @Valid ApplyReq request);
|
||||
|
||||
/**
|
||||
* 分页查询好友申请
|
||||
*
|
||||
* @param request 请求
|
||||
* @return {@link PageBaseResp}<{@link FriendApplyResp}>
|
||||
*/
|
||||
PageBaseResp<FriendApplyResp> pageApplyFriend(Long uid, PageBaseReq request);
|
||||
|
||||
/**
|
||||
* 申请未读数
|
||||
*
|
||||
* @return {@link WSFriendApply}
|
||||
*/
|
||||
WSFriendApply unread(Long uid);
|
||||
|
||||
/**
|
||||
* 删除申请
|
||||
*
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.luohuo.flex.im.core.user.service;
|
||||
|
||||
import com.luohuo.flex.im.domain.entity.Notice;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeTypeEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.NoticeVO;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
|
||||
public interface NoticeService {
|
||||
|
||||
Notice getByApplyId(Long uid, Long applyId);
|
||||
|
||||
/**
|
||||
* 创建通知
|
||||
* @param applyType 通知类型 1群聊 2单聊
|
||||
* @param type 具体的事件类型
|
||||
* @param senderId 发起人
|
||||
* @param receiverId 接收人UID
|
||||
* @param applyId 申请ID
|
||||
* @param operate 被操作的人
|
||||
* @param content 消息内容
|
||||
*/
|
||||
void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String content);
|
||||
|
||||
/**
|
||||
* 更新通知状态
|
||||
* @param notice
|
||||
*/
|
||||
void updateNotice(Notice notice);
|
||||
|
||||
/**
|
||||
* 批量更新通知状态
|
||||
* @param notice
|
||||
*/
|
||||
void updateNotices(Notice notice);
|
||||
|
||||
/**
|
||||
* 获取用户通知
|
||||
*/
|
||||
PageBaseResp<NoticeVO> getUserNotices(Long userId, PageBaseReq request);
|
||||
|
||||
/**
|
||||
* 标记为已读
|
||||
*/
|
||||
void markAsRead(Long noticeId);
|
||||
|
||||
/**
|
||||
* 查询未读数
|
||||
*/
|
||||
WSNotice unread(Long uid);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.luohuo.flex.im.core.user.service;
|
||||
|
||||
import com.luohuo.flex.im.api.vo.UserRegisterVo;
|
||||
import com.luohuo.flex.im.domain.dto.ItemInfoDTO;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import com.luohuo.flex.im.domain.entity.User;
|
||||
import com.luohuo.flex.model.entity.base.IpInfo;
|
||||
import com.luohuo.flex.model.vo.query.BindEmailReq;
|
||||
@@ -59,6 +60,14 @@ public interface UserService {
|
||||
*/
|
||||
UserInfoResp getUserInfo(Long uid);
|
||||
|
||||
/**
|
||||
* 查询用户列表
|
||||
*
|
||||
* @param uidList
|
||||
*
|
||||
*/
|
||||
List<SummeryInfoDTO> getUserInfo(List<Long> uidList);
|
||||
|
||||
/**
|
||||
* 修改用户名
|
||||
*
|
||||
|
||||
@@ -34,20 +34,6 @@ public class FriendAdapter {
|
||||
return userApplyNew;
|
||||
}
|
||||
|
||||
public static List<FriendApplyResp> buildFriendApplyList(List<UserApply> records) {
|
||||
return records.stream().map(userApply -> {
|
||||
FriendApplyResp friendApplyResp = new FriendApplyResp();
|
||||
friendApplyResp.setUid(userApply.getUid());
|
||||
friendApplyResp.setTargetId(userApply.getTargetId());
|
||||
friendApplyResp.setType(userApply.getType());
|
||||
friendApplyResp.setApplyId(userApply.getId());
|
||||
friendApplyResp.setMsg(userApply.getMsg());
|
||||
friendApplyResp.setStatus(userApply.getStatus());
|
||||
friendApplyResp.setCreateTime(userApply.getCreateTime());
|
||||
return friendApplyResp;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param friendPage 好友列表
|
||||
* @param onlineList 在线用户id
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.room.UserApplyResp;
|
||||
import com.luohuo.flex.model.entity.ws.*;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.luohuo.flex.im.domain.dto.ChatMessageMarkDTO;
|
||||
import com.luohuo.flex.model.entity.dto.ChatMsgRecallDTO;
|
||||
@@ -85,8 +84,8 @@ public class WsAdapter {
|
||||
return wsBaseResp;
|
||||
}
|
||||
|
||||
public static WsBaseResp<WSFriendApply> buildApplySend(WSFriendApply resp) {
|
||||
WsBaseResp<WSFriendApply> wsBaseResp = new WsBaseResp<>();
|
||||
public static WsBaseResp<WSNotice> buildApplySend(WSNotice resp) {
|
||||
WsBaseResp<WSNotice> wsBaseResp = new WsBaseResp<>();
|
||||
wsBaseResp.setType(WSRespTypeEnum.NEW_APPLY.getType());
|
||||
wsBaseResp.setData(resp);
|
||||
return wsBaseResp;
|
||||
|
||||
@@ -1,32 +1,62 @@
|
||||
package com.luohuo.flex.im.core.user.service.cache;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.luohuo.flex.im.common.constant.RedisKey;
|
||||
import com.luohuo.flex.im.common.service.cache.AbstractRedisStringCache;
|
||||
import com.luohuo.flex.im.core.user.dao.ItemConfigDao;
|
||||
import com.luohuo.flex.im.domain.entity.ItemConfig;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 用户相关缓存
|
||||
* 用户徽章基本信息的缓存
|
||||
* @author nyh
|
||||
*/
|
||||
@Component
|
||||
public class ItemCache {
|
||||
// todo 多级缓存
|
||||
public class ItemCache extends AbstractRedisStringCache<Long, ItemConfig> {
|
||||
@Resource
|
||||
private ItemConfigDao itemConfigDao;
|
||||
|
||||
@Resource
|
||||
private ItemConfigDao itemConfigDao;
|
||||
|
||||
@Cacheable(cacheNames = "luohuo:item", key = "'itemsByType:'+#type")
|
||||
public List<ItemConfig> getByType(Integer type) {
|
||||
return itemConfigDao.getByType(type);
|
||||
@Override
|
||||
protected String getKey(Long uid) {
|
||||
return RedisKey.getKey(RedisKey.USER_ITEM, uid);
|
||||
}
|
||||
|
||||
@Cacheable(cacheNames = "luohuo:item", key = "'item:'+#itemId", unless = "#result == null")
|
||||
public ItemConfig getById(Long itemId) {
|
||||
return itemConfigDao.getById(itemId);
|
||||
@Override
|
||||
protected Long getExpireSeconds() {
|
||||
return -1L;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Long, ItemConfig> load(List<Long> uidList) {
|
||||
List<ItemConfig> needLoadUserList = itemConfigDao.listByIds(uidList);
|
||||
return needLoadUserList.stream().collect(Collectors.toMap(ItemConfig::getId, Function.identity()));
|
||||
}
|
||||
|
||||
@Cacheable(cacheNames = "luohuo:userItem", key = "'itemsByType:'+#type")
|
||||
public List<ItemConfig> getByType(Integer type) {
|
||||
return itemConfigDao.getByType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有徽章列表
|
||||
*/
|
||||
@Cacheable(cacheNames = "luohuo:userItem", key = "'allItems'")
|
||||
public List<ItemConfig> getAllItems() {
|
||||
return itemConfigDao.list();
|
||||
}
|
||||
|
||||
/**
|
||||
* 当有徽章数据变更时,清除所有徽章的缓存,确保下次获取时是最新数据
|
||||
* 可以使用@CacheEvict注解
|
||||
*/
|
||||
@CacheEvict(cacheNames = "luohuo:userItem", key = "'all_items'")
|
||||
public void evictAllItemsCache() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,14 @@ import com.luohuo.flex.im.core.user.dao.UserApplyDao;
|
||||
import com.luohuo.flex.im.core.user.dao.UserFriendDao;
|
||||
import com.luohuo.flex.im.core.user.service.ApplyService;
|
||||
import com.luohuo.flex.im.core.user.service.FriendService;
|
||||
import com.luohuo.flex.im.core.user.service.NoticeService;
|
||||
import com.luohuo.flex.im.core.user.service.adapter.FriendAdapter;
|
||||
import com.luohuo.flex.im.core.user.service.adapter.WsAdapter;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import com.luohuo.flex.im.domain.dto.RequestApprovalDto;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import com.luohuo.flex.im.domain.entity.GroupMember;
|
||||
import com.luohuo.flex.im.domain.entity.Notice;
|
||||
import com.luohuo.flex.im.domain.entity.Room;
|
||||
import com.luohuo.flex.im.domain.entity.RoomFriend;
|
||||
import com.luohuo.flex.im.domain.entity.RoomGroup;
|
||||
@@ -44,6 +46,8 @@ import com.luohuo.flex.im.domain.enums.ApplyDeletedEnum;
|
||||
import com.luohuo.flex.im.domain.enums.ApplyReadStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.ApplyStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.GroupRoleEnum;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeTypeEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.req.friend.FriendApplyReq;
|
||||
@@ -52,7 +56,6 @@ import com.luohuo.flex.im.domain.vo.request.member.ApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.GroupApplyHandleReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendApplyResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import com.luohuo.flex.model.redis.annotation.RedissonLock;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -90,6 +93,7 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
private RoomGroupCache roomGroupCache;
|
||||
private GroupMemberDao groupMemberDao;
|
||||
private FriendService friendService;
|
||||
private NoticeService noticeService;
|
||||
private CachePlusOps cachePlusOps;
|
||||
private RoomAppService roomAppService;
|
||||
private TransactionTemplate transactionTemplate;
|
||||
@@ -120,6 +124,27 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
// 申请入库
|
||||
UserApply newApply = FriendAdapter.buildFriendApply(uid, request);
|
||||
userApplyDao.save(newApply);
|
||||
|
||||
noticeService.createNotice(
|
||||
RoomTypeEnum.FRIEND,
|
||||
NoticeTypeEnum.ADD_ME,
|
||||
uid,
|
||||
request.getTargetUid(),
|
||||
newApply.getId(),
|
||||
request.getTargetUid(),
|
||||
request.getMsg()
|
||||
);
|
||||
|
||||
noticeService.createNotice(
|
||||
RoomTypeEnum.FRIEND,
|
||||
NoticeTypeEnum.FRIEND_APPLY,
|
||||
uid,
|
||||
uid,
|
||||
newApply.getId(),
|
||||
request.getTargetUid(),
|
||||
request.getMsg()
|
||||
);
|
||||
|
||||
// 申请事件
|
||||
SpringUtils.publishEvent(new UserApplyEvent(this, newApply));
|
||||
return newApply;
|
||||
@@ -175,8 +200,18 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
throw new BizException("无效的审批");
|
||||
}
|
||||
|
||||
Notice notice = noticeService.getByApplyId(uid, invite.getId());
|
||||
if(ObjectUtil.isNull(notice)){
|
||||
throw new BizException("通知无法处理");
|
||||
}
|
||||
|
||||
switch (request.getState()){
|
||||
case 0 -> userApplyDao.updateStatus(request.getApplyId(), ApplyStatusEnum.REJECT);
|
||||
case 0 -> {
|
||||
userApplyDao.updateStatus(request.getApplyId(), ApplyStatusEnum.REJECT);
|
||||
// 发送通知
|
||||
notice.setStatus(NoticeStatusEnum.REJECTED.getStatus());
|
||||
noticeService.updateNotice(notice);
|
||||
}
|
||||
case 2 -> {
|
||||
// 处理加好友
|
||||
invite.setStatus(request.getState());
|
||||
@@ -219,45 +254,56 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
chatService.sendMsg(MessageAdapter.buildAgreeMsg(atomicRoomId.get(), true), uid);
|
||||
}
|
||||
|
||||
// 通过好友申请
|
||||
notice.setStatus(NoticeStatusEnum.ACCEPTED.getStatus());
|
||||
noticeService.updateNotice(notice);
|
||||
|
||||
// 通知请求方已处理好友申请
|
||||
SpringUtils.publishEvent(new UserApprovalEvent(this, RequestApprovalDto.builder().uid(uid).targetUid(invite.getUid()).build()));
|
||||
} else {
|
||||
// 处理加群
|
||||
// 处理加群, 如果是申请进群,那么用uid、否则是拉进群
|
||||
Long infoUid = invite.getApplyFor() ? invite.getUid() : invite.getTargetId();
|
||||
RoomGroup roomGroup = roomGroupCache.getByRoomId(invite.getRoomId());
|
||||
Room room = roomCache.get(invite.getRoomId());
|
||||
GroupMember member = groupMemberDao.getMemberByGroupId(roomGroup.getId(), uid);
|
||||
GroupMember member = groupMemberDao.getMemberByGroupId(roomGroup.getId(), infoUid);
|
||||
if(ObjectUtil.isNotNull(member)){
|
||||
throw new BizException(StrUtil.format("{}已经在{}里", userSummaryCache.get(invite.getTargetId()).getName(), roomGroup.getName()));
|
||||
}
|
||||
|
||||
transactionTemplate.execute(e -> {
|
||||
groupMemberDao.save(MemberAdapter.buildMemberAdd(roomGroup.getId(), invite.getTargetId()));
|
||||
groupMemberDao.save(MemberAdapter.buildMemberAdd(roomGroup.getId(), infoUid));
|
||||
|
||||
// 创建进群后的会话
|
||||
chatService.createContact(uid, roomGroup.getRoomId());
|
||||
chatService.createContact(infoUid, roomGroup.getRoomId());
|
||||
|
||||
// 更新邀请状态
|
||||
userApplyDao.updateById(invite);
|
||||
return true;
|
||||
});
|
||||
|
||||
// 加群申请已同意
|
||||
notice.setStatus(NoticeStatusEnum.ACCEPTED.getStatus());
|
||||
noticeService.updateNotices(notice);
|
||||
|
||||
// 3.3 写入缓存
|
||||
groupMemberCache.evictMemberList(invite.getRoomId());
|
||||
groupMemberCache.evictExceptMemberList(invite.getRoomId());
|
||||
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(invite.getTargetId());
|
||||
CacheKey uKey = PresenceCacheKeyBuilder.userGroupsKey(infoUid);
|
||||
CacheKey gKey = PresenceCacheKeyBuilder.groupMembersKey(room.getId());
|
||||
CacheKey onlineGroupMembersKey = PresenceCacheKeyBuilder.onlineGroupMembersKey(room.getId());
|
||||
cachePlusOps.sAdd(uKey, room.getId());
|
||||
cachePlusOps.sAdd(gKey, invite.getTargetId());
|
||||
roomAppService.asyncOnline(Arrays.asList(invite.getTargetId()), room.getId(), true);
|
||||
cachePlusOps.sAdd(gKey, infoUid);
|
||||
roomAppService.asyncOnline(Arrays.asList(infoUid), room.getId(), true);
|
||||
|
||||
SpringUtils.publishEvent(new GroupInviteMemberEvent(this, room.getId(), Arrays.asList(invite.getTargetId()), invite.getUid()));
|
||||
SpringUtils.publishEvent(new GroupMemberAddEvent(this, room.getId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), Arrays.asList(invite.getTargetId()), invite.getUid()));
|
||||
SpringUtils.publishEvent(new GroupInviteMemberEvent(this, room.getId(), Arrays.asList(infoUid), invite.getUid(), invite.getApplyFor()));
|
||||
SpringUtils.publishEvent(new GroupMemberAddEvent(this, room.getId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), Arrays.asList(infoUid), uid));
|
||||
}
|
||||
}
|
||||
case 3 -> {
|
||||
checkRecord(request);
|
||||
userApplyDao.updateStatus(request.getApplyId(), ApplyStatusEnum.IGNORE);
|
||||
notice.setStatus(NoticeStatusEnum.IGNORE.getStatus());
|
||||
noticeService.updateNotice(notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,7 +361,7 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
roomAppService.asyncOnline(Arrays.asList(apply.getUid()), room.getId(), true);
|
||||
|
||||
// 5.5 发布成员增加事件
|
||||
SpringUtils.publishEvent(new GroupInviteMemberEvent(this, room.getId(), Arrays.asList(apply.getUid()), apply.getUid()));
|
||||
SpringUtils.publishEvent(new GroupInviteMemberEvent(this, room.getId(), Arrays.asList(apply.getUid()), apply.getUid(), false));
|
||||
SpringUtils.publishEvent(new GroupMemberAddEvent(this, room.getId(), Math.toIntExact(cachePlusOps.sCard(gKey)), Math.toIntExact(cachePlusOps.sCard(onlineGroupMembersKey)), Collections.singletonList(apply.getUid()), apply.getUid()));
|
||||
}
|
||||
|
||||
@@ -323,41 +369,6 @@ public class ApplyServiceImpl implements ApplyService {
|
||||
pushService.sendPushMsg(WsAdapter.buildApplyResultWS(apply.getUid(), group.getRoomId(), uid, apply.getMsg(), apply.getStatus(), apply.getReadStatus()), apply.getUid(), uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询好友申请
|
||||
*
|
||||
* @param request 请求
|
||||
* @return {@link PageBaseResp}<{@link FriendApplyResp}>
|
||||
*/
|
||||
@Override
|
||||
public PageBaseResp<FriendApplyResp> pageApplyFriend(Long uid, PageBaseReq request) {
|
||||
IPage<UserApply> userApplyIPage = userApplyDao.friendApplyPage(uid, request.plusPage());
|
||||
if (CollectionUtil.isEmpty(userApplyIPage.getRecords())) {
|
||||
return PageBaseResp.empty();
|
||||
}
|
||||
// 将这些申请列表设为已读
|
||||
readApples(uid, userApplyIPage);
|
||||
// 返回消息
|
||||
return PageBaseResp.init(userApplyIPage, FriendAdapter.buildFriendApplyList(userApplyIPage.getRecords()));
|
||||
}
|
||||
|
||||
private void readApples(Long uid, IPage<UserApply> userApplyIpage) {
|
||||
List<Long> applyIds = userApplyIpage.getRecords()
|
||||
.stream().map(UserApply::getId)
|
||||
.collect(Collectors.toList());
|
||||
userApplyDao.readApples(uid, applyIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请未读数
|
||||
*
|
||||
* @return {@link WSFriendApply}
|
||||
*/
|
||||
@Override
|
||||
public WSFriendApply unread(Long uid) {
|
||||
return userApplyDao.getUnReadCount(uid, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@RedissonLock(prefixKey = "friend:deleteApprove", key = "#uid")
|
||||
public void deleteApprove(Long uid, ApplyReq request) {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.luohuo.flex.im.core.user.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.luohuo.flex.im.core.user.dao.NoticeDao;
|
||||
import com.luohuo.flex.im.core.user.service.NoticeService;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import com.luohuo.flex.im.domain.entity.Notice;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeTypeEnum;
|
||||
import com.luohuo.flex.im.domain.enums.RoomTypeEnum;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.NoticeVO;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.model.entity.WSRespTypeEnum;
|
||||
import com.luohuo.flex.model.entity.WsBaseResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NoticeServiceImpl implements NoticeService {
|
||||
|
||||
private final NoticeDao noticeDao;
|
||||
private final PushService pushService;
|
||||
private final UserSummaryCache userSummaryCache;
|
||||
|
||||
private void pushNoticeToUser(Long receiverId, Notice notice) {
|
||||
WsBaseResp<NoticeVO> wsMsg = new WsBaseResp<>();
|
||||
wsMsg.setData(convertToVO(notice));
|
||||
wsMsg.setType(WSRespTypeEnum.NOTICE.getType());
|
||||
pushService.sendPushMsg(wsMsg, Collections.singletonList(receiverId), notice.getSenderId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Notice getByApplyId(Long uid, Long applyId) {
|
||||
return noticeDao.getBaseMapper().selectOne(new QueryWrapper<Notice>().eq("receiver_id", uid).eq("apply_id", applyId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createNotice(RoomTypeEnum applyType, NoticeTypeEnum type, Long senderId, Long receiverId, Long applyId, Long operate, String content) {
|
||||
Notice notice = new Notice();
|
||||
notice.setType(applyType.getType());
|
||||
notice.setEventType(type.getType());
|
||||
notice.setSenderId(senderId);
|
||||
notice.setReceiverId(receiverId);
|
||||
notice.setApplyId(applyId);
|
||||
notice.setOperateId(operate);
|
||||
notice.setContent(content);
|
||||
notice.setStatus(NoticeStatusEnum.UNTREATED.getStatus());
|
||||
noticeDao.save(notice);
|
||||
|
||||
// 实时推送
|
||||
pushNoticeToUser(receiverId, notice);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotice(Notice notice) {
|
||||
noticeDao.update(Wrappers.<Notice>lambdaUpdate().set(Notice::getStatus, notice.getStatus()).eq(Notice::getApplyId, notice.getApplyId()));
|
||||
|
||||
// 实时推送
|
||||
pushNoticeToUser(notice.getReceiverId(), notice);
|
||||
}
|
||||
|
||||
public void updateNotices(Notice notice) {
|
||||
noticeDao.update(Wrappers.<Notice>lambdaUpdate().set(Notice::getStatus, notice.getStatus()).eq(Notice::getApplyId, notice.getApplyId()));
|
||||
|
||||
List<Notice> notices = noticeDao.getBaseMapper().selectList(new QueryWrapper<Notice>().eq("apply_id", notice.getApplyId()));
|
||||
for (Notice n : notices) {
|
||||
// 实时推送
|
||||
pushNoticeToUser(n.getReceiverId(), n);
|
||||
}
|
||||
}
|
||||
|
||||
private void readNotices(Long uid, IPage<Notice> noticeIPage) {
|
||||
List<Long> notices = noticeIPage.getRecords()
|
||||
.stream().map(Notice::getId)
|
||||
.collect(Collectors.toList());
|
||||
noticeDao.readNotices(uid, notices);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageBaseResp<NoticeVO> getUserNotices(Long uid, PageBaseReq request) {
|
||||
IPage<Notice> noticeIPage = noticeDao.getUserNotices(uid, true, request.plusPage());
|
||||
// 将这些通知设为已读
|
||||
readNotices(uid, noticeIPage);
|
||||
return PageBaseResp.init(noticeIPage, noticeIPage.getRecords().stream().map(notice -> convertToVO(notice)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private NoticeVO convertToVO(Notice notice) {
|
||||
NoticeVO vo = new NoticeVO();
|
||||
vo.setId(notice.getId());
|
||||
vo.setApplyId(notice.getApplyId());
|
||||
vo.setSenderId(notice.getSenderId());
|
||||
vo.setReceiverId(notice.getReceiverId());
|
||||
vo.setOperateId(notice.getOperateId());
|
||||
vo.setContent(notice.getContent());
|
||||
vo.setEventType(notice.getEventType());
|
||||
vo.setType(notice.getType());
|
||||
vo.setStatus(notice.getStatus());
|
||||
vo.setCreateTime(notice.getCreateTime());
|
||||
vo.setRead(notice.getIsRead());
|
||||
|
||||
// 填充发送人信息
|
||||
SummeryInfoDTO sender = userSummaryCache.get(notice.getSenderId());
|
||||
vo.setSenderName(sender.getName());
|
||||
vo.setSenderAvatar(sender.getAvatar());
|
||||
|
||||
// 填充接收人信息
|
||||
SummeryInfoDTO receiver = userSummaryCache.get(notice.getReceiverId());
|
||||
vo.setReceiverName(receiver.getName());
|
||||
vo.setReceiverAvatar(receiver.getAvatar());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsRead(Long noticeId) {
|
||||
noticeDao.markAsRead(noticeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WSNotice unread(Long uid) {
|
||||
return noticeDao.getUnReadCount(uid, uid);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.luohuo.flex.im.core.user.service.impl;
|
||||
|
||||
import com.luohuo.basic.utils.SpringUtils;
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
import com.luohuo.flex.model.redis.annotation.RedissonLock;
|
||||
import com.luohuo.flex.im.common.enums.IdempotentEnum;
|
||||
import com.luohuo.flex.im.common.enums.YesOrNoEnum;
|
||||
@@ -10,7 +11,6 @@ import com.luohuo.flex.im.domain.entity.ItemConfig;
|
||||
import com.luohuo.flex.im.domain.entity.UserBackpack;
|
||||
import com.luohuo.flex.im.domain.enums.ItemTypeEnum;
|
||||
import com.luohuo.flex.im.core.user.service.UserBackpackService;
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -49,7 +49,7 @@ public class UserBackpackServiceImpl implements UserBackpackService {
|
||||
return;
|
||||
}
|
||||
// 业务检查
|
||||
ItemConfig itemConfig = itemCache.getById(itemId);
|
||||
ItemConfig itemConfig = itemCache.get(itemId);
|
||||
if (ItemTypeEnum.BADGE.getType().equals(itemConfig.getType())) {
|
||||
// 徽章类型做唯一性检查
|
||||
Integer countByValidItemId = userBackpackDao.getCountByValidItemId(uid, itemId);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.luohuo.flex.im.core.user.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
@@ -13,6 +14,7 @@ import com.luohuo.flex.im.api.vo.UserRegisterVo;
|
||||
import com.luohuo.flex.im.common.event.UserRegisterEvent;
|
||||
import com.luohuo.flex.im.core.chat.service.RoomAppService;
|
||||
import com.luohuo.flex.im.core.user.service.cache.DefUserCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserCache;
|
||||
import com.luohuo.flex.model.entity.base.IpInfo;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -49,11 +51,11 @@ import com.luohuo.flex.im.domain.vo.resp.user.BadgeResp;
|
||||
import com.luohuo.flex.im.domain.vo.resp.user.UserInfoResp;
|
||||
import com.luohuo.flex.im.core.user.service.UserService;
|
||||
import com.luohuo.flex.im.core.user.service.adapter.UserAdapter;
|
||||
import com.luohuo.flex.im.core.user.service.cache.ItemCache;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -120,6 +122,11 @@ public class UserServiceImpl implements UserService {
|
||||
return UserAdapter.buildUserInfoResp(userInfo, countByValidItemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SummeryInfoDTO> getUserInfo(List<Long> uidList) {
|
||||
return new ArrayList<>(userSummaryCache.getBatch(uidList).values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void modifyInfo(Long uid, ModifyNameReq req) {
|
||||
@@ -213,8 +220,20 @@ public class UserServiceImpl implements UserService {
|
||||
|
||||
@Override
|
||||
public List<ItemInfoDTO> getItemInfo(ItemInfoReq req) {//简单做,更新时间可判断被修改
|
||||
if(CollUtil.isEmpty(req.getReqList())){
|
||||
List<ItemConfig> allItems = itemCache.getAllItems();
|
||||
|
||||
return allItems.stream().map(itemConfig -> {
|
||||
ItemInfoDTO dto = new ItemInfoDTO();
|
||||
dto.setItemId(itemConfig.getId());
|
||||
dto.setImg(itemConfig.getImg());
|
||||
dto.setDescribe(itemConfig.getDescribe());
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return req.getReqList().stream().map(a -> {
|
||||
ItemConfig itemConfig = itemCache.getById(a.getItemId());
|
||||
ItemConfig itemConfig = itemCache.get(a.getItemId());
|
||||
if (Objects.nonNull(a.getLastModifyTime()) && a.getLastModifyTime() >= TimeUtils.getTime(itemConfig.getUpdateTime())) {
|
||||
return ItemInfoDTO.skip(a.getItemId());
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.luohuo.flex.im.core.user.mapper.UserApplyMapper">
|
||||
<mapper namespace="com.luohuo.flex.im.core.user.mapper.NoticeMapper">
|
||||
|
||||
<select id="getUnReadCountByType" resultType="com.luohuo.flex.im.domain.vo.resp.friend.FriendUnreadDto">
|
||||
SELECT type, COUNT(*) as count
|
||||
FROM im_user_apply
|
||||
WHERE target_id = #{targetId} AND deleted = #{normal} AND read_status = #{readStatus}
|
||||
GROUP BY type, `status` order by `status`
|
||||
FROM im_notice
|
||||
WHERE receiver_id = #{receiverId} AND is_read = #{isRead}
|
||||
GROUP BY type
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -4,21 +4,16 @@ import com.luohuo.basic.base.R;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.flex.im.core.user.service.ApplyService;
|
||||
import com.luohuo.flex.im.domain.entity.UserApply;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.req.friend.FriendApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.RoomApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.ApplyReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.member.GroupApplyHandleReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.im.domain.vo.resp.friend.FriendApplyResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSFriendApply;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -36,26 +31,12 @@ public class ApplyController {
|
||||
@Resource
|
||||
private ApplyService applyService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "申请列表 [好友、群聊]")
|
||||
public R<PageBaseResp<FriendApplyResp>> page(@Valid PageBaseReq request) {
|
||||
Long uid = ContextUtil.getUid();
|
||||
return R.success(applyService.pageApplyFriend(uid, request));
|
||||
}
|
||||
|
||||
@PostMapping("/apply")
|
||||
@Operation(summary = "好友申请")
|
||||
public R<UserApply> apply(@Valid @RequestBody FriendApplyReq request) {
|
||||
return R.success(applyService.handlerApply(ContextUtil.getUid(), request));
|
||||
}
|
||||
|
||||
@GetMapping("/unread")
|
||||
@Operation(summary = "申请未读数")
|
||||
public R<WSFriendApply> unread() {
|
||||
Long uid = ContextUtil.getUid();
|
||||
return R.success(applyService.unread(uid));
|
||||
}
|
||||
|
||||
@Operation(summary ="审批别人邀请的进群、好友申请")
|
||||
@PostMapping("/handler/apply")
|
||||
public R<Void> handlerApply(@Valid @RequestBody ApplyReq request) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.luohuo.flex.im.controller;
|
||||
|
||||
import com.luohuo.basic.base.R;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.flex.im.core.user.service.NoticeService;
|
||||
import com.luohuo.flex.im.domain.vo.req.NoticeReadReq;
|
||||
import com.luohuo.flex.im.domain.vo.req.PageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.res.NoticeVO;
|
||||
import com.luohuo.flex.im.domain.vo.res.PageBaseResp;
|
||||
import com.luohuo.flex.model.entity.ws.WSNotice;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/room/notice")
|
||||
public class NoticeController {
|
||||
@Resource
|
||||
private NoticeService noticeService;
|
||||
|
||||
@GetMapping("/page")
|
||||
public R<PageBaseResp<NoticeVO>> getNotices(@Valid PageBaseReq request) {
|
||||
Long uid = ContextUtil.getUid();
|
||||
return R.success(noticeService.getUserNotices(uid, request));
|
||||
}
|
||||
|
||||
@PostMapping("/read")
|
||||
public R<Void> markAsRead(@RequestBody NoticeReadReq req) {
|
||||
noticeService.markAsRead(req.getNoticeId());
|
||||
return R.success();
|
||||
}
|
||||
|
||||
@GetMapping("/unread")
|
||||
@Operation(summary = "通知未读数")
|
||||
public R<WSNotice> unread() {
|
||||
Long uid = ContextUtil.getUid();
|
||||
return R.success(noticeService.unread(uid));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.luohuo.flex.im.controller.chat;
|
||||
|
||||
import com.luohuo.basic.tenant.core.aop.TenantIgnore;
|
||||
import com.luohuo.flex.im.core.user.service.cache.UserSummaryCache;
|
||||
import com.luohuo.flex.im.domain.vo.request.*;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -12,19 +13,11 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.luohuo.basic.base.R;
|
||||
import com.luohuo.basic.context.ContextUtil;
|
||||
import com.luohuo.flex.im.domain.vo.res.CursorPageBaseResp;
|
||||
import com.luohuo.flex.im.domain.dto.MsgReadInfoDTO;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageBaseReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMarkReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageMemberReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessagePageReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadInfoReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReadReq;
|
||||
import com.luohuo.flex.im.domain.vo.request.ChatMessageReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMessageReadResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.core.chat.service.ChatService;
|
||||
@@ -63,11 +56,11 @@ public class ChatController {
|
||||
return R.success(msgPage);
|
||||
}
|
||||
|
||||
@GetMapping("/msg/list")
|
||||
@PostMapping("/msg/list")
|
||||
@Operation(summary ="消息列表")
|
||||
// @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP)
|
||||
public R<List<ChatMessageResp>> getMsgPage(@RequestParam(value = "lastOptTime", required = false) Long lastOptTime) {
|
||||
List<ChatMessageResp> msgPage = chatService.getMsgList(lastOptTime, ContextUtil.getUid());
|
||||
public R<List<ChatMessageResp>> getMsgPage(@RequestBody MsgReq msgReq) {
|
||||
List<ChatMessageResp> msgPage = chatService.getMsgList(msgReq, ContextUtil.getUid());
|
||||
// Set<String> blackMembers = getBlackUidSet();
|
||||
// msgPage.removeIf(a -> blackMembers.contains(a.getFromUser().getUid().toString()));
|
||||
return R.success(msgPage);
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.luohuo.flex.im.domain.vo.request.room.AnnouncementsParam;
|
||||
import com.luohuo.flex.im.domain.vo.request.room.ReadAnnouncementsParam;
|
||||
import com.luohuo.flex.im.domain.vo.request.room.RoomGroupReq;
|
||||
import com.luohuo.flex.im.domain.vo.response.ChatMemberListResp;
|
||||
import com.luohuo.flex.model.entity.ws.ChatMessageResp;
|
||||
import com.luohuo.flex.im.domain.vo.response.MemberResp;
|
||||
import com.luohuo.flex.im.core.chat.service.RoomAppService;
|
||||
import com.luohuo.flex.im.domain.vo.req.MergeMessageReq;
|
||||
@@ -95,7 +94,7 @@ public class RoomController {
|
||||
@DeleteMapping("/group/member/exit")
|
||||
@Operation(summary ="退出群聊 | 解散群聊")
|
||||
public R<Boolean> exitGroup(@Valid @RequestBody MemberExitReq request) {
|
||||
roomService.exitGroup(ContextUtil.getUid(), request);
|
||||
roomService.exitGroup(false, ContextUtil.getUid(), request);
|
||||
return R.success();
|
||||
}
|
||||
|
||||
@@ -190,7 +189,8 @@ public class RoomController {
|
||||
|
||||
@Operation(summary = "合并消息")
|
||||
@PostMapping("mergeMessage")
|
||||
public R<ChatMessageResp> mergeMessage(@Validated @RequestBody MergeMessageReq req){
|
||||
return R.success(roomService.mergeMessage(ContextUtil.getUid(), req));
|
||||
public R<Void> mergeMessage(@Validated @RequestBody MergeMessageReq req){
|
||||
roomService.mergeMessage(ContextUtil.getUid(), req);
|
||||
return R.success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.luohuo.flex.im.controller.user;
|
||||
|
||||
import com.luohuo.basic.tenant.core.aop.TenantIgnore;
|
||||
import com.luohuo.flex.im.api.vo.UserRegisterVo;
|
||||
import com.luohuo.flex.im.domain.dto.SummeryInfoDTO;
|
||||
import com.luohuo.flex.model.entity.base.RefreshIpInfo;
|
||||
import com.luohuo.flex.model.entity.base.UserReq;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -46,6 +48,12 @@ public class UserController {
|
||||
return R.success(userService.refreshIpInfo(refreshIpInfo.getUid(), refreshIpInfo.getIpInfo()));
|
||||
}
|
||||
|
||||
@PostMapping("getUserByIds")
|
||||
@Operation(summary ="查询用户id")
|
||||
public R<List<SummeryInfoDTO>> getUserByIds(@RequestBody UserReq userReq) {
|
||||
return R.success(userService.getUserInfo(userReq.getUidList()));
|
||||
}
|
||||
|
||||
@GetMapping("/checkEmail")
|
||||
@Operation(summary ="绑定邮箱")
|
||||
@TenantIgnore
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.luohuo.flex.im.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.luohuo.basic.base.entity.Entity;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeStatusEnum;
|
||||
import com.luohuo.flex.im.domain.enums.NoticeTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 统一通知表
|
||||
* </p>
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("im_notice")
|
||||
public class Notice extends Entity<Long> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @see NoticeTypeEnum
|
||||
*/
|
||||
@Schema(description = "通知类型:1-好友申请;2-群申请;3-群事件")
|
||||
private Integer eventType;
|
||||
|
||||
@Schema(description = "通知类型 1群聊 2加好友")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "发起人UID")
|
||||
@TableField("sender_id")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "接收人UID")
|
||||
@TableField("receiver_id")
|
||||
private Long receiverId;
|
||||
|
||||
@Schema(description = "申请ID")
|
||||
@TableField("apply_id")
|
||||
private Long applyId;
|
||||
|
||||
@Schema(description = "被操作的人")
|
||||
@TableField("operate_id")
|
||||
private Long operateId;
|
||||
|
||||
@Schema(description = "通知内容 申请时填写的, 进群、移除时是群聊的名称")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* @see NoticeStatusEnum
|
||||
*/
|
||||
@Schema(description = "处理状态:0-未处理;1-已同意;2-已拒绝;3-忽略")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否已读")
|
||||
@TableField("is_read")
|
||||
private Integer isRead;
|
||||
|
||||
@Schema(description = "租户id")
|
||||
@TableField("tenant_id")
|
||||
private Long tenantId;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.luohuo.flex.im.domain.entity.msg;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BodyDTO implements Serializable {
|
||||
@Schema(description = "用户uid")
|
||||
private String uid;
|
||||
@Schema(description = "消息id")
|
||||
private String messageId;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.luohuo.flex.im.domain.entity.msg;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 合并消息实体
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MergeMsg implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description ="内容")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "发送时间")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@Schema(description ="发送人名称")
|
||||
private String name;
|
||||
}
|
||||
@@ -22,12 +22,19 @@ public class MergeMsgDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description ="合并的内容")
|
||||
private List<MergeMsg> messages;
|
||||
@Schema(description ="消息id")
|
||||
private List<BodyDTO> body;
|
||||
|
||||
@Schema(description ="回复的消息id")
|
||||
private Long replyMsgId;
|
||||
|
||||
@Schema(description ="预览的消息内容")
|
||||
private List<String> content;
|
||||
|
||||
@Schema(description ="父消息,如果没有父消息,返回的是null")
|
||||
private ReplyMsg reply;
|
||||
|
||||
public MergeMsgDTO(List<BodyDTO> body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.luohuo.flex.im.domain.vo.request.msg;
|
||||
package com.luohuo.flex.im.domain.entity.msg;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
public class TextMsgReq {
|
||||
|
||||
@NotBlank(message = "内容不能为空")
|
||||
@Size(max = 1024, message = "消息内容过长,服务器扛不住啊,兄dei")
|
||||
@Size(max = 1024, message = "消息内容过长")
|
||||
@Schema(description ="消息内容")
|
||||
private String content;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.luohuo.flex.im.domain.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 转发类型的枚举
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum MergeTypeEnum implements Serializable {
|
||||
|
||||
SINGLE(1, "单一转发"),
|
||||
MERGE(2, "合并转发");
|
||||
|
||||
private final Integer type;
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 根据当前枚举的name匹配
|
||||
*/
|
||||
public static MergeTypeEnum match(Integer val) {
|
||||
return Stream.of(values()).parallel().filter(item -> item.getType().equals(val)).findAny().orElse(SINGLE);
|
||||
}
|
||||
|
||||
public static MergeTypeEnum get(Integer val) {
|
||||
return match(val);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.luohuo.flex.im.domain.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 事件处理的枚举
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum NoticeStatusEnum implements Serializable {
|
||||
UNTREATED(0, "待审批"),
|
||||
ACCEPTED(1, "已同意"),
|
||||
REJECTED(2, "已拒绝"),
|
||||
IGNORE(3, "已忽略");
|
||||
|
||||
private final Integer status;
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 根据当前枚举的name匹配
|
||||
*/
|
||||
public static NoticeStatusEnum match(Integer val) {
|
||||
return Stream.of(values()).parallel().filter(item -> item.getStatus().equals(val)).findAny().orElse(ACCEPTED);
|
||||
}
|
||||
|
||||
public static NoticeStatusEnum get(Integer val) {
|
||||
return match(val);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.luohuo.flex.im.domain.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 事件通知的枚举
|
||||
*
|
||||
* @author 乾乾
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum NoticeTypeEnum implements Serializable {
|
||||
|
||||
FRIEND_APPLY(1, "好友申请"),
|
||||
ADD_ME(6, "好友被申请"),
|
||||
GROUP_APPLY(2, "加群申请"),
|
||||
GROUP_INVITE(3, "群邀请"),
|
||||
GROUP_MEMBER_DELETE(5, "移除群成员"),
|
||||
GROUP_INVITE_ME(7, "被邀请进群"),
|
||||
GROUP_SET_ADMIN(8, "设置群管理员"),
|
||||
GROUP_RECALL_ADMIN(9, "取消群管理员");
|
||||
|
||||
private final Integer type;
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* 根据当前枚举的name匹配
|
||||
*/
|
||||
public static NoticeTypeEnum match(Integer val) {
|
||||
return Stream.of(values()).parallel().filter(item -> item.getType().equals(val)).findAny().orElse(FRIEND_APPLY);
|
||||
}
|
||||
|
||||
public static NoticeTypeEnum get(Integer val) {
|
||||
return match(val);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.luohuo.flex.im.domain.vo.req;
|
||||
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 java.io.Serializable;
|
||||
@@ -19,9 +20,14 @@ public class MergeMessageReq implements Serializable {
|
||||
@NotNull(message = "请选择消息来源房间")
|
||||
private Long fromRoomId;
|
||||
|
||||
@Schema(description = "转发类型")
|
||||
@NotNull(message = "转发类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "接收的房间ID")
|
||||
@NotNull(message = "房间不能为空")
|
||||
private Long roomId;
|
||||
@Size(max = 100, message = "最多只能转发100条消息")
|
||||
@NotEmpty(message = "请选择接收消息的房间")
|
||||
private List<Long> roomIds;
|
||||
|
||||
@Schema(description = "合并消息的子消息列表")
|
||||
@NotEmpty(message = "请选择要转发的消息")
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.luohuo.flex.im.domain.vo.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "标记通知已读请求")
|
||||
public class NoticeReadReq {
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "通知ID", required = true)
|
||||
private Long noticeId;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.luohuo.flex.im.domain.vo.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息请求
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MsgReq implements Serializable {
|
||||
@Schema(description ="消息id")
|
||||
private List<Long> msgIds;
|
||||
|
||||
@Schema(description ="最后一次ws连接的时间")
|
||||
private Long lastOptTime;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.luohuo.flex.im.domain.vo.res;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知视图对象
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "通知视图对象")
|
||||
public class NoticeVO {
|
||||
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "事件类型:1-好友申请;2-群申请;3-群事件")
|
||||
private Integer eventType;
|
||||
|
||||
@Schema(description = "通知类型 1群聊 2加好友")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "申请ID")
|
||||
private Long applyId;
|
||||
|
||||
@Schema(description = "被操作的人")
|
||||
private Long operateId;
|
||||
|
||||
@Schema(description = "通知内容 申请时填写的")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "处理状态:0-未处理;1-已同意;2-已拒绝;3-忽略")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "是否已读")
|
||||
private Integer read;
|
||||
|
||||
@Schema(description = "发送人名称")
|
||||
private String senderName;
|
||||
|
||||
@Schema(description = "发送人头像")
|
||||
private String senderAvatar;
|
||||
|
||||
@Schema(description = "接收人名称")
|
||||
private String receiverName;
|
||||
|
||||
@Schema(description = "接收人头像")
|
||||
private String receiverAvatar;
|
||||
|
||||
@Schema(description = "发送人ID")
|
||||
private Long senderId;
|
||||
|
||||
@Schema(description = "接收人ID")
|
||||
private Long receiverId;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class IpServiceImpl implements IpService, DisposableBean {
|
||||
public static IpDetail getIpDetailOrNull(String ip) {
|
||||
String body = HttpUtil.get("https://ip.taobao.com/outGetIpInfo?ip=" + ip + "&accessKey=alibaba-inc");
|
||||
try {
|
||||
R<IpDetail> result = JsonUtils.toObj(body, new TypeReference<>() {});
|
||||
R<IpDetail> result = JsonUtils.toObj(body.replace("XX", "").replace("xx", ""), new TypeReference<>() {});
|
||||
return result.getData();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public class IpServiceImpl implements IpService, DisposableBean {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int finalI = i;
|
||||
EXECUTOR.execute(() -> {
|
||||
IpDetail ipDetail = tryGetIpDetailOrNullTreeTimes("113.90.36.126");
|
||||
IpDetail ipDetail = tryGetIpDetailOrNullTreeTimes("127.0.0.1");
|
||||
if (Objects.nonNull(ipDetail)) {
|
||||
LocalDateTime date = LocalDateTime.now();
|
||||
System.out.println(String.format("第%d次成功,目前耗时:%dms", finalI, (TimeUtils.getTime(date) - TimeUtils.getTime(begin))));
|
||||
|
||||
@@ -25,23 +25,26 @@ public enum WSRespTypeEnum {
|
||||
USER_STATE_CHANGE("userStateChange", "用户状态改变", null),
|
||||
ROOM_INFO_CHANGE("roomInfoChange", "管理员修改群聊信息", ChatRoomGroupChange.class),
|
||||
MY_ROOM_INFO_CHANGE("myRoomInfoChange", "自己修改我在群里的信息", ChatMyRoomGroupChange.class),
|
||||
ROOM_GROUP_MSG("roomGroupMsg", "用户申请加群通知消息", null),
|
||||
GROUP_APPLY_NOTICE("GroupApplyNotice", "管理员用户申请加群通知消息", null),
|
||||
TOKEN_EXPIRED("tokenExpired", "使前端的token失效,意味着前端需要重新登录", OffLineResp.class),
|
||||
INVALID_USER("invalidUser", "拉黑用户", WSBlack.class),
|
||||
MSG_MARK_ITEM("msgMarkItem", "消息标记", WSMsgMark.class),
|
||||
MSG_RECALL("msgRecall", "消息撤回", WSMsgRecall.class),
|
||||
|
||||
NOTICE("notice", "通知总线", null),
|
||||
REQUEST_APPROVAL_FRIEND("requestApprovalFriend", "同意好友请求", WSFriendApproval.class),
|
||||
NEW_APPLY("newApply", "好友申请、群聊邀请", WSNotice.class),
|
||||
ROOM_DISSOLUTION("roomDissolution", "群解散", null),
|
||||
ROOM_GROUP_MSG("roomGroupMsg", "用户申请加群通知消息", null),
|
||||
GROUP_APPLY_NOTICE("GroupApplyNotice", "管理员用户申请加群通知消息", null),
|
||||
|
||||
ROOM_GROUP_NOTICE_READ_MSG("roomGroupNoticeReadMsg", "群公告已读", null),
|
||||
FEED_SEND_MSG("feedSendMsg", "朋友圈发布", null),
|
||||
ROOM_DISSOLUTION("roomDissolution", "群解散", null),
|
||||
ROOM_NOTIFICATION("roomNotification", "会话消息接收类型改变", null),
|
||||
SHIELD("shield", "你已屏蔽好友的消息", null),
|
||||
UNBLOCK("unblock", "你已解除屏蔽好友的消息", null),
|
||||
NEW_APPLY("newApply", "好友申请、群聊邀请", WSFriendApply.class),
|
||||
memberChange("memberChange", "成员变动", WSMemberChange.class),
|
||||
OFFLINE("offline", "下线通知", WSOnlineNotify.class),
|
||||
WSReconnect("WSReconnect", "ws消息重连", null),
|
||||
REQUEST_APPROVAL_FRIEND("requestApprovalFriend", "同意好友请求", WSFriendApproval.class),
|
||||
JoinVideo("JoinVideo", "加入视频会议", null),
|
||||
VideoCallRequest("VideoCallRequest","发起通话请求", null),
|
||||
StartSignaling("StartSignaling","开始呼叫", null),
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.luohuo.flex.model.entity.base;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户列表
|
||||
* @author 乾乾
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UserReq implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private List<Long> uidList;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import java.io.Serializable;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class WSFriendApply implements Serializable {
|
||||
public class WSNotice implements Serializable {
|
||||
@Schema(description ="申请人、被邀请人")
|
||||
private Long uid;
|
||||
@Schema(description ="好友申请列表的未读数")
|
||||
BIN
preview/wx.png
|
Before Width: | Height: | Size: 502 KiB After Width: | Height: | Size: 464 KiB |