mirror of
https://github.com/zongzibinbin/MallChat.git
synced 2026-03-23 13:23:44 +08:00
Merge branch 'main' into main
This commit is contained in:
@@ -34,11 +34,11 @@ CREATE TABLE `message` (
|
|||||||
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
|
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
`room_id` bigint(20) NOT NULL COMMENT '会话表id',
|
`room_id` bigint(20) NOT NULL COMMENT '会话表id',
|
||||||
`from_uid` bigint(20) NOT NULL COMMENT '消息发送者uid',
|
`from_uid` bigint(20) NOT NULL COMMENT '消息发送者uid',
|
||||||
`content` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息内容',
|
`content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '消息内容',
|
||||||
`reply_msg_id` bigint(20) NULL DEFAULT NULL COMMENT '回复的消息内容',
|
`reply_msg_id` bigint(20) NULL DEFAULT NULL COMMENT '回复的消息内容',
|
||||||
`status` int(11) NOT NULL COMMENT '消息状态 0正常 1删除',
|
`status` int(11) NOT NULL COMMENT '消息状态 0正常 1删除',
|
||||||
`gap_count` int(11) NULL DEFAULT NULL COMMENT '与回复的消息间隔多少条',
|
`gap_count` int(11) NULL DEFAULT NULL COMMENT '与回复的消息间隔多少条',
|
||||||
`type` int(11) NULL DEFAULT 1 COMMENT '消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)',
|
`type` int(11) NULL DEFAULT 1 COMMENT '消息类型 1正常文本 2.撤回消息',
|
||||||
`extra` json DEFAULT NULL COMMENT '扩展信息',
|
`extra` json DEFAULT NULL COMMENT '扩展信息',
|
||||||
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
||||||
@@ -155,4 +155,30 @@ CREATE TABLE `black` (
|
|||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `idx_type_target`(`type`, `target`) USING BTREE
|
UNIQUE INDEX `idx_type_target`(`type`, `target`) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '黑名单' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '黑名单' ROW_FORMAT = Dynamic;
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
|
||||||
|
DROP TABLE IF EXISTS `role`;
|
||||||
|
CREATE TABLE `role` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
|
`name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '角色名称',
|
||||||
|
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_update_time` (`update_time`) USING BTREE
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色表';
|
||||||
|
insert into role(id,`name`) values(1,'超级管理员');
|
||||||
|
insert into role(id,`name`) values(2,'抹茶群聊管理员');
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `user_role`;
|
||||||
|
CREATE TABLE `user_role` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
|
`uid` bigint(20) NOT NULL COMMENT 'uid',
|
||||||
|
`role_id` bigint(20) NOT NULL COMMENT '角色id',
|
||||||
|
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_uid` (`uid`) USING BTREE,
|
||||||
|
KEY `idx_role_id` (`role_id`) USING BTREE,
|
||||||
|
KEY `idx_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_update_time` (`update_time`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户角色关系表';
|
||||||
30
docs/version/2023-06-04.sql
Normal file
30
docs/version/2023-06-04.sql
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#1.撤回消息2.管理员权限
|
||||||
|
|
||||||
|
CREATE TABLE `role` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
|
`name` varchar(64) NOT NULL COMMENT '角色名称',
|
||||||
|
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_update_time` (`update_time`) USING BTREE
|
||||||
|
) COMMENT='角色表';
|
||||||
|
|
||||||
|
insert into role(id,`name`) values(1,'超级管理员');
|
||||||
|
insert into role(id,`name`) values(2,'抹茶群聊管理员');
|
||||||
|
|
||||||
|
CREATE TABLE `user_role` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
|
`uid`bigint(20) NOT NULL COMMENT 'uid',
|
||||||
|
`role_id`bigint(20) NOT NULL COMMENT '角色id',
|
||||||
|
`create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||||||
|
`update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_uid` (`uid`) USING BTREE,
|
||||||
|
KEY `idx_role_id` (`role_id`) USING BTREE,
|
||||||
|
KEY `idx_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_update_time` (`update_time`) USING BTREE
|
||||||
|
) COMMENT='用户角色关系表';
|
||||||
|
|
||||||
|
alter table `message` MODIFY COLUMN `type` int(11) DEFAULT '1' COMMENT '消息类型 1普通消息 2.撤回消息';
|
||||||
|
alter table `message` MODIFY COLUMN `content` varchar(1024) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '消息内容';
|
||||||
@@ -49,10 +49,10 @@ public class MessageDao extends ServiceImpl<MessageMapper, Message> {
|
|||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateGapCount(Long id, Integer gapCount) {
|
public void invalidByUid(Long uid) {
|
||||||
lambdaUpdate()
|
lambdaUpdate()
|
||||||
.eq(Message::getId, id)
|
.eq(Message::getFromUid, uid)
|
||||||
.set(Message::getGapCount, gapCount)
|
.set(Message::getStatus, MessageStatusEnum.DELETE.getStatus())
|
||||||
.update();
|
.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.abin.mallchat.common.chat.domain.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:消息撤回的推送类
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ChatMsgRecallDTO {
|
||||||
|
private Long msgId;
|
||||||
|
private Long roomId;
|
||||||
|
//撤回的用户
|
||||||
|
private Long recallUid;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.abin.mallchat.common.chat.domain.entity;
|
package com.abin.mallchat.common.chat.domain.entity;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
@@ -73,7 +74,7 @@ public class Message implements Serializable {
|
|||||||
private Integer gapCount;
|
private Integer gapCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)
|
* 消息类型 1正常文本 2.撤回消息
|
||||||
*
|
*
|
||||||
* @see com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum
|
* @see com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum
|
||||||
*/
|
*/
|
||||||
@@ -81,7 +82,7 @@ public class Message implements Serializable {
|
|||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 最后上下线时间
|
* 消息扩展字段
|
||||||
*/
|
*/
|
||||||
@TableField(value = "extra", typeHandler = JacksonTypeHandler.class)
|
@TableField(value = "extra", typeHandler = JacksonTypeHandler.class)
|
||||||
private MessageExtra extra;
|
private MessageExtra extra;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.abin.mallchat.common.chat.domain.entity;
|
package com.abin.mallchat.common.chat.domain.entity.msg;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -17,8 +18,11 @@ import java.util.Map;
|
|||||||
@Builder
|
@Builder
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class MessageExtra implements Serializable {
|
public class MessageExtra implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
//注册时的ip
|
//url跳转链接
|
||||||
private Map<String, String> urlTitleMap;
|
private Map<String, String> urlTitleMap;
|
||||||
|
//消息撤回详情
|
||||||
|
private MsgRecall recall;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.abin.mallchat.common.chat.domain.entity.msg;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 消息撤回
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MsgRecall implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
//撤回消息的uid
|
||||||
|
private Long recallUid;
|
||||||
|
//撤回的时间点
|
||||||
|
private Date recallTime;
|
||||||
|
}
|
||||||
@@ -16,14 +16,13 @@ import java.util.stream.Collectors;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public enum MessageMarkTypeEnum {
|
public enum MessageMarkTypeEnum {
|
||||||
LIKE(1, "点赞", 10, MessageTypeEnum.LIKE),
|
LIKE(1, "点赞", 10),
|
||||||
DISLIKE(2, "点踩", 5, MessageTypeEnum.DISLIKE),
|
DISLIKE(2, "点踩", 5),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Integer type;
|
private final Integer type;
|
||||||
private final String desc;
|
private final String desc;
|
||||||
private final Integer riseNum;//需要多少个标记升级
|
private final Integer riseNum;//需要多少个标记升级
|
||||||
private final MessageTypeEnum riseEnum;//消息升级成什么类型的消息
|
|
||||||
|
|
||||||
private static Map<Integer, MessageMarkTypeEnum> cache;
|
private static Map<Integer, MessageMarkTypeEnum> cache;
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ import java.util.stream.Collectors;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
public enum MessageTypeEnum {
|
public enum MessageTypeEnum {
|
||||||
NORMAL(1, "正常"),
|
TEXT(1, "正常"),
|
||||||
LIKE(2, "爆赞"),
|
RECALL(2, "撤回消息"),
|
||||||
DISLIKE(3, "危险发言"),
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Integer type;
|
private final Integer type;
|
||||||
|
|||||||
42
mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/MsgCache.java
vendored
Normal file
42
mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/MsgCache.java
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package com.abin.mallchat.common.chat.service.cache;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
|
import com.abin.mallchat.common.common.utils.CursorUtils;
|
||||||
|
import com.abin.mallchat.common.user.dao.BlackDao;
|
||||||
|
import com.abin.mallchat.common.user.dao.RoleDao;
|
||||||
|
import com.abin.mallchat.common.user.dao.UserDao;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 消息相关缓存
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-27
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MsgCache {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CursorUtils cursorUtils;
|
||||||
|
@Autowired
|
||||||
|
private UserDao userDao;
|
||||||
|
@Autowired
|
||||||
|
private BlackDao blackDao;
|
||||||
|
@Autowired
|
||||||
|
private RoleDao roleDao;
|
||||||
|
@Autowired
|
||||||
|
private MessageDao messageDao;
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = "msg", key = "'msg'+#msgId")
|
||||||
|
public Message getMsg(Long msgId) {
|
||||||
|
return messageDao.getById(msgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEvict(cacheNames = "msg", key = "'msg'+#msgId")
|
||||||
|
public Message evictMsg(Long msgId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public class CursorPageBaseReq {
|
|||||||
|
|
||||||
@ApiModelProperty("页面大小")
|
@ApiModelProperty("页面大小")
|
||||||
@Min(0)
|
@Min(0)
|
||||||
@Max(50)
|
@Max(100)
|
||||||
private Integer pageSize = 10;
|
private Integer pageSize = 10;
|
||||||
|
|
||||||
@ApiModelProperty("游标(初始为null,后续请求附带上次翻页的游标)")
|
@ApiModelProperty("游标(初始为null,后续请求附带上次翻页的游标)")
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.abin.mallchat.common.common.event;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.dto.ChatMsgRecallDTO;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class MessageRecallEvent extends ApplicationEvent {
|
||||||
|
private ChatMsgRecallDTO recallDTO;
|
||||||
|
|
||||||
|
public MessageRecallEvent(Object source, ChatMsgRecallDTO recallDTO) {
|
||||||
|
super(source);
|
||||||
|
this.recallDTO = recallDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.abin.mallchat.common.common.event;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class UserBlackEvent extends ApplicationEvent {
|
||||||
|
private final User user;
|
||||||
|
|
||||||
|
public UserBlackEvent(Object source, User user) {
|
||||||
|
super(source);
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class UserOfflineEvent extends ApplicationEvent {
|
public class UserOfflineEvent extends ApplicationEvent {
|
||||||
private User user;
|
private final User user;
|
||||||
|
|
||||||
public UserOfflineEvent(Object source, User user) {
|
public UserOfflineEvent(Object source, User user) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class UserOnlineEvent extends ApplicationEvent {
|
public class UserOnlineEvent extends ApplicationEvent {
|
||||||
private User user;
|
private final User user;
|
||||||
|
|
||||||
public UserOnlineEvent(Object source, User user) {
|
public UserOnlineEvent(Object source, User user) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class UserRegisterEvent extends ApplicationEvent {
|
public class UserRegisterEvent extends ApplicationEvent {
|
||||||
private User user;
|
private final User user;
|
||||||
|
|
||||||
public UserRegisterEvent(Object source, User user) {
|
public UserRegisterEvent(Object source, User user) {
|
||||||
super(source);
|
super(source);
|
||||||
|
|||||||
@@ -67,6 +67,12 @@ public class AssertUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void notEqual(Object o1, Object o2, String msg) {
|
||||||
|
if (ObjectUtil.equal(o1, o2)) {
|
||||||
|
throwException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isEmpty(Object obj) {
|
private static boolean isEmpty(Object obj) {
|
||||||
return ObjectUtil.isEmpty(obj);
|
return ObjectUtil.isEmpty(obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.abin.mallchat.common.user.dao;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.Role;
|
||||||
|
import com.abin.mallchat.common.user.mapper.RoleMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RoleDao extends ServiceImpl<RoleMapper, Role> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.abin.mallchat.common.user.dao;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.UserRole;
|
||||||
|
import com.abin.mallchat.common.user.mapper.UserRoleMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户角色关系表 服务实现类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserRoleDao extends ServiceImpl<UserRoleMapper, UserRole> {
|
||||||
|
public List<UserRole> listByUid(Long uid) {
|
||||||
|
return lambdaQuery()
|
||||||
|
.eq(UserRole::getUid, Objects.requireNonNull(uid))
|
||||||
|
.list();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.abin.mallchat.common.user.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@TableName("role")
|
||||||
|
public class Role implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色名称
|
||||||
|
*/
|
||||||
|
@TableField("name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改时间
|
||||||
|
*/
|
||||||
|
@TableField("update_time")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.abin.mallchat.common.user.domain.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户角色关系表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
@TableName("user_role")
|
||||||
|
public class UserRole implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uid
|
||||||
|
*/
|
||||||
|
@TableField("uid")
|
||||||
|
private Long uid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色id
|
||||||
|
*/
|
||||||
|
@TableField("role_id")
|
||||||
|
private Long roleId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField("create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改时间
|
||||||
|
*/
|
||||||
|
@TableField("update_time")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.abin.mallchat.common.user.domain.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 角色枚举
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-19
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum RoleEnum {
|
||||||
|
ADMIN(1L, "超级管理员"),
|
||||||
|
CHAT_MANAGER(2L, "抹茶群聊管理"),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
private static Map<Long, RoleEnum> cache;
|
||||||
|
|
||||||
|
static {
|
||||||
|
cache = Arrays.stream(RoleEnum.values()).collect(Collectors.toMap(RoleEnum::getId, Function.identity()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RoleEnum of(Integer type) {
|
||||||
|
return cache.get(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.abin.mallchat.common.user.mapper;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.Role;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
public interface RoleMapper extends BaseMapper<Role> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.abin.mallchat.common.user.mapper;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.UserRole;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户角色关系表 Mapper 接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
public interface UserRoleMapper extends BaseMapper<UserRole> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.abin.mallchat.common.user.service;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
public interface IRoleService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有某个权限,临时做法
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean hasPower(Long uid, RoleEnum roleEnum);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.abin.mallchat.common.user.service;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.UserRole;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 用户角色关系表 服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* @since 2023-06-04
|
||||||
|
*/
|
||||||
|
public interface IUserRoleService extends IService<UserRole> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,9 +8,12 @@ import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
|||||||
import com.abin.mallchat.common.common.utils.CursorUtils;
|
import com.abin.mallchat.common.common.utils.CursorUtils;
|
||||||
import com.abin.mallchat.common.common.utils.RedisUtils;
|
import com.abin.mallchat.common.common.utils.RedisUtils;
|
||||||
import com.abin.mallchat.common.user.dao.BlackDao;
|
import com.abin.mallchat.common.user.dao.BlackDao;
|
||||||
|
import com.abin.mallchat.common.user.dao.RoleDao;
|
||||||
import com.abin.mallchat.common.user.dao.UserDao;
|
import com.abin.mallchat.common.user.dao.UserDao;
|
||||||
|
import com.abin.mallchat.common.user.dao.UserRoleDao;
|
||||||
import com.abin.mallchat.common.user.domain.entity.Black;
|
import com.abin.mallchat.common.user.domain.entity.Black;
|
||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.UserRole;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
@@ -34,6 +37,10 @@ public class UserCache {
|
|||||||
private UserDao userDao;
|
private UserDao userDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private BlackDao blackDao;
|
private BlackDao blackDao;
|
||||||
|
@Autowired
|
||||||
|
private RoleDao roleDao;
|
||||||
|
@Autowired
|
||||||
|
private UserRoleDao userRoleDao;
|
||||||
|
|
||||||
public Long getOnlineNum() {
|
public Long getOnlineNum() {
|
||||||
String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
|
String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
|
||||||
@@ -45,6 +52,16 @@ public class UserCache {
|
|||||||
return RedisUtils.zCard(offlineKey);
|
return RedisUtils.zCard(offlineKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//移除用户
|
||||||
|
public void remove(Long uid) {
|
||||||
|
String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
|
||||||
|
String offlineKey = RedisKey.getKey(RedisKey.OFFLINE_UID_ZET);
|
||||||
|
//移除离线表
|
||||||
|
RedisUtils.zRemove(offlineKey, uid);
|
||||||
|
//移除上线表
|
||||||
|
RedisUtils.zRemove(onlineKey, uid);
|
||||||
|
}
|
||||||
|
|
||||||
//用户上线
|
//用户上线
|
||||||
public void online(Long uid, Date optTime) {
|
public void online(Long uid, Date optTime) {
|
||||||
String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
|
String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET);
|
||||||
@@ -80,9 +97,6 @@ public class UserCache {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户信息,盘路缓存模式
|
* 获取用户信息,盘路缓存模式
|
||||||
*
|
|
||||||
* @param uid
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public User getUserInfo(Long uid) {//todo 后期做二级缓存
|
public User getUserInfo(Long uid) {//todo 后期做二级缓存
|
||||||
return getUserInfoBatch(Collections.singleton(uid)).get(uid);
|
return getUserInfoBatch(Collections.singleton(uid)).get(uid);
|
||||||
@@ -90,9 +104,6 @@ public class UserCache {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户信息,盘路缓存模式
|
* 获取用户信息,盘路缓存模式
|
||||||
*
|
|
||||||
* @param uids
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public Map<Long, User> getUserInfoBatch(Set<Long> uids) {
|
public Map<Long, User> getUserInfoBatch(Set<Long> uids) {
|
||||||
List<String> keys = uids.stream().map(a -> RedisKey.getKey(RedisKey.USER_INFO_STRING, a)).collect(Collectors.toList());
|
List<String> keys = uids.stream().map(a -> RedisKey.getKey(RedisKey.USER_INFO_STRING, a)).collect(Collectors.toList());
|
||||||
@@ -128,4 +139,12 @@ public class UserCache {
|
|||||||
public Map<Integer, Set<String>> evictBlackMap() {
|
public Map<Integer, Set<String>> evictBlackMap() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = "user", key = "'roles'+#uid")
|
||||||
|
public Set<Long> getRoleSet(Long uid) {
|
||||||
|
List<UserRole> userRoles = userRoleDao.listByUid(uid);
|
||||||
|
return userRoles.stream()
|
||||||
|
.map(UserRole::getRoleId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.abin.mallchat.common.user.service.impl;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||||
|
import com.abin.mallchat.common.user.service.IRoleService;
|
||||||
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 角色管理
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class RoleServiceImpl implements IRoleService {
|
||||||
|
@Autowired
|
||||||
|
private UserCache userCache;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPower(Long uid, RoleEnum roleEnum) {//超级管理员无敌的好吧,后期做成权限=》资源模式
|
||||||
|
Set<Long> roleSet = userCache.getRoleSet(uid);
|
||||||
|
return isAdmin(roleSet) || roleSet.contains(roleEnum.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAdmin(Set<Long> roleSet) {
|
||||||
|
return Objects.requireNonNull(roleSet).contains(RoleEnum.ADMIN.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import com.abin.mallchat.common.common.annotation.RedissonLock;
|
|||||||
import com.abin.mallchat.common.common.domain.enums.IdempotentEnum;
|
import com.abin.mallchat.common.common.domain.enums.IdempotentEnum;
|
||||||
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
||||||
import com.abin.mallchat.common.common.event.ItemReceiveEvent;
|
import com.abin.mallchat.common.common.event.ItemReceiveEvent;
|
||||||
import com.abin.mallchat.common.user.dao.ItemConfigDao;
|
|
||||||
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
||||||
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
||||||
import com.abin.mallchat.common.user.domain.entity.UserBackpack;
|
import com.abin.mallchat.common.user.domain.entity.UserBackpack;
|
||||||
@@ -13,6 +12,7 @@ import com.abin.mallchat.common.user.service.IUserBackpackService;
|
|||||||
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -30,12 +30,11 @@ public class UserBackpackServiceImpl implements IUserBackpackService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UserBackpackDao userBackpackDao;
|
private UserBackpackDao userBackpackDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemConfigDao itemConfigDao;
|
|
||||||
@Autowired
|
|
||||||
private ItemCache itemCache;
|
private ItemCache itemCache;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationEventPublisher applicationEventPublisher;
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@Lazy
|
||||||
private UserBackpackServiceImpl userBackpackService;
|
private UserBackpackServiceImpl userBackpackService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?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.abin.mallchat.common.user.mapper.RoleMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?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.abin.mallchat.common.user.mapper.UserRoleMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -15,7 +15,7 @@ import org.springframework.boot.web.servlet.ServletComponentScan;
|
|||||||
public class MallchatCustomApplication {
|
public class MallchatCustomApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(MallchatCustomApplication.class);
|
SpringApplication.run(MallchatCustomApplication.class,args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,9 +8,11 @@ import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
|||||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||||
import com.abin.mallchat.common.user.domain.enums.BlackTypeEnum;
|
import com.abin.mallchat.common.user.domain.enums.BlackTypeEnum;
|
||||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.msg.TextMsgReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberStatisticResp;
|
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberStatisticResp;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||||
@@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,6 +92,10 @@ public class ChatController {
|
|||||||
@FrequencyControl(time = 30, count = 5, target = FrequencyControl.Target.UID)
|
@FrequencyControl(time = 30, count = 5, target = FrequencyControl.Target.UID)
|
||||||
@FrequencyControl(time = 60, count = 10, target = FrequencyControl.Target.UID)
|
@FrequencyControl(time = 60, count = 10, target = FrequencyControl.Target.UID)
|
||||||
public ApiResult<ChatMessageResp> sendMsg(@Valid @RequestBody ChatMessageReq request) {
|
public ApiResult<ChatMessageResp> sendMsg(@Valid @RequestBody ChatMessageReq request) {
|
||||||
|
if (Objects.isNull(request.getBody())) {
|
||||||
|
TextMsgReq req = new TextMsgReq(request.getContent(), request.getReplyMsgId());//todo 消息兼容之后删了
|
||||||
|
request.setBody(req);
|
||||||
|
}
|
||||||
Long msgId = chatService.sendMsg(request, RequestHolder.get().getUid());
|
Long msgId = chatService.sendMsg(request, RequestHolder.get().getUid());
|
||||||
//返回完整消息格式,方便前端展示
|
//返回完整消息格式,方便前端展示
|
||||||
return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid()));
|
return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid()));
|
||||||
@@ -100,7 +107,14 @@ public class ChatController {
|
|||||||
public ApiResult<Void> setMsgMark(@Valid @RequestBody ChatMessageMarkReq request) {
|
public ApiResult<Void> setMsgMark(@Valid @RequestBody ChatMessageMarkReq request) {
|
||||||
chatService.setMsgMark(RequestHolder.get().getUid(), request);
|
chatService.setMsgMark(RequestHolder.get().getUid(), request);
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/msg/recall")
|
||||||
|
@ApiOperation("撤回消息")
|
||||||
|
@FrequencyControl(time = 20, count = 3, target = FrequencyControl.Target.UID)
|
||||||
|
public ApiResult<Void> recallMsg(@Valid @RequestBody ChatMessageBaseReq request) {
|
||||||
|
chatService.recallMsg(RequestHolder.get().getUid(), request);
|
||||||
|
return ApiResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.domain.vo.request;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 消息基础请求体
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ChatMessageBaseReq {
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty("消息id")
|
||||||
|
private Long msgId;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty("会话id")
|
||||||
|
private Long roomId;
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.abin.mallchat.custom.chat.domain.vo.request;
|
package com.abin.mallchat.custom.chat.domain.vo.request;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.hibernate.validator.constraints.Length;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
@@ -20,16 +20,21 @@ import javax.validation.constraints.NotNull;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class ChatMessageReq {
|
public class ChatMessageReq {
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Length(max = 10000, message = "消息内容过长,服务器扛不住啊,兄dei")
|
|
||||||
@ApiModelProperty("消息内容")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ApiModelProperty("会话id")
|
@ApiModelProperty("会话id")
|
||||||
private Long roomId;
|
private Long roomId;
|
||||||
|
|
||||||
|
@ApiModelProperty("消息类型")
|
||||||
|
private Integer msgType = MessageTypeEnum.TEXT.getType();
|
||||||
|
|
||||||
|
@ApiModelProperty("消息内容,类型不同传值不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd")
|
||||||
|
private Object body;
|
||||||
|
|
||||||
|
@ApiModelProperty("消息内容")
|
||||||
|
@Deprecated
|
||||||
|
private String content;
|
||||||
|
|
||||||
@ApiModelProperty("回复的消息id,如果没有别传就好")
|
@ApiModelProperty("回复的消息id,如果没有别传就好")
|
||||||
|
@Deprecated
|
||||||
private Long replyMsgId;
|
private Long replyMsgId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.domain.vo.request.msg;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 文本消息入参
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TextMsgReq {
|
||||||
|
|
||||||
|
@ApiModelProperty("消息内容")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@ApiModelProperty("回复的消息id,如果没有别传就好")
|
||||||
|
private Long replyMsgId;
|
||||||
|
}
|
||||||
@@ -45,12 +45,16 @@ public class ChatMessageResp {
|
|||||||
private Long id;
|
private Long id;
|
||||||
@ApiModelProperty("消息发送时间")
|
@ApiModelProperty("消息发送时间")
|
||||||
private Date sendTime;
|
private Date sendTime;
|
||||||
@ApiModelProperty("消息内容")
|
@ApiModelProperty("消息内容-废弃")
|
||||||
|
@Deprecated
|
||||||
private String content;
|
private String content;
|
||||||
@ApiModelProperty("消息链接映射")
|
@ApiModelProperty("消息链接映射-废弃")
|
||||||
|
@Deprecated
|
||||||
private Map<String, String> urlTitleMap;
|
private Map<String, String> urlTitleMap;
|
||||||
@ApiModelProperty("消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)")
|
@ApiModelProperty("消息类型 1正常文本 2.撤回消息")
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
@ApiModelProperty("消息内容不同的消息类型,内容体不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd")
|
||||||
|
private Object body;
|
||||||
@ApiModelProperty("消息标记")
|
@ApiModelProperty("消息标记")
|
||||||
private MessageMark messageMark;
|
private MessageMark messageMark;
|
||||||
@ApiModelProperty("父消息,如果没有父消息,返回的是null")
|
@ApiModelProperty("父消息,如果没有父消息,返回的是null")
|
||||||
@@ -59,6 +63,7 @@ public class ChatMessageResp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Deprecated
|
||||||
public static class ReplyMsg {
|
public static class ReplyMsg {
|
||||||
@ApiModelProperty("消息id")
|
@ApiModelProperty("消息id")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.domain.vo.response.msg;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 文本消息返回体
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TextMsgResp {
|
||||||
|
@ApiModelProperty("消息内容")
|
||||||
|
private String content;
|
||||||
|
@ApiModelProperty("消息链接映射")
|
||||||
|
private Map<String, String> urlTitleMap;
|
||||||
|
@ApiModelProperty("父消息,如果没有父消息,返回的是null")
|
||||||
|
private TextMsgResp.ReplyMsg reply;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class ReplyMsg {
|
||||||
|
@ApiModelProperty("消息id")
|
||||||
|
private Long id;
|
||||||
|
@ApiModelProperty("用户uid")
|
||||||
|
private Long uid;
|
||||||
|
@ApiModelProperty("用户名称")
|
||||||
|
private String username;
|
||||||
|
@ApiModelProperty("消息类型 1正常文本 2.撤回消息")
|
||||||
|
private Integer type;
|
||||||
|
@ApiModelProperty("消息内容不同的消息类型,见父消息内容体")
|
||||||
|
private Object body;
|
||||||
|
@ApiModelProperty("是否可消息跳转 0否 1是")
|
||||||
|
private Integer canCallback;
|
||||||
|
@ApiModelProperty("跳转间隔的消息条数")
|
||||||
|
private Integer gapCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.abin.mallchat.custom.chat.service;
|
|||||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
|
import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
|
||||||
import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
@@ -73,4 +74,6 @@ public interface ChatService {
|
|||||||
ChatMemberStatisticResp getMemberStatistic();
|
ChatMemberStatisticResp getMemberStatistic();
|
||||||
|
|
||||||
void setMsgMark(Long uid, ChatMessageMarkReq request);
|
void setMsgMark(Long uid, ChatMessageMarkReq request);
|
||||||
|
|
||||||
|
void recallMsg(Long uid, ChatMessageBaseReq request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package com.abin.mallchat.custom.chat.service.adapter;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.abin.mallchat.common.chat.domain.entity.Message;
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
import com.abin.mallchat.common.chat.domain.entity.MessageExtra;
|
|
||||||
import com.abin.mallchat.common.chat.domain.entity.MessageMark;
|
import com.abin.mallchat.common.chat.domain.entity.MessageMark;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
|
||||||
import com.abin.mallchat.common.chat.domain.enums.MessageMarkTypeEnum;
|
import com.abin.mallchat.common.chat.domain.enums.MessageMarkTypeEnum;
|
||||||
import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum;
|
import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum;
|
||||||
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
||||||
@@ -14,6 +14,8 @@ import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
|||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp;
|
||||||
|
import com.abin.mallchat.custom.chat.service.strategy.msg.AbstractMsgHandler;
|
||||||
|
import com.abin.mallchat.custom.chat.service.strategy.msg.MsgHandlerFactory;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -24,14 +26,12 @@ import java.util.stream.Collectors;
|
|||||||
* Date: 2023-03-26
|
* Date: 2023-03-26
|
||||||
*/
|
*/
|
||||||
public class MessageAdapter {
|
public class MessageAdapter {
|
||||||
public static final int CAN_CALLBACK_GAP_COUNT = 50;
|
public static final int CAN_CALLBACK_GAP_COUNT = 100;
|
||||||
private static final PrioritizedUrlTitleDiscover URL_TITLE_DISCOVER = new PrioritizedUrlTitleDiscover();
|
private static final PrioritizedUrlTitleDiscover URL_TITLE_DISCOVER = new PrioritizedUrlTitleDiscover();
|
||||||
|
|
||||||
public static Message buildMsgSave(ChatMessageReq request, Long uid) {
|
public static Message buildMsgSave(ChatMessageReq request, Long uid) {
|
||||||
|
|
||||||
return Message.builder()
|
return Message.builder()
|
||||||
.replyMsgId(request.getReplyMsgId())
|
|
||||||
.content(request.getContent())
|
|
||||||
.fromUid(uid)
|
.fromUid(uid)
|
||||||
.roomId(request.getRoomId())
|
.roomId(request.getRoomId())
|
||||||
.status(MessageStatusEnum.NORMAL.getStatus())
|
.status(MessageStatusEnum.NORMAL.getStatus())
|
||||||
@@ -61,8 +61,11 @@ public class MessageAdapter {
|
|||||||
ChatMessageResp.Message messageVO = new ChatMessageResp.Message();
|
ChatMessageResp.Message messageVO = new ChatMessageResp.Message();
|
||||||
BeanUtil.copyProperties(message, messageVO);
|
BeanUtil.copyProperties(message, messageVO);
|
||||||
messageVO.setSendTime(message.getCreateTime());
|
messageVO.setSendTime(message.getCreateTime());
|
||||||
|
AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(message.getType());
|
||||||
|
messageVO.setBody(msgHandler.showMsg(message));
|
||||||
messageVO.setUrlTitleMap(Optional.ofNullable(message.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
|
messageVO.setUrlTitleMap(Optional.ofNullable(message.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
|
||||||
Message replyMessage = replyMap.get(message.getReplyMsgId());
|
Message replyMessage = replyMap.get(message.getReplyMsgId());
|
||||||
|
|
||||||
//回复消息
|
//回复消息
|
||||||
if (Objects.nonNull(replyMessage)) {
|
if (Objects.nonNull(replyMessage)) {
|
||||||
ChatMessageResp.ReplyMsg replyMsgVO = new ChatMessageResp.ReplyMsg();
|
ChatMessageResp.ReplyMsg replyMsgVO = new ChatMessageResp.ReplyMsg();
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.abin.mallchat.custom.chat.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.date.DateUnit;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.lang.Pair;
|
import cn.hutool.core.lang.Pair;
|
||||||
import com.abin.mallchat.common.chat.dao.MessageDao;
|
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||||
import com.abin.mallchat.common.chat.dao.MessageMarkDao;
|
import com.abin.mallchat.common.chat.dao.MessageMarkDao;
|
||||||
@@ -10,19 +12,21 @@ import com.abin.mallchat.common.chat.domain.entity.Message;
|
|||||||
import com.abin.mallchat.common.chat.domain.entity.MessageMark;
|
import com.abin.mallchat.common.chat.domain.entity.MessageMark;
|
||||||
import com.abin.mallchat.common.chat.domain.entity.Room;
|
import com.abin.mallchat.common.chat.domain.entity.Room;
|
||||||
import com.abin.mallchat.common.chat.domain.enums.MessageMarkActTypeEnum;
|
import com.abin.mallchat.common.chat.domain.enums.MessageMarkActTypeEnum;
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||||
import com.abin.mallchat.common.common.annotation.RedissonLock;
|
import com.abin.mallchat.common.common.annotation.RedissonLock;
|
||||||
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
|
||||||
import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
|
import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq;
|
||||||
import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp;
|
||||||
import com.abin.mallchat.common.common.event.MessageSendEvent;
|
import com.abin.mallchat.common.common.event.MessageSendEvent;
|
||||||
import com.abin.mallchat.common.common.exception.BusinessException;
|
|
||||||
import com.abin.mallchat.common.common.utils.AssertUtil;
|
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||||
import com.abin.mallchat.common.user.dao.UserDao;
|
import com.abin.mallchat.common.user.dao.UserDao;
|
||||||
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
import com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum;
|
import com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum;
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||||
|
import com.abin.mallchat.common.user.service.IRoleService;
|
||||||
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
||||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageBaseReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMarkReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessagePageReq;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
@@ -37,6 +41,9 @@ import com.abin.mallchat.custom.chat.service.adapter.RoomAdapter;
|
|||||||
import com.abin.mallchat.custom.chat.service.helper.ChatMemberHelper;
|
import com.abin.mallchat.custom.chat.service.helper.ChatMemberHelper;
|
||||||
import com.abin.mallchat.custom.chat.service.strategy.mark.AbstractMsgMarkStrategy;
|
import com.abin.mallchat.custom.chat.service.strategy.mark.AbstractMsgMarkStrategy;
|
||||||
import com.abin.mallchat.custom.chat.service.strategy.mark.MsgMarkFactory;
|
import com.abin.mallchat.custom.chat.service.strategy.mark.MsgMarkFactory;
|
||||||
|
import com.abin.mallchat.custom.chat.service.strategy.msg.AbstractMsgHandler;
|
||||||
|
import com.abin.mallchat.custom.chat.service.strategy.msg.MsgHandlerFactory;
|
||||||
|
import com.abin.mallchat.custom.chat.service.strategy.msg.RecallMsgHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
@@ -73,6 +80,10 @@ public class ChatServiceImpl implements ChatService {
|
|||||||
private MessageMarkDao messageMarkDao;
|
private MessageMarkDao messageMarkDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemCache itemCache;
|
private ItemCache itemCache;
|
||||||
|
@Autowired
|
||||||
|
private IRoleService iRoleService;
|
||||||
|
@Autowired
|
||||||
|
private RecallMsgHandler recallMsgHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
@@ -80,22 +91,12 @@ public class ChatServiceImpl implements ChatService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long sendMsg(ChatMessageReq request, Long uid) {
|
public Long sendMsg(ChatMessageReq request, Long uid) {
|
||||||
//校验下回复消息
|
AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());//todo 这里先不扩展,后续再改
|
||||||
Message replyMsg = null;
|
msgHandler.checkMsg(request);
|
||||||
if (Objects.nonNull(request.getReplyMsgId())) {
|
|
||||||
replyMsg = messageDao.getById(request.getReplyMsgId());
|
|
||||||
AssertUtil.isNotEmpty(replyMsg, "回复消息不存在");
|
|
||||||
AssertUtil.equal(replyMsg.getRoomId(), request.getRoomId(), "只能回复相同会话内的消息");
|
|
||||||
|
|
||||||
}
|
|
||||||
//同步获取消息的跳转链接标题
|
//同步获取消息的跳转链接标题
|
||||||
Message insert = MessageAdapter.buildMsgSave(request, uid);
|
Message insert = MessageAdapter.buildMsgSave(request, uid);
|
||||||
messageDao.save(insert);
|
messageDao.save(insert);
|
||||||
//如果有回复消息
|
msgHandler.saveMsg(insert, request);
|
||||||
if (Objects.nonNull(replyMsg)) {
|
|
||||||
Integer gapCount = messageDao.getGapCount(request.getRoomId(), replyMsg.getId(), insert.getId());
|
|
||||||
messageDao.updateGapCount(insert.getId(), gapCount);
|
|
||||||
}
|
|
||||||
//发布消息发送事件
|
//发布消息发送事件
|
||||||
applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId()));
|
applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId()));
|
||||||
return insert.getId();
|
return insert.getId();
|
||||||
@@ -186,13 +187,26 @@ public class ChatServiceImpl implements ChatService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer transformAct(Integer actType) {
|
@Override
|
||||||
if (actType == 1) {
|
public void recallMsg(Long uid, ChatMessageBaseReq request) {
|
||||||
return YesOrNoEnum.NO.getStatus();
|
Message message = messageDao.getById(request.getMsgId());
|
||||||
} else if (actType == 2) {
|
//校验能不能执行撤回
|
||||||
return YesOrNoEnum.YES.getStatus();
|
checkRecall(uid, message);
|
||||||
|
//执行消息撤回
|
||||||
|
recallMsgHandler.recall(uid, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRecall(Long uid, Message message) {
|
||||||
|
AssertUtil.isNotEmpty(message, "消息有误");
|
||||||
|
AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL, "消息无法撤回");
|
||||||
|
boolean hasPower = iRoleService.hasPower(uid, RoleEnum.CHAT_MANAGER);
|
||||||
|
if (hasPower) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
throw new BusinessException("动作类型 1确认 2取消");
|
boolean self = Objects.equals(uid, message.getFromUid());
|
||||||
|
AssertUtil.isTrue(self, "抱歉,您没有权限");
|
||||||
|
long between = DateUtil.between(message.getCreateTime(), new Date(), DateUnit.MINUTE);
|
||||||
|
AssertUtil.isTrue(between < 2, "覆水难收,超过2分钟的消息不能撤回哦~~");
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ChatMessageResp> getMsgRespBatch(List<Message> messages, Long receiveUid) {
|
public List<ChatMessageResp> getMsgRespBatch(List<Message> messages, Long receiveUid) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class DisLikeStrategy extends AbstractMsgMarkStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doMark(Long uid, Long msgId) {
|
public void doMark(Long uid, Long msgId) {
|
||||||
super.mark(uid, msgId);
|
super.doMark(uid, msgId);
|
||||||
//同时取消点赞的动作
|
//同时取消点赞的动作
|
||||||
MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.LIKE.getType()).unMark(uid, msgId);
|
MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.LIKE.getType()).unMark(uid, msgId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class LikeStrategy extends AbstractMsgMarkStrategy {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doMark(Long uid, Long msgId) {
|
public void doMark(Long uid, Long msgId) {
|
||||||
super.mark(uid, msgId);
|
super.doMark(uid, msgId);
|
||||||
//同时取消点踩的动作
|
//同时取消点踩的动作
|
||||||
MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.DISLIKE.getType()).unMark(uid, msgId);
|
MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.DISLIKE.getType()).unMark(uid, msgId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.service.strategy.msg;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 消息处理器抽象类
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMsgHandler {
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
MsgHandlerFactory.register(getMsgTypeEnum().getType(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract MessageTypeEnum getMsgTypeEnum();
|
||||||
|
|
||||||
|
public abstract void checkMsg(ChatMessageReq req);
|
||||||
|
|
||||||
|
public abstract void saveMsg(Message msg, ChatMessageReq req);
|
||||||
|
|
||||||
|
public abstract Object showMsg(Message msg);
|
||||||
|
|
||||||
|
public abstract Object showReplyMsg(Message msg);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.service.strategy.msg;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
|
|
||||||
|
public interface MsgHandler<RESP, REQ> {
|
||||||
|
|
||||||
|
void saveMsg(Message msg, REQ req);
|
||||||
|
|
||||||
|
RESP showMsg(Message msg);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.service.strategy.msg;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.common.exception.CommonErrorEnum;
|
||||||
|
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
public class MsgHandlerFactory {
|
||||||
|
private static final Map<Integer, AbstractMsgHandler> STRATEGY_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
public static void register(Integer code, AbstractMsgHandler strategy) {
|
||||||
|
STRATEGY_MAP.put(code, strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AbstractMsgHandler getStrategyNoNull(Integer code) {
|
||||||
|
AbstractMsgHandler strategy = STRATEGY_MAP.get(code);
|
||||||
|
AssertUtil.isNotEmpty(strategy, CommonErrorEnum.PARAM_VALID);
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.service.strategy.msg;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||||
|
import com.abin.mallchat.common.chat.domain.dto.ChatMsgRecallDTO;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.msg.MsgRecall;
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||||
|
import com.abin.mallchat.common.chat.service.cache.MsgCache;
|
||||||
|
import com.abin.mallchat.common.common.event.MessageRecallEvent;
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 撤回文本消息
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RecallMsgHandler extends AbstractMsgHandler {
|
||||||
|
@Autowired
|
||||||
|
private MessageDao messageDao;
|
||||||
|
@Autowired
|
||||||
|
private UserCache userCache;
|
||||||
|
@Autowired
|
||||||
|
private MsgCache msgCache;
|
||||||
|
@Autowired
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MessageTypeEnum getMsgTypeEnum() {
|
||||||
|
return MessageTypeEnum.RECALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkMsg(ChatMessageReq request) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveMsg(Message msg, ChatMessageReq request) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object showMsg(Message msg) {//todo 后期让前端来做
|
||||||
|
MsgRecall recall = msg.getExtra().getRecall();
|
||||||
|
if (!Objects.equals(recall.getRecallUid(), msg.getFromUid())) {
|
||||||
|
User userInfo = userCache.getUserInfo(recall.getRecallUid());
|
||||||
|
return "管理员\"" + userInfo.getName() + "\"撤回了一条成员消息";
|
||||||
|
}
|
||||||
|
User userInfo = userCache.getUserInfo(msg.getFromUid());
|
||||||
|
return "\"" + userInfo.getName() + "\"撤回了一条消息";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object showReplyMsg(Message msg) {
|
||||||
|
return "原消息已被撤回";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recall(Long recallUid, Message message) {//todo 消息覆盖问题用版本号解决
|
||||||
|
MessageExtra extra = message.getExtra();
|
||||||
|
extra.setRecall(new MsgRecall(recallUid, new Date()));
|
||||||
|
Message update = new Message();
|
||||||
|
update.setId(message.getId());
|
||||||
|
update.setType(MessageTypeEnum.RECALL.getType());
|
||||||
|
update.setExtra(extra);
|
||||||
|
messageDao.updateById(update);
|
||||||
|
applicationEventPublisher.publishEvent(new MessageRecallEvent(this, new ChatMsgRecallDTO(message.getId(), message.getRoomId(), recallUid)));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package com.abin.mallchat.custom.chat.service.strategy.msg;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.Message;
|
||||||
|
import com.abin.mallchat.common.chat.domain.entity.msg.MessageExtra;
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum;
|
||||||
|
import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum;
|
||||||
|
import com.abin.mallchat.common.chat.service.cache.MsgCache;
|
||||||
|
import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum;
|
||||||
|
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.request.msg.TextMsgReq;
|
||||||
|
import com.abin.mallchat.custom.chat.domain.vo.response.msg.TextMsgResp;
|
||||||
|
import com.abin.mallchat.custom.chat.service.adapter.MessageAdapter;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 普通文本消息
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-06-04
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TextMsgHandler extends AbstractMsgHandler {
|
||||||
|
@Autowired
|
||||||
|
private MessageDao messageDao;
|
||||||
|
@Autowired
|
||||||
|
private MsgCache msgCache;
|
||||||
|
@Autowired
|
||||||
|
private UserCache userCache;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MessageTypeEnum getMsgTypeEnum() {
|
||||||
|
return MessageTypeEnum.TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkMsg(ChatMessageReq request) {
|
||||||
|
TextMsgReq body = BeanUtil.toBean(request.getBody(), TextMsgReq.class);
|
||||||
|
AssertUtil.isNotEmpty(body.getContent(), "内容不能为空");
|
||||||
|
AssertUtil.isTrue(body.getContent().length() < 500, "消息内容过长,服务器扛不住啊,兄dei");
|
||||||
|
//校验下回复消息
|
||||||
|
if (Objects.nonNull(body.getReplyMsgId())) {
|
||||||
|
Message replyMsg = messageDao.getById(body.getReplyMsgId());
|
||||||
|
AssertUtil.isNotEmpty(replyMsg, "回复消息不存在");
|
||||||
|
AssertUtil.equal(replyMsg.getRoomId(), request.getRoomId(), "只能回复相同会话内的消息");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveMsg(Message msg, ChatMessageReq request) {//插入文本内容
|
||||||
|
TextMsgReq body = BeanUtil.toBean(request.getBody(), TextMsgReq.class);
|
||||||
|
Message update = new Message();
|
||||||
|
update.setId(msg.getId());
|
||||||
|
update.setContent(body.getContent());
|
||||||
|
//如果有回复消息
|
||||||
|
if (Objects.nonNull(body.getReplyMsgId())) {
|
||||||
|
Integer gapCount = messageDao.getGapCount(request.getRoomId(), body.getReplyMsgId(), msg.getId());
|
||||||
|
update.setGapCount(gapCount);
|
||||||
|
update.setReplyMsgId(body.getReplyMsgId());
|
||||||
|
|
||||||
|
}
|
||||||
|
messageDao.updateById(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object showMsg(Message msg) {
|
||||||
|
TextMsgResp resp = new TextMsgResp();
|
||||||
|
resp.setContent(msg.getContent());
|
||||||
|
resp.setUrlTitleMap(Optional.ofNullable(msg.getExtra()).map(MessageExtra::getUrlTitleMap).orElse(null));
|
||||||
|
//回复消息
|
||||||
|
Optional<Message> reply = Optional.ofNullable(msg.getReplyMsgId())
|
||||||
|
.map(msgCache::getMsg)
|
||||||
|
.filter(a -> Objects.equals(a.getStatus(), MessageStatusEnum.NORMAL.getStatus()));
|
||||||
|
if (reply.isPresent()) {
|
||||||
|
Message replyMessage = reply.get();
|
||||||
|
TextMsgResp.ReplyMsg replyMsgVO = new TextMsgResp.ReplyMsg();
|
||||||
|
replyMsgVO.setId(replyMessage.getId());
|
||||||
|
replyMsgVO.setUid(replyMessage.getFromUid());
|
||||||
|
replyMessage.setType(replyMessage.getType());
|
||||||
|
replyMsgVO.setBody(MsgHandlerFactory.getStrategyNoNull(replyMessage.getType()).showReplyMsg(replyMessage));
|
||||||
|
User replyUser = userCache.getUserInfo(replyMessage.getFromUid());
|
||||||
|
replyMsgVO.setUsername(replyUser.getName());
|
||||||
|
replyMsgVO.setCanCallback(YesOrNoEnum.toStatus(Objects.nonNull(msg.getGapCount()) && msg.getGapCount() <= MessageAdapter.CAN_CALLBACK_GAP_COUNT));
|
||||||
|
replyMsgVO.setGapCount(msg.getGapCount());
|
||||||
|
resp.setReply(replyMsgVO);
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object showReplyMsg(Message msg) {
|
||||||
|
return msg.getContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ public class MessageMarkListener {
|
|||||||
public void changeMsgType(MessageMarkEvent event) {
|
public void changeMsgType(MessageMarkEvent event) {
|
||||||
ChatMessageMarkDTO dto = event.getDto();
|
ChatMessageMarkDTO dto = event.getDto();
|
||||||
Message msg = messageDao.getById(dto.getMsgId());
|
Message msg = messageDao.getById(dto.getMsgId());
|
||||||
if (!Objects.equals(msg.getType(), MessageTypeEnum.NORMAL.getType())) {//普通消息才需要升级
|
if (!Objects.equals(msg.getType(), MessageTypeEnum.TEXT.getType())) {//普通消息才需要升级
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//消息被标记次数
|
//消息被标记次数
|
||||||
@@ -51,8 +51,7 @@ public class MessageMarkListener {
|
|||||||
if (markCount < markTypeEnum.getRiseNum()) {
|
if (markCount < markTypeEnum.getRiseNum()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean updateSuccess = messageDao.riseOptimistic(msg.getId(), msg.getType(), markTypeEnum.getRiseEnum().getType());
|
if (MessageMarkTypeEnum.LIKE.getType().equals(dto.getMarkType())) {//尝试给用户发送一张徽章
|
||||||
if (MessageMarkTypeEnum.LIKE.getType().equals(dto.getMarkType()) && updateSuccess) {//尝试给用户发送一张徽章
|
|
||||||
iUserBackpackService.acquireItem(msg.getFromUid(), ItemEnum.LIKE_BADGE.getId(), IdempotentEnum.MSG_ID, msg.getId().toString());
|
iUserBackpackService.acquireItem(msg.getFromUid(), ItemEnum.LIKE_BADGE.getId(), IdempotentEnum.MSG_ID, msg.getId().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.abin.mallchat.custom.common.event.listener;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.dto.ChatMsgRecallDTO;
|
||||||
|
import com.abin.mallchat.common.chat.service.cache.MsgCache;
|
||||||
|
import com.abin.mallchat.common.common.event.MessageRecallEvent;
|
||||||
|
import com.abin.mallchat.custom.chat.service.ChatService;
|
||||||
|
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||||
|
import com.abin.mallchat.custom.user.service.adapter.WSAdapter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.event.TransactionalEventListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息撤回监听器
|
||||||
|
*
|
||||||
|
* @author zhongzb create on 2022/08/26
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class MessageRecallListener {
|
||||||
|
@Autowired
|
||||||
|
private WebSocketService webSocketService;
|
||||||
|
@Autowired
|
||||||
|
private ChatService chatService;
|
||||||
|
@Autowired
|
||||||
|
private MsgCache msgCache;
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@TransactionalEventListener(classes = MessageRecallEvent.class, fallbackExecution = true)
|
||||||
|
public void evictMsg(MessageRecallEvent event) {
|
||||||
|
ChatMsgRecallDTO recallDTO = event.getRecallDTO();
|
||||||
|
msgCache.evictMsg(recallDTO.getMsgId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@TransactionalEventListener(classes = MessageRecallEvent.class, fallbackExecution = true)
|
||||||
|
public void sendToAll(MessageRecallEvent event) {
|
||||||
|
webSocketService.sendToAllOnline(WSAdapter.buildMsgRecall(event.getRecallDTO()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.abin.mallchat.custom.common.event.listener;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.dao.MessageDao;
|
||||||
|
import com.abin.mallchat.common.common.event.UserBlackEvent;
|
||||||
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.user.domain.enums.WSRespTypeEnum;
|
||||||
|
import com.abin.mallchat.custom.user.domain.vo.response.ws.WSBaseResp;
|
||||||
|
import com.abin.mallchat.custom.user.domain.vo.response.ws.WSBlack;
|
||||||
|
import com.abin.mallchat.custom.user.service.WebSocketService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户拉黑监听器
|
||||||
|
*
|
||||||
|
* @author zhongzb create on 2022/08/26
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class UserBlackListener {
|
||||||
|
@Autowired
|
||||||
|
private MessageDao messageDao;
|
||||||
|
@Autowired
|
||||||
|
private WebSocketService webSocketService;
|
||||||
|
@Autowired
|
||||||
|
private UserCache userCache;
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@EventListener(classes = UserBlackEvent.class)
|
||||||
|
public void refreshRedis(UserBlackEvent event) {
|
||||||
|
userCache.evictBlackMap();
|
||||||
|
userCache.remove(event.getUser().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@EventListener(classes = UserBlackEvent.class)
|
||||||
|
public void deleteMsg(UserBlackEvent event) {
|
||||||
|
messageDao.invalidByUid(event.getUser().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@EventListener(classes = UserBlackEvent.class)
|
||||||
|
public void sendPush(UserBlackEvent event) {
|
||||||
|
Long uid = event.getUser().getId();
|
||||||
|
WSBaseResp<WSBlack> resp = new WSBaseResp<>();
|
||||||
|
WSBlack black = new WSBlack(uid);
|
||||||
|
resp.setData(black);
|
||||||
|
resp.setType(WSRespTypeEnum.BLACK.getType());
|
||||||
|
webSocketService.sendToAllOnline(resp, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,11 @@ package com.abin.mallchat.custom.user.controller;
|
|||||||
|
|
||||||
|
|
||||||
import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
|
import com.abin.mallchat.common.common.domain.vo.response.ApiResult;
|
||||||
|
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||||
import com.abin.mallchat.common.common.utils.RequestHolder;
|
import com.abin.mallchat.common.common.utils.RequestHolder;
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||||
|
import com.abin.mallchat.common.user.service.IRoleService;
|
||||||
|
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||||
@@ -30,6 +34,8 @@ import java.util.List;
|
|||||||
public class UserController {
|
public class UserController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
@Autowired
|
||||||
|
private IRoleService iRoleService;
|
||||||
|
|
||||||
@GetMapping("/userInfo")
|
@GetMapping("/userInfo")
|
||||||
@ApiOperation("用户详情")
|
@ApiOperation("用户详情")
|
||||||
@@ -56,5 +62,15 @@ public class UserController {
|
|||||||
userService.wearingBadge(RequestHolder.get().getUid(), req);
|
userService.wearingBadge(RequestHolder.get().getUid(), req);
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/black")
|
||||||
|
@ApiOperation("拉黑用户")
|
||||||
|
public ApiResult<Void> black(@Valid @RequestBody BlackReq req) {
|
||||||
|
Long uid = RequestHolder.get().getUid();
|
||||||
|
boolean hasPower = iRoleService.hasPower(uid, RoleEnum.ADMIN);
|
||||||
|
AssertUtil.isTrue(hasPower, "没有权限");
|
||||||
|
userService.black(req);
|
||||||
|
return ApiResult.success();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public enum WSRespTypeEnum {
|
|||||||
INVALIDATE_TOKEN(6, "使前端的token失效,意味着前端需要重新登录", null),
|
INVALIDATE_TOKEN(6, "使前端的token失效,意味着前端需要重新登录", null),
|
||||||
BLACK(7, "拉黑用户", WSBlack.class),
|
BLACK(7, "拉黑用户", WSBlack.class),
|
||||||
MARK(8, "消息标记", WSMsgMark.class),
|
MARK(8, "消息标记", WSMsgMark.class),
|
||||||
|
RECALL(9, "消息撤回", WSMsgRecall.class),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Integer type;
|
private final Integer type;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.abin.mallchat.custom.user.domain.vo.request.user;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 拉黑目标
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class BlackReq {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@ApiModelProperty("拉黑目标uid")
|
||||||
|
private Long uid;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,4 +19,6 @@ public class WSLoginSuccess {
|
|||||||
private String avatar;
|
private String avatar;
|
||||||
private String token;
|
private String token;
|
||||||
private String name;
|
private String name;
|
||||||
|
//用户权限 0普通用户 1超管
|
||||||
|
private Integer power;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.abin.mallchat.custom.user.domain.vo.response.ws;
|
||||||
|
|
||||||
|
import com.abin.mallchat.common.chat.domain.dto.ChatMsgRecallDTO;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description:消息撤回的推送类
|
||||||
|
* Author: <a href="https://github.com/zongzibinbin">abin</a>
|
||||||
|
* Date: 2023-03-19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class WSMsgRecall extends ChatMsgRecallDTO {
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.abin.mallchat.custom.user.service;
|
package com.abin.mallchat.custom.user.service;
|
||||||
|
|
||||||
|
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||||
@@ -54,4 +55,6 @@ public interface UserService {
|
|||||||
* @param openId
|
* @param openId
|
||||||
*/
|
*/
|
||||||
void register(String openId);
|
void register(String openId);
|
||||||
|
|
||||||
|
void black(BlackReq req);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.abin.mallchat.custom.user.service.adapter;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.abin.mallchat.common.chat.domain.dto.ChatMessageMarkDTO;
|
import com.abin.mallchat.common.chat.domain.dto.ChatMessageMarkDTO;
|
||||||
|
import com.abin.mallchat.common.chat.domain.dto.ChatMsgRecallDTO;
|
||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
import com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum;
|
import com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum;
|
||||||
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp;
|
||||||
@@ -34,7 +35,7 @@ public class WSAdapter {
|
|||||||
return wsBaseResp;
|
return wsBaseResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WSBaseResp<WSLoginSuccess> buildLoginSuccessResp(User user, String token) {
|
public static WSBaseResp<WSLoginSuccess> buildLoginSuccessResp(User user, String token, boolean hasPower) {
|
||||||
WSBaseResp<WSLoginSuccess> wsBaseResp = new WSBaseResp<>();
|
WSBaseResp<WSLoginSuccess> wsBaseResp = new WSBaseResp<>();
|
||||||
wsBaseResp.setType(WSRespTypeEnum.LOGIN_SUCCESS.getType());
|
wsBaseResp.setType(WSRespTypeEnum.LOGIN_SUCCESS.getType());
|
||||||
WSLoginSuccess wsLoginSuccess = WSLoginSuccess.builder()
|
WSLoginSuccess wsLoginSuccess = WSLoginSuccess.builder()
|
||||||
@@ -42,6 +43,7 @@ public class WSAdapter {
|
|||||||
.name(user.getName())
|
.name(user.getName())
|
||||||
.token(token)
|
.token(token)
|
||||||
.uid(user.getId())
|
.uid(user.getId())
|
||||||
|
.power(hasPower ? 1 : 0)
|
||||||
.build();
|
.build();
|
||||||
wsBaseResp.setData(wsLoginSuccess);
|
wsBaseResp.setData(wsLoginSuccess);
|
||||||
return wsBaseResp;
|
return wsBaseResp;
|
||||||
@@ -53,6 +55,15 @@ public class WSAdapter {
|
|||||||
return wsBaseResp;
|
return wsBaseResp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static WSBaseResp<?> buildMsgRecall(ChatMsgRecallDTO recallDTO) {
|
||||||
|
WSBaseResp<WSMsgRecall> wsBaseResp = new WSBaseResp<>();
|
||||||
|
wsBaseResp.setType(WSRespTypeEnum.RECALL.getType());
|
||||||
|
WSMsgRecall recall = new WSMsgRecall();
|
||||||
|
BeanUtils.copyProperties(recallDTO, recall);
|
||||||
|
wsBaseResp.setData(recall);
|
||||||
|
return wsBaseResp;
|
||||||
|
}
|
||||||
|
|
||||||
public WSBaseResp<WSOnlineOfflineNotify> buildOnlineNotifyResp(User user) {
|
public WSBaseResp<WSOnlineOfflineNotify> buildOnlineNotifyResp(User user) {
|
||||||
WSBaseResp<WSOnlineOfflineNotify> wsBaseResp = new WSBaseResp<>();
|
WSBaseResp<WSOnlineOfflineNotify> wsBaseResp = new WSBaseResp<>();
|
||||||
wsBaseResp.setType(WSRespTypeEnum.ONLINE_OFFLINE_NOTIFY.getType());
|
wsBaseResp.setType(WSRespTypeEnum.ONLINE_OFFLINE_NOTIFY.getType());
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
package com.abin.mallchat.custom.user.service.impl;
|
package com.abin.mallchat.custom.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.abin.mallchat.common.common.event.UserBlackEvent;
|
||||||
import com.abin.mallchat.common.common.event.UserRegisterEvent;
|
import com.abin.mallchat.common.common.event.UserRegisterEvent;
|
||||||
import com.abin.mallchat.common.common.utils.AssertUtil;
|
import com.abin.mallchat.common.common.utils.AssertUtil;
|
||||||
|
import com.abin.mallchat.common.user.dao.BlackDao;
|
||||||
import com.abin.mallchat.common.user.dao.ItemConfigDao;
|
import com.abin.mallchat.common.user.dao.ItemConfigDao;
|
||||||
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
import com.abin.mallchat.common.user.dao.UserBackpackDao;
|
||||||
import com.abin.mallchat.common.user.dao.UserDao;
|
import com.abin.mallchat.common.user.dao.UserDao;
|
||||||
|
import com.abin.mallchat.common.user.domain.entity.Black;
|
||||||
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
import com.abin.mallchat.common.user.domain.entity.ItemConfig;
|
||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
import com.abin.mallchat.common.user.domain.entity.UserBackpack;
|
import com.abin.mallchat.common.user.domain.entity.UserBackpack;
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.BlackTypeEnum;
|
||||||
import com.abin.mallchat.common.user.domain.enums.ItemEnum;
|
import com.abin.mallchat.common.user.domain.enums.ItemEnum;
|
||||||
import com.abin.mallchat.common.user.domain.enums.ItemTypeEnum;
|
import com.abin.mallchat.common.user.domain.enums.ItemTypeEnum;
|
||||||
import com.abin.mallchat.common.user.service.IUserBackpackService;
|
|
||||||
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
import com.abin.mallchat.common.user.service.cache.ItemCache;
|
||||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
|
import com.abin.mallchat.custom.user.domain.vo.request.user.BlackReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.ModifyNameReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
import com.abin.mallchat.custom.user.domain.vo.request.user.WearingBadgeReq;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp;
|
||||||
@@ -46,11 +51,11 @@ public class UserServiceImpl implements UserService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ItemConfigDao itemConfigDao;
|
private ItemConfigDao itemConfigDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IUserBackpackService iUserBackpackService;
|
|
||||||
@Autowired
|
|
||||||
private ApplicationEventPublisher applicationEventPublisher;
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemCache itemCache;
|
private ItemCache itemCache;
|
||||||
|
@Autowired
|
||||||
|
private BlackDao blackDao;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserInfoResp getUserInfo(Long uid) {
|
public UserInfoResp getUserInfo(Long uid) {
|
||||||
@@ -109,4 +114,31 @@ public class UserServiceImpl implements UserService {
|
|||||||
userDao.save(insert);
|
userDao.save(insert);
|
||||||
applicationEventPublisher.publishEvent(new UserRegisterEvent(this, insert));
|
applicationEventPublisher.publishEvent(new UserRegisterEvent(this, insert));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void black(BlackReq req) {
|
||||||
|
Long uid = req.getUid();
|
||||||
|
Black user = new Black();
|
||||||
|
user.setTarget(uid.toString());
|
||||||
|
user.setType(BlackTypeEnum.UID.getType());
|
||||||
|
blackDao.save(user);
|
||||||
|
User byId = userDao.getById(uid);
|
||||||
|
blackIp(byId.getIpInfo().getCreateIp());
|
||||||
|
blackIp(byId.getIpInfo().getUpdateIp());
|
||||||
|
applicationEventPublisher.publishEvent(new UserBlackEvent(this, byId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void blackIp(String ip) {
|
||||||
|
if (StrUtil.isBlank(ip)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Black user = new Black();
|
||||||
|
user.setTarget(ip);
|
||||||
|
user.setType(BlackTypeEnum.IP.getType());
|
||||||
|
blackDao.save(user);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("duplicate black ip:{}", ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import com.abin.mallchat.common.common.event.UserOfflineEvent;
|
|||||||
import com.abin.mallchat.common.common.event.UserOnlineEvent;
|
import com.abin.mallchat.common.common.event.UserOnlineEvent;
|
||||||
import com.abin.mallchat.common.user.dao.UserDao;
|
import com.abin.mallchat.common.user.dao.UserDao;
|
||||||
import com.abin.mallchat.common.user.domain.entity.User;
|
import com.abin.mallchat.common.user.domain.entity.User;
|
||||||
|
import com.abin.mallchat.common.user.domain.enums.RoleEnum;
|
||||||
|
import com.abin.mallchat.common.user.service.IRoleService;
|
||||||
import com.abin.mallchat.common.user.service.cache.UserCache;
|
import com.abin.mallchat.common.user.service.cache.UserCache;
|
||||||
import com.abin.mallchat.custom.user.domain.dto.ws.WSChannelExtraDTO;
|
import com.abin.mallchat.custom.user.domain.dto.ws.WSChannelExtraDTO;
|
||||||
import com.abin.mallchat.custom.user.domain.vo.request.ws.WSAuthorize;
|
import com.abin.mallchat.custom.user.domain.vo.request.ws.WSAuthorize;
|
||||||
@@ -77,6 +79,8 @@ public class WebSocketServiceImpl implements WebSocketService {
|
|||||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserCache userCache;
|
private UserCache userCache;
|
||||||
|
@Autowired
|
||||||
|
private IRoleService iRoleService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理用户登录请求,需要返回一张带code的二维码
|
* 处理用户登录请求,需要返回一张带code的二维码
|
||||||
@@ -152,7 +156,8 @@ public class WebSocketServiceImpl implements WebSocketService {
|
|||||||
//更新上线列表
|
//更新上线列表
|
||||||
online(channel, user.getId());
|
online(channel, user.getId());
|
||||||
//返回给用户登录成功
|
//返回给用户登录成功
|
||||||
sendMsg(channel, WSAdapter.buildLoginSuccessResp(user, token));
|
boolean hasPower = iRoleService.hasPower(user.getId(), RoleEnum.CHAT_MANAGER);
|
||||||
|
sendMsg(channel, WSAdapter.buildLoginSuccessResp(user, token, hasPower));
|
||||||
//发送用户上线事件
|
//发送用户上线事件
|
||||||
boolean online = userCache.isOnline(user.getId());
|
boolean online = userCache.isOnline(user.getId());
|
||||||
if (!online) {
|
if (!online) {
|
||||||
|
|||||||
Reference in New Issue
Block a user