diff --git a/docs/version/2023-07-17.sql b/docs/version/2023-07-17.sql index c9c28f4..49dac82 100644 --- a/docs/version/2023-07-17.sql +++ b/docs/version/2023-07-17.sql @@ -28,7 +28,7 @@ CREATE TABLE `user_apply` ( `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, - UNIQUE KEY `uniq_target_id_uid` (`target_id`,`uid`) USING BTREE, + KEY `idx_target_id_uid_status` (`target_id`,`uid`,`status`) USING BTREE, KEY `idx_target_id` (`target_id`) USING BTREE, KEY `idx_create_time` (`create_time`) USING BTREE, KEY `idx_update_time` (`update_time`) USING BTREE @@ -38,10 +38,11 @@ CREATE TABLE `user_friend` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `uid` bigint(20) NOT NULL COMMENT 'uid', `friend_uid` bigint(20) NOT NULL COMMENT '好友uid', + `delete_status` int(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除(0-正常,1-删除)', `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, - UNIQUE KEY `uniq_uid_friend_uid` (`uid`,`friend_uid`) USING BTREE, + KEY `idx_uid_friend_uid` (`uid`,`friend_uid`) 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='用户联系人表'; @@ -50,7 +51,7 @@ CREATE TABLE `group_member` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `room_id` bigint(20) NOT NULL COMMENT '房间id', `uid` bigint(20) NOT NULL COMMENT '成员uid', - `type` int(11) NOT NULL COMMENT '成员类型 1群主 2管理员 3普通成员', + `role` int(11) NOT NULL COMMENT '成员角色 1群主 2管理员 3普通成员', `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, diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/ContactController.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/ContactController.java deleted file mode 100644 index d530605..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/ContactController.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.abin.mallchat.common.chat.controller; - - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - *

- * 会话列表 前端控制器 - *

- * - * @author abin - * @since 2023-07-16 - */ -@Controller -@RequestMapping("/contact") -public class ContactController { - -} - diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/GroupMemberController.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/GroupMemberController.java deleted file mode 100644 index ece7322..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/GroupMemberController.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.abin.mallchat.common.chat.controller; - - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - *

- * 群成员表 前端控制器 - *

- * - * @author abin - * @since 2023-07-16 - */ -@Controller -@RequestMapping("/groupMember") -public class GroupMemberController { - -} - diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/RoomController.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/RoomController.java deleted file mode 100644 index ef4f012..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/controller/RoomController.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.abin.mallchat.common.chat.controller; - - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - *

- * 房间表 前端控制器 - *

- * - * @author abin - * @since 2023-07-16 - */ -@Controller -@RequestMapping("/room") -public class RoomController { - -} - diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/ContactDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/ContactDao.java index efd2bf0..ca18abb 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/ContactDao.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/ContactDao.java @@ -1,8 +1,11 @@ package com.abin.mallchat.common.chat.dao; import com.abin.mallchat.common.chat.domain.entity.Contact; +import com.abin.mallchat.common.chat.domain.entity.Message; import com.abin.mallchat.common.chat.mapper.ContactMapper; -import com.abin.mallchat.common.chat.service.IContactService; +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.utils.CursorUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; @@ -15,6 +18,57 @@ import org.springframework.stereotype.Service; * @since 2023-07-16 */ @Service -public class ContactDao extends ServiceImpl implements IContactService { +public class ContactDao extends ServiceImpl { + public Contact get(Long uid, Long roomId) { + return lambdaQuery() + .eq(Contact::getUid, uid) + .eq(Contact::getRoomId, roomId) + .one(); + } + + public Integer getReadCount(Message message) { + return lambdaQuery() + .eq(Contact::getRoomId, message.getRoomId()) + .ge(Contact::getReadTime, message.getCreateTime()) + .count(); + } + + public Integer getTotalCount(Long roomId) { + return lambdaQuery() + .eq(Contact::getRoomId, roomId) + .count(); + } + + public Integer getUnReadCount(Message message) { + return lambdaQuery() + .eq(Contact::getRoomId, message.getRoomId()) + .lt(Contact::getReadTime, message.getCreateTime()) + .count(); + } + + public CursorPageBaseResp getReadPage(Message message, CursorPageBaseReq cursorPageBaseReq) { + return CursorUtils.getCursorPageByMysql(this, cursorPageBaseReq, wrapper -> { + wrapper.eq(Contact::getRoomId, message.getRoomId()); + wrapper.ne(Contact::getUid, message.getFromUid());//不需要查询出自己 + wrapper.ge(Contact::getReadTime, message.getCreateTime());//已读时间大于等于消息发送时间 + }, Contact::getReadTime); + } + + public CursorPageBaseResp getUnReadPage(Message message, CursorPageBaseReq cursorPageBaseReq) { + return CursorUtils.getCursorPageByMysql(this, cursorPageBaseReq, wrapper -> { + wrapper.eq(Contact::getRoomId, message.getRoomId()); + wrapper.ne(Contact::getUid, message.getFromUid());//不需要查询出自己 + wrapper.lt(Contact::getReadTime, message.getCreateTime());//已读时间小于消息发送时间 + }, Contact::getReadTime); + } + + /** + * 获取用户会话列表 + */ + public CursorPageBaseResp getContactPage(Long uid, CursorPageBaseReq request) { + return CursorUtils.getCursorPageByMysql(this, request, wrapper -> { + wrapper.eq(Contact::getUid, uid); + }, Contact::getActiveTime); + } } 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 09e8bdb..6ba262c 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 @@ -7,7 +7,6 @@ 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.utils.CursorUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** @@ -20,11 +19,9 @@ import org.springframework.stereotype.Service; */ @Service public class MessageDao extends ServiceImpl { - @Autowired - private CursorUtils cursorUtils; public CursorPageBaseResp getCursorPage(Long roomId, CursorPageBaseReq request) { - return cursorUtils.getCursorPageByMysql(this, request, wrapper -> { + return CursorUtils.getCursorPageByMysql(this, request, wrapper -> { wrapper.eq(Message::getRoomId, roomId); wrapper.eq(Message::getStatus, MessageStatusEnum.NORMAL.getStatus()); }, Message::getId); diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomDao.java index c43b483..ef28254 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomDao.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomDao.java @@ -2,7 +2,7 @@ package com.abin.mallchat.common.chat.dao; import com.abin.mallchat.common.chat.domain.entity.Room; import com.abin.mallchat.common.chat.mapper.RoomMapper; -import com.abin.mallchat.common.chat.service.IRoomService; +import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; @@ -15,6 +15,6 @@ import org.springframework.stereotype.Service; * @since 2023-07-16 */ @Service -public class RoomDao extends ServiceImpl implements IRoomService { +public class RoomDao extends ServiceImpl implements IService { } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomFriendDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomFriendDao.java new file mode 100644 index 0000000..540ba16 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomFriendDao.java @@ -0,0 +1,38 @@ +package com.abin.mallchat.common.chat.dao; + +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.abin.mallchat.common.chat.mapper.RoomFriendMapper; +import com.abin.mallchat.common.common.domain.enums.NormalOrNoEnum; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 单聊房间表 服务实现类 + *

+ * + * @author abin + * @since 2023-07-22 + */ +@Service +public class RoomFriendDao extends ServiceImpl { + + public RoomFriend getByKey(String key) { + return lambdaQuery().eq(RoomFriend::getKey, key).one(); + } + + public void restoreRoom(Long id) { + lambdaUpdate() + .eq(RoomFriend::getId, id) + .set(RoomFriend::getStatus, NormalOrNoEnum.NORMAL.getStatus()) + .update(); + } + + public List listByRoomIds(List roomIds) { + return lambdaQuery() + .eq(RoomFriend::getRoomId, roomIds) + .list(); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomGroupDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomGroupDao.java new file mode 100644 index 0000000..52e38f4 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/dao/RoomGroupDao.java @@ -0,0 +1,26 @@ +package com.abin.mallchat.common.chat.dao; + +import com.abin.mallchat.common.chat.domain.entity.RoomGroup; +import com.abin.mallchat.common.chat.mapper.RoomGroupMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 群聊房间表 服务实现类 + *

+ * + * @author abin + * @since 2023-07-22 + */ +@Service +public class RoomGroupDao extends ServiceImpl { + + public List listByRoomIds(List roomIds) { + return lambdaQuery() + .in(RoomGroup::getRoomId, roomIds) + .list(); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/MsgReadInfoDTO.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/MsgReadInfoDTO.java new file mode 100644 index 0000000..1bac181 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/MsgReadInfoDTO.java @@ -0,0 +1,28 @@ +package com.abin.mallchat.common.chat.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Description: + * Author: abin + * Date: 2023-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MsgReadInfoDTO { + @ApiModelProperty("消息id") + private Long msgId; + + @ApiModelProperty("已读数") + private Integer readCount; + + @ApiModelProperty("未读数") + private Integer unReadCount; + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/RoomBaseInfo.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/RoomBaseInfo.java new file mode 100644 index 0000000..b491f05 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/dto/RoomBaseInfo.java @@ -0,0 +1,19 @@ +package com.abin.mallchat.common.chat.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * Description: 房间详情 + * Author: abin + * Date: 2023-07-22 + */ +@Data +public class RoomBaseInfo { + @ApiModelProperty("房间id") + private Long roomId; + @ApiModelProperty("会话名称") + private String name; + @ApiModelProperty("会话头像") + private String avatar; +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Contact.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Contact.java index dae18dc..0a2afbc 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Contact.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Contact.java @@ -38,22 +38,10 @@ public class Contact implements Serializable { private Long uid; /** - * 聊天类型 1单聊 2普通群聊 + * 房间id */ - @TableField("type") - private Integer type; - - /** - * 是否全员展示 0否 1是 - */ - @TableField("hot_flag") - private Integer hotFlag; - - /** - * 聊天对象type=1:uid,type=2:房间id - */ - @TableField("target_id") - private Long targetId; + @TableField("room_id") + private Long roomId; /** * 阅读到的时间 @@ -67,6 +55,12 @@ public class Contact implements Serializable { @TableField("active_time") private LocalDateTime activeTime; + /** + * 最后一条消息id + */ + @TableField("last_msg_id") + private Long lastMsgId; + /** * 创建时间 */ diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/GroupMember.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/GroupMember.java index 1b8ed4f..2add870 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/GroupMember.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/GroupMember.java @@ -44,10 +44,10 @@ public class GroupMember implements Serializable { private Long uid; /** - * 成员类型 1群主 2管理员 3普通成员 + * 成员角色1群主 2管理员 3普通成员 */ - @TableField("type") - private Integer type; + @TableField("role") + private Integer role; /** * 创建时间 diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Room.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Room.java index 67a6ec2..6ac70ac 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Room.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/Room.java @@ -24,7 +24,6 @@ import java.time.LocalDateTime; public class Room implements Serializable { private static final long serialVersionUID = 1L; - /** * id */ @@ -32,25 +31,15 @@ public class Room implements Serializable { private Long id; /** - * 群名称 - */ - @TableField("name") - private String name; - - /** - * 群头像 - */ - @TableField("avatar") - private String avatar; - - /** - * 房间类型 1群聊 + * 房间类型 1群聊 2单聊 */ @TableField("type") private Integer type; /** * 是否全员展示 0否 1是 + * + * @see com.abin.mallchat.common.chat.domain.enums.HotFlagEnum */ @TableField("hot_flag") private Integer hotFlag; diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomFriend.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomFriend.java new file mode 100644 index 0000000..c118540 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomFriend.java @@ -0,0 +1,76 @@ +package com.abin.mallchat.common.chat.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-07-22 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("room_friend") +public class RoomFriend implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 房间id + */ + @TableField("room_id") + private Long roomId; + + /** + * uid1(更小的uid) + */ + @TableField("uid1") + private Long uid1; + + /** + * uid2(更大的uid) + */ + @TableField("uid2") + private Long uid2; + + /** + * 房间key由两个uid拼接,先做排序uid1_uid2 + */ + @TableField("key") + private String key; + + /** + * 房间状态 0正常 1禁用(删好友了禁用) + */ + @TableField("status") + private Integer status; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomGroup.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomGroup.java new file mode 100644 index 0000000..0df77d8 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/entity/RoomGroup.java @@ -0,0 +1,75 @@ +package com.abin.mallchat.common.chat.domain.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 群聊房间表 + *

+ * + * @author abin + * @since 2023-07-22 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("room_group") +public class RoomGroup implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 房间id + */ + @TableField("room_id") + private Long roomId; + + /** + * 群名称 + */ + @TableField("name") + private String name; + + /** + * 群头像 + */ + @TableField("avatar") + private String avatar; + + /** + * 额外信息(根据不同类型房间有不同存储的东西) + */ + @TableField("ext_json") + private String extJson; + + /** + * 逻辑删除(0-正常,1-删除) + */ + @TableField("delete_status") + @TableLogic(value = "0", delval = "1") + private Integer deleteStatus; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + /** + * 修改时间 + */ + @TableField("update_time") + private LocalDateTime updateTime; + + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/HotFlagEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/HotFlagEnum.java new file mode 100644 index 0000000..e5e7bea --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/HotFlagEnum.java @@ -0,0 +1,35 @@ +package com.abin.mallchat.common.chat.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 HotFlagEnum { + NOT(0, "非热点"), + YES(1, "热点"), + ; + + private final Integer type; + private final String desc; + + private static Map cache; + + static { + cache = Arrays.stream(HotFlagEnum.values()).collect(Collectors.toMap(HotFlagEnum::getType, Function.identity())); + } + + public static HotFlagEnum of(Integer type) { + return cache.get(type); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/RoomTypeEnum.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/RoomTypeEnum.java index c255add..64a4c7c 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/RoomTypeEnum.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/domain/enums/RoomTypeEnum.java @@ -16,17 +16,17 @@ import java.util.stream.Collectors; @AllArgsConstructor @Getter public enum RoomTypeEnum { - GROUP(1, "大群聊"), - BOILING(2, "沸点"), + GROUP(1, "群聊"), + FRIEND(2, "单聊"), ; - private final Integer status; + private final Integer type; private final String desc; private static Map cache; static { - cache = Arrays.stream(RoomTypeEnum.values()).collect(Collectors.toMap(RoomTypeEnum::getStatus, Function.identity())); + cache = Arrays.stream(RoomTypeEnum.values()).collect(Collectors.toMap(RoomTypeEnum::getType, Function.identity())); } public static RoomTypeEnum of(Integer type) { diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomFriendMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomFriendMapper.java new file mode 100644 index 0000000..a7f9a86 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomFriendMapper.java @@ -0,0 +1,16 @@ +package com.abin.mallchat.common.chat.mapper; + +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 单聊房间表 Mapper 接口 + *

+ * + * @author abin + * @since 2023-07-22 + */ +public interface RoomFriendMapper extends BaseMapper { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomGroupMapper.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomGroupMapper.java new file mode 100644 index 0000000..92fc0c5 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/RoomGroupMapper.java @@ -0,0 +1,16 @@ +package com.abin.mallchat.common.chat.mapper; + +import com.abin.mallchat.common.chat.domain.entity.RoomGroup; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * 群聊房间表 Mapper 接口 + *

+ * + * @author abin + * @since 2023-07-22 + */ +public interface RoomGroupMapper extends BaseMapper { + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomFriendMapper.xml b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomFriendMapper.xml new file mode 100644 index 0000000..664cfae --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomFriendMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomGroupMapper.xml b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomGroupMapper.xml new file mode 100644 index 0000000..cbe5e1e --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomGroupMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomMapper.xml b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomMapper.xml new file mode 100644 index 0000000..463b963 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/mapper/xml/RoomMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/ContactService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/ContactService.java new file mode 100644 index 0000000..6fd4c7f --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/ContactService.java @@ -0,0 +1,29 @@ +package com.abin.mallchat.common.chat.service; + +import com.abin.mallchat.common.chat.domain.dto.MsgReadInfoDTO; +import com.abin.mallchat.common.chat.domain.entity.Contact; +import com.abin.mallchat.common.chat.domain.entity.Message; + +import java.util.List; +import java.util.Map; + +/** + *

+ * 会话列表 服务类 + *

+ * + * @author abin + * @since 2023-07-16 + */ +public interface ContactService { + /** + * 创建会话 + */ + Contact createContact(Long uid, Long roomId); + + Integer getMsgReadCount(Message message); + + Integer getMsgUnReadCount(Message message); + + Map getMsgReadInfo(List messages); +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IContactService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IContactService.java deleted file mode 100644 index a6af570..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IContactService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.abin.mallchat.common.chat.service; - -import com.abin.mallchat.common.chat.domain.entity.Contact; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 会话列表 服务类 - *

- * - * @author abin - * @since 2023-07-16 - */ -public interface IContactService extends IService { - -} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IRoomService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IRoomService.java deleted file mode 100644 index 380208f..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IRoomService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.abin.mallchat.common.chat.service; - -import com.abin.mallchat.common.chat.domain.entity.Room; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 房间表 服务类 - *

- * - * @author abin - * @since 2023-07-16 - */ -public interface IRoomService extends IService { - -} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IWxMsgService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IWxMsgService.java deleted file mode 100644 index bd81574..0000000 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/IWxMsgService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.abin.mallchat.common.chat.service; - -import com.abin.mallchat.common.chat.domain.entity.WxMsg; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 微信消息表 服务类 - *

- * - * @author abin - * @since 2023-05-16 - */ -public interface IWxMsgService extends IService { - -} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/RoomService.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/RoomService.java new file mode 100644 index 0000000..1f7c8d8 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/RoomService.java @@ -0,0 +1,18 @@ +package com.abin.mallchat.common.chat.service; + +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; + +import java.util.List; + +/** + * Description: 房间底层管理 + * Author: abin + * Date: 2023-07-22 + */ +public interface RoomService { + + /** + * 创建一个单聊房间 + */ + RoomFriend createFriendRoom(List uidList); +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/adapter/ChatAdapter.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/adapter/ChatAdapter.java new file mode 100644 index 0000000..8b1a59b --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/adapter/ChatAdapter.java @@ -0,0 +1,68 @@ +package com.abin.mallchat.common.chat.service.adapter; + +import com.abin.mallchat.common.chat.domain.entity.Contact; +import com.abin.mallchat.common.chat.domain.entity.Room; +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.abin.mallchat.common.chat.domain.enums.HotFlagEnum; +import com.abin.mallchat.common.chat.domain.enums.RoomTypeEnum; +import com.abin.mallchat.common.common.domain.enums.NormalOrNoEnum; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Description: + * Author: abin + * Date: 2023-07-22 + */ +public class ChatAdapter { + public static final String SEPARATOR = ","; + + public static String generateRoomKey(List uidList) { + return uidList.stream() + .sorted() + .map(String::valueOf) + .collect(Collectors.joining(SEPARATOR)); + } + + public static Room buildRoom(RoomTypeEnum typeEnum) { + Room room = new Room(); + room.setType(typeEnum.getType()); + room.setHotFlag(HotFlagEnum.NOT.getType()); + return room; + } + + public static RoomFriend buildFriendRoom(Long roomId, List uidList) { + List collect = uidList.stream().sorted().collect(Collectors.toList()); + RoomFriend roomFriend = new RoomFriend(); + roomFriend.setRoomId(roomId); + roomFriend.setUid1(collect.get(0)); + roomFriend.setUid2(collect.get(1)); + roomFriend.setKey(generateRoomKey(uidList)); + roomFriend.setStatus(NormalOrNoEnum.NORMAL.getStatus()); + return roomFriend; + } + + public static Contact buildContact(Long uid, Long roomId) { + Contact contact = new Contact(); + contact.setRoomId(roomId); + contact.setUid(uid); + return contact; + } + + public static Set getFriendUidSet(Collection values, Long uid) { + return values.stream() + .map(a -> getFriendUid(a, uid)) + .collect(Collectors.toSet()); + } + + /** + * 获取好友uid + */ + public static Long getFriendUid(RoomFriend roomFriend, Long uid) { + return Objects.equals(uid, roomFriend.getUid1()) ? roomFriend.getUid2() : roomFriend.getUid1(); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomCache.java new file mode 100644 index 0000000..cf298f0 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomCache.java @@ -0,0 +1,46 @@ +package com.abin.mallchat.common.chat.service.cache; + +import com.abin.mallchat.common.chat.dao.RoomDao; +import com.abin.mallchat.common.chat.dao.RoomFriendDao; +import com.abin.mallchat.common.chat.domain.entity.Room; +import com.abin.mallchat.common.common.constant.RedisKey; +import com.abin.mallchat.common.common.service.cache.AbstractRedisStringCache; +import com.abin.mallchat.common.user.dao.UserDao; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Description: 房间基本信息的缓存 + * Author: abin + * Date: 2023-06-10 + */ +@Component +public class RoomCache extends AbstractRedisStringCache { + @Autowired + private UserDao userDao; + @Autowired + private RoomDao roomDao; + @Autowired + private RoomFriendDao roomFriendDao; + + @Override + protected String getKey(Long roomId) { + return RedisKey.getKey(RedisKey.ROOM_INFO_STRING, roomId); + } + + @Override + protected Long getExpireSeconds() { + return 5 * 60L; + } + + @Override + protected Map load(List roomIds) { + List rooms = roomDao.listByIds(roomIds); + return rooms.stream().collect(Collectors.toMap(Room::getId, Function.identity())); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomFriendCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomFriendCache.java new file mode 100644 index 0000000..5e48a82 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomFriendCache.java @@ -0,0 +1,40 @@ +package com.abin.mallchat.common.chat.service.cache; + +import com.abin.mallchat.common.chat.dao.RoomFriendDao; +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.abin.mallchat.common.common.constant.RedisKey; +import com.abin.mallchat.common.common.service.cache.AbstractRedisStringCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Description: 群组基本信息的缓存 + * Author: abin + * Date: 2023-06-10 + */ +@Component +public class RoomFriendCache extends AbstractRedisStringCache { + @Autowired + private RoomFriendDao roomFriendDao; + + @Override + protected String getKey(Long groupId) { + return RedisKey.getKey(RedisKey.GROUP_INFO_STRING, groupId); + } + + @Override + protected Long getExpireSeconds() { + return 5 * 60L; + } + + @Override + protected Map load(List roomIds) { + List roomGroups = roomFriendDao.listByRoomIds(roomIds); + return roomGroups.stream().collect(Collectors.toMap(RoomFriend::getRoomId, Function.identity())); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomGroupCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomGroupCache.java new file mode 100644 index 0000000..28ba198 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/cache/RoomGroupCache.java @@ -0,0 +1,40 @@ +package com.abin.mallchat.common.chat.service.cache; + +import com.abin.mallchat.common.chat.dao.RoomGroupDao; +import com.abin.mallchat.common.chat.domain.entity.RoomGroup; +import com.abin.mallchat.common.common.constant.RedisKey; +import com.abin.mallchat.common.common.service.cache.AbstractRedisStringCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Description: 群组基本信息的缓存 + * Author: abin + * Date: 2023-06-10 + */ +@Component +public class RoomGroupCache extends AbstractRedisStringCache { + @Autowired + private RoomGroupDao roomGroupDao; + + @Override + protected String getKey(Long groupId) { + return RedisKey.getKey(RedisKey.GROUP_INFO_STRING, groupId); + } + + @Override + protected Long getExpireSeconds() { + return 5 * 60L; + } + + @Override + protected Map load(List roomIds) { + List roomGroups = roomGroupDao.listByRoomIds(roomIds); + return roomGroups.stream().collect(Collectors.toMap(RoomGroup::getRoomId, Function.identity())); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/ContactServiceImpl.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/ContactServiceImpl.java new file mode 100644 index 0000000..119aef5 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/ContactServiceImpl.java @@ -0,0 +1,68 @@ +package com.abin.mallchat.common.chat.service.impl; + +import com.abin.mallchat.common.chat.dao.ContactDao; +import com.abin.mallchat.common.chat.dao.MessageDao; +import com.abin.mallchat.common.chat.domain.dto.MsgReadInfoDTO; +import com.abin.mallchat.common.chat.domain.entity.Contact; +import com.abin.mallchat.common.chat.domain.entity.Message; +import com.abin.mallchat.common.chat.service.ContactService; +import com.abin.mallchat.common.chat.service.adapter.ChatAdapter; +import com.abin.mallchat.common.common.utils.AssertUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Description: 会话列表 + * Author: abin + * Date: 2023-07-22 + */ +@Service +public class ContactServiceImpl implements ContactService { + + @Autowired + private ContactDao contactDao; + @Autowired + private MessageDao messageDao; + + @Override + public Contact createContact(Long uid, Long roomId) { + Contact contact = contactDao.get(uid, roomId); + if (Objects.isNull(contact)) { + contact = ChatAdapter.buildContact(uid, roomId); + contactDao.save(contact); + } + return contact; + } + + @Override + public Integer getMsgReadCount(Message message) { + return contactDao.getReadCount(message); + } + + @Override + public Integer getMsgUnReadCount(Message message) { + return contactDao.getUnReadCount(message); + } + + @Override + public Map getMsgReadInfo(List messages) { + Map> roomGroup = messages.stream().collect(Collectors.groupingBy(Message::getRoomId)); + AssertUtil.equal(roomGroup.size(), 1, "只能查相同房间下的消息"); + Long roomId = roomGroup.keySet().iterator().next(); + Integer totalCount = contactDao.getTotalCount(roomId); + return messages.stream().map(message -> { + MsgReadInfoDTO readInfoDTO = new MsgReadInfoDTO(); + readInfoDTO.setMsgId(message.getId()); + Integer readCount = contactDao.getReadCount(message); + readInfoDTO.setReadCount(readCount); + readInfoDTO.setUnReadCount(totalCount - readCount); + return readInfoDTO; + }).collect(Collectors.toMap(MsgReadInfoDTO::getMsgId, Function.identity())); + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/RoomServiceImpl.java b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/RoomServiceImpl.java new file mode 100644 index 0000000..4903fa3 --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/chat/service/impl/RoomServiceImpl.java @@ -0,0 +1,66 @@ +package com.abin.mallchat.common.chat.service.impl; + +import com.abin.mallchat.common.chat.dao.RoomDao; +import com.abin.mallchat.common.chat.dao.RoomFriendDao; +import com.abin.mallchat.common.chat.domain.entity.Room; +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.abin.mallchat.common.chat.domain.enums.RoomTypeEnum; +import com.abin.mallchat.common.chat.service.RoomService; +import com.abin.mallchat.common.chat.service.adapter.ChatAdapter; +import com.abin.mallchat.common.common.domain.enums.NormalOrNoEnum; +import com.abin.mallchat.common.common.utils.AssertUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; + +/** + * Description: + * Author: abin + * Date: 2023-07-22 + */ +@Service +public class RoomServiceImpl implements RoomService { + + @Autowired + private RoomFriendDao roomFriendDao; + @Autowired + private RoomDao roomDao; + + @Override + @Transactional(rollbackFor = Exception.class) + public RoomFriend createFriendRoom(List uidList) { + AssertUtil.isNotEmpty(uidList, "房间创建失败,好友数量不对"); + AssertUtil.equal(uidList.size(), 2, "房间创建失败,好友数量不对"); + String key = ChatAdapter.generateRoomKey(uidList); + + RoomFriend roomFriend = roomFriendDao.getByKey(key); + if (Objects.nonNull(roomFriend)) { //如果存在房间就恢复,适用于恢复好友场景 + restoreRoomIfNeed(roomFriend); + } else {//新建房间 + Room room = createRoom(RoomTypeEnum.GROUP); + roomFriend = createFriendRoom(room.getId(), uidList); + } + return roomFriend; + } + + private RoomFriend createFriendRoom(Long roomId, List uidList) { + RoomFriend insert = ChatAdapter.buildFriendRoom(roomId, uidList); + roomFriendDao.save(insert); + return insert; + } + + private Room createRoom(RoomTypeEnum typeEnum) { + Room insert = ChatAdapter.buildRoom(typeEnum); + roomDao.save(insert); + return insert; + } + + private void restoreRoomIfNeed(RoomFriend room) { + if (Objects.equals(room.getStatus(), NormalOrNoEnum.NOT_NORMAL.getStatus())) { + roomFriendDao.restoreRoom(room.getId()); + } + } +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java index 9194e7a..96bbb5a 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/constant/RedisKey.java @@ -21,6 +21,16 @@ public class RedisKey { */ public static final String USER_INFO_STRING = "userInfo:uid_%d"; + /** + * 房间详情 + */ + public static final String ROOM_INFO_STRING = "roomInfo:roomId_%d"; + + /** + * 群组详情 + */ + public static final String GROUP_INFO_STRING = "groupInfo:roomId_%d"; + /** * 用户token存放 */ diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/response/PageBaseResp.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/response/PageBaseResp.java index 144a390..346ece9 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/response/PageBaseResp.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/domain/vo/response/PageBaseResp.java @@ -36,13 +36,13 @@ public class PageBaseResp { private List list; - public static PageBaseResp empty() { - PageBaseResp r = new PageBaseResp(); + public static PageBaseResp empty() { + PageBaseResp r = new PageBaseResp<>(); r.setPageNo(1); r.setPageSize(0); r.setIsLast(true); r.setTotalRecords(0L); - r.setList(new ArrayList()); + r.setList(new ArrayList<>()); return r; } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserApplyEvent.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserApplyEvent.java new file mode 100644 index 0000000..6ffa68c --- /dev/null +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/event/UserApplyEvent.java @@ -0,0 +1,16 @@ +package com.abin.mallchat.common.common.event; + +import com.abin.mallchat.common.user.domain.entity.UserApply; +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public class UserApplyEvent extends ApplicationEvent { + private UserApply userApply; + + public UserApplyEvent(Object source, UserApply userApply) { + super(source); + this.userApply = userApply; + } + +} diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/AbstractRedisStringCache.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/AbstractRedisStringCache.java index 0614a8e..f1b80df 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/AbstractRedisStringCache.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/service/cache/AbstractRedisStringCache.java @@ -35,6 +35,9 @@ public abstract class AbstractRedisStringCache implements BatchCache getBatch(List req) { + if (CollectionUtil.isEmpty(req)) {//防御性编程 + return new HashMap<>(); + } req = req.stream().distinct().collect(Collectors.toList()); List keys = req.stream().map(this::getKey).collect(Collectors.toList()); List valueList = RedisUtils.mget(keys, outClass); diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/CursorUtils.java b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/CursorUtils.java index 4d2a391..ced5b1d 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/CursorUtils.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/common/utils/CursorUtils.java @@ -10,7 +10,6 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.data.redis.core.ZSetOperations; -import org.springframework.stereotype.Component; import java.util.List; import java.util.Optional; @@ -24,10 +23,9 @@ import java.util.stream.Collectors; * Author: abin * Date: 2023-03-28 */ -@Component public class CursorUtils { - public CursorPageBaseResp> getCursorPageByRedis(CursorPageBaseReq cursorPageBaseReq, String redisKey, Function typeConvert) { + public static CursorPageBaseResp> getCursorPageByRedis(CursorPageBaseReq cursorPageBaseReq, String redisKey, Function typeConvert) { Set> typedTuples; if (StrUtil.isBlank(cursorPageBaseReq.getCursor())) {//第一次 typedTuples = RedisUtils.zReverseRangeWithScores(redisKey, cursorPageBaseReq.getPageSize()); @@ -47,7 +45,7 @@ public class CursorUtils { return new CursorPageBaseResp<>(cursor, isLast, result); } - public CursorPageBaseResp getCursorPageByMysql(IService mapper, CursorPageBaseReq request, Consumer> initWrapper, SFunction cursorColumn) { + public static CursorPageBaseResp getCursorPageByMysql(IService mapper, CursorPageBaseReq request, Consumer> initWrapper, SFunction cursorColumn) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); initWrapper.accept(wrapper); if (StrUtil.isNotBlank(request.getCursor())) { diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserApplyDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserApplyDao.java index 0beacd6..187cea4 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserApplyDao.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserApplyDao.java @@ -1,11 +1,20 @@ package com.abin.mallchat.common.user.dao; import com.abin.mallchat.common.user.domain.entity.UserApply; +import com.abin.mallchat.common.user.domain.enums.ApplyStatusEnum; +import com.abin.mallchat.common.user.domain.enums.ApplyTypeEnum; import com.abin.mallchat.common.user.mapper.UserApplyMapper; -import com.abin.mallchat.common.user.service.IUserApplyService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; +import java.util.List; + +import static com.abin.mallchat.common.user.domain.enums.ApplyReadStatusEnum.READ; +import static com.abin.mallchat.common.user.domain.enums.ApplyReadStatusEnum.UNREAD; +import static com.abin.mallchat.common.user.domain.enums.ApplyStatusEnum.AGREE; + /** *

* 用户申请表 服务实现类 @@ -15,6 +24,42 @@ import org.springframework.stereotype.Service; * @since 2023-07-16 */ @Service -public class UserApplyDao extends ServiceImpl implements IUserApplyService { +public class UserApplyDao extends ServiceImpl { + public UserApply getFriendApproving(Long uid, Long targetUid) { + return lambdaQuery().eq(UserApply::getUid, uid) + .eq(UserApply::getTargetId, targetUid) + .eq(UserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL) + .eq(UserApply::getType, ApplyTypeEnum.ADD_FRIEND.getCode()) + .one(); + } + + public Integer getUnReadCount(Long targetId) { + return lambdaQuery().eq(UserApply::getTargetId, targetId) + .eq(UserApply::getReadStatus, UNREAD.getCode()) + .count(); + } + + public IPage FriendApplyPage(Long uid, Page page) { + return lambdaQuery() + .eq(UserApply::getTargetId, uid) + .eq(UserApply::getType, ApplyTypeEnum.ADD_FRIEND.getCode()) + .orderByAsc(UserApply::getCreateTime) + .page(page); + } + + public void readApples(Long uid, List applyIds) { + lambdaUpdate() + .set(UserApply::getReadStatus, READ.getCode()) + .eq(UserApply::getReadStatus, UNREAD.getCode()) + .in(UserApply::getId, applyIds) + .eq(UserApply::getTargetId, uid) + .update(); + } + + public void agree(Long applyId) { + lambdaUpdate().set(UserApply::getStatus, AGREE.getCode()) + .eq(UserApply::getId, applyId) + .update(); + } } diff --git a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserFriendDao.java b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserFriendDao.java index 5921882..8dcc587 100644 --- a/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserFriendDao.java +++ b/mallchat-common/src/main/java/com/abin/mallchat/common/user/dao/UserFriendDao.java @@ -2,10 +2,11 @@ package com.abin.mallchat.common.user.dao; import com.abin.mallchat.common.user.domain.entity.UserFriend; import com.abin.mallchat.common.user.mapper.UserFriendMapper; -import com.abin.mallchat.common.user.service.IUserFriendService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; +import java.util.List; + /** *

* 用户联系人表 服务实现类 @@ -15,6 +16,17 @@ import org.springframework.stereotype.Service; * @since 2023-07-16 */ @Service -public class UserFriendDao extends ServiceImpl implements IUserFriendService { +public class UserFriendDao extends ServiceImpl { + public List getByFriends(Long uid, List uidList) { + return lambdaQuery().eq(UserFriend::getUid, uid) + .in(UserFriend::getFriendUid, uidList) + .list(); + } + + public UserFriend getByFriend(Long uid, Long targetUid) { + return lambdaQuery().eq(UserFriend::getUid, uid) + .eq(UserFriend::getFriendUid, targetUid) + .one(); + } } 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 index 9d8340a..075ffc9 100644 --- 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 @@ -54,6 +54,4 @@ public class UserRole implements Serializable { */ @TableField("update_time") private LocalDateTime updateTime; - - } 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 44b7321..c5cc861 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 @@ -31,8 +31,6 @@ import java.util.stream.Collectors; @Component public class UserCache { - @Autowired - private CursorUtils cursorUtils; @Autowired private UserDao userDao; @Autowired @@ -88,11 +86,11 @@ public class UserCache { } public CursorPageBaseResp> getOnlineCursorPage(CursorPageBaseReq pageBaseReq) { - return cursorUtils.getCursorPageByRedis(pageBaseReq, RedisKey.getKey(RedisKey.ONLINE_UID_ZET), Long::parseLong); + return CursorUtils.getCursorPageByRedis(pageBaseReq, RedisKey.getKey(RedisKey.ONLINE_UID_ZET), Long::parseLong); } public CursorPageBaseResp> getOfflineCursorPage(CursorPageBaseReq pageBaseReq) { - return cursorUtils.getCursorPageByRedis(pageBaseReq, RedisKey.getKey(RedisKey.OFFLINE_UID_ZET), Long::parseLong); + return CursorUtils.getCursorPageByRedis(pageBaseReq, RedisKey.getKey(RedisKey.OFFLINE_UID_ZET), Long::parseLong); } public List getUserModifyTime(List uidList) { 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 10bbbd6..1cf8b36 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 @@ -1,6 +1,7 @@ package com.abin.mallchat.custom.chat.controller; +import com.abin.mallchat.common.chat.domain.dto.MsgReadInfoDTO; import com.abin.mallchat.common.common.annotation.FrequencyControl; import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq; import com.abin.mallchat.common.common.domain.vo.response.ApiResult; @@ -19,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,7 +53,6 @@ public class ChatController { @ApiOperation("群成员列表") @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP) public ApiResult> getMemberPage(@Valid CursorPageBaseReq request) { -// black(request); CursorPageBaseResp memberPage = chatService.getMemberPage(request); filterBlackMember(memberPage); return ApiResult.success(memberPage); @@ -59,6 +60,7 @@ public class ChatController { @GetMapping("/member/list") @ApiOperation("房间内的所有群成员列表-@专用") + @Deprecated public ApiResult> getMemberList(@Valid ChatMessageMemberReq chatMessageMemberReq) { return ApiResult.success(chatService.getMemberList(chatMessageMemberReq)); } @@ -74,6 +76,7 @@ public class ChatController { @GetMapping("public/member/statistic") @ApiOperation("群成员人数统计") + @Deprecated public ApiResult getMemberStatistic() { return ApiResult.success(chatService.getMemberStatistic()); } @@ -85,7 +88,6 @@ public class ChatController { @ApiOperation("消息列表") @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP) public ApiResult> getMsgPage(@Valid ChatMessagePageReq request) { -// black(request); CursorPageBaseResp msgPage = chatService.getMsgPage(request, RequestHolder.get().getUid()); filterBlackMsg(msgPage); return ApiResult.success(msgPage); @@ -101,7 +103,7 @@ public class ChatController { @FrequencyControl(time = 5, count = 3, target = FrequencyControl.Target.UID) @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) { + public ApiResult sendMsg(@Valid @RequestBody ChatMessageReq request) {//todo 发送给单聊 Long msgId = chatService.sendMsg(request, RequestHolder.get().getUid()); //返回完整消息格式,方便前端展示 return ApiResult.success(chatService.getMsgResp(msgId, RequestHolder.get().getUid())); @@ -122,5 +124,19 @@ public class ChatController { chatService.recallMsg(RequestHolder.get().getUid(), request); return ApiResult.success(); } + + @GetMapping("/msg/read/page") + @ApiOperation("消息的已读未读列表") + public ApiResult> getReadPage(@Valid ChatMessageReadReq request) { + Long uid = RequestHolder.get().getUid(); + return ApiResult.success(chatService.getReadPage(uid, request)); + } + + @GetMapping("/msg/read") + @ApiOperation("获取消息的已读未读总数") + public ApiResult> getReadInfo(@Valid ChatMessageReadInfoReq request) { + Long uid = RequestHolder.get().getUid(); + return ApiResult.success(chatService.getMsgReadInfo(uid, request)); + } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ContactController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ContactController.java new file mode 100644 index 0000000..cbb5ee5 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/ContactController.java @@ -0,0 +1,48 @@ +package com.abin.mallchat.custom.chat.controller; + + +import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq; +import com.abin.mallchat.common.common.domain.vo.response.ApiResult; +import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp; +import com.abin.mallchat.common.common.utils.RequestHolder; +import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp; +import com.abin.mallchat.custom.chat.service.ChatService; +import com.abin.mallchat.custom.chat.service.RoomService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +/** + *

+ * 会话相关接口 + *

+ * + * @author abin + * @since 2023-03-19 + */ +@RestController +@RequestMapping("/capi/chat") +@Api(tags = "聊天室相关接口") +@Slf4j +public class ContactController { + @Autowired + private ChatService chatService; + @Autowired + private RoomService roomService; + + @GetMapping("/public/contact/page") + @ApiOperation("会话列表") + public ApiResult> getRoomPage(@Valid CursorPageBaseReq request) { + Long uid = RequestHolder.get().getUid(); + return ApiResult.success(roomService.getContactPage(request, uid)); + } + + +} + diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/RoomController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/RoomController.java new file mode 100644 index 0000000..fb71cbf --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/controller/RoomController.java @@ -0,0 +1,79 @@ +package com.abin.mallchat.custom.chat.controller; + + +import com.abin.mallchat.common.common.annotation.FrequencyControl; +import com.abin.mallchat.common.common.domain.vo.request.IdReqVO; +import com.abin.mallchat.common.common.domain.vo.response.ApiResult; +import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp; +import com.abin.mallchat.common.common.utils.RequestHolder; +import com.abin.mallchat.common.user.service.cache.UserCache; +import com.abin.mallchat.custom.chat.domain.vo.request.ChatMessageMemberReq; +import com.abin.mallchat.custom.chat.domain.vo.request.MemberAddReq; +import com.abin.mallchat.custom.chat.domain.vo.request.MemberDelReq; +import com.abin.mallchat.custom.chat.domain.vo.request.MemberReq; +import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberListResp; +import com.abin.mallchat.custom.chat.domain.vo.response.ChatMemberResp; +import com.abin.mallchat.custom.chat.domain.vo.response.MemberResp; +import com.abin.mallchat.custom.chat.service.ChatService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + *

+ * 房间相关接口 + *

+ * + * @author abin + * @since 2023-03-19 + */ +@RestController +@RequestMapping("/capi/room") +@Api(tags = "聊天室相关接口") +@Slf4j +public class RoomController { + @Autowired + private ChatService chatService; + @Autowired + private UserCache userCache; + + @GetMapping("/public/group") + @ApiOperation("群组详情") + public ApiResult groupDetail(@Valid IdReqVO request) { + return ApiResult.success(); + } + + @GetMapping("/public/group/member/page") + @ApiOperation("群成员列表") + @FrequencyControl(time = 120, count = 20, target = FrequencyControl.Target.IP) + public ApiResult> getMemberPage(@Valid MemberReq request) { + CursorPageBaseResp memberPage = chatService.getMemberPage(request); + return ApiResult.success(memberPage); + } + + @GetMapping("/group/member/list") + @ApiOperation("房间内的所有群成员列表-@专用") + public ApiResult> getMemberList(@Valid ChatMessageMemberReq request) { + return ApiResult.success(chatService.getMemberList(request)); + } + + @DeleteMapping("/group/member") + @ApiOperation("移除成员") + public ApiResult delMember(@Valid @RequestBody MemberDelReq request) { + Long uid = RequestHolder.get().getUid(); + return ApiResult.success(); + } + + @PostMapping("/group/member") + @ApiOperation("邀请好友") + public ApiResult> addMember(@Valid @RequestBody MemberAddReq request) { + Long uid = RequestHolder.get().getUid(); + return ApiResult.success(); + } +} + diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadInfoReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadInfoReq.java new file mode 100644 index 0000000..2b1c585 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadInfoReq.java @@ -0,0 +1,25 @@ +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.Size; +import java.util.List; + +/** + * Description: + * Author: abin + * Date: 2023-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageReadInfoReq { + @ApiModelProperty("消息id集合(只查本人)") + @Size(max = 20) + private List msgIds; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadReq.java new file mode 100644 index 0000000..686318a --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/ChatMessageReadReq.java @@ -0,0 +1,29 @@ +package com.abin.mallchat.custom.chat.domain.vo.request; + +import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq; +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-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageReadReq extends CursorPageBaseReq { + @ApiModelProperty("消息id") + @NotNull + private Long msgId; + + @ApiModelProperty("查询类型 1已读 2未读") + @NotNull + private Long searchType; +} 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 b255a34..4300f94 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 @@ -24,7 +24,7 @@ import javax.validation.constraints.NotNull; @NoArgsConstructor public class ChatMessageReq { @NotNull - @ApiModelProperty("会话id") + @ApiModelProperty("房间id") private Long roomId; @ApiModelProperty("消息类型") diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberAddReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberAddReq.java new file mode 100644 index 0000000..661148a --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberAddReq.java @@ -0,0 +1,31 @@ +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; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * Description: 移除群成员 + * Author: abin + * Date: 2023-03-29 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MemberAddReq { + @NotNull + @ApiModelProperty("会话id") + private Long roomId; + + @NotNull + @Size(min = 1, max = 50) + @ApiModelProperty("邀请的uid") + private List uidList; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberDelReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberDelReq.java new file mode 100644 index 0000000..7951023 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberDelReq.java @@ -0,0 +1,28 @@ +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-29 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MemberDelReq { + @NotNull + @ApiModelProperty("会话id") + private Long roomId; + + @NotNull + @ApiModelProperty("被移除的uid(主动退群填自己)") + private Long uid; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberReq.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberReq.java new file mode 100644 index 0000000..ce41b7c --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/request/MemberReq.java @@ -0,0 +1,25 @@ +package com.abin.mallchat.custom.chat.domain.vo.request; + +import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq; +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-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MemberReq extends CursorPageBaseReq { + @ApiModelProperty("房间号") + @NotNull + private Long roomId; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadInfoResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadInfoResp.java new file mode 100644 index 0000000..dd6cb71 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadInfoResp.java @@ -0,0 +1,28 @@ +package com.abin.mallchat.custom.chat.domain.vo.response; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Description: + * Author: abin + * Date: 2023-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageReadInfoResp { + @ApiModelProperty("消息id") + private Long msgId; + + @ApiModelProperty("已读数") + private Integer readCount; + + @ApiModelProperty("未读数") + private Integer unReadCount; + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadResp.java new file mode 100644 index 0000000..4b187c8 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatMessageReadResp.java @@ -0,0 +1,21 @@ +package com.abin.mallchat.custom.chat.domain.vo.response; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Description: + * Author: abin + * Date: 2023-03-23 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageReadResp { + @ApiModelProperty("已读或者未读的用户uid") + private Long uid; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatRoomResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatRoomResp.java index b7f22b7..9913bf8 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatRoomResp.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/ChatRoomResp.java @@ -18,12 +18,20 @@ import java.util.Date; @AllArgsConstructor @NoArgsConstructor public class ChatRoomResp { - @ApiModelProperty("会话id") - private Long id; + @ApiModelProperty("房间id") + private Long roomId; + @ApiModelProperty("房间类型 1群聊 2单聊") + private Integer type; + @ApiModelProperty("是否全员展示的会话 0否 1是") + private Integer hot_Flag; + @ApiModelProperty("最新消息") + private String text; @ApiModelProperty("会话名称") private String name; - @ApiModelProperty("会话类型 1大群聊 2沸点") - private Integer type; - @ApiModelProperty("房间最后活跃时间") + @ApiModelProperty("会话头像") + private String avatar; + @ApiModelProperty("房间最后活跃时间(用来排序)") private Date lastActiveTime; + @ApiModelProperty("未读数") + private Integer unreadCount; } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/MemberResp.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/MemberResp.java new file mode 100644 index 0000000..0bc8c79 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/domain/vo/response/MemberResp.java @@ -0,0 +1,29 @@ +package com.abin.mallchat.custom.chat.domain.vo.response; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Description: + * Author: abin + * Date: 2023-07-17 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MemberResp { + @ApiModelProperty("群id") + private Long id; + @ApiModelProperty("群名称") + private Long groupName; + @ApiModelProperty("在线人数") + private Long onlineNum;//在线人数 + @ApiModelProperty("群聊描述") + private String desc;//在线人数 + @ApiModelProperty("成员角色 1群主 2管理员 3普通成员 4踢出群聊") + private Integer role;//在线人数 +} 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 43e00cc..48c083f 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 @@ -1,5 +1,6 @@ package com.abin.mallchat.custom.chat.service; +import com.abin.mallchat.common.chat.domain.dto.MsgReadInfoDTO; 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; @@ -7,6 +8,7 @@ import com.abin.mallchat.custom.chat.domain.vo.request.*; import com.abin.mallchat.custom.chat.domain.vo.response.*; import javax.annotation.Nullable; +import java.util.Collection; import java.util.List; /** @@ -73,4 +75,8 @@ public interface ChatService { void recallMsg(Long uid, ChatMessageBaseReq request); List getMemberList(ChatMessageMemberReq chatMessageMemberReq); + + Collection getMsgReadInfo(Long uid, ChatMessageReadInfoReq request); + + CursorPageBaseResp getReadPage(Long uid, ChatMessageReadReq request); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/RoomService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/RoomService.java new file mode 100644 index 0000000..0266882 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/RoomService.java @@ -0,0 +1,17 @@ +package com.abin.mallchat.custom.chat.service; + +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.response.ChatRoomResp; + +/** + * Description: + * Author: abin + * Date: 2023-07-22 + */ +public interface RoomService { + /** + * 获取会话列表--支持未登录态 + */ + CursorPageBaseResp getContactPage(CursorPageBaseReq request, Long uid); +} 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 b1bdf8d..5fa2a71 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 @@ -5,20 +5,16 @@ 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.enums.MessageMarkTypeEnum; import com.abin.mallchat.common.chat.domain.enums.MessageStatusEnum; +import com.abin.mallchat.common.chat.domain.enums.MessageTypeEnum; import com.abin.mallchat.common.common.domain.enums.YesOrNoEnum; import com.abin.mallchat.common.user.domain.entity.UserApply; 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.ChatMessageResp; 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.user.domain.vo.response.ws.WSApplyMessage; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; /** @@ -99,4 +95,13 @@ public class MessageAdapter { } + public static ChatMessageReq buildAgreeMsg(Long roomId) { + ChatMessageReq chatMessageReq = new ChatMessageReq(); + chatMessageReq.setRoomId(roomId); + chatMessageReq.setMsgType(MessageTypeEnum.TEXT.getType()); + TextMsgReq textMsgReq = new TextMsgReq(); + textMsgReq.setContent("我们已经成为好友了,开始聊天吧"); + chatMessageReq.setBody(textMsgReq); + return chatMessageReq; + } } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/RoomAdapter.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/RoomAdapter.java index 58a69c4..360883d 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/RoomAdapter.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/adapter/RoomAdapter.java @@ -1,7 +1,9 @@ package com.abin.mallchat.custom.chat.service.adapter; import cn.hutool.core.bean.BeanUtil; +import com.abin.mallchat.common.chat.domain.entity.Contact; import com.abin.mallchat.common.chat.domain.entity.Room; +import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageReadResp; import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp; import java.util.List; @@ -24,4 +26,12 @@ public class RoomAdapter { return resp; }).collect(Collectors.toList()); } + + public static List buildReadResp(List list) { + return list.stream().map(contact -> { + ChatMessageReadResp resp = new ChatMessageReadResp(); + resp.setUid(contact.getUid()); + return resp; + }).collect(Collectors.toList()); + } } 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 03ab62f..cb9539b 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 @@ -5,14 +5,18 @@ 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.ContactDao; import com.abin.mallchat.common.chat.dao.MessageDao; import com.abin.mallchat.common.chat.dao.MessageMarkDao; import com.abin.mallchat.common.chat.dao.RoomDao; +import com.abin.mallchat.common.chat.domain.dto.MsgReadInfoDTO; +import com.abin.mallchat.common.chat.domain.entity.Contact; 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.chat.service.ContactService; import com.abin.mallchat.common.common.annotation.RedissonLock; import com.abin.mallchat.common.common.domain.vo.request.CursorPageBaseReq; import com.abin.mallchat.common.common.domain.vo.response.CursorPageBaseResp; @@ -44,6 +48,7 @@ import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import javax.annotation.Nullable; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -77,6 +82,10 @@ public class ChatServiceImpl implements ChatService { private IRoleService iRoleService; @Autowired private RecallMsgHandler recallMsgHandler; + @Autowired + private ContactService contactService; + @Autowired + private ContactDao contactDao; /** * 发送消息 @@ -205,6 +214,32 @@ public class ChatServiceImpl implements ChatService { return null; } + @Override + public Collection getMsgReadInfo(Long uid, ChatMessageReadInfoReq request) { + List messages = messageDao.listByIds(request.getMsgIds()); + messages.forEach(message -> { + AssertUtil.equal(uid, message.getFromUid(), "只能查询自己发送的消息"); + }); + return contactService.getMsgReadInfo(messages).values(); + } + + @Override + public CursorPageBaseResp getReadPage(@Nullable Long uid, ChatMessageReadReq request) { + Message message = messageDao.getById(request.getMsgId()); + AssertUtil.isNotEmpty(message, "消息id有误"); + AssertUtil.equal(uid, message.getFromUid(), "只能查看自己的消息"); + CursorPageBaseResp page; + if (request.getSearchType() == 1) {//已读 + page = contactDao.getReadPage(message, request); + } else { + page = contactDao.getUnReadPage(message, request); + } + if (CollectionUtil.isEmpty(page.getList())) { + return CursorPageBaseResp.empty(); + } + return CursorPageBaseResp.init(page, RoomAdapter.buildReadResp(page.getList())); + } + private void checkRecall(Long uid, Message message) { AssertUtil.isNotEmpty(message, "消息有误"); AssertUtil.notEqual(message.getType(), MessageTypeEnum.RECALL, "消息无法撤回"); diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/RoomServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/RoomServiceImpl.java new file mode 100644 index 0000000..001ef38 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/chat/service/impl/RoomServiceImpl.java @@ -0,0 +1,114 @@ +package com.abin.mallchat.custom.chat.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.abin.mallchat.common.chat.dao.ContactDao; +import com.abin.mallchat.common.chat.dao.MessageDao; +import com.abin.mallchat.common.chat.domain.dto.RoomBaseInfo; +import com.abin.mallchat.common.chat.domain.entity.*; +import com.abin.mallchat.common.chat.domain.enums.RoomTypeEnum; +import com.abin.mallchat.common.chat.service.adapter.ChatAdapter; +import com.abin.mallchat.common.chat.service.cache.RoomCache; +import com.abin.mallchat.common.chat.service.cache.RoomFriendCache; +import com.abin.mallchat.common.chat.service.cache.RoomGroupCache; +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.user.domain.entity.User; +import com.abin.mallchat.common.user.service.cache.UserInfoCache; +import com.abin.mallchat.custom.chat.domain.vo.response.ChatRoomResp; +import com.abin.mallchat.custom.chat.service.RoomService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Description: + * Author: abin + * Date: 2023-07-22 + */ +@Service +public class RoomServiceImpl implements RoomService { + + @Autowired + private ContactDao contactDao; + @Autowired + private RoomCache roomCache; + @Autowired + private RoomGroupCache roomGroupCache; + @Autowired + private RoomFriendCache roomFriendCache; + @Autowired + private UserInfoCache userInfoCache; + @Autowired + private MessageDao messageDao; + + @Override + public CursorPageBaseResp getContactPage(CursorPageBaseReq request, Long uid) { + + if (Objects.nonNull(uid)) { + CursorPageBaseResp contactPage = contactDao.getContactPage(uid, request); + List roomIds = contactPage.getList().stream().map(Contact::getRoomId).collect(Collectors.toList()); + //表情和头像 + Map roomBaseInfoMap = getRoomBaseInfoMap(roomIds, uid); + //最后一条消息 + List msgIds = contactPage.getList().stream().map(Contact::getLastMsgId).collect(Collectors.toList()); + List messages = messageDao.listByIds(msgIds); + Map msgMap = messages.stream().collect(Collectors.toMap(Message::getId, Function.identity())); + List collect = contactPage.getList().stream().map(contact -> { + ChatRoomResp resp = new ChatRoomResp(); + BeanUtil.copyProperties(contact, resp); + RoomBaseInfo roomBaseInfo = roomBaseInfoMap.get(contact.getRoomId()); + resp.setAvatar(roomBaseInfo.getAvatar()); + resp.setName(roomBaseInfo.getName()); + Message message = msgMap.get(contact.getLastMsgId()); + if (Objects.nonNull(message)) { + resp.setText(); + } + return resp; + }).collect(Collectors.toList()); + CursorPageBaseResp.init(contactPage, collect); + } + return null; + } + + private Map getFriendRoomMap(List roomIds, Long uid) { + Map roomFriendMap = roomFriendCache.getBatch(roomIds); + Set friendUidSet = ChatAdapter.getFriendUidSet(roomFriendMap.values(), uid); + Map userBatch = userInfoCache.getBatch(new ArrayList<>(friendUidSet)); + return roomFriendMap.values() + .stream() + .collect(Collectors.toMap(RoomFriend::getRoomId, roomFriend -> { + Long friendUid = ChatAdapter.getFriendUid(roomFriend, uid); + return userBatch.get(friendUid); + })); + } + + private Map getRoomBaseInfoMap(List roomIds, Long uid) { + Map roomMap = roomCache.getBatch(roomIds); + Map> groupRoomIdMap = roomMap.values().stream().collect(Collectors.groupingBy(Room::getType, + Collectors.mapping(Room::getId, Collectors.toList()))); + //获取群组信息 + List groupRoomId = groupRoomIdMap.get(RoomTypeEnum.GROUP.getType()); + Map roomInfoBatch = roomGroupCache.getBatch(groupRoomId); + //获取好友信息 + List friendRoomId = groupRoomIdMap.get(RoomTypeEnum.FRIEND.getType()); + Map friendRoomMap = getFriendRoomMap(friendRoomId, uid); + return roomMap.values().stream().map(room -> { + RoomBaseInfo roomBaseInfo = new RoomBaseInfo(); + roomBaseInfo.setRoomId(room.getId()); + if (RoomTypeEnum.of(room.getType()) == RoomTypeEnum.GROUP) { + RoomGroup roomGroup = roomInfoBatch.get(room.getId()); + roomBaseInfo.setName(roomGroup.getName()); + roomBaseInfo.setAvatar(roomGroup.getAvatar()); + } else if (RoomTypeEnum.of(room.getType()) == RoomTypeEnum.FRIEND) { + User user = friendRoomMap.get(room.getId()); + roomBaseInfo.setName(user.getName()); + roomBaseInfo.setAvatar(user.getAvatar()); + } + return roomBaseInfo; + }).collect(Collectors.toMap(RoomBaseInfo::getRoomId, Function.identity())); + } + +} 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 index 1715937..6ea052b 100644 --- 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 @@ -18,14 +18,29 @@ public abstract class AbstractMsgHandler { MsgHandlerFactory.register(getMsgTypeEnum().getType(), this); } + /** + * 消息类型 + */ abstract MessageTypeEnum getMsgTypeEnum(); + /** + * 校验消息——保存前校验 + */ public abstract void checkMsg(ChatMessageReq req, Long uid); + /** + * 保存消息 + */ 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/common/event/listener/UserApplyListener.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/UserApplyListener.java new file mode 100644 index 0000000..a95cd23 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/common/event/listener/UserApplyListener.java @@ -0,0 +1,36 @@ +package com.abin.mallchat.custom.common.event.listener; + +import com.abin.mallchat.common.common.event.UserApplyEvent; +import com.abin.mallchat.common.user.dao.UserApplyDao; +import com.abin.mallchat.common.user.domain.entity.UserApply; +import com.abin.mallchat.custom.user.domain.vo.response.ws.WSFriendApply; +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 UserApplyListener { + @Autowired + private UserApplyDao userApplyDao; + @Autowired + private WebSocketService webSocketService; + + @Async + @TransactionalEventListener(classes = UserApplyEvent.class, fallbackExecution = true) + public void notifyFriend(UserApplyEvent event) { + UserApply userApply = event.getUserApply(); + Integer unReadCount = userApplyDao.getUnReadCount(userApply.getTargetId()); + webSocketService.sendToFriend(WSAdapter.buildApplySend(new WSFriendApply(userApply.getUid(), unReadCount)), userApply.getTargetId()); + } + +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/FriendController.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/FriendController.java index f3ae8fe..e94288d 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/FriendController.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/controller/FriendController.java @@ -88,7 +88,7 @@ public class FriendController { @PutMapping("/apply") @ApiOperation("申请审批") public ApiResult applyApprove(@Valid @RequestBody FriendApproveReq request) { - friendService.applyApprove(request); + friendService.applyApprove(RequestHolder.get().getUid(), request); 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 e8ab2fe..a201691 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 @@ -26,7 +26,9 @@ public enum WSRespTypeEnum { BLACK(7, "拉黑用户", WSBlack.class), MARK(8, "消息标记", WSMsgMark.class), RECALL(9, "消息撤回", WSMsgRecall.class), - APPLY(10,"好友申请", WSApplyMessage.class), + APPLY(10, "好友申请", WSFriendApply.class), + MEMBER_CHANGE(11, "成员变动", WSMemberChange.class), + MESSAGE_READ(12, "消息已读数", WSMessageRead.class), ; private final Integer type; diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSApplyMessage.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSApplyMessage.java deleted file mode 100644 index 192d33f..0000000 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSApplyMessage.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.abin.mallchat.custom.user.domain.vo.response.ws; - -import com.abin.mallchat.custom.chat.domain.vo.response.ChatMessageResp; -import lombok.AllArgsConstructor; - -/** - * @author : limeng - * @description : 好友申请消息推送 - * @date : 2023/07/21 - */ -@AllArgsConstructor -public class WSApplyMessage extends ChatMessageResp { - -} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSFriendApply.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSFriendApply.java new file mode 100644 index 0000000..07cb8b4 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSFriendApply.java @@ -0,0 +1,23 @@ +package com.abin.mallchat.custom.user.domain.vo.response.ws; + +import io.swagger.annotations.ApiModelProperty; +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 WSFriendApply { + @ApiModelProperty("申请人") + private Long uid; + @ApiModelProperty("申请未读数") + private Integer unreadCount; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMemberChange.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMemberChange.java new file mode 100644 index 0000000..d6f291c --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMemberChange.java @@ -0,0 +1,34 @@ +package com.abin.mallchat.custom.user.domain.vo.response.ws; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * Description: + * Author: abin + * Date: 2023-03-19 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WSMemberChange { + @ApiModelProperty("群组id") + private Long roomId; + @ApiModelProperty("变动人") + private Long uid; + @ApiModelProperty("变动类型 1加入群组 2移除群组") + private Integer changeType; + /** + * @see com.abin.mallchat.common.user.domain.enums.ChatActiveStatusEnum + */ + @ApiModelProperty("在线状态 1在线 2离线") + private Integer activeStatus; + @ApiModelProperty("最后一次上下线时间") + private Date lastOptTime; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMessageRead.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMessageRead.java new file mode 100644 index 0000000..37e56d7 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSMessageRead.java @@ -0,0 +1,23 @@ +package com.abin.mallchat.custom.user.domain.vo.response.ws; + +import io.swagger.annotations.ApiModelProperty; +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 WSMessageRead { + @ApiModelProperty("消息") + private Long msgId; + @ApiModelProperty("阅读人数(可能为0)") + private Integer readCount; +} diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSOnlineOfflineNotify.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSOnlineOfflineNotify.java index 9d9c82f..f0f077e 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSOnlineOfflineNotify.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/domain/vo/response/ws/WSOnlineOfflineNotify.java @@ -21,7 +21,4 @@ import java.util.List; public class WSOnlineOfflineNotify { private List changeList = new ArrayList<>();//新的上下线用户 private Long onlineNum;//在线人数 - @Deprecated - private Long totalNum;//总人数 - } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/FriendService.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/FriendService.java index dc8b0b5..7502827 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/FriendService.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/FriendService.java @@ -56,5 +56,5 @@ public interface FriendService { * @param uid uid * @param request 请求 */ - void applyApprove(FriendApproveReq request); + void applyApprove(Long uid, FriendApproveReq request); } diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/FriendAdapter.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/FriendAdapter.java new file mode 100644 index 0000000..6525007 --- /dev/null +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/adapter/FriendAdapter.java @@ -0,0 +1,43 @@ +package com.abin.mallchat.custom.user.service.adapter; + +import com.abin.mallchat.common.user.domain.entity.UserApply; +import com.abin.mallchat.custom.user.domain.vo.request.friend.FriendApplyReq; +import com.abin.mallchat.custom.user.domain.vo.response.friend.FriendApplyResp; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.abin.mallchat.common.user.domain.enums.ApplyReadStatusEnum.UNREAD; +import static com.abin.mallchat.common.user.domain.enums.ApplyStatusEnum.WAIT_APPROVAL; +import static com.abin.mallchat.common.user.domain.enums.ApplyTypeEnum.ADD_FRIEND; + +/** + * Description: 好友适配器 + * Author: abin + * Date: 2023-07-22 + */ +public class FriendAdapter { + + + public static UserApply buildFriendApply(Long uid, FriendApplyReq request) { + UserApply userApplyNew = new UserApply(); + userApplyNew.setUid(uid); + userApplyNew.setMsg(request.getMsg()); + userApplyNew.setType(ADD_FRIEND.getCode()); + userApplyNew.setTargetId(request.getTargetUid()); + userApplyNew.setStatus(WAIT_APPROVAL.getCode()); + userApplyNew.setReadStatus(UNREAD.getCode()); + return userApplyNew; + } + + public static List buildFriendApplyList(List records) { + return records.stream().map(userApply -> { + FriendApplyResp friendApplyResp = new FriendApplyResp(); + friendApplyResp.setUid(userApply.getUid()); + friendApplyResp.setType(userApply.getType()); + friendApplyResp.setMsg(userApply.getMsg()); + friendApplyResp.setStatus(userApply.getStatus()); + return friendApplyResp; + }).collect(Collectors.toList()); + } +} 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 7739026..4956491 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 @@ -133,8 +133,8 @@ public class WSAdapter { return wsBaseResp; } - public static WSBaseResp buildApplySend(WSApplyMessage resp) { - WSBaseResp wsBaseResp = new WSBaseResp<>(); + public static WSBaseResp buildApplySend(WSFriendApply resp) { + WSBaseResp wsBaseResp = new WSBaseResp<>(); wsBaseResp.setType(WSRespTypeEnum.APPLY.getType()); wsBaseResp.setData(resp); return wsBaseResp; diff --git a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/FriendServiceImpl.java b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/FriendServiceImpl.java index 5c5343b..bc16a2e 100644 --- a/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/FriendServiceImpl.java +++ b/mallchat-custom-server/src/main/java/com/abin/mallchat/custom/user/service/impl/FriendServiceImpl.java @@ -1,11 +1,20 @@ package com.abin.mallchat.custom.user.service.impl; +import cn.hutool.core.collection.CollectionUtil; +import com.abin.mallchat.common.chat.dao.RoomFriendDao; +import com.abin.mallchat.common.chat.domain.entity.RoomFriend; +import com.abin.mallchat.common.chat.service.ContactService; +import com.abin.mallchat.common.chat.service.RoomService; +import com.abin.mallchat.common.common.annotation.RedissonLock; import com.abin.mallchat.common.common.domain.vo.request.PageBaseReq; import com.abin.mallchat.common.common.domain.vo.response.PageBaseResp; +import com.abin.mallchat.common.common.event.UserApplyEvent; +import com.abin.mallchat.common.common.utils.AssertUtil; +import com.abin.mallchat.common.user.dao.UserApplyDao; +import com.abin.mallchat.common.user.dao.UserFriendDao; import com.abin.mallchat.common.user.domain.entity.UserApply; import com.abin.mallchat.common.user.domain.entity.UserFriend; -import com.abin.mallchat.common.user.service.IUserApplyService; -import com.abin.mallchat.common.user.service.IUserFriendService; +import com.abin.mallchat.custom.chat.service.ChatService; import com.abin.mallchat.custom.chat.service.adapter.MessageAdapter; import com.abin.mallchat.custom.user.domain.vo.request.friend.FriendApplyReq; import com.abin.mallchat.custom.user.domain.vo.request.friend.FriendApproveReq; @@ -13,27 +22,24 @@ import com.abin.mallchat.custom.user.domain.vo.request.friend.FriendCheckReq; import com.abin.mallchat.custom.user.domain.vo.response.friend.FriendApplyResp; import com.abin.mallchat.custom.user.domain.vo.response.friend.FriendCheckResp; import com.abin.mallchat.custom.user.domain.vo.response.friend.FriendUnreadResp; -import com.abin.mallchat.custom.user.domain.vo.response.ws.WSApplyMessage; import com.abin.mallchat.custom.user.service.FriendService; import com.abin.mallchat.custom.user.service.WebSocketService; -import com.abin.mallchat.custom.user.service.adapter.WSAdapter; -import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; -import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.abin.mallchat.custom.user.service.adapter.FriendAdapter; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.annotation.Resource; +import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; -import static com.abin.mallchat.common.user.domain.enums.ApplyReadStatusEnum.UNREAD; import static com.abin.mallchat.common.user.domain.enums.ApplyStatusEnum.AGREE; -import static com.abin.mallchat.common.user.domain.enums.ApplyStatusEnum.WAIT_APPROVAL; -import static com.abin.mallchat.common.user.domain.enums.ApplyTypeEnum.ADD_FRIEND; /** * @author : limeng @@ -44,15 +50,24 @@ import static com.abin.mallchat.common.user.domain.enums.ApplyTypeEnum.ADD_FRIEN @Service public class FriendServiceImpl implements FriendService { - @Resource - private IUserFriendService friendService; - - @Resource - private IUserApplyService applyService; - - @Resource + @Autowired private WebSocketService webSocketService; + @Autowired + private UserFriendDao userFriendDao; + @Autowired + private UserApplyDao userApplyDao; + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + @Autowired + private RoomFriendDao roomFriendDao; + @Autowired + private RoomService roomService; + @Autowired + private ContactService contactService; + @Autowired + private ChatService chatService; + /** * 检查 * 检查是否是自己好友 @@ -63,15 +78,13 @@ public class FriendServiceImpl implements FriendService { */ @Override public FriendCheckResp check(Long uid, FriendCheckReq request) { - LambdaQueryChainWrapper wrapper = friendService.lambdaQuery(); - wrapper.eq(UserFriend::getUid, uid) - .in(UserFriend::getFriendUid, request.getUidList()); - List friendList = friendService.list(wrapper); - Map friendMap = friendList.stream().collect(Collectors.toMap(UserFriend::getFriendUid, friend -> friend)); + List friendList = userFriendDao.getByFriends(uid, request.getUidList()); + + Set friendUidSet = friendList.stream().map(UserFriend::getFriendUid).collect(Collectors.toSet()); List friendCheckList = request.getUidList().stream().map(friendUid -> { FriendCheckResp.FriendCheck friendCheck = new FriendCheckResp.FriendCheck(); friendCheck.setUid(friendUid); - friendCheck.setIsFriend(friendMap.containsKey(friendUid)); + friendCheck.setIsFriend(friendUidSet.contains(friendUid)); return friendCheck; }).collect(Collectors.toList()); return new FriendCheckResp(friendCheckList); @@ -84,25 +97,20 @@ public class FriendServiceImpl implements FriendService { */ @Override public void apply(Long uid, FriendApplyReq request) { - LambdaQueryChainWrapper wrapper = applyService.lambdaQuery(); - wrapper.eq(UserApply::getUid, uid) - .eq(UserApply::getTargetId, request.getTargetUid()); - UserApply userApply = applyService.getOne(wrapper); - if (Objects.nonNull(userApply)) { + //是否有好友关系 + UserFriend friend = userFriendDao.getByFriend(uid, request.getTargetUid()); + AssertUtil.isEmpty(friend, "你们已经是好友了"); + //是否有待审批的申请记录 + UserApply friendApproving = userApplyDao.getFriendApproving(uid, request.getTargetUid()); + if (Objects.nonNull(friendApproving)) { log.info("已有好友申请记录,uid:{}, targetId:{}", uid, request.getTargetUid()); return; } - UserApply userApplyNew = new UserApply(); - userApplyNew.setUid(uid); - userApplyNew.setMsg(request.getMsg()); - userApplyNew.setType(ADD_FRIEND.getCode()); - userApplyNew.setTargetId(request.getTargetUid()); - userApplyNew.setStatus(WAIT_APPROVAL.getCode()); - userApplyNew.setReadStatus(UNREAD.getCode()); - applyService.save(userApplyNew); - - WSApplyMessage applyMessage = MessageAdapter.buildApplyResp(userApplyNew); - webSocketService.sendToFriend(WSAdapter.buildApplySend(applyMessage), request.getTargetUid()); + //申请入库 + UserApply insert = FriendAdapter.buildFriendApply(uid, request); + userApplyDao.save(insert); + //申请事件 + applicationEventPublisher.publishEvent(new UserApplyEvent(this, insert)); } /** @@ -113,23 +121,15 @@ public class FriendServiceImpl implements FriendService { */ @Override public PageBaseResp pageApplyFriend(Long uid, PageBaseReq request) { - // todo 分页 - LambdaQueryChainWrapper wrapper = applyService.lambdaQuery(); - wrapper.eq(UserApply::getUid, uid) - .or() - .eq(UserApply::getTargetId, uid); - List userApplyList = applyService.list(wrapper); - List friendApplyResps = userApplyList.stream().map(userApply -> { - FriendApplyResp friendApplyResp = new FriendApplyResp(); - friendApplyResp.setUid(userApply.getUid()); - friendApplyResp.setType(userApply.getType()); - friendApplyResp.setMsg(userApply.getMsg()); - friendApplyResp.setStatus(userApply.getStatus()); - return friendApplyResp; - }).collect(Collectors.toList()); - PageBaseResp pageBaseResp = new PageBaseResp<>(); - pageBaseResp.setList(friendApplyResps); - return pageBaseResp; + IPage userApplyIPage = userApplyDao.FriendApplyPage(uid, request.plusPage()); + if (CollectionUtil.isEmpty(userApplyIPage.getRecords())) { + return PageBaseResp.empty(); + } + //将这些申请列表设为已读 + List applyIds = userApplyIPage.getRecords().stream().map(UserApply::getId).collect(Collectors.toList()); + userApplyDao.readApples(uid, applyIds); + //返回消息 + return PageBaseResp.init(userApplyIPage, FriendAdapter.buildFriendApplyList(userApplyIPage.getRecords())); } /** @@ -139,34 +139,38 @@ public class FriendServiceImpl implements FriendService { */ @Override public FriendUnreadResp unread(Long uid) { - LambdaQueryChainWrapper wrapper = applyService.lambdaQuery(); - wrapper.eq(UserApply::getTargetId, uid) - .eq(UserApply::getReadStatus, UNREAD.getCode()); - return new FriendUnreadResp(applyService.count(wrapper)); + Integer unReadCount = userApplyDao.getUnReadCount(uid); + return new FriendUnreadResp(unReadCount); } @Override @Transactional - public void applyApprove(FriendApproveReq request) { - UserApply userApply = applyService.getById(request.getApplyId()); - if (Objects.isNull(userApply)) { - log.error("不存在申请记录:{}", request.getApplyId()); - return; - } - if (Objects.equals(userApply.getStatus(), AGREE.getCode())) { - log.error("已同意好友申请:{}", request.getApplyId()); - return; - } - LambdaUpdateChainWrapper updateWrapper = applyService.lambdaUpdate(); - updateWrapper.set(UserApply::getStatus, AGREE.getCode()) - .eq(UserApply::getId, request.getApplyId()); - applyService.update(updateWrapper); + @RedissonLock(key = "#uid") + public void applyApprove(Long uid, FriendApproveReq request) { + UserApply userApply = userApplyDao.getById(request.getApplyId()); + AssertUtil.isNotEmpty(userApply, "不存在申请记录"); + AssertUtil.equal(userApply.getTargetId(), uid, "不存在申请记录"); + AssertUtil.equal(userApply.getStatus(), AGREE.getCode(), "已同意好友申请"); + //同意申请 + userApplyDao.agree(request.getApplyId()); + //创建双方好友关系 + createFriend(uid, userApply.getUid()); + //创建一个聊天房间 + RoomFriend roomFriend = roomService.createFriendRoom(Arrays.asList(uid, userApply.getUid())); + //创建双方的会话 + contactService.createContact(uid, roomFriend.getRoomId()); + contactService.createContact(userApply.getUid(), roomFriend.getRoomId()); + //发送一条同意消息。。我们已经是好友了,开始聊天吧 + chatService.sendMsg(MessageAdapter.buildAgreeMsg(roomFriend.getRoomId()), uid); + } + + private void createFriend(Long uid, Long targetUid) { UserFriend userFriend1 = new UserFriend(); - userFriend1.setUid(userApply.getUid()); - userFriend1.setFriendUid(userApply.getTargetId()); + userFriend1.setUid(uid); + userFriend1.setFriendUid(targetUid); UserFriend userFriend2 = new UserFriend(); - userFriend2.setUid(userApply.getTargetId()); - userFriend2.setFriendUid(userApply.getUid()); - friendService.saveBatch(Lists.newArrayList(userFriend1, userFriend2)); + userFriend2.setUid(targetUid); + userFriend2.setFriendUid(uid); + userFriendDao.saveBatch(Lists.newArrayList(userFriend1, userFriend2)) } } diff --git a/mallchat-custom-server/src/test/java/com/abin/mallchat/custom/common/CommonTest.java b/mallchat-custom-server/src/test/java/com/abin/mallchat/custom/common/CommonTest.java new file mode 100644 index 0000000..96fb649 --- /dev/null +++ b/mallchat-custom-server/src/test/java/com/abin/mallchat/custom/common/CommonTest.java @@ -0,0 +1,18 @@ +package com.abin.mallchat.custom.common; + +import org.junit.Test; + +import static com.abin.mallchat.custom.user.service.adapter.FriendAdapter.buildFriendRoomKey; + +/** + * Description: + * Author: abin + * Date: 2023-07-22 + */ +public class CommonTest { + @Test + public void test() { + System.out.println(buildFriendRoomKey(100L, 102L)); + } + +}