diff --git a/commom/src/main/java/com/lx/common/contant/RedisKey.java b/commom/src/main/java/com/lx/common/contant/RedisKey.java index 104f808..97756c6 100644 --- a/commom/src/main/java/com/lx/common/contant/RedisKey.java +++ b/commom/src/main/java/com/lx/common/contant/RedisKey.java @@ -2,17 +2,25 @@ package com.lx.common.contant; public class RedisKey { + // im-server最大id,从0开始递增 + public final static String IM_MAX_SERVER_ID = "im:max_server_id"; + // 用户ID所连接的IM-server的ID + public final static String IM_USER_SERVER_ID = "im:user:server_id:"; + // 未读私聊消息队列 + public final static String IM_UNREAD_PRIVATE_MESSAGE = "im:unread:private:"; + // 未读群聊消息队列 + public final static String IM_UNREAD_GROUP_MESSAGE = "im:unread:group:"; + // 已读私聊消息id队列 + public final static String IM_READED_PRIVATE_MESSAGE_ID = "im:readed:private:id"; + // 已读群聊消息位置(已读最大id) + public final static String IM_GROUP_READED_POSITION = "im:readed:group:position"; + // 缓存前缀 public final static String IM_CACHE = "im:cache:"; - + // 缓存是否好友:bool public final static String IM_CACHE_FRIEND = IM_CACHE+"friend"; - + // 缓存群聊信息 public final static String IM_CACHE_GROUP = IM_CACHE+"group"; + // 缓存群聊成员id + public final static String IM_CACHE_GROUP_MEMBER_ID = IM_CACHE+"group_member_ids"; - public final static String IM_CACHE_GROUP_MEMBER = IM_CACHE+"groupMember"; - - public final static String IM_USER_SERVER_ID = "im:user_server_id:"; - - public final static String IM_UNREAD_MESSAGE = "im:unread_msg:"; - - public final static String IM_ALREADY_READED_MESSAGE = "im:already_read_msg"; } diff --git a/commom/src/main/java/com/lx/common/enums/WSCmdEnum.java b/commom/src/main/java/com/lx/common/enums/WSCmdEnum.java index 9444b44..ccac251 100644 --- a/commom/src/main/java/com/lx/common/enums/WSCmdEnum.java +++ b/commom/src/main/java/com/lx/common/enums/WSCmdEnum.java @@ -3,7 +3,7 @@ package com.lx.common.enums; public enum WSCmdEnum { HEARTBEAT(0,"心跳"), - SINGLE_MESSAGE(1,"单发消息"), + PRIVATE_MESSAGE(1,"私聊消息"), GROUP_MESSAGE(2,"群发消息"); diff --git a/commom/src/main/java/com/lx/common/model/im/GroupMessageInfo.java b/commom/src/main/java/com/lx/common/model/im/GroupMessageInfo.java new file mode 100644 index 0000000..524fd47 --- /dev/null +++ b/commom/src/main/java/com/lx/common/model/im/GroupMessageInfo.java @@ -0,0 +1,24 @@ +package com.lx.common.model.im; + +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class GroupMessageInfo { + + private Long id; + + private Long groupId; + + private Long sendId; + + private List recvIds; + + private String content; + + private Integer type; + + private Date sendTime; +} diff --git a/commom/src/main/java/com/lx/common/model/im/SingleMessageInfo.java b/commom/src/main/java/com/lx/common/model/im/PrivateMessageInfo.java similarity index 68% rename from commom/src/main/java/com/lx/common/model/im/SingleMessageInfo.java rename to commom/src/main/java/com/lx/common/model/im/PrivateMessageInfo.java index ba4383f..e671a57 100644 --- a/commom/src/main/java/com/lx/common/model/im/SingleMessageInfo.java +++ b/commom/src/main/java/com/lx/common/model/im/PrivateMessageInfo.java @@ -5,13 +5,13 @@ import lombok.Data; import java.util.Date; @Data -public class SingleMessageInfo { +public class PrivateMessageInfo { private long id; - private Long sendUserId; + private Long sendId; - private Long recvUserId; + private Long recvId; private String content; diff --git a/im-platform/src/main/java/com/lx/implatform/controller/GroupMessageController.java b/im-platform/src/main/java/com/lx/implatform/controller/GroupMessageController.java index d3e5784..e872ea3 100644 --- a/im-platform/src/main/java/com/lx/implatform/controller/GroupMessageController.java +++ b/im-platform/src/main/java/com/lx/implatform/controller/GroupMessageController.java @@ -1,14 +1,37 @@ package com.lx.implatform.controller; +import com.lx.common.result.Result; +import com.lx.common.result.ResultUtils; +import com.lx.implatform.service.IGroupMemberService; +import com.lx.implatform.service.IGroupMessageService; +import com.lx.implatform.vo.GroupMessageVO; +import com.lx.implatform.vo.PrivateMessageVO; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; + @RestController @RequestMapping("/group/message") public class GroupMessageController { + @Autowired + private IGroupMessageService groupMessageService; + + + @PostMapping("/send") + @ApiOperation(value = "发送群聊消息",notes="发送群聊消息") + public Result register(@Valid @RequestBody GroupMessageVO vo){ + groupMessageService.sendMessage(vo); + return ResultUtils.success(); + } + } diff --git a/im-platform/src/main/java/com/lx/implatform/entity/GroupMessage.java b/im-platform/src/main/java/com/lx/implatform/entity/GroupMessage.java index ccb8ffd..93d1542 100644 --- a/im-platform/src/main/java/com/lx/implatform/entity/GroupMessage.java +++ b/im-platform/src/main/java/com/lx/implatform/entity/GroupMessage.java @@ -45,8 +45,8 @@ public class GroupMessage extends Model { /** * 发送用户id */ - @TableField("send_user_id") - private Long sendUserId; + @TableField("send_id") + private Long sendId; /** * 发送内容 diff --git a/im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java b/im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java index a147b6b..dec2d41 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java +++ b/im-platform/src/main/java/com/lx/implatform/service/IGroupMemberService.java @@ -18,17 +18,19 @@ public interface IGroupMemberService extends IService { - GroupMember findByGroupAndUserId(long groupId,long userId); + GroupMember findByGroupAndUserId(Long groupId,Long userId); - List findByUserId(long userId); + List findByUserId(Long userId); - List findByGroupId(long groupId); + List findByGroupId(Long groupId); + + List findUserIdsByGroupId(Long groupId); boolean save(GroupMember member); - boolean saveBatch(long groupId,List members); + boolean saveBatch(Long groupId,List members); - void removeByGroupId(long groupId); + void removeByGroupId(Long groupId); - void removeByGroupAndUserId(long groupId,long userId); + void removeByGroupAndUserId(Long groupId,Long userId); } diff --git a/im-platform/src/main/java/com/lx/implatform/service/IGroupMessageService.java b/im-platform/src/main/java/com/lx/implatform/service/IGroupMessageService.java index 546f3eb..d805dca 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/IGroupMessageService.java +++ b/im-platform/src/main/java/com/lx/implatform/service/IGroupMessageService.java @@ -2,15 +2,14 @@ package com.lx.implatform.service; import com.lx.implatform.entity.GroupMessage; import com.baomidou.mybatisplus.extension.service.IService; +import com.lx.implatform.vo.GroupMessageVO; +import com.lx.implatform.vo.PrivateMessageVO; + -/** - *

- * 群消息 服务类 - *

- * - * @author blue - * @since 2022-10-31 - */ public interface IGroupMessageService extends IService { + + void sendMessage(GroupMessageVO vo); + + void pullUnreadMessage(); } diff --git a/im-platform/src/main/java/com/lx/implatform/service/IPrivateMessageService.java b/im-platform/src/main/java/com/lx/implatform/service/IPrivateMessageService.java index 242bce3..012f78f 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/IPrivateMessageService.java +++ b/im-platform/src/main/java/com/lx/implatform/service/IPrivateMessageService.java @@ -4,14 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.lx.implatform.entity.PrivateMessage; import com.lx.implatform.vo.PrivateMessageVO; -/** - *

- * 服务类 - *

- * - * @author blue - * @since 2022-10-01 - */ + public interface IPrivateMessageService extends IService { void sendMessage(PrivateMessageVO vo); diff --git a/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java b/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java index bf1de49..7d745c4 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java +++ b/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMemberServiceImpl.java @@ -8,13 +8,14 @@ import com.lx.implatform.service.IGroupMemberService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; -import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; -@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER) +@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER_ID) @Service public class GroupMemberServiceImpl extends ServiceImpl implements IGroupMemberService { @@ -41,7 +42,7 @@ public class GroupMemberServiceImpl extends ServiceImpl members) { + public boolean saveBatch(Long groupId,List members) { return super.saveBatch(members); } @@ -53,7 +54,7 @@ public class GroupMemberServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); wrapper.lambda().eq(GroupMember::getGroupId,groupId) .eq(GroupMember::getUserId,userId); @@ -67,7 +68,7 @@ public class GroupMemberServiceImpl extends ServiceImpl findByUserId(long userId) { + public List findByUserId(Long userId) { QueryWrapper memberWrapper = new QueryWrapper(); memberWrapper.lambda().eq(GroupMember::getUserId, userId); return this.list(memberWrapper); @@ -80,12 +81,20 @@ public class GroupMemberServiceImpl extends ServiceImpl findByGroupId(long groupId) { + public List findByGroupId(Long groupId) { QueryWrapper memberWrapper = new QueryWrapper(); memberWrapper.lambda().eq(GroupMember::getGroupId, groupId); return this.list(memberWrapper); } + + @Cacheable(key="#groupId") + @Override + public List findUserIdsByGroupId(Long groupId) { + List members = this.findByGroupId(groupId); + return members.stream().map(m->m.getUserId()).collect(Collectors.toList()); + } + /** *根据群聊id删除成员信息 * @@ -94,7 +103,7 @@ public class GroupMemberServiceImpl extends ServiceImpl wrapper = new QueryWrapper(); wrapper.lambda().eq(GroupMember::getGroupId,groupId); this.remove(wrapper); @@ -109,7 +118,7 @@ public class GroupMemberServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); wrapper.lambda().eq(GroupMember::getGroupId,groupId) .eq(GroupMember::getUserId,userId); diff --git a/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMessageServiceImpl.java index a186758..e9a8ad4 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/lx/implatform/service/impl/GroupMessageServiceImpl.java @@ -1,20 +1,91 @@ package com.lx.implatform.service.impl; +import com.lx.common.contant.RedisKey; +import com.lx.common.enums.ResultCode; +import com.lx.common.model.im.GroupMessageInfo; +import com.lx.common.util.BeanUtils; +import com.lx.implatform.entity.Group; import com.lx.implatform.entity.GroupMessage; +import com.lx.implatform.exception.GlobalException; import com.lx.implatform.mapper.GroupMessageMapper; +import com.lx.implatform.service.IGroupMemberService; import com.lx.implatform.service.IGroupMessageService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.lx.implatform.service.IGroupService; +import com.lx.implatform.session.SessionContext; +import com.lx.implatform.vo.GroupMessageVO; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -/** - *

- * 群消息 服务实现类 - *

- * - * @author blue - * @since 2022-10-31 - */ +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + + @Service public class GroupMessageServiceImpl extends ServiceImpl implements IGroupMessageService { + + @Autowired + private IGroupService groupService; + + @Autowired + private IGroupMemberService groupMemberService; + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 发送群聊消息(与mysql所有交换都要进行缓存) + * + * @param vo + * @return + */ + @Override + public void sendMessage(GroupMessageVO vo) { + Long userId = SessionContext.getSession().getId(); + Group group = groupService.findById(vo.getGroupId()); + if(group == null){ + throw new GlobalException(ResultCode.PROGRAM_ERROR,"群聊不存在或已解散"); + } + // 保存消息 + GroupMessage msg = BeanUtils.copyProperties(vo, GroupMessage.class); + msg.setSendId(userId); + msg.setSendTime(new Date()); + this.save(msg); + // 根据群聊每个成员所连的IM-server,进行分组 + Map> serverMap = new ConcurrentHashMap<>(); + List userIds = groupMemberService.findUserIdsByGroupId(group.getId()); + userIds.parallelStream().forEach(id->{ + String key = RedisKey.IM_USER_SERVER_ID + id; + Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + if(serverId != null){ + if(serverMap.containsKey(serverId)){ + serverMap.get(serverId).add(id); + }else { + List list = Collections.synchronizedList(new LinkedList()); + list.add(id); + serverMap.put(serverId,list); + } + } + }); + // 逐个server发送 + for (Map.Entry> entry : serverMap.entrySet()) { + GroupMessageInfo msgInfo = BeanUtils.copyProperties(msg, GroupMessageInfo.class); + msgInfo.setRecvIds(entry.getValue()); + String key = RedisKey.IM_UNREAD_PRIVATE_MESSAGE +entry.getKey(); + redisTemplate.opsForList().rightPush(key,msgInfo); + } + } + + /** + * 异步拉取群聊消息,通过websocket异步推送 + * + * @return + */ + @Override + public void pullUnreadMessage() { + + } } diff --git a/im-platform/src/main/java/com/lx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/lx/implatform/service/impl/PrivateMessageServiceImpl.java index 3f646d8..b176a01 100644 --- a/im-platform/src/main/java/com/lx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/lx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -32,6 +32,12 @@ public class PrivateMessageServiceImpl extends ServiceImpl redisTemplate; + /** + * 发送私聊消息 + * + * @param vo + * @return + */ @Override public void sendMessage(PrivateMessageVO vo) { Long userId = SessionContext.getSession().getId(); @@ -47,22 +53,27 @@ public class PrivateMessageServiceImpl extends ServiceImpl implements IU private boolean isOnline(Long userId){ String key = RedisKey.IM_USER_SERVER_ID + userId; - String serverId = (String) redisTemplate.opsForValue().get(key); - return StringUtils.isNotEmpty(serverId); + Integer serverId = (Integer) redisTemplate.opsForValue().get(key); + return serverId!=null && serverId>=0; } } diff --git a/im-platform/src/main/java/com/lx/implatform/task/PullAlreadyReadMessageTask.java b/im-platform/src/main/java/com/lx/implatform/task/PullAlreadyReadMessageTask.java index fa1b805..c9c1595 100644 --- a/im-platform/src/main/java/com/lx/implatform/task/PullAlreadyReadMessageTask.java +++ b/im-platform/src/main/java/com/lx/implatform/task/PullAlreadyReadMessageTask.java @@ -40,7 +40,7 @@ public class PullAlreadyReadMessageTask { @Override public void run() { try { - String key = RedisKey.IM_ALREADY_READED_MESSAGE; + String key = RedisKey.IM_READED_PRIVATE_MESSAGE_ID; Integer msgId = (Integer)redisTemplate.opsForList().leftPop(key,1, TimeUnit.SECONDS); if(msgId!=null){ UpdateWrapper updateWrapper = new UpdateWrapper<>(); diff --git a/im-platform/src/main/java/com/lx/implatform/vo/GroupMessageVO.java b/im-platform/src/main/java/com/lx/implatform/vo/GroupMessageVO.java new file mode 100644 index 0000000..297a418 --- /dev/null +++ b/im-platform/src/main/java/com/lx/implatform/vo/GroupMessageVO.java @@ -0,0 +1,28 @@ +package com.lx.implatform.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("群聊消息VO") +public class GroupMessageVO { + + @NotNull(message="群聊id不可为空") + @ApiModelProperty(value = "群聊id") + private Long groupId; + + + @Length(max=1024,message = "内容长度不得大于1024") + @NotEmpty(message="发送内容不可为空") + @ApiModelProperty(value = "发送内容") + private String content; + + @NotNull(message="发送内容不可为空") + @ApiModelProperty(value = "消息类型") + private Integer type; +} diff --git a/im-platform/src/main/java/com/lx/implatform/vo/PrivateMessageVO.java b/im-platform/src/main/java/com/lx/implatform/vo/PrivateMessageVO.java index d781e53..ac4f0e0 100644 --- a/im-platform/src/main/java/com/lx/implatform/vo/PrivateMessageVO.java +++ b/im-platform/src/main/java/com/lx/implatform/vo/PrivateMessageVO.java @@ -10,7 +10,7 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; @Data -@ApiModel("单发消息VO") +@ApiModel("私聊消息VO") public class PrivateMessageVO { diff --git a/im-server/src/main/java/com/lx/implatform/imserver/IMServerApp.java b/im-server/src/main/java/com/lx/implatform/imserver/IMServerApp.java index 123804a..b4a66de 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/IMServerApp.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/IMServerApp.java @@ -2,6 +2,7 @@ package com.lx.implatform.imserver; import com.lx.implatform.imserver.websocket.WebsocketServer; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -20,6 +21,8 @@ public class IMServerApp implements CommandLineRunner { @Value("${websocket.port}") private int port; + @Autowired + private WebsocketServer WSServer; public static void main(String[] args) { SpringApplication.run(IMServerApp.class); @@ -27,6 +30,6 @@ public class IMServerApp implements CommandLineRunner { public void run(String... args) throws Exception { - new WebsocketServer().start(port); + WSServer.start(port); } } diff --git a/im-server/src/main/java/com/lx/implatform/imserver/task/AbstractPullMessageTask.java b/im-server/src/main/java/com/lx/implatform/imserver/task/AbstractPullMessageTask.java new file mode 100644 index 0000000..603ef11 --- /dev/null +++ b/im-server/src/main/java/com/lx/implatform/imserver/task/AbstractPullMessageTask.java @@ -0,0 +1,49 @@ +package com.lx.implatform.imserver.task; + +import com.lx.implatform.imserver.websocket.WebsocketServer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Slf4j +public abstract class AbstractPullMessageTask{ + + private int threadNum = 1; + private ExecutorService executorService; + + @Autowired + private WebsocketServer WSServer; + + public AbstractPullMessageTask(){ + this.threadNum = 1; + } + + public AbstractPullMessageTask(int threadNum){ + this.threadNum = threadNum; + } + + @PostConstruct + public void init(){ + // 初始化定时器 + executorService = Executors.newFixedThreadPool(threadNum); + executorService.execute(new Runnable() { + @Override + public void run() { + try{ + if(WSServer.isReady()){ + pullMessage(); + } + Thread.sleep(100); + }catch (Exception e){ + log.error("任务调度异常",e); + } + executorService.execute(this); + } + }); + } + + public abstract void pullMessage(); +} diff --git a/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadGroupMessageTask.java b/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadGroupMessageTask.java new file mode 100644 index 0000000..3138487 --- /dev/null +++ b/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadGroupMessageTask.java @@ -0,0 +1,46 @@ +package com.lx.implatform.imserver.task; + +import com.lx.common.contant.RedisKey; +import com.lx.common.enums.WSCmdEnum; +import com.lx.common.model.im.GroupMessageInfo; +import com.lx.common.model.im.PrivateMessageInfo; +import com.lx.implatform.imserver.websocket.WebsocketChannelCtxHloder; +import com.lx.implatform.imserver.websocket.WebsocketServer; +import com.lx.implatform.imserver.websocket.processor.MessageProcessor; +import com.lx.implatform.imserver.websocket.processor.ProcessorFactory; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class PullUnreadGroupMessageTask extends AbstractPullMessageTask { + + @Autowired + private WebsocketServer WSServer; + + @Autowired + private RedisTemplate redisTemplate; + + + @Override + public void pullMessage() { + // 从redis拉取未读消息 + String key = RedisKey.IM_UNREAD_GROUP_MESSAGE + WSServer.getServerId(); + List messageInfos = redisTemplate.opsForList().range(key,0,-1); + for(Object o: messageInfos){ + redisTemplate.opsForList().leftPop(key); + GroupMessageInfo messageInfo = (GroupMessageInfo)o; + MessageProcessor processor = ProcessorFactory.createProcessor(WSCmdEnum.PRIVATE_MESSAGE); + processor.process(null,messageInfo); + } + } + + + +} diff --git a/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadMessageTask.java b/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadPrivateMessageTask.java similarity index 71% rename from im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadMessageTask.java rename to im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadPrivateMessageTask.java index d6a0bd7..f802282 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadMessageTask.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/task/PullUnreadPrivateMessageTask.java @@ -3,7 +3,7 @@ package com.lx.implatform.imserver.task; import com.lx.common.contant.RedisKey; import com.lx.common.enums.WSCmdEnum; -import com.lx.common.model.im.SingleMessageInfo; +import com.lx.common.model.im.PrivateMessageInfo; import com.lx.implatform.imserver.websocket.WebsocketChannelCtxHloder; import com.lx.implatform.imserver.websocket.WebsocketServer; import com.lx.implatform.imserver.websocket.processor.MessageProcessor; @@ -20,26 +20,29 @@ import java.util.List; @Slf4j @Component -public class PullUnreadMessageTask { +public class PullUnreadPrivateMessageTask extends AbstractPullMessageTask { + @Autowired + private WebsocketServer WSServer; @Autowired private RedisTemplate redisTemplate; - @Scheduled(fixedRate=100) - public void pullUnreadMessage() { - + @Override + public void pullMessage() { + log.info(Thread.currentThread().getName()); // 从redis拉取未读消息 - String key = RedisKey.IM_UNREAD_MESSAGE + WebsocketServer.LOCAL_SERVER_ID; + String key = RedisKey.IM_UNREAD_PRIVATE_MESSAGE + WSServer.getServerId(); List messageInfos = redisTemplate.opsForList().range(key,0,-1); for(Object o: messageInfos){ redisTemplate.opsForList().leftPop(key); - SingleMessageInfo messageInfo = (SingleMessageInfo)o; - ChannelHandlerContext ctx = WebsocketChannelCtxHloder.getChannelCtx(messageInfo.getRecvUserId()); + PrivateMessageInfo messageInfo = (PrivateMessageInfo)o; + ChannelHandlerContext ctx = WebsocketChannelCtxHloder.getChannelCtx(messageInfo.getRecvId()); if(ctx != null){ - MessageProcessor processor = ProcessorFactory.createProcessor(WSCmdEnum.SINGLE_MESSAGE); + MessageProcessor processor = ProcessorFactory.createProcessor(WSCmdEnum.PRIVATE_MESSAGE); processor.process(ctx,messageInfo); } } } + } diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebSocketHandler.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebSocketHandler.java index 4c4a4a6..65ec25b 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebSocketHandler.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebSocketHandler.java @@ -1,7 +1,9 @@ package com.lx.implatform.imserver.websocket; +import cn.hutool.core.bean.BeanUtil; import com.lx.common.contant.RedisKey; import com.lx.common.enums.WSCmdEnum; +import com.lx.common.model.im.HeartbeatInfo; import com.lx.common.model.im.SendInfo; import com.lx.common.util.SpringContextHolder; import com.lx.implatform.imserver.websocket.processor.MessageProcessor; @@ -14,6 +16,8 @@ import io.netty.util.AttributeKey; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; +import java.util.HashMap; + /** * WebSocket 长连接下 文本帧的处理器 @@ -27,8 +31,10 @@ public class WebSocketHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, SendInfo sendInfo) throws Exception { // 创建处理器进行处理 + HashMap map = (HashMap)sendInfo.getData(); + HeartbeatInfo beatInfo = BeanUtil.fillBeanWithMap(map, new HeartbeatInfo(), false); MessageProcessor processor = ProcessorFactory.createProcessor(WSCmdEnum.fromCode(sendInfo.getCmd())); - processor.process(ctx,processor.transform(sendInfo.getData())); + processor.process(ctx,beatInfo); } /** diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebsocketServer.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebsocketServer.java index c083859..7a64946 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebsocketServer.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/WebsocketServer.java @@ -1,5 +1,6 @@ package com.lx.implatform.imserver.websocket; +import com.lx.common.contant.RedisKey; import com.lx.implatform.imserver.websocket.endecode.MessageProtocolDecoder; import com.lx.implatform.imserver.websocket.endecode.MessageProtocolEncoder; import io.netty.bootstrap.ServerBootstrap; @@ -11,7 +12,9 @@ import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.timeout.IdleStateHandler; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @@ -21,13 +24,27 @@ import java.util.concurrent.TimeUnit; @Component public class WebsocketServer { - public static String LOCAL_SERVER_ID = UUID.randomUUID().toString(); + public static long serverId = 0; + + @Autowired + RedisTemplate redisTemplate; + + private volatile boolean ready = false; + - @Value("${websocket.port}") - private int port; @PostConstruct public void init(){ - //this.start(port); + // 初始化SERVER_ID + String key = RedisKey.IM_MAX_SERVER_ID; + serverId = redisTemplate.opsForValue().increment(key,1); + } + + public boolean isReady(){ + return ready; + } + + public long getServerId(){ + return serverId; } public void start(int port) { @@ -64,10 +81,12 @@ public class WebsocketServer { .option(ChannelOption.SO_BACKLOG, 5) // 表示连接保活,相当于心跳机制,默认为7200s .childOption(ChannelOption.SO_KEEPALIVE, true); - + // 就绪标志 + this.ready = true; try { // 绑定端口,启动select线程,轮询监听channel事件,监听到事件之后就会交给从线程池处理 Channel channel = bootstrap.bind(port).sync().channel(); + // 等待服务端口关闭 channel.closeFuture().sync(); } catch (InterruptedException e) { diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/GroupMessageProcessor.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/GroupMessageProcessor.java new file mode 100644 index 0000000..4efa1db --- /dev/null +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/GroupMessageProcessor.java @@ -0,0 +1,46 @@ +package com.lx.implatform.imserver.websocket.processor; + +import com.lx.common.contant.RedisKey; +import com.lx.common.enums.WSCmdEnum; +import com.lx.common.model.im.GroupMessageInfo; +import com.lx.common.model.im.SendInfo; +import com.lx.implatform.imserver.websocket.WebsocketChannelCtxHloder; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Slf4j +@Component +public class GroupMessageProcessor implements MessageProcessor { + + @Autowired + private RedisTemplate redisTemplate; + + @Async + @Override + public void process(ChannelHandlerContext ctx, GroupMessageInfo data) { + log.info("接收到群消息,发送者:{},群id:{},内容:{}",data.getSendId(),data.getGroupId(),data.getContent()); + List recvIds = data.getRecvIds(); + // 接收者id列表不需要传输,节省带宽 + data.setRecvIds(null); + for(Long recvId:recvIds){ + ChannelHandlerContext channelCtx = WebsocketChannelCtxHloder.getChannelCtx(recvId); + if(channelCtx != null){ + // 推送消息到用户 + SendInfo sendInfo = new SendInfo(); + sendInfo.setCmd(WSCmdEnum.GROUP_MESSAGE.getCode()); + sendInfo.setData(data); + channelCtx.channel().writeAndFlush(sendInfo); + // 设置已读最大id + String key = RedisKey.IM_GROUP_READED_POSITION + data.getGroupId(); + redisTemplate.opsForValue().set(key,data.getId()); + } + } + } + +} diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/HeartbeatProcessor.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/HeartbeatProcessor.java index 79f793e..933c525 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/HeartbeatProcessor.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/HeartbeatProcessor.java @@ -21,12 +21,17 @@ import java.util.concurrent.TimeUnit; @Component public class HeartbeatProcessor implements MessageProcessor { + + @Autowired + private WebsocketServer WSServer; + @Autowired RedisTemplate redisTemplate; @Override public void process(ChannelHandlerContext ctx, HeartbeatInfo beatInfo) { - log.info("接收到心跳,channelId:{},userId:{}",ctx.channel().id().asLongText(),beatInfo.getUserId()); + log.info("接收到心跳,userId:{}",beatInfo.getUserId()); + // 绑定用户和channel WebsocketChannelCtxHloder.addChannelCtx(beatInfo.getUserId(),ctx); // 设置属性 @@ -35,7 +40,7 @@ public class HeartbeatProcessor implements MessageProcessor { // 在redis上记录每个user的channelId,15秒没有心跳,则自动过期 String key = RedisKey.IM_USER_SERVER_ID+beatInfo.getUserId(); - redisTemplate.opsForValue().set(key, WebsocketServer.LOCAL_SERVER_ID,15, TimeUnit.SECONDS); + redisTemplate.opsForValue().set(key, WSServer.getServerId(),15, TimeUnit.SECONDS); // 响应ws SendInfo sendInfo = new SendInfo(); @@ -43,9 +48,4 @@ public class HeartbeatProcessor implements MessageProcessor { ctx.channel().writeAndFlush(sendInfo); } - public HeartbeatInfo transform(Object o){ - HashMap map = (HashMap)o; - HeartbeatInfo beatInfo =BeanUtil.fillBeanWithMap(map, new HeartbeatInfo(), false); - return beatInfo; - } } diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/MessageProcessor.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/MessageProcessor.java index e6c7400..71f4ac9 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/MessageProcessor.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/MessageProcessor.java @@ -6,5 +6,4 @@ public interface MessageProcessor { void process(ChannelHandlerContext ctx,T data); - T transform(Object o); } diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/SingleMessageProcessor.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/PrivateMessageProcessor.java similarity index 58% rename from im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/SingleMessageProcessor.java rename to im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/PrivateMessageProcessor.java index 1eaf2ad..6450172 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/SingleMessageProcessor.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/PrivateMessageProcessor.java @@ -1,10 +1,9 @@ package com.lx.implatform.imserver.websocket.processor; -import cn.hutool.core.bean.BeanUtil; import com.lx.common.contant.RedisKey; import com.lx.common.enums.WSCmdEnum; import com.lx.common.model.im.SendInfo; -import com.lx.common.model.im.SingleMessageInfo; +import com.lx.common.model.im.PrivateMessageInfo; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -12,34 +11,26 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; -import java.util.HashMap; - @Slf4j @Component -public class SingleMessageProcessor implements MessageProcessor { +public class PrivateMessageProcessor implements MessageProcessor { @Autowired private RedisTemplate redisTemplate; @Async @Override - public void process(ChannelHandlerContext ctx, SingleMessageInfo data) { - log.info("接收到消息,发送者:{},接收者:{},内容:{}",data.getSendUserId(),data.getRecvUserId(),data.getContent()); + public void process(ChannelHandlerContext ctx, PrivateMessageInfo data) { + log.info("接收到消息,发送者:{},接收者:{},内容:{}",data.getSendId(),data.getRecvId(),data.getContent()); // 推送消息到用户 SendInfo sendInfo = new SendInfo(); - sendInfo.setCmd(WSCmdEnum.SINGLE_MESSAGE.getCode()); + sendInfo.setCmd(WSCmdEnum.PRIVATE_MESSAGE.getCode()); sendInfo.setData(data); ctx.channel().writeAndFlush(sendInfo); // 已读消息推送至redis,等待更新数据库 - String key = RedisKey.IM_ALREADY_READED_MESSAGE; + String key = RedisKey.IM_READED_PRIVATE_MESSAGE_ID; redisTemplate.opsForList().rightPush(key,data.getId()); } - @Override - public SingleMessageInfo transform(Object o) { - HashMap map = (HashMap)o; - SingleMessageInfo info = BeanUtil.fillBeanWithMap(map, new SingleMessageInfo(), false); - return info; - } } diff --git a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/ProcessorFactory.java b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/ProcessorFactory.java index f402f9f..8574abf 100644 --- a/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/ProcessorFactory.java +++ b/im-server/src/main/java/com/lx/implatform/imserver/websocket/processor/ProcessorFactory.java @@ -11,8 +11,8 @@ public class ProcessorFactory { case HEARTBEAT: processor = (MessageProcessor) SpringContextHolder.getApplicationContext().getBean("heartbeatProcessor"); break; - case SINGLE_MESSAGE: - processor = (MessageProcessor)SpringContextHolder.getApplicationContext().getBean("singleMessageProcessor"); + case PRIVATE_MESSAGE: + processor = (MessageProcessor)SpringContextHolder.getApplicationContext().getBean("privateMessageProcessor"); break; default: break; diff --git a/im-ui/src/store/chatStore.js b/im-ui/src/store/chatStore.js index 50fa08a..30b65ba 100644 --- a/im-ui/src/store/chatStore.js +++ b/im-ui/src/store/chatStore.js @@ -6,6 +6,9 @@ export default { }, mutations: { + initChatStore(state) { + state.activeIndex = -1; + }, openChat(state,chatInfo){ let chat = null; for(let i in state.chats){ @@ -45,7 +48,7 @@ export default { }, insertMessage(state, msgInfo) { - let targetId = msgInfo.selfSend?msgInfo.recvUserId:msgInfo.sendUserId; + let targetId = msgInfo.selfSend?msgInfo.recvId:msgInfo.sendId; let chat = state.chats.find((chat)=>chat.targetId==targetId); chat.lastContent = msgInfo.content; diff --git a/im-ui/src/store/index.js b/im-ui/src/store/index.js index 9705f11..e4ded4b 100644 --- a/im-ui/src/store/index.js +++ b/im-ui/src/store/index.js @@ -24,6 +24,7 @@ export default new Vuex.Store({ initStore(state){ this.commit("initFriendStore"); this.commit("initGroupStore"); + this.commit("initChatStore"); } }, diff --git a/im-ui/src/view/Chat.vue b/im-ui/src/view/Chat.vue index 07d2c0a..19be328 100644 --- a/im-ui/src/view/Chat.vue +++ b/im-ui/src/view/Chat.vue @@ -7,55 +7,12 @@
- +
- - {{activeChat.showName}} - - -
-
    -
  • - - -
  • -
-
-
- -
-
-
- - - -
-
- - - -
-
-
- -
- - 发送 -
-
+
@@ -66,7 +23,8 @@ import MessageItem from "../components/chat/MessageItem.vue"; import HeadImage from "../components/common/HeadImage.vue"; import FileUpload from "../components/common/FileUpload.vue"; - + import ChatPrivate from "../components/chat/ChatPrivate.vue"; + export default { name: "chat", components: { @@ -74,7 +32,8 @@ ChatTime, HeadImage, FileUpload, - MessageItem + MessageItem, + ChatPrivate }, data() { return { @@ -85,155 +44,34 @@ methods: { handleActiveItem(index) { this.$store.commit("activeChat", index); - // 获取对方 - let userId = this.chatStore.chats[index].targetId; - this.$http({ - url: `/api/user/find/${userId}`, - method: 'get' - }).then((user) => { - // 如果发现好友的头像和昵称改了,进行更新 - let chat = this.chatStore.chats[index]; - if (user.headImageThumb != chat.headImage || - user.nickName != chat.showName) { - this.updateFriendInfo(user, index) - } - }) - }, - handleSendMessage() { - let msgInfo = { - recvUserId: this.activeChat.targetId, - content: this.messageContent, - type: 0 + let chat = this.chatStore.chats[index]; + if (chat.type == "GROUP") { + let groupId = this.chatStore.chats[index].targetId; + + } else { + this.refreshNameAndHeadImage(chat); } - this.sendMessage(msgInfo); }, handleDelItem(chat, index) { this.$store.commit("removeChat", index); }, - - handleImageSuccess(res, file) { - let msgInfo = { - recvUserId: file.raw.targetId, - content: JSON.stringify(res.data), - type: 1 - } - this.$http({ - url: '/api/message/single/send', - method: 'post', - data: msgInfo - }).then((data) => { - let info = { - targetId : file.raw.targetId, - fileId: file.raw.uid, - content: JSON.stringify(res.data), - loadStatus: "ok" - } - this.$store.commit("handleFileUpload", info); - }) - }, - handleImageFail(res,file){ - let info = { - targetId : file.raw.targetId, - fileId: file.raw.uid, - loadStatus: "fail" - } - this.$store.commit("handleFileUpload", info); - }, - handleImageBefore(file) { - let url = URL.createObjectURL(file); - let data = { - originUrl : url, - thumbUrl: url - } - let msgInfo = { - fileId: file.uid, - sendUserId: this.$store.state.userStore.userInfo.id, - recvUserId: this.activeChat.targetId, - content: JSON.stringify(data), - sendTime: new Date().getTime(), - selfSend: true, - type: 1, - loadStatus: "loadding" - } - // 插入消息 - this.$store.commit("insertMessage", msgInfo); - // 滚动到底部 - this.scrollToBottom(); - // 借助file对象保存对方id - file.targetId = this.activeChat.targetId; - }, - handleFileSuccess(res, file) { - console.log(res.data); - let data = { - name: file.name, - size: file.size, - url: res.data - } - let msgInfo = { - recvUserId: file.raw.targetId, - content: JSON.stringify(data), - type: 2 - } - this.$http({ - url: '/api/message/single/send', - method: 'post', - data: msgInfo - }).then(() => { - let info = { - targetId : file.raw.targetId, - fileId: file.raw.uid, - content: JSON.stringify(data), - loadStatus: "ok" - } - this.$store.commit("handleFileUpload", info); - }) - }, - handleFileFail(res, file) { - let info = { - targetId : file.raw.targetId, - fileId: file.raw.uid, - loadStatus: "fail" - } - this.$store.commit("handleFileUpload", info); - }, - handleFileBefore(file) { - let url = URL.createObjectURL(file); - let data = { - name: file.name, - size: file.size, - url: url - } + sendGroupMessage() { let msgInfo = { - fileId: file.uid, - sendUserId: this.$store.state.userStore.userInfo.id, - recvUserId: this.activeChat.targetId, - content: JSON.stringify(data), - sendTime: new Date().getTime(), - selfSend: true, - type: 2, - loadStatus: "loading" + groupId: this.activeChat.targetId, + content: this.messageContent, + type: 0 } - - // 插入消息 - this.$store.commit("insertMessage", msgInfo); - // 滚动到底部 - this.scrollToBottom(); - // 借助file对象保存对方id - file.targetId = this.activeChat.targetId; - }, - sendMessage(msgInfo) { this.$http({ - url: '/api/message/single/send', + url: '/api/message/group/send', method: 'post', data: msgInfo }).then((data) => { this.$message.success("发送成功"); this.messageContent = ""; msgInfo.sendTime = new Date().getTime(); - msgInfo.sendUserId = this.$store.state.userStore.userInfo.id; + msgInfo.sendId = this.$store.state.userStore.userInfo.id; msgInfo.selfSend = true; - msgInfo.loadStatus = "ok"; this.$store.commit("insertMessage", msgInfo); // 保持输入框焦点 this.$refs.sendBox.focus(); @@ -241,7 +79,22 @@ this.scrollToBottom(); }) }, - updateFriendInfo(user, index) { + refreshNameAndHeadImage(chat){ + // 获取对方最新信息 + let userId = chat.targetId; + this.$http({ + url: `/api/user/find/${userId}`, + method: 'get' + }).then((user) => { + // 如果发现好友的头像和昵称改了,进行更新 + if (user.headImageThumb != chat.headImage || + user.nickName != chat.showName) { + this.updateFriendInfo(user) + this.$store.commit("updateChatFromUser", user); + } + }) + }, + updateFriendInfo(user) { let friendInfo = { id: user.id, nickName: user.nickName, @@ -253,29 +106,8 @@ data: friendInfo }).then(() => { this.$store.commit("updateFriend", friendInfo); - this.$store.commit("updateChatFromUser", user); }) }, - showName(msg) { - if (msg.sendUserId == this.$store.state.userStore.userInfo.id) { - return this.$store.state.userStore.userInfo.nickName; - } - return this.activeChat.showName; - }, - headImage(msg) { - - if (msg.sendUserId == this.$store.state.userStore.userInfo.id) { - return this.$store.state.userStore.userInfo.headImageThumb; - } - return this.activeChat.headImage; - }, - scrollToBottom(){ - this.$nextTick(() => { - const div = document.getElementById("chatScrollBox"); - div.scrollTop = div.scrollHeight; - }); - } - }, computed: { chatStore() { @@ -287,16 +119,14 @@ if (index >= 0 && chats.length > 0) { return chats[index]; } - return this.emptyChat; - }, - emptyChat() { - // 当没有激活任何会话时,创建一个空会话,防止报错 - return { + // 当没有激活任何会话时,创建一个空会话,不然控制台会有很多报错 + let emptyChat = { targetId: -1, showName: "", headImage: "", messages: [] } + return emptyChat; } } } @@ -308,6 +138,7 @@ border: #dddddd solid 1px; background: white; width: 3rem; + .l-chat-header { padding: 5px; background-color: white; @@ -318,40 +149,42 @@ .r-chat-box { background: white; border: #dddddd solid 1px; + .el-header { padding: 5px; background-color: white; line-height: 50px; } + .im-chat-main { padding: 0; border: #dddddd solid 1px; + .im-chat-box { ul { padding: 20px; - + li { - list-style-type:none; + list-style-type: none; } } } } - - .im-chat-footer { display: flex; flex-direction: column; padding: 0; .chat-tool-bar { - + display: flex; position: relative; width: 100%; height: 40px; text-align: left; border: #dddddd solid 1px; + >div { margin-left: 10px; font-size: 22px; @@ -361,10 +194,8 @@ &:hover { color: black; - } } - } .send-text-area { diff --git a/im-ui/src/view/Friend.vue b/im-ui/src/view/Friend.vue index 1c86413..24eced0 100644 --- a/im-ui/src/view/Friend.vue +++ b/im-ui/src/view/Friend.vue @@ -87,12 +87,11 @@ handleSendMessage() { let user = this.userInfo; let chat = { - type: 'single', + type: 'PRIVATE', targetId: user.id, showName: user.nickName, headImage: user.headImage, }; - console.log(chat); this.$store.commit("openChat", chat); this.$store.commit("activeChat", 0); this.$router.push("/home/chat"); diff --git a/im-ui/src/view/Group.vue b/im-ui/src/view/Group.vue index b69f8ef..f6379f5 100644 --- a/im-ui/src/view/Group.vue +++ b/im-ui/src/view/Group.vue @@ -193,7 +193,15 @@ }, handleSendMessage() { - + let chat = { + type: 'GROUP', + targetId: this.activeGroup.id, + showName: this.activeGroup.remark, + headImage: this.activeGroup.headImage, + }; + this.$store.commit("openChat", chat); + this.$store.commit("activeChat", 0); + this.$router.push("/home/chat"); }, loadGroupMembers() { this.$http({ diff --git a/im-ui/src/view/Home.vue b/im-ui/src/view/Home.vue index 3c34418..b2312d7 100644 --- a/im-ui/src/view/Home.vue +++ b/im-ui/src/view/Home.vue @@ -61,21 +61,21 @@ console.log(e); if(e.cmd==1){ // 插入私聊消息 - this.handleSingleMessage(e.data); + this.handlePrivateMessage(e.data); } }) }, pullUnreadMessage(){ this.$http({ - url: "/api/message/single/pullUnreadMessage", + url: "/api/message/private/pullUnreadMessage", method: 'post' }) }, - handleSingleMessage(msg){ + handlePrivateMessage(msg){ // 插入私聊消息 - let f = this.$store.state.friendStore.friends.find((f)=>f.id==msg.sendUserId); + let f = this.$store.state.friendStore.friends.find((f)=>f.id==msg.sendId); let chatInfo = { - type: 'single', + type: 'PRIVATE', targetId: f.id, showName: f.nickName, headImage: f.headImage