diff --git a/docs/mallchat.sql b/docs/mallchat.sql index d747885..9c7ffba 100644 --- a/docs/mallchat.sql +++ b/docs/mallchat.sql @@ -34,11 +34,11 @@ CREATE TABLE `message` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'id', `room_id` bigint(20) NOT NULL COMMENT '会话表id', `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 '回复的消息内容', `status` int(11) NOT NULL COMMENT '消息状态 0正常 1删除', `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 '扩展信息', `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 '修改时间', @@ -155,4 +155,30 @@ CREATE TABLE `black` ( PRIMARY KEY (`id`) 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; -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='用户角色关系表'; \ No newline at end of file diff --git a/docs/version/2023-06-04.sql b/docs/version/2023-06-04.sql new file mode 100644 index 0000000..4fab24f --- /dev/null +++ b/docs/version/2023-06-04.sql @@ -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 '消息内容'; \ No newline at end of file diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/MessageDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/MessageDao.java index 65949fb..09e8bdb 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/MessageDao.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/MessageDao.java @@ -49,10 +49,10 @@ public class MessageDao extends ServiceImpl { .count(); } - public void updateGapCount(Long id, Integer gapCount) { + public void invalidByUid(Long uid) { lambdaUpdate() - .eq(Message::getId, id) - .set(Message::getGapCount, gapCount) + .eq(Message::getFromUid, uid) + .set(Message::getStatus, MessageStatusEnum.DELETE.getStatus()) .update(); } } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/ChatMsgRecallDTO.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/ChatMsgRecallDTO.java new file mode 100644 index 0000000..70158f6 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/ChatMsgRecallDTO.java @@ -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: abin + * Date: 2023-03-19 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMsgRecallDTO { + private Long msgId; + private Long roomId; + //撤回的用户 + private Long recallUid; +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Message.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Message.java index c0a4b65..1fceab2 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Message.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Message.java @@ -1,5 +1,6 @@ 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.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -73,7 +74,7 @@ public class Message implements Serializable { private Integer gapCount; /** - * 消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5) + * 消息类型 1正常文本 2.撤回消息 * * @see com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum */ @@ -81,7 +82,7 @@ public class Message implements Serializable { private Integer type; /** - * 最后上下线时间 + * 消息扩展字段 */ @TableField(value = "extra", typeHandler = JacksonTypeHandler.class) private MessageExtra extra; diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/MessageExtra.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java similarity index 67% rename from mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/MessageExtra.java rename to mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java index 33ed8bc..94dfcfc 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/MessageExtra.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MessageExtra.java @@ -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.Builder; import lombok.Data; @@ -17,8 +18,11 @@ import java.util.Map; @Builder @AllArgsConstructor @NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) public class MessageExtra implements Serializable { private static final long serialVersionUID = 1L; - //注册时的ip + //url跳转链接 private Map urlTitleMap; + //消息撤回详情 + private MsgRecall recall; } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MsgRecall.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MsgRecall.java new file mode 100644 index 0000000..66c025e --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/msg/MsgRecall.java @@ -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: abin + * 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; +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageMarkTypeEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageMarkTypeEnum.java index b8010dd..71072ae 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageMarkTypeEnum.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageMarkTypeEnum.java @@ -16,14 +16,13 @@ import java.util.stream.Collectors; @AllArgsConstructor @Getter public enum MessageMarkTypeEnum { - LIKE(1, "点赞", 10, MessageTypeEnum.LIKE), - DISLIKE(2, "点踩", 5, MessageTypeEnum.DISLIKE), + LIKE(1, "点赞", 10), + DISLIKE(2, "点踩", 5), ; private final Integer type; private final String desc; private final Integer riseNum;//需要多少个标记升级 - private final MessageTypeEnum riseEnum;//消息升级成什么类型的消息 private static Map cache; diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java index 0470531..db08546 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/MessageTypeEnum.java @@ -16,9 +16,8 @@ import java.util.stream.Collectors; @AllArgsConstructor @Getter public enum MessageTypeEnum { - NORMAL(1, "正常"), - LIKE(2, "爆赞"), - DISLIKE(3, "危险发言"), + TEXT(1, "正常"), + RECALL(2, "撤回消息"), ; private final Integer type; diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/MsgCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/MsgCache.java new file mode 100644 index 0000000..4ca0a9e --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/MsgCache.java @@ -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: abin + * 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; + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/CursorPageBaseReq.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/CursorPageBaseReq.java index d0a4381..d0d5e19 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/CursorPageBaseReq.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/request/CursorPageBaseReq.java @@ -22,7 +22,7 @@ import javax.validation.constraints.Max; public class CursorPageBaseReq { @ApiModelProperty("页面大小") - @Max(50) + @Max(100) private Integer pageSize = 10; @ApiModelProperty("游标(初始为null,后续请求附带上次翻页的游标)") diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/MessageRecallEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/MessageRecallEvent.java new file mode 100644 index 0000000..c32f397 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/MessageRecallEvent.java @@ -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; + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserBlackEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserBlackEvent.java new file mode 100644 index 0000000..7b03631 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserBlackEvent.java @@ -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; + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOfflineEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOfflineEvent.java index affe673..e1e0036 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOfflineEvent.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOfflineEvent.java @@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent; @Getter public class UserOfflineEvent extends ApplicationEvent { - private User user; + private final User user; public UserOfflineEvent(Object source, User user) { super(source); diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOnlineEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOnlineEvent.java index 9948c42..84cfa50 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOnlineEvent.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserOnlineEvent.java @@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent; @Getter public class UserOnlineEvent extends ApplicationEvent { - private User user; + private final User user; public UserOnlineEvent(Object source, User user) { super(source); diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserRegisterEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserRegisterEvent.java index 4f82b3b..01ef651 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserRegisterEvent.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserRegisterEvent.java @@ -6,7 +6,7 @@ import org.springframework.context.ApplicationEvent; @Getter public class UserRegisterEvent extends ApplicationEvent { - private User user; + private final User user; public UserRegisterEvent(Object source, User user) { super(source); diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/AssertUtil.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/AssertUtil.java index 4c28bcb..77e5102 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/AssertUtil.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/AssertUtil.java @@ -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) { return ObjectUtil.isEmpty(obj); } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/RoleDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/RoleDao.java new file mode 100644 index 0000000..62b2e4a --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/RoleDao.java @@ -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; + +/** + *

+ * 角色表 服务实现类 + *

+ * + * @author abin + * @since 2023-06-04 + */ +@Service +public class RoleDao extends ServiceImpl { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserRoleDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserRoleDao.java new file mode 100644 index 0000000..6670cb8 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserRoleDao.java @@ -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; + +/** + *

+ * 用户角色关系表 服务实现类 + *

+ * + * @author abin + * @since 2023-06-04 + */ +@Service +public class UserRoleDao extends ServiceImpl { + public List listByUid(Long uid) { + return lambdaQuery() + .eq(UserRole::getUid, Objects.requireNonNull(uid)) + .list(); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/Role.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/Role.java new file mode 100644 index 0000000..4fac5a1 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/Role.java @@ -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; + +/** + *

+ * 角色表 + *

+ * + * @author abin + * @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; + + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserRole.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserRole.java new file mode 100644 index 0000000..9d8340a --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/entity/UserRole.java @@ -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; + +/** + *

+ * 用户角色关系表 + *

+ * + * @author abin + * @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; + + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/enums/RoleEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/enums/RoleEnum.java new file mode 100644 index 0000000..d233508 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/domain/enums/RoleEnum.java @@ -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: abin + * 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 cache; + + static { + cache = Arrays.stream(RoleEnum.values()).collect(Collectors.toMap(RoleEnum::getId, Function.identity())); + } + + public static RoleEnum of(Integer type) { + return cache.get(type); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/RoleMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/RoleMapper.java new file mode 100644 index 0000000..40dda37 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/RoleMapper.java @@ -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; + +/** + *

+ * 角色表 Mapper 接口 + *

+ * + * @author abin + * @since 2023-06-04 + */ +public interface RoleMapper extends BaseMapper { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserRoleMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserRoleMapper.java new file mode 100644 index 0000000..9af4320 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/UserRoleMapper.java @@ -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; + +/** + *

+ * 用户角色关系表 Mapper 接口 + *

+ * + * @author abin + * @since 2023-06-04 + */ +public interface UserRoleMapper extends BaseMapper { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IRoleService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IRoleService.java new file mode 100644 index 0000000..b91b6ad --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IRoleService.java @@ -0,0 +1,22 @@ +package com.abin.mallchat.common.user.service; + +import com.abin.mallchat.common.user.domain.enums.RoleEnum; + +/** + *

+ * 角色表 服务类 + *

+ * + * @author abin + * @since 2023-06-04 + */ +public interface IRoleService { + + /** + * 是否有某个权限,临时做法 + * + * @return + */ + boolean hasPower(Long uid, RoleEnum roleEnum); + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IUserRoleService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IUserRoleService.java new file mode 100644 index 0000000..aac1201 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/IUserRoleService.java @@ -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; + +/** + *

+ * 用户角色关系表 服务类 + *

+ * + * @author abin + * @since 2023-06-04 + */ +public interface IUserRoleService extends IService { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserCache.java index ee759e0..7bee2ac 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserCache.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/cache/UserCache.java @@ -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.RedisUtils; 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.UserRoleDao; 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.UserRole; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -34,6 +37,10 @@ public class UserCache { private UserDao userDao; @Autowired private BlackDao blackDao; + @Autowired + private RoleDao roleDao; + @Autowired + private UserRoleDao userRoleDao; public Long getOnlineNum() { String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET); @@ -45,6 +52,16 @@ public class UserCache { 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) { String onlineKey = RedisKey.getKey(RedisKey.ONLINE_UID_ZET); @@ -80,9 +97,6 @@ public class UserCache { /** * 获取用户信息,盘路缓存模式 - * - * @param uid - * @return */ public User getUserInfo(Long uid) {//todo 后期做二级缓存 return getUserInfoBatch(Collections.singleton(uid)).get(uid); @@ -90,9 +104,6 @@ public class UserCache { /** * 获取用户信息,盘路缓存模式 - * - * @param uids - * @return */ public Map getUserInfoBatch(Set uids) { List keys = uids.stream().map(a -> RedisKey.getKey(RedisKey.USER_INFO_STRING, a)).collect(Collectors.toList()); @@ -128,4 +139,12 @@ public class UserCache { public Map> evictBlackMap() { return null; } + + @Cacheable(cacheNames = "user", key = "'roles'+#uid") + public Set getRoleSet(Long uid) { + List userRoles = userRoleDao.listByUid(uid); + return userRoles.stream() + .map(UserRole::getRoleId) + .collect(Collectors.toSet()); + } } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/RoleServiceImpl.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..b1b9181 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/RoleServiceImpl.java @@ -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: abin + * Date: 2023-06-04 + */ +@Service +public class RoleServiceImpl implements IRoleService { + @Autowired + private UserCache userCache; + + @Override + public boolean hasPower(Long uid, RoleEnum roleEnum) {//超级管理员无敌的好吧,后期做成权限=》资源模式 + Set roleSet = userCache.getRoleSet(uid); + return isAdmin(roleSet) || roleSet.contains(roleEnum.getId()); + } + + private boolean isAdmin(Set roleSet) { + return Objects.requireNonNull(roleSet).contains(RoleEnum.ADMIN.getId()); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/UserBackpackServiceImpl.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/UserBackpackServiceImpl.java index ae05046..45a4f4e 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/UserBackpackServiceImpl.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/service/impl/UserBackpackServiceImpl.java @@ -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.YesOrNoEnum; 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.domain.entity.ItemConfig; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import java.util.Objects; @@ -30,12 +30,11 @@ public class UserBackpackServiceImpl implements IUserBackpackService { @Autowired private UserBackpackDao userBackpackDao; @Autowired - private ItemConfigDao itemConfigDao; - @Autowired private ItemCache itemCache; @Autowired private ApplicationEventPublisher applicationEventPublisher; @Autowired + @Lazy private UserBackpackServiceImpl userBackpackService; @Override diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/xml/BlackMapper.xml b/mallchat-common/src/main/resources/mapper/user/BlackMapper.xml similarity index 100% rename from mallchat-common/src/main/java/com/abin/mallchat/common/user/mapper/xml/BlackMapper.xml rename to mallchat-common/src/main/resources/mapper/user/BlackMapper.xml diff --git a/mallchat-common/src/main/resources/mapper/user/RoleMapper.xml b/mallchat-common/src/main/resources/mapper/user/RoleMapper.xml new file mode 100644 index 0000000..e898802 --- /dev/null +++ b/mallchat-common/src/main/resources/mapper/user/RoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mallchat-common/src/main/resources/mapper/user/UserRoleMapper.xml b/mallchat-common/src/main/resources/mapper/user/UserRoleMapper.xml new file mode 100644 index 0000000..bbb0bc7 --- /dev/null +++ b/mallchat-common/src/main/resources/mapper/user/UserRoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java index 1bcb118..b667b07 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ChatController.java @@ -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.user.domain.enums.BlackTypeEnum; 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.ChatMessagePageReq; 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.ChatMemberStatisticResp; 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 java.util.HashSet; +import java.util.Objects; import java.util.Set; /** @@ -89,6 +92,10 @@ public class ChatController { @FrequencyControl(time = 30, count = 5, target = FrequencyControl.Target.UID) @FrequencyControl(time = 60, count = 10, target = FrequencyControl.Target.UID) public ApiResult 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()); //返回完整消息格式,方便前端展示 return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid())); @@ -100,7 +107,14 @@ public class ChatController { public ApiResult setMsgMark(@Valid @RequestBody ChatMessageMarkReq request) { chatService.setMsgMark(RequestHolder.get().getUid(), request); return ApiResult.success(); + } + @PutMapping("/msg/recall") + @ApiOperation("撤回消息") + @FrequencyControl(time = 20, count = 3, target = FrequencyControl.Target.UID) + public ApiResult recallMsg(@Valid @RequestBody ChatMessageBaseReq request) { + chatService.recallMsg(RequestHolder.get().getUid(), request); + return ApiResult.success(); } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageBaseReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageBaseReq.java new file mode 100644 index 0000000..2a08032 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageBaseReq.java @@ -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: abin + * Date: 2023-03-23 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageBaseReq { + @NotNull + @ApiModelProperty("消息id") + private Long msgId; + + @NotNull + @ApiModelProperty("会话id") + private Long roomId; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java index 0d3b589..eb2041b 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReq.java @@ -1,11 +1,11 @@ package com.abin.mallchat.custom.chat.domain.vo.request; +import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotNull; @@ -20,16 +20,21 @@ import javax.validation.constraints.NotNull; @AllArgsConstructor @NoArgsConstructor public class ChatMessageReq { - - @NotNull - @Length(max = 10000, message = "消息内容过长,服务器扛不住啊,兄dei") - @ApiModelProperty("消息内容") - private String content; - @NotNull @ApiModelProperty("会话id") 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,如果没有别传就好") + @Deprecated private Long replyMsgId; } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/msg/TextMsgReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/msg/TextMsgReq.java new file mode 100644 index 0000000..841c75b --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/msg/TextMsgReq.java @@ -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: abin + * Date: 2023-06-04 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TextMsgReq { + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("回复的消息id,如果没有别传就好") + private Long replyMsgId; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java index 76f67a3..968aae9 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageResp.java @@ -45,12 +45,16 @@ public class ChatMessageResp { private Long id; @ApiModelProperty("消息发送时间") private Date sendTime; - @ApiModelProperty("消息内容") + @ApiModelProperty("消息内容-废弃") + @Deprecated private String content; - @ApiModelProperty("消息链接映射") + @ApiModelProperty("消息链接映射-废弃") + @Deprecated private Map urlTitleMap; - @ApiModelProperty("消息类型 1正常文本 2.爆赞 (点赞超过10)3.危险发言(举报超5)") + @ApiModelProperty("消息类型 1正常文本 2.撤回消息") private Integer type; + @ApiModelProperty("消息内容不同的消息类型,内容体不同,见https://www.yuque.com/snab/mallcaht/rkb2uz5k1qqdmcmd") + private Object body; @ApiModelProperty("消息标记") private MessageMark messageMark; @ApiModelProperty("父消息,如果没有父消息,返回的是null") @@ -59,6 +63,7 @@ public class ChatMessageResp { } @Data + @Deprecated public static class ReplyMsg { @ApiModelProperty("消息id") private Long id; diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java new file mode 100644 index 0000000..5b7d18b --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/msg/TextMsgResp.java @@ -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: abin + * Date: 2023-06-04 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TextMsgResp { + @ApiModelProperty("消息内容") + private String content; + @ApiModelProperty("消息链接映射") + private Map 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; + } +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/ChatService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/ChatService.java index 19e2cf2..bbf4778 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/ChatService.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/ChatService.java @@ -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.common.domain.vo.request.CursorPageBaseReq; 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.ChatMessagePageReq; import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageReq; @@ -73,4 +74,6 @@ public interface ChatService { ChatMemberStatisticResp getMemberStatistic(); void setMsgMark(Long uid, ChatMessageMarkReq request); + + void recallMsg(Long uid, ChatMessageBaseReq request); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java index 25df8c6..aa4f4a4 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/MessageAdapter.java @@ -2,8 +2,8 @@ package com.abin.mallchat.custom.chat.service.adapter; import cn.hutool.core.bean.BeanUtil; 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.msg.MessageExtra; import com.abin.mallchat.common.chat.domain.enums.MessageMarkTypeEnum; import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum; 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.custom.chat.domain.vo.request.ChatMessageReq; 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.stream.Collectors; @@ -24,14 +26,12 @@ import java.util.stream.Collectors; * Date: 2023-03-26 */ 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(); public static Message buildMsgSave(ChatMessageReq request, Long uid) { return Message.builder() - .replyMsgId(request.getReplyMsgId()) - .content(request.getContent()) .fromUid(uid) .roomId(request.getRoomId()) .status(MessageStatusEnum.NORMAL.getStatus()) @@ -61,8 +61,11 @@ public class MessageAdapter { ChatMessageResp.Message messageVO = new ChatMessageResp.Message(); BeanUtil.copyProperties(message, messageVO); 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)); Message replyMessage = replyMap.get(message.getReplyMsgId()); + //回复消息 if (Objects.nonNull(replyMessage)) { ChatMessageResp.ReplyMsg replyMsgVO = new ChatMessageResp.ReplyMsg(); diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java index 191fcba..355fca8 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/ChatServiceImpl.java @@ -2,6 +2,8 @@ package com.abin.mallchat.custom.chat.service.impl; import cn.hutool.core.collection.CollUtil; 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 com.abin.mallchat.common.chat.dao.MessageDao; 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.Room; 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.domain.enums.YesOrNoEnum; 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.event.MessageSendEvent; -import com.abin.mallchat.common.common.exception.BusinessException; import com.abin.mallchat.common.common.utils.AssertUtil; 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.User; 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.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.ChatMessagePageReq; 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.strategy.mark.AbstractMsgMarkStrategy; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; @@ -73,6 +80,10 @@ public class ChatServiceImpl implements ChatService { private MessageMarkDao messageMarkDao; @Autowired private ItemCache itemCache; + @Autowired + private IRoleService iRoleService; + @Autowired + private RecallMsgHandler recallMsgHandler; /** * 发送消息 @@ -80,22 +91,12 @@ public class ChatServiceImpl implements ChatService { @Override @Transactional public Long sendMsg(ChatMessageReq request, Long uid) { - //校验下回复消息 - Message replyMsg = null; - if (Objects.nonNull(request.getReplyMsgId())) { - replyMsg = messageDao.getById(request.getReplyMsgId()); - AssertUtil.isNotEmpty(replyMsg, "回复消息不存在"); - AssertUtil.equal(replyMsg.getRoomId(), request.getRoomId(), "只能回复相同会话内的消息"); - - } + AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());//todo 这里先不扩展,后续再改 + msgHandler.checkMsg(request); //同步获取消息的跳转链接标题 Message insert = MessageAdapter.buildMsgSave(request, uid); messageDao.save(insert); - //如果有回复消息 - if (Objects.nonNull(replyMsg)) { - Integer gapCount = messageDao.getGapCount(request.getRoomId(), replyMsg.getId(), insert.getId()); - messageDao.updateGapCount(insert.getId(), gapCount); - } + msgHandler.saveMsg(insert, request); //发布消息发送事件 applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId())); return insert.getId(); @@ -186,13 +187,26 @@ public class ChatServiceImpl implements ChatService { } } - private Integer transformAct(Integer actType) { - if (actType == 1) { - return YesOrNoEnum.NO.getStatus(); - } else if (actType == 2) { - return YesOrNoEnum.YES.getStatus(); + @Override + public void recallMsg(Long uid, ChatMessageBaseReq request) { + Message message = messageDao.getById(request.getMsgId()); + //校验能不能执行撤回 + 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 getMsgRespBatch(List messages, Long receiveUid) { diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/DisLikeStrategy.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/DisLikeStrategy.java index 5b13d99..299881f 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/DisLikeStrategy.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/DisLikeStrategy.java @@ -23,7 +23,7 @@ public class DisLikeStrategy extends AbstractMsgMarkStrategy { @Override public void doMark(Long uid, Long msgId) { - super.mark(uid, msgId); + super.doMark(uid, msgId); //同时取消点赞的动作 MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.LIKE.getType()).unMark(uid, msgId); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/LikeStrategy.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/LikeStrategy.java index 90c4427..3b92528 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/LikeStrategy.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/mark/LikeStrategy.java @@ -18,7 +18,7 @@ public class LikeStrategy extends AbstractMsgMarkStrategy { @Override public void doMark(Long uid, Long msgId) { - super.mark(uid, msgId); + super.doMark(uid, msgId); //同时取消点踩的动作 MsgMarkFactory.getStrategyNoNull(MessageMarkTypeEnum.DISLIKE.getType()).unMark(uid, msgId); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/AbstractMsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/AbstractMsgHandler.java new file mode 100644 index 0000000..5c88033 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/AbstractMsgHandler.java @@ -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: abin + * 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); + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandler.java new file mode 100644 index 0000000..589589f --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandler.java @@ -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 { + + void saveMsg(Message msg, REQ req); + + RESP showMsg(Message msg); + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandlerFactory.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandlerFactory.java new file mode 100644 index 0000000..22563cf --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/MsgHandlerFactory.java @@ -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: abin + * Date: 2023-06-04 + */ +public class MsgHandlerFactory { + private static final Map 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; + } +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/RecallMsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/RecallMsgHandler.java new file mode 100644 index 0000000..3bba9e7 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/RecallMsgHandler.java @@ -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: abin + * 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))); + + } +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java new file mode 100644 index 0000000..08a8e84 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/strategy/msg/TextMsgHandler.java @@ -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: abin + * 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 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(); + } +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageMarkListener.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageMarkListener.java index afbab99..485dc61 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageMarkListener.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageMarkListener.java @@ -42,7 +42,7 @@ public class MessageMarkListener { public void changeMsgType(MessageMarkEvent event) { ChatMessageMarkDTO dto = event.getDto(); Message msg = messageDao.getById(dto.getMsgId()); - if (!Objects.equals(msg.getType(), MessageTypeEnum.NORMAL.getType())) {//普通消息才需要升级 + if (!Objects.equals(msg.getType(), MessageTypeEnum.TEXT.getType())) {//普通消息才需要升级 return; } //消息被标记次数 @@ -51,8 +51,7 @@ public class MessageMarkListener { if (markCount < markTypeEnum.getRiseNum()) { return; } - boolean updateSuccess = messageDao.riseOptimistic(msg.getId(), msg.getType(), markTypeEnum.getRiseEnum().getType()); - if (MessageMarkTypeEnum.LIKE.getType().equals(dto.getMarkType()) && updateSuccess) {//尝试给用户发送一张徽章 + if (MessageMarkTypeEnum.LIKE.getType().equals(dto.getMarkType())) {//尝试给用户发送一张徽章 iUserBackpackService.acquireItem(msg.getFromUid(), ItemEnum.LIKE_BADGE.getId(), IdempotentEnum.MSG_ID, msg.getId().toString()); } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageRecallListener.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageRecallListener.java new file mode 100644 index 0000000..02b9ea2 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/MessageRecallListener.java @@ -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())); + } + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/UserBlackListener.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/UserBlackListener.java new file mode 100644 index 0000000..8f7ba89 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/UserBlackListener.java @@ -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 resp = new WSBaseResp<>(); + WSBlack black = new WSBlack(uid); + resp.setData(black); + resp.setType(WSRespTypeEnum.BLACK.getType()); + webSocketService.sendToAllOnline(resp, uid); + } + + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserController.java index 2fbda4e..bd1c1a7 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserController.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/UserController.java @@ -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.utils.AssertUtil; 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.WearingBadgeReq; import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp; @@ -30,6 +34,8 @@ import java.util.List; public class UserController { @Autowired private UserService userService; + @Autowired + private IRoleService iRoleService; @GetMapping("/userInfo") @ApiOperation("用户详情") @@ -56,5 +62,15 @@ public class UserController { userService.wearingBadge(RequestHolder.get().getUid(), req); return ApiResult.success(); } + + @PutMapping("/black") + @ApiOperation("拉黑用户") + public ApiResult 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(); + } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/WSRespTypeEnum.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/WSRespTypeEnum.java index cd8649f..0ccfa2d 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/WSRespTypeEnum.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/enums/WSRespTypeEnum.java @@ -25,6 +25,7 @@ public enum WSRespTypeEnum { INVALIDATE_TOKEN(6, "使前端的token失效,意味着前端需要重新登录", null), BLACK(7, "拉黑用户", WSBlack.class), MARK(8, "消息标记", WSMsgMark.class), + RECALL(9, "消息撤回", WSMsgRecall.class), ; private final Integer type; diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/BlackReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/BlackReq.java new file mode 100644 index 0000000..99c88b0 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/request/user/BlackReq.java @@ -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: abin + * Date: 2023-03-23 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BlackReq { + + @NotNull + @ApiModelProperty("拉黑目标uid") + private Long uid; + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSLoginSuccess.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSLoginSuccess.java index 4d312f9..f27de78 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSLoginSuccess.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSLoginSuccess.java @@ -19,4 +19,6 @@ public class WSLoginSuccess { private String avatar; private String token; private String name; + //用户权限 0普通用户 1超管 + private Integer power; } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMsgRecall.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMsgRecall.java new file mode 100644 index 0000000..e11b83b --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMsgRecall.java @@ -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: abin + * Date: 2023-03-19 + */ +@Data +public class WSMsgRecall extends ChatMsgRecallDTO { +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserService.java index f70db05..a8a8e0e 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserService.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/UserService.java @@ -1,5 +1,6 @@ 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.WearingBadgeReq; import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp; @@ -54,4 +55,6 @@ public interface UserService { * @param openId */ void register(String openId); + + void black(BlackReq req); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/WSAdapter.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/WSAdapter.java index 49bddb0..2a51379 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/WSAdapter.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/WSAdapter.java @@ -2,6 +2,7 @@ package com.abin.mallchat.custom.user.service.adapter; import cn.hutool.core.bean.BeanUtil; 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.enums.ChatActiveStatusEnum; import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp; @@ -34,7 +35,7 @@ public class WSAdapter { return wsBaseResp; } - public static WSBaseResp buildLoginSuccessResp(User user, String token) { + public static WSBaseResp buildLoginSuccessResp(User user, String token, boolean hasPower) { WSBaseResp wsBaseResp = new WSBaseResp<>(); wsBaseResp.setType(WSRespTypeEnum.LOGIN_SUCCESS.getType()); WSLoginSuccess wsLoginSuccess = WSLoginSuccess.builder() @@ -42,6 +43,7 @@ public class WSAdapter { .name(user.getName()) .token(token) .uid(user.getId()) + .power(hasPower ? 1 : 0) .build(); wsBaseResp.setData(wsLoginSuccess); return wsBaseResp; @@ -53,6 +55,15 @@ public class WSAdapter { return wsBaseResp; } + public static WSBaseResp buildMsgRecall(ChatMsgRecallDTO recallDTO) { + WSBaseResp wsBaseResp = new WSBaseResp<>(); + wsBaseResp.setType(WSRespTypeEnum.RECALL.getType()); + WSMsgRecall recall = new WSMsgRecall(); + BeanUtils.copyProperties(recallDTO, recall); + wsBaseResp.setData(recall); + return wsBaseResp; + } + public WSBaseResp buildOnlineNotifyResp(User user) { WSBaseResp wsBaseResp = new WSBaseResp<>(); wsBaseResp.setType(WSRespTypeEnum.ONLINE_OFFLINE_NOTIFY.getType()); diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java index 03bdb37..2ddde78 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/UserServiceImpl.java @@ -1,18 +1,23 @@ 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.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.UserBackpackDao; 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.User; 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.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.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.WearingBadgeReq; import com.abin.mallchat.custom.user.domain.vo.response.user.BadgeResp; @@ -46,11 +51,11 @@ public class UserServiceImpl implements UserService { @Autowired private ItemConfigDao itemConfigDao; @Autowired - private IUserBackpackService iUserBackpackService; - @Autowired private ApplicationEventPublisher applicationEventPublisher; @Autowired private ItemCache itemCache; + @Autowired + private BlackDao blackDao; @Override public UserInfoResp getUserInfo(Long uid) { @@ -109,4 +114,31 @@ public class UserServiceImpl implements UserService { userDao.save(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); + } + } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java index dd43158..20d5aaf 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/WebSocketServiceImpl.java @@ -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.user.dao.UserDao; 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.custom.user.domain.dto.ws.WSChannelExtraDTO; import com.abin.mallchat.custom.user.domain.vo.request.ws.WSAuthorize; @@ -77,6 +79,8 @@ public class WebSocketServiceImpl implements WebSocketService { private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Autowired private UserCache userCache; + @Autowired + private IRoleService iRoleService; /** * 处理用户登录请求,需要返回一张带code的二维码 @@ -152,7 +156,8 @@ public class WebSocketServiceImpl implements WebSocketService { //更新上线列表 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()); if (!online) {