Merge pull request #143 from Kkuil/friend

feat: 增加显示群主和管理员的功能
This commit is contained in:
zongzibinbin
2023-10-22 18:06:08 +08:00
committed by GitHub
9 changed files with 70 additions and 36 deletions

View File

@@ -5,10 +5,14 @@ import com.abin.mallchat.common.chat.domain.enums.GroupRoleEnum;
import com.abin.mallchat.common.chat.mapper.GroupMemberMapper; import com.abin.mallchat.common.chat.mapper.GroupMemberMapper;
import com.abin.mallchat.common.chat.service.cache.GroupMemberCache; import com.abin.mallchat.common.chat.service.cache.GroupMemberCache;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -23,6 +27,7 @@ import java.util.stream.Collectors;
public class GroupMemberDao extends ServiceImpl<GroupMemberMapper, GroupMember> { public class GroupMemberDao extends ServiceImpl<GroupMemberMapper, GroupMember> {
@Autowired @Autowired
@Lazy
private GroupMemberCache groupMemberCache; private GroupMemberCache groupMemberCache;
public List<Long> getMemberUidList(Long groupId) { public List<Long> getMemberUidList(Long groupId) {
@@ -42,6 +47,22 @@ public class GroupMemberDao extends ServiceImpl<GroupMemberMapper, GroupMember>
return list.stream().map(GroupMember::getUid).collect(Collectors.toList()); return list.stream().map(GroupMember::getUid).collect(Collectors.toList());
} }
/**
* 批量获取成员群角色
*
* @param groupId 群ID
* @param uidList 用户列表
* @return 成员群角色列表
*/
public Map<Long, Integer> getMemberMapRole(Long groupId, List<Long> uidList) {
List<GroupMember> list = lambdaQuery()
.eq(GroupMember::getGroupId, groupId)
.in(GroupMember::getUid, uidList)
.select(GroupMember::getUid, GroupMember::getRole)
.list();
return list.stream().collect(Collectors.toMap(GroupMember::getUid, GroupMember::getRole));
}
public GroupMember getMember(Long groupId, Long uid) { public GroupMember getMember(Long groupId, Long uid) {
return lambdaQuery() return lambdaQuery()
.eq(GroupMember::getGroupId, groupId) .eq(GroupMember::getGroupId, groupId)

View File

@@ -1,5 +1,6 @@
package com.abin.mallchat.common.user.domain.vo.response.ws; package com.abin.mallchat.common.user.domain.vo.response.ws;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
@@ -17,6 +18,7 @@ import java.util.Date;
@Builder @Builder
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ChatMemberResp { public class ChatMemberResp {
@ApiModelProperty("uid") @ApiModelProperty("uid")
private Long uid; private Long uid;
@@ -25,6 +27,12 @@ public class ChatMemberResp {
*/ */
@ApiModelProperty("在线状态 1在线 2离线") @ApiModelProperty("在线状态 1在线 2离线")
private Integer activeStatus; private Integer activeStatus;
/**
* 角色ID
*/
private Integer roleId;
@ApiModelProperty("最后一次上下线时间") @ApiModelProperty("最后一次上下线时间")
private Date lastOptTime; private Date lastOptTime;
} }

View File

@@ -1,25 +1,25 @@
#todo 记得把这些配置信息补充了 #todo ????????????
##################mysql配置################## ##################mysql??##################
mallchat.mysql.ip=127.0.0.1 mallchat.mysql.ip=127.0.0.1
mallchat.mysql.port=3306 mallchat.mysql.port=3306
mallchat.mysql.db=mallchat mallchat.mysql.db=mallchat
mallchat.mysql.username=root mallchat.mysql.username=root
mallchat.mysql.password=123456 mallchat.mysql.password=123456
##################redis配置################## ##################redis??##################
mallchat.redis.host=127.0.0.1 mallchat.redis.host=127.0.0.1
mallchat.redis.port=6379 mallchat.redis.port=6379
mallchat.redis.password=123456 mallchat.redis.password=123456
##################jwt################## ##################jwt##################
mallchat.jwt.secret=dsfsdfsdfsdfsd mallchat.jwt.secret=dsfsdfsdfsdfsd
##################微信公众号信息################## ##################???????##################
mallchat.wx.callback=http://limeng-test.nat300.top/ mallchat.wx.callback=http://limeng-test.nat300.top/
mallchat.wx.appId=wx6cb0974bff30cce0 mallchat.wx.appId=wx6cb0974bff30cce0
mallchat.wx.secret=072c615d9704d2e9bf0a048407928258 mallchat.wx.secret=072c615d9704d2e9bf0a048407928258
# 接口配置里的Token # ??????Token?
mallchat.wx.token=sdfsf mallchat.wx.token=sdfsf
# 接口配置里的EncodingAESKey # ??????EncodingAESKey?
mallchat.wx.aesKey=sha1 mallchat.wx.aesKey=sha1
##################OSS配置################## ##################OSS??##################
oss.enabled=true oss.enabled=true
oss.type=minio oss.type=minio
oss.endpoint=http://localhost:9000 oss.endpoint=http://localhost:9000
@@ -30,11 +30,11 @@ oss.bucketName=default
rocketmq.name-server=127.0.0.1:9876 rocketmq.name-server=127.0.0.1:9876
rocketmq.access-key=root rocketmq.access-key=root
rocketmq.secret-key=123456 rocketmq.secret-key=123456
##################gpt配置################## ##################gpt??##################
mallchat.chatgpt.use=false mallchat.chatgpt.use=false
mallchat.chatgpt.uid=10001 mallchat.chatgpt.uid=10001
mallchat.chatgpt.key=sk-wvWM0xGcxFfsddfsgxixbXK5tHovM mallchat.chatgpt.key=sk-wvWM0xGcxFfsddfsgxixbXK5tHovM
mallchat.chatgpt.proxyUrl=https://123.cc mallchat.chatgpt.proxyUrl=https://123.cc
mallchat.chatglm2.use=false mallchat.chatglm2.use=false
mallchat.chatglm2.url=http://v32134.cc mallchat.chatglm2.url=http://v32134.cc
mallchat.chatglm2.uid=10002 mallchat.chatglm2.uid=10002

View File

@@ -11,7 +11,7 @@ mybatis-plus:
spring: spring:
profiles: profiles:
#运行的环境 #运行的环境
active: my-prod active: test
application: application:
name: mallchat name: mallchat
datasource: datasource:

View File

@@ -42,7 +42,7 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin> </plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@@ -54,7 +54,7 @@ public interface ChatService {
* @param request * @param request
* @return * @return
*/ */
CursorPageBaseResp<ChatMemberResp> getMemberPage(List<Long> memberUidList, CursorPageBaseReq request); CursorPageBaseResp<ChatMemberResp> getMemberPage(List<Long> memberUidList, MemberReq request);
/** /**
* 获取消息列表 * 获取消息列表

View File

@@ -1,7 +1,9 @@
package com.abin.mallchat.custom.chat.service.adapter; package com.abin.mallchat.custom.chat.service.adapter;
import com.abin.mallchat.common.chat.dao.GroupMemberDao;
import com.abin.mallchat.common.chat.domain.entity.GroupMember; import com.abin.mallchat.common.chat.domain.entity.GroupMember;
import com.abin.mallchat.common.chat.domain.enums.GroupRoleEnum; import com.abin.mallchat.common.chat.domain.enums.GroupRoleEnum;
import com.abin.mallchat.common.chat.service.cache.GroupMemberCache;
import com.abin.mallchat.common.user.domain.entity.User; import com.abin.mallchat.common.user.domain.entity.User;
import com.abin.mallchat.common.user.domain.entity.UserFriend; import com.abin.mallchat.common.user.domain.entity.UserFriend;
import com.abin.mallchat.common.user.domain.enums.WSBaseResp; import com.abin.mallchat.common.user.domain.enums.WSBaseResp;
@@ -32,10 +34,8 @@ import static com.abin.mallchat.common.user.domain.vo.response.ws.WSMemberChange
@Component @Component
@Slf4j @Slf4j
public class MemberAdapter { public class MemberAdapter {
@Autowired
private UserCache userCache;
public static List<ChatMemberResp> buildMember(List<User> list) { public static List<ChatMemberResp> buildMember(Long roomId, List<User> list) {
return list.stream().map(a -> { return list.stream().map(a -> {
ChatMemberResp resp = new ChatMemberResp(); ChatMemberResp resp = new ChatMemberResp();
resp.setActiveStatus(a.getActiveStatus()); resp.setActiveStatus(a.getActiveStatus());

View File

@@ -95,7 +95,7 @@ public class ChatServiceImpl implements ChatService {
@Autowired @Autowired
private RoomGroupCache roomGroupCache; private RoomGroupCache roomGroupCache;
@Autowired @Autowired
private MQProducer mqProducer; private RoomGroupDao roomGroupDao;
/** /**
* 发送消息 * 发送消息
@@ -104,20 +104,20 @@ public class ChatServiceImpl implements ChatService {
@Transactional @Transactional
public Long sendMsg(ChatMessageReq request, Long uid) { public Long sendMsg(ChatMessageReq request, Long uid) {
check(request, uid); check(request, uid);
AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());//todo 这里先不扩展,后续再改 AbstractMsgHandler msgHandler = MsgHandlerFactory.getStrategyNoNull(request.getMsgType());// todo 这里先不扩展,后续再改
msgHandler.checkMsg(request, uid); msgHandler.checkMsg(request, uid);
//同步获取消息的跳转链接标题 // 同步获取消息的跳转链接标题
Message insert = MessageAdapter.buildMsgSave(request, uid); Message insert = MessageAdapter.buildMsgSave(request, uid);
messageDao.save(insert); messageDao.save(insert);
msgHandler.saveMsg(insert, request); msgHandler.saveMsg(insert, request);
//发布消息发送事件 // 发布消息发送事件
applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId())); applicationEventPublisher.publishEvent(new MessageSendEvent(this, insert.getId()));
return insert.getId(); return insert.getId();
} }
private void check(ChatMessageReq request, Long uid) { private void check(ChatMessageReq request, Long uid) {
Room room = roomCache.get(request.getRoomId()); Room room = roomCache.get(request.getRoomId());
if (room.isHotRoom()) {//全员群跳过校验 if (room.isHotRoom()) {// 全员群跳过校验
return; return;
} }
if (room.isRoomFriend()) { if (room.isRoomFriend()) {
@@ -145,36 +145,41 @@ public class ChatServiceImpl implements ChatService {
} }
@Override @Override
public CursorPageBaseResp<ChatMemberResp> getMemberPage(List<Long> memberUidList, CursorPageBaseReq request) { public CursorPageBaseResp<ChatMemberResp> getMemberPage(List<Long> memberUidList, MemberReq request) {
Pair<ChatActiveStatusEnum, String> pair = ChatMemberHelper.getCursorPair(request.getCursor()); Pair<ChatActiveStatusEnum, String> pair = ChatMemberHelper.getCursorPair(request.getCursor());
ChatActiveStatusEnum activeStatusEnum = pair.getKey(); ChatActiveStatusEnum activeStatusEnum = pair.getKey();
String timeCursor = pair.getValue(); String timeCursor = pair.getValue();
List<ChatMemberResp> resultList = new ArrayList<>();//最终列表 List<ChatMemberResp> resultList = new ArrayList<>();// 最终列表
Boolean isLast = Boolean.FALSE; Boolean isLast = Boolean.FALSE;
if (activeStatusEnum == ChatActiveStatusEnum.ONLINE) {//在线列表 if (activeStatusEnum == ChatActiveStatusEnum.ONLINE) {//在线列表
CursorPageBaseResp<User> cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(request.getPageSize(), timeCursor), ChatActiveStatusEnum.ONLINE); CursorPageBaseResp<User> cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(request.getPageSize(), timeCursor), ChatActiveStatusEnum.ONLINE);
resultList.addAll(MemberAdapter.buildMember(cursorPage.getList()));//添加在线列表 resultList.addAll(MemberAdapter.buildMember(request.getRoomId(), cursorPage.getList()));//添加在线列表
if (cursorPage.getIsLast()) {//如果是最后一页,从离线列表再补点数据 if (cursorPage.getIsLast()) {//如果是最后一页,从离线列表再补点数据
activeStatusEnum = ChatActiveStatusEnum.OFFLINE; activeStatusEnum = ChatActiveStatusEnum.OFFLINE;
Integer leftSize = request.getPageSize() - cursorPage.getList().size(); Integer leftSize = request.getPageSize() - cursorPage.getList().size();
cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(leftSize, null), ChatActiveStatusEnum.OFFLINE); cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(leftSize, null), ChatActiveStatusEnum.OFFLINE);
resultList.addAll(MemberAdapter.buildMember(cursorPage.getList()));//添加离线线列表 resultList.addAll(MemberAdapter.buildMember(request.getRoomId(), cursorPage.getList()));//添加离线线列表
} }
timeCursor = cursorPage.getCursor(); timeCursor = cursorPage.getCursor();
isLast = cursorPage.getIsLast(); isLast = cursorPage.getIsLast();
} else if (activeStatusEnum == ChatActiveStatusEnum.OFFLINE) {//离线列表 } else if (activeStatusEnum == ChatActiveStatusEnum.OFFLINE) {//离线列表
CursorPageBaseResp<User> cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(request.getPageSize(), timeCursor), ChatActiveStatusEnum.OFFLINE); CursorPageBaseResp<User> cursorPage = userDao.getCursorPage(memberUidList, new CursorPageBaseReq(request.getPageSize(), timeCursor), ChatActiveStatusEnum.OFFLINE);
resultList.addAll(MemberAdapter.buildMember(cursorPage.getList()));//添加离线线列表 resultList.addAll(MemberAdapter.buildMember(request.getRoomId(), cursorPage.getList()));//添加离线线列表
timeCursor = cursorPage.getCursor(); timeCursor = cursorPage.getCursor();
isLast = cursorPage.getIsLast(); isLast = cursorPage.getIsLast();
} }
//组装结果 // 获取群成员角色ID
List<Long> uidList = resultList.stream().map(ChatMemberResp::getUid).collect(Collectors.toList());
RoomGroup roomGroup = roomGroupDao.getByRoomId(request.getRoomId());
Map<Long, Integer> uidMapRole = groupMemberDao.getMemberMapRole(roomGroup.getId(), uidList);
resultList.forEach(member -> member.setRoleId(uidMapRole.get(member.getUid())));
// 组装结果
return new CursorPageBaseResp<>(ChatMemberHelper.generateCursor(activeStatusEnum, timeCursor), isLast, resultList); return new CursorPageBaseResp<>(ChatMemberHelper.generateCursor(activeStatusEnum, timeCursor), isLast, resultList);
} }
@Override @Override
public CursorPageBaseResp<ChatMessageResp> getMsgPage(ChatMessagePageReq request, Long receiveUid) { public CursorPageBaseResp<ChatMessageResp> getMsgPage(ChatMessagePageReq request, Long receiveUid) {
//用最后一条消息id来限制被踢出的人能看见的最大一条消息 // 用最后一条消息id来限制被踢出的人能看见的最大一条消息
Long lastMsgId = getLastMsgId(request.getRoomId(), receiveUid); Long lastMsgId = getLastMsgId(request.getRoomId(), receiveUid);
CursorPageBaseResp<Message> cursorPage = messageDao.getCursorPage(request.getRoomId(), request, lastMsgId); CursorPageBaseResp<Message> cursorPage = messageDao.getCursorPage(request.getRoomId(), request, lastMsgId);
if (cursorPage.isEmpty()) { if (cursorPage.isEmpty()) {
@@ -222,16 +227,16 @@ public class ChatServiceImpl implements ChatService {
@Override @Override
public void recallMsg(Long uid, ChatMessageBaseReq request) { public void recallMsg(Long uid, ChatMessageBaseReq request) {
Message message = messageDao.getById(request.getMsgId()); Message message = messageDao.getById(request.getMsgId());
//校验能不能执行撤回 // 校验能不能执行撤回
checkRecall(uid, message); checkRecall(uid, message);
//执行消息撤回 // 执行消息撤回
recallMsgHandler.recall(uid, message); recallMsgHandler.recall(uid, message);
} }
@Override @Override
@Cacheable(cacheNames = "member", key = "'memberList.'+#req.roomId") @Cacheable(cacheNames = "member", key = "'memberList.'+#req.roomId")
public List<ChatMemberListResp> getMemberList(ChatMessageMemberReq req) { public List<ChatMemberListResp> getMemberList(ChatMessageMemberReq req) {
if (Objects.equals(1L, req.getRoomId())) {//大群聊可看见所有人 if (Objects.equals(1L, req.getRoomId())) {// 大群聊可看见所有人
return userDao.getMemberList() return userDao.getMemberList()
.stream() .stream()
.map(a -> { .map(a -> {
@@ -259,7 +264,7 @@ public class ChatServiceImpl implements ChatService {
AssertUtil.isNotEmpty(message, "消息id有误"); AssertUtil.isNotEmpty(message, "消息id有误");
AssertUtil.equal(uid, message.getFromUid(), "只能查看自己的消息"); AssertUtil.equal(uid, message.getFromUid(), "只能查看自己的消息");
CursorPageBaseResp<Contact> page; CursorPageBaseResp<Contact> page;
if (request.getSearchType() == 1) {//已读 if (request.getSearchType() == 1) {// 已读
page = contactDao.getReadPage(message, request); page = contactDao.getReadPage(message, request);
} else { } else {
page = contactDao.getUnReadPage(message, request); page = contactDao.getUnReadPage(message, request);
@@ -306,12 +311,12 @@ public class ChatServiceImpl implements ChatService {
return new ArrayList<>(); return new ArrayList<>();
} }
Map<Long, Message> replyMap = new HashMap<>(); Map<Long, Message> replyMap = new HashMap<>();
//批量查出回复的消息 // 批量查出回复的消息
List<Long> replyIds = messages.stream().map(Message::getReplyMsgId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); List<Long> replyIds = messages.stream().map(Message::getReplyMsgId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(replyIds)) { if (CollectionUtil.isNotEmpty(replyIds)) {
replyMap = messageDao.listByIds(replyIds).stream().collect(Collectors.toMap(Message::getId, Function.identity())); replyMap = messageDao.listByIds(replyIds).stream().collect(Collectors.toMap(Message::getId, Function.identity()));
} }
//查询消息标志 // 查询消息标志
List<MessageMark> msgMark = messageMarkDao.getValidMarkByMsgIdBatch(messages.stream().map(Message::getId).collect(Collectors.toList())); List<MessageMark> msgMark = messageMarkDao.getValidMarkByMsgIdBatch(messages.stream().map(Message::getId).collect(Collectors.toList()));
return MessageAdapter.buildMsgResp(messages, replyMap, msgMark, receiveUid); return MessageAdapter.buildMsgResp(messages, replyMap, msgMark, receiveUid);
} }

View File

@@ -17,14 +17,14 @@ public class CreateTokenTest {
@Test @Test
public void create(){ public void create(){
String token = JWT.create() String token = JWT.create()
.withClaim("uid", 10004L) // 只存一个uid信息其他的自己去redis查 .withClaim("uid", 10276L) // 只存一个uid信息其他的自己去redis查
.withClaim("createTime", new Date()) .withClaim("createTime", new Date())
.sign(Algorithm.HMAC256("dsfsdfsdfsdfsd")); // signature .sign(Algorithm.HMAC256("dsfsdfsdfsdfsd")); // signature
log.info("生成的token为 {}",token); log.info("生成的token为 {}",token);
try { try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256("dsfsdfsdfsdfsc")).build(); JWTVerifier verifier = JWT.require(Algorithm.HMAC256("dsfsdfsdfsdfsd")).build();
DecodedJWT jwt = verifier.verify(token); DecodedJWT jwt = verifier.verify(token);
log.info(jwt.getClaims().toString()); log.info(jwt.getClaims().toString());
} catch (Exception e) { } catch (Exception e) {