diff --git a/.gitignore b/.gitignore index 79e1582..4e519b4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /im-server/src/main/resources/application-prod.yml /im-server/src/main/resources/logback-prod.xml /im-commom/im-commom.iml +/im-uniapp/node_modules/ diff --git a/im-client/src/main/java/com/bx/imclient/IMClient.java b/im-client/src/main/java/com/bx/imclient/IMClient.java index 05a238d..d47b082 100644 --- a/im-client/src/main/java/com/bx/imclient/IMClient.java +++ b/im-client/src/main/java/com/bx/imclient/IMClient.java @@ -1,13 +1,12 @@ package com.bx.imclient; -import com.bx.imclient.listener.MessageListenerMulticaster; import com.bx.imclient.sender.IMSender; -import com.bx.imcommon.model.GroupMessageInfo; -import com.bx.imcommon.model.PrivateMessageInfo; +import com.bx.imcommon.model.IMGroupMessage; +import com.bx.imcommon.model.IMPrivateMessage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; -import java.util.List; + @Configuration public class IMClient { @@ -27,21 +26,19 @@ public class IMClient { /** * 发送私聊消息(发送结果通过MessageListener接收) * - * @param recvId 接收用户id - * @param messageInfo 消息体,将转成json发送到客户端 + * @param message 私有消息 */ - public void sendPrivateMessage(Long recvId, PrivateMessageInfo... messageInfo){ - imSender.sendPrivateMessage(recvId,messageInfo); + public void sendPrivateMessage(IMPrivateMessage message){ + imSender.sendPrivateMessage(message); } /** * 发送群聊消息(发送结果通过MessageListener接收) * - * @param recvIds 群聊用户id列表 - * @param messageInfo 消息体,将转成json发送到客户端 + * @param message 群聊消息 */ - public void sendGroupMessage(List recvIds, GroupMessageInfo... messageInfo){ - imSender.sendGroupMessage(recvIds,messageInfo); + public void sendGroupMessage(IMGroupMessage message){ + imSender.sendGroupMessage(message); } diff --git a/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java b/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java index 23fac7c..a9799f8 100644 --- a/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java +++ b/im-client/src/main/java/com/bx/imclient/config/RedisConfig.java @@ -1,5 +1,6 @@ package com.bx.imclient.config; +import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; @@ -9,6 +10,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -17,16 +19,13 @@ import javax.annotation.Resource; @Configuration("IMRedisConfig") public class RedisConfig { - @Resource - private RedisConnectionFactory factory; - @Bean("IMRedisTemplate") public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); - // 设置值(value)的序列化采用jackson2JsonRedisSerializer - redisTemplate.setValueSerializer(jackson2JsonRedisSerializer()); - redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer()); + // 设置值(value)的序列化采用FastJsonRedisSerializer + redisTemplate.setValueSerializer(fastJsonRedisSerializer()); + redisTemplate.setHashValueSerializer(fastJsonRedisSerializer()); // 设置键(key)的序列化采用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); @@ -34,16 +33,9 @@ public class RedisConfig { return redisTemplate; } - @Bean - public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer(){ - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); - ObjectMapper om = new ObjectMapper(); - om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); - // 解决jackson2无法反序列化LocalDateTime的问题 - om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); - jackson2JsonRedisSerializer.setObjectMapper(om); - return jackson2JsonRedisSerializer; + public FastJsonRedisSerializer fastJsonRedisSerializer(){ + FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + return fastJsonRedisSerializer; } } diff --git a/im-client/src/main/java/com/bx/imclient/listener/MessageListener.java b/im-client/src/main/java/com/bx/imclient/listener/MessageListener.java index 95ae871..26636dd 100644 --- a/im-client/src/main/java/com/bx/imclient/listener/MessageListener.java +++ b/im-client/src/main/java/com/bx/imclient/listener/MessageListener.java @@ -1,10 +1,10 @@ package com.bx.imclient.listener; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMSendResult; -public interface MessageListener { +public interface MessageListener { - void process(SendResult result); + void process(IMSendResult result); } diff --git a/im-client/src/main/java/com/bx/imclient/listener/MessageListenerMulticaster.java b/im-client/src/main/java/com/bx/imclient/listener/MessageListenerMulticaster.java index 8d91a3c..05eb5b4 100644 --- a/im-client/src/main/java/com/bx/imclient/listener/MessageListenerMulticaster.java +++ b/im-client/src/main/java/com/bx/imclient/listener/MessageListenerMulticaster.java @@ -1,12 +1,15 @@ package com.bx.imclient.listener; +import com.alibaba.fastjson.JSONObject; import com.bx.imclient.annotation.IMListener; import com.bx.imcommon.enums.IMListenerType; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMSendResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.Collections; import java.util.List; @@ -16,12 +19,22 @@ public class MessageListenerMulticaster { @Autowired(required = false) private List messageListeners = Collections.emptyList(); - public void multicast(IMListenerType type, SendResult result){ + public void multicast(IMListenerType listenerType, IMSendResult result){ for(MessageListener listener:messageListeners){ IMListener annotation = listener.getClass().getAnnotation(IMListener.class); - if(annotation!=null && (annotation.type().equals(IMListenerType.ALL) || annotation.type().equals(type))){ + if(annotation!=null && (annotation.type().equals(IMListenerType.ALL) || annotation.type().equals(listenerType))){ + // 将data转回对象类型 + if(result.getData() instanceof JSONObject){ + Type superClass = listener.getClass().getGenericInterfaces()[0]; + Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; + JSONObject data = (JSONObject)result.getData(); + result.setData(data.toJavaObject(type)); + } + // 回调到调用方处理 listener.process(result); } } } + + } diff --git a/im-client/src/main/java/com/bx/imclient/sender/IMSender.java b/im-client/src/main/java/com/bx/imclient/sender/IMSender.java index b4ce5c3..035f936 100644 --- a/im-client/src/main/java/com/bx/imclient/sender/IMSender.java +++ b/im-client/src/main/java/com/bx/imclient/sender/IMSender.java @@ -1,14 +1,12 @@ package com.bx.imclient.sender; import com.bx.imclient.listener.MessageListenerMulticaster; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; -import com.bx.imcommon.model.GroupMessageInfo; -import com.bx.imcommon.model.IMRecvInfo; -import com.bx.imcommon.model.PrivateMessageInfo; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.enums.IMTerminalType; +import com.bx.imcommon.model.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.RedisTemplate; @@ -25,91 +23,130 @@ public class IMSender { @Autowired @Qualifier("IMRedisTemplate") - private RedisTemplate redisTemplate; + private RedisTemplate redisTemplate; @Autowired private MessageListenerMulticaster listenerMulticaster; - public void sendPrivateMessage(Long recvId, PrivateMessageInfo... messageInfos){ - // 获取对方连接的channelId - String key = RedisKey.IM_USER_SERVER_ID + recvId; - Integer serverId = (Integer) redisTemplate.opsForValue().get(key); - // 如果对方在线,将数据存储至redis,等待拉取推送 - if (serverId != null) { - String sendKey = RedisKey.IM_UNREAD_PRIVATE_QUEUE + serverId; - IMRecvInfo[] recvInfos = new IMRecvInfo[messageInfos.length]; - for (int i=0;i recvInfo = new IMRecvInfo<>(); + public void sendPrivateMessage(IMPrivateMessage message) { + for (Integer terminal : message.getRecvTerminals()) { + // 获取对方连接的channelId + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getRecvId().toString(), terminal.toString()); + Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + // 如果对方在线,将数据存储至redis,等待拉取推送 + if (serverId != null) { + String sendKey = String.join(":", IMRedisKey.IM_UNREAD_PRIVATE_QUEUE, serverId.toString()); + IMRecvInfo recvInfo = new IMRecvInfo(); recvInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code()); - List recvIds = new LinkedList(); - recvIds.add(recvId); - recvInfo.setRecvIds(recvIds); - recvInfo.setData(messageInfos[i]); - recvInfos[i] = recvInfo; - } - redisTemplate.opsForList().rightPushAll(sendKey, recvInfos); - }else{ - // 回复消息状态 - for(PrivateMessageInfo messageInfo : messageInfos ) { - SendResult result = new SendResult(); - result.setMessageInfo(messageInfo); - result.setRecvId(recvId); - result.setCode(IMSendCode.NOT_ONLINE); + recvInfo.setSendResult(message.getSendResult()); + recvInfo.setSender(message.getSender()); + recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getRecvId(), terminal))); + recvInfo.setData(message.getData()); + redisTemplate.opsForList().rightPush(sendKey, recvInfo); + } else if (message.getSendResult()) { + // 回复消息状态 + IMSendResult result = new IMSendResult(); + result.setSender(message.getSender()); + result.setReceiver(new IMUserInfo(message.getRecvId(), terminal)); + result.setCode(IMSendCode.NOT_ONLINE.code()); + result.setData(message.getData()); listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, result); } } + // 推送给自己的其他终端 + if(message.getSendToSelf()){ + for (Integer terminal : IMTerminalType.codes()) { + if (message.getSender().getTerminal().equals(terminal)) { + continue; + } + // 获取终端连接的channelId + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getSender().getId().toString(), terminal.toString()); + Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + // 如果终端在线,将数据存储至redis,等待拉取推送 + if (serverId != null) { + String sendKey = String.join(":", IMRedisKey.IM_UNREAD_PRIVATE_QUEUE, serverId.toString()); + IMRecvInfo recvInfo = new IMRecvInfo(); + // 自己的消息不需要回推消息结果 + recvInfo.setSendResult(false); + recvInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code()); + recvInfo.setSender(message.getSender()); + recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getSender().getId(), terminal))); + recvInfo.setData(message.getData()); + redisTemplate.opsForList().rightPush(sendKey, recvInfo); + } + } + } + } - public void sendGroupMessage(List recvIds, GroupMessageInfo... messageInfos){ + public void sendGroupMessage(IMGroupMessage message) { // 根据群聊每个成员所连的IM-server,进行分组 - List offLineIds = Collections.synchronizedList(new LinkedList()); - Map> serverMap = new ConcurrentHashMap<>(); - recvIds.parallelStream().forEach(id->{ - String key = RedisKey.IM_USER_SERVER_ID + id; - Integer serverId = (Integer)redisTemplate.opsForValue().get(key); - if(serverId != null){ - // 此处需要加锁,否则list可以会被覆盖 - synchronized(serverMap){ - if(serverMap.containsKey(serverId)){ - serverMap.get(serverId).add(id); - }else { - List list = Collections.synchronizedList(new LinkedList()); - list.add(id); - serverMap.put(serverId,list); - } + List offLineUsers = Collections.synchronizedList(new LinkedList<>()); + // 格式:map<服务器id,list<接收方>> + Map> serverMap = new ConcurrentHashMap<>(); + for (Integer terminal : message.getRecvTerminals()) { + message.getRecvIds().parallelStream().forEach(id -> { + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString()); + Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + if (serverId != null) { + List list = serverMap.computeIfAbsent(serverId, o -> Collections.synchronizedList(new LinkedList<>())); + list.add(new IMUserInfo(id, terminal)); + } else { + // 加入离线列表 + offLineUsers.add(new IMUserInfo(id, terminal)); } - }else{ - offLineIds.add(id); - } - }); + }); + } // 逐个server发送 - for (Map.Entry> entry : serverMap.entrySet()) { - IMRecvInfo[] recvInfos = new IMRecvInfo[messageInfos.length]; - for (int i=0;i recvInfo = new IMRecvInfo<>(); - recvInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); - recvInfo.setRecvIds(new LinkedList<>(entry.getValue())); - recvInfo.setData(messageInfos[i]); - recvInfos[i] = recvInfo; + for (Map.Entry> entry : serverMap.entrySet()) { + IMRecvInfo recvInfo = new IMRecvInfo(); + recvInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); + recvInfo.setReceivers(new LinkedList<>(entry.getValue())); + recvInfo.setSender(message.getSender()); + recvInfo.setSendResult(message.getSendResult()); + recvInfo.setData(message.getData()); + // 推送至队列 + String key = String.join(":", IMRedisKey.IM_UNREAD_GROUP_QUEUE, entry.getKey().toString()); + redisTemplate.opsForList().rightPush(key, recvInfo); + } + // 对离线用户回复消息状态 + if (message.getSendResult()) { + for (IMUserInfo offLineUser : offLineUsers) { + IMSendResult result = new IMSendResult(); + result.setSender(message.getSender()); + result.setReceiver(offLineUser); + result.setCode(IMSendCode.NOT_ONLINE.code()); + result.setData(message.getData()); + listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE, result); } - String key = RedisKey.IM_UNREAD_GROUP_QUEUE +entry.getKey(); - redisTemplate.opsForList().rightPushAll(key,recvInfos); } - // 不在线的用户,回复消息状态 - for(GroupMessageInfo messageInfo:messageInfos ){ - for(Long id : offLineIds){ - // 回复消息状态 - SendResult result = new SendResult(); - result.setMessageInfo(messageInfo); - result.setRecvId(id); - result.setCode(IMSendCode.NOT_ONLINE); - listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE,result); + // 推送给自己的其他终端 + if (message.getSendToSelf()) { + for (Integer terminal : IMTerminalType.codes()) { + if (terminal.equals(message.getSender().getTerminal())) { + continue; + } + // 获取终端连接的channelId + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, message.getSender().getId().toString(), terminal.toString()); + Integer serverId = (Integer)redisTemplate.opsForValue().get(key); + // 如果终端在线,将数据存储至redis,等待拉取推送 + if (serverId != null) { + IMRecvInfo recvInfo = new IMRecvInfo(); + recvInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); + recvInfo.setSender(message.getSender()); + recvInfo.setReceivers(Collections.singletonList(new IMUserInfo(message.getSender().getId(), terminal))); + // 自己的消息不需要回推消息结果 + recvInfo.setSendResult(false); + recvInfo.setData(message.getData()); + String sendKey = String.join(":", IMRedisKey.IM_UNREAD_GROUP_QUEUE, serverId.toString()); + redisTemplate.opsForList().rightPush(sendKey, recvInfo); + } } } } - public Boolean isOnline(Long userId){ - String key = RedisKey.IM_USER_SERVER_ID + userId; - return redisTemplate.hasKey(key); + public Boolean isOnline(Long userId) { + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*"); + return !redisTemplate.keys(key).isEmpty(); } } diff --git a/im-client/src/main/java/com/bx/imclient/task/AbstractPullMessageTask.java b/im-client/src/main/java/com/bx/imclient/task/AbstractPullMessageTask.java index 53b368f..a77c45f 100644 --- a/im-client/src/main/java/com/bx/imclient/task/AbstractPullMessageTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/AbstractPullMessageTask.java @@ -5,8 +5,7 @@ import lombok.extern.slf4j.Slf4j; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.*; @Slf4j public abstract class AbstractPullMessageTask { diff --git a/im-client/src/main/java/com/bx/imclient/task/PullSendResultGroupMessageTask.java b/im-client/src/main/java/com/bx/imclient/task/PullSendResultGroupMessageTask.java index 3de0494..2fa6e62 100644 --- a/im-client/src/main/java/com/bx/imclient/task/PullSendResultGroupMessageTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/PullSendResultGroupMessageTask.java @@ -1,9 +1,10 @@ package com.bx.imclient.task; +import com.alibaba.fastjson.JSONObject; import com.bx.imclient.listener.MessageListenerMulticaster; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMListenerType; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMSendResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.RedisTemplate; @@ -23,9 +24,10 @@ public class PullSendResultGroupMessageTask extends AbstractPullMessageTask{ @Override public void pullMessage() { - String key = RedisKey.IM_RESULT_GROUP_QUEUE; - SendResult result = (SendResult)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); - if(result != null) { + String key = IMRedisKey.IM_RESULT_GROUP_QUEUE; + JSONObject jsonObject = (JSONObject)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); + if(jsonObject != null) { + IMSendResult result = jsonObject.toJavaObject(IMSendResult.class); listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE,result); } } diff --git a/im-client/src/main/java/com/bx/imclient/task/PullSendResultPrivateMessageTask.java b/im-client/src/main/java/com/bx/imclient/task/PullSendResultPrivateMessageTask.java index e634493..c0fa2bb 100644 --- a/im-client/src/main/java/com/bx/imclient/task/PullSendResultPrivateMessageTask.java +++ b/im-client/src/main/java/com/bx/imclient/task/PullSendResultPrivateMessageTask.java @@ -1,9 +1,10 @@ package com.bx.imclient.task; +import com.alibaba.fastjson.JSONObject; import com.bx.imclient.listener.MessageListenerMulticaster; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMListenerType; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMSendResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -28,9 +29,10 @@ public class PullSendResultPrivateMessageTask extends AbstractPullMessageTask{ @Override public void pullMessage() { - String key = RedisKey.IM_RESULT_PRIVATE_QUEUE; - SendResult result = (SendResult)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); - if(result != null) { + String key = IMRedisKey.IM_RESULT_PRIVATE_QUEUE; + JSONObject jsonObject = (JSONObject)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); + if(jsonObject != null) { + IMSendResult result = jsonObject.toJavaObject(IMSendResult.class); listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, result); } } diff --git a/im-commom/src/main/java/com/bx/imcommon/contant/Constant.java b/im-commom/src/main/java/com/bx/imcommon/contant/IMConstant.java similarity index 89% rename from im-commom/src/main/java/com/bx/imcommon/contant/Constant.java rename to im-commom/src/main/java/com/bx/imcommon/contant/IMConstant.java index 4284a5d..7f833d0 100644 --- a/im-commom/src/main/java/com/bx/imcommon/contant/Constant.java +++ b/im-commom/src/main/java/com/bx/imcommon/contant/IMConstant.java @@ -1,7 +1,7 @@ package com.bx.imcommon.contant; -public class Constant { +public class IMConstant { // 在线状态过期时间 600s public static final long ONLINE_TIMEOUT_SECOND = 600; @@ -9,5 +9,4 @@ public class Constant { public static final long ALLOW_RECALL_SECOND = 300; - } diff --git a/im-commom/src/main/java/com/bx/imcommon/contant/RedisKey.java b/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java similarity index 91% rename from im-commom/src/main/java/com/bx/imcommon/contant/RedisKey.java rename to im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java index e8c2d7e..a3d7ad4 100644 --- a/im-commom/src/main/java/com/bx/imcommon/contant/RedisKey.java +++ b/im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java @@ -1,19 +1,18 @@ package com.bx.imcommon.contant; -public class RedisKey { +public class IMRedisKey { // 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_USER_SERVER_ID = "im:user:server_id"; // 未读私聊消息队列 - public final static String IM_UNREAD_PRIVATE_QUEUE = "im:unread:private:"; + public final static String IM_UNREAD_PRIVATE_QUEUE = "im:unread:private"; // 未读群聊消息队列 - public final static String IM_UNREAD_GROUP_QUEUE = "im:unread:group:"; + public final static String IM_UNREAD_GROUP_QUEUE = "im:unread:group"; // 私聊消息发送结果队列 public final static String IM_RESULT_PRIVATE_QUEUE = "im:result:private"; // 群聊消息发送结果队列 public final static String IM_RESULT_GROUP_QUEUE = "im:result:group"; - } diff --git a/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java b/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java index aedfde0..6ae35de 100644 --- a/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java +++ b/im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java @@ -11,6 +11,7 @@ public enum IMCmdType { GROUP_MESSAGE(4,"群发消息"); + private Integer code; private String desc; diff --git a/im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java b/im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java index 62ad254..37de1d7 100644 --- a/im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java +++ b/im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java @@ -8,7 +8,7 @@ public enum IMSendCode { NOT_FIND_CHANNEL(2,"未找到对方的channel"), UNKONW_ERROR(9999,"未知异常"); - private int code; + private Integer code; private String desc; // 构造方法 @@ -17,6 +17,16 @@ public enum IMSendCode { this.desc = desc; } + public static IMSendCode fromCode(Integer code){ + for (IMSendCode typeEnum:values()) { + if (typeEnum.code.equals(code)) { + return typeEnum; + } + } + return null; + } + + public String description() { return desc; } diff --git a/im-commom/src/main/java/com/bx/imcommon/enums/IMTerminalType.java b/im-commom/src/main/java/com/bx/imcommon/enums/IMTerminalType.java new file mode 100644 index 0000000..7ca76f1 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/enums/IMTerminalType.java @@ -0,0 +1,42 @@ +package com.bx.imcommon.enums; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public enum IMTerminalType { + + WEB(0,"web"), + APP(1,"app"); + + private Integer code; + + private String desc; + + IMTerminalType(Integer index, String desc) { + this.code =index; + this.desc=desc; + } + + public static IMTerminalType fromCode(Integer code){ + for (IMTerminalType typeEnum:values()) { + if (typeEnum.code.equals(code)) { + return typeEnum; + } + } + return null; + } + + public static List codes(){ + return Arrays.stream(values()).map(IMTerminalType::code).collect(Collectors.toList()); + } + + public String description() { + return desc; + } + + public Integer code(){ + return this.code; + } + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/GroupMessageInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/GroupMessageInfo.java deleted file mode 100644 index 7706868..0000000 --- a/im-commom/src/main/java/com/bx/imcommon/model/GroupMessageInfo.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.bx.imcommon.model; - -import com.bx.imcommon.serializer.DateToLongSerializer; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import lombok.Data; - -import java.util.Date; - -@Data -public class GroupMessageInfo { - - /* - * 消息id - */ - private Long id; - - /* - * 群聊id - */ - private Long groupId; - - /* - * 发送者id - */ - private Long sendId; - - /* - * 消息内容 - */ - private String content; - - /* - * 消息内容类型 具体枚举值由应用层定义 - */ - private Integer type; - - /** - * 发送时间 - */ - @JsonSerialize(using = DateToLongSerializer.class) - private Date sendTime; -} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMGroupMessage.java b/im-commom/src/main/java/com/bx/imcommon/model/IMGroupMessage.java new file mode 100644 index 0000000..9bbc905 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMGroupMessage.java @@ -0,0 +1,43 @@ +package com.bx.imcommon.model; + +import com.bx.imcommon.enums.IMTerminalType; +import lombok.Data; + +import java.util.List; + +@Data +public class IMGroupMessage { + + /** + * 发送方 + */ + private IMUserInfo sender; + + /** + * 接收者id列表(群成员列表) + */ + private List recvIds; + + + /** + * 接收者终端类型,默认全部 + */ + private List recvTerminals = IMTerminalType.codes(); + + /** + * 是否发送给自己的其他终端,默认true + */ + private Boolean sendToSelf = true; + + /** + * 是否需要回推发送结果,默认true + */ + private Boolean sendResult = true; + + /** + * 消息内容 + */ + private T data; + + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/HeartbeatInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/IMHeartbeatInfo.java similarity index 66% rename from im-commom/src/main/java/com/bx/imcommon/model/HeartbeatInfo.java rename to im-commom/src/main/java/com/bx/imcommon/model/IMHeartbeatInfo.java index d05f305..4b50271 100644 --- a/im-commom/src/main/java/com/bx/imcommon/model/HeartbeatInfo.java +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMHeartbeatInfo.java @@ -3,5 +3,5 @@ package com.bx.imcommon.model; import lombok.Data; @Data -public class HeartbeatInfo { +public class IMHeartbeatInfo { } diff --git a/im-commom/src/main/java/com/bx/imcommon/model/LoginInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/IMLoginInfo.java similarity index 77% rename from im-commom/src/main/java/com/bx/imcommon/model/LoginInfo.java rename to im-commom/src/main/java/com/bx/imcommon/model/IMLoginInfo.java index f4a365f..afccfca 100644 --- a/im-commom/src/main/java/com/bx/imcommon/model/LoginInfo.java +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMLoginInfo.java @@ -3,7 +3,7 @@ package com.bx.imcommon.model; import lombok.Data; @Data -public class LoginInfo { +public class IMLoginInfo { private String accessToken; } diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java b/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java new file mode 100644 index 0000000..63d3689 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java @@ -0,0 +1,44 @@ +package com.bx.imcommon.model; + +import com.bx.imcommon.enums.IMTerminalType; +import lombok.Data; + +import java.util.List; + + +@Data +public class IMPrivateMessage { + + /** + * 发送方 + */ + private IMUserInfo sender; + + /** + * 接收者id + */ + private Long recvId; + + + /** + * 接收者终端类型,默认全部 + */ + private List recvTerminals = IMTerminalType.codes(); + + /** + * 是否发送给自己的其他终端,默认true + */ + private Boolean sendToSelf = true; + + /** + * 是否需要回推发送结果,默认true + */ + private Boolean sendResult = true; + + /** + * 消息内容 + */ + private T data; + + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java index 289e2fc..b0939aa 100644 --- a/im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java @@ -5,22 +5,32 @@ import lombok.Data; import java.util.List; @Data -public class IMRecvInfo { +public class IMRecvInfo { /* - * 命令类型 + * 命令类型 IMCmdType */ private Integer cmd; /* - * 接收者id列表 + * 发送方 */ - private List recvIds; + private IMUserInfo sender; + + /* + * 接收方用户列表 + */ + List receivers; + + /* + * 是否需要回调发送结果 + */ + private Boolean sendResult; /* * 推送消息体 */ - private T data; + private Object data; } diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java b/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java new file mode 100644 index 0000000..15d1b43 --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java @@ -0,0 +1,28 @@ +package com.bx.imcommon.model; + +import lombok.Data; + +@Data +public class IMSendResult { + + /** + * 发送方 + */ + private IMUserInfo sender; + + /** + * 接收方 + */ + private IMUserInfo receiver; + + /* + * 发送状态 IMCmdType + */ + private Integer code; + + /* + * 消息内容 + */ + private T data; + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMSessionInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/IMSessionInfo.java new file mode 100644 index 0000000..d97256e --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMSessionInfo.java @@ -0,0 +1,18 @@ +package com.bx.imcommon.model; + +import com.bx.imcommon.enums.IMTerminalType; +import lombok.Data; + +@Data +public class IMSessionInfo { + /* + * 用户id + */ + private Long userId; + + /* + * 终端类型 + */ + private Integer terminal; + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/IMUserInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/IMUserInfo.java new file mode 100644 index 0000000..72007ea --- /dev/null +++ b/im-commom/src/main/java/com/bx/imcommon/model/IMUserInfo.java @@ -0,0 +1,30 @@ +package com.bx.imcommon.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @author: 谢绍许 + * @date: 2023-09-24 09:23:11 + * @version: 1.0 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class IMUserInfo { + + /** + * 用户id + */ + private Long id; + + /** + * 用户终端类型 IMTerminalType + */ + private Integer terminal; + + +} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/PrivateMessageInfo.java b/im-commom/src/main/java/com/bx/imcommon/model/PrivateMessageInfo.java deleted file mode 100644 index be5c753..0000000 --- a/im-commom/src/main/java/com/bx/imcommon/model/PrivateMessageInfo.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.bx.imcommon.model; - -import com.bx.imcommon.serializer.DateToLongSerializer; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import lombok.Data; - -import java.util.Date; - -@Data -public class PrivateMessageInfo { - - /* - * 消息id - */ - private long id; - - /* - * 发送者id - */ - private Long sendId; - - /* - * 接收者id - */ - private Long recvId; - - /* - * 发送内容 - */ - private String content; - - /* - * 消息内容类型 具体枚举值由应用层定义 - */ - private Integer type; - - /** - * 发送时间 - */ - @JsonSerialize(using = DateToLongSerializer.class) - private Date sendTime; -} diff --git a/im-commom/src/main/java/com/bx/imcommon/model/SendResult.java b/im-commom/src/main/java/com/bx/imcommon/model/SendResult.java deleted file mode 100644 index 2a65b82..0000000 --- a/im-commom/src/main/java/com/bx/imcommon/model/SendResult.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bx.imcommon.model; - -import com.bx.imcommon.enums.IMSendCode; -import lombok.Data; - -@Data -public class SendResult { - - /* - * 接收者id - */ - private Long recvId; - - /* - * 发送状态 - */ - private IMSendCode code; - - /* - * 消息体(透传) - */ - private T messageInfo; - -} diff --git a/im-platform/src/main/java/com/bx/implatform/ImplatformApp.java b/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java similarity index 88% rename from im-platform/src/main/java/com/bx/implatform/ImplatformApp.java rename to im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java index baf7338..7e2f59b 100644 --- a/im-platform/src/main/java/com/bx/implatform/ImplatformApp.java +++ b/im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java @@ -12,9 +12,9 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableAspectJAutoProxy(exposeProxy = true) @MapperScan(basePackages = {"com.bx.implatform.mapper"}) @SpringBootApplication(exclude= {SecurityAutoConfiguration.class })// 禁用secrity -public class ImplatformApp { +public class IMPlatformApp { public static void main(String[] args) { - SpringApplication.run(ImplatformApp.class,args); + SpringApplication.run(IMPlatformApp.class,args); } } diff --git a/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java b/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java index 8144a56..9462aef 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java @@ -20,10 +20,9 @@ public class MinIoClientConfig { @Bean public MinioClient minioClient(){ // 注入minio 客户端 - MinioClient client = MinioClient.builder() + return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); - return client; } } \ No newline at end of file diff --git a/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java b/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java index 32a3777..4ebff3c 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java @@ -16,7 +16,7 @@ public class MvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(XssInterceptor()) + registry.addInterceptor(xssInterceptor()) .addPathPatterns("/**"); registry.addInterceptor(authInterceptor()) .addPathPatterns("/**") @@ -30,7 +30,7 @@ public class MvcConfig implements WebMvcConfigurer { } @Bean - public XssInterceptor XssInterceptor() { + public XssInterceptor xssInterceptor() { return new XssInterceptor(); } diff --git a/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java b/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java index 1dec3cc..54bffe8 100644 --- a/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java +++ b/im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java @@ -38,7 +38,7 @@ public class RedisConfig extends CachingConfigurerSupport { @Primary @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate(); + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 设置值(value)的序列化采用jackson2JsonRedisSerializer @@ -52,8 +52,8 @@ public class RedisConfig extends CachingConfigurerSupport { } @Bean - public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer(){ - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer(){ + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 解决jackson2无法反序列化LocalDateTime的问题 diff --git a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java index 0f764c3..19daa41 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/Constant.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/Constant.java @@ -8,13 +8,5 @@ public class Constant { public static final long MAX_FILE_SIZE = 10*1024*1024; // 群聊最大人数 public static final long MAX_GROUP_MEMBER = 500; - // accessToken 过期时间(半小时) - public static final Integer ACCESS_TOKEN_EXPIRE = 30 * 60; - // refreshToken 过期时间(7天) - public static final Integer REFRESH_TOKEN_EXPIRE = 7 * 24 * 60 * 60 ; - // accessToken 加密秘钥 - // refreshToken 加密秘钥 - public static final String ACCESS_TOKEN_SECRET = "MIIBIjANBgkq"; - public static final String REFRESH_TOKEN_SECRET = "IKDiqVmn0VFU"; - + } diff --git a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java index 9d25026..f66091d 100644 --- a/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java +++ b/im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java @@ -3,7 +3,9 @@ package com.bx.implatform.contant; public class RedisKey { // 已读群聊消息位置(已读最大id) - public final static String IM_GROUP_READED_POSITION = "im:readed:group:position:"; + public final static String IM_GROUP_READED_POSITION = "im:readed:group:position"; + // webrtc 会话信息 + public final static String IM_WEBRTC_SESSION = "im:webrtc:session"; // 缓存前缀 public final static String IM_CACHE = "im:cache:"; // 缓存是否好友:bool diff --git a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java index 9d97450..fc4d568 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/FriendController.java @@ -27,7 +27,7 @@ public class FriendController { @GetMapping("/list") @ApiOperation(value = "好友列表",notes="获取好友列表") public Result< List> findFriends(){ - List friends = friendService.findFriendByUserId(SessionContext.getSession().getId()); + List friends = friendService.findFriendByUserId(SessionContext.getSession().getUserId()); List vos = friends.stream().map(f->{ FriendVO vo = new FriendVO(); vo.setId(f.getFriendId()); diff --git a/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java b/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java index 250ebbb..709397a 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/GroupController.java @@ -28,8 +28,8 @@ public class GroupController { @ApiOperation(value = "创建群聊",notes="创建群聊") @PostMapping("/create") - public Result createGroup(@NotEmpty(message = "群名不能为空") @RequestParam String groupName){ - return ResultUtils.success(groupService.createGroup(groupName)); + public Result createGroup(@Valid @RequestBody GroupVO vo){ + return ResultUtils.success(groupService.createGroup(vo)); } @ApiOperation(value = "修改群聊信息",notes="修改群聊信息") diff --git a/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java b/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java index 48d0665..8d57a81 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java @@ -1,11 +1,11 @@ package com.bx.implatform.controller; -import com.bx.imcommon.model.GroupMessageInfo; +import com.bx.implatform.vo.GroupMessageVO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.IGroupMessageService; -import com.bx.implatform.vo.GroupMessageVO; +import com.bx.implatform.dto.GroupMessageDTO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -27,7 +27,7 @@ public class GroupMessageController { @PostMapping("/send") @ApiOperation(value = "发送群聊消息",notes="发送群聊消息") - public Result sendMessage(@Valid @RequestBody GroupMessageVO vo){ + public Result sendMessage(@Valid @RequestBody GroupMessageDTO vo){ return ResultUtils.success(groupMessageService.sendMessage(vo)); } @@ -47,7 +47,7 @@ public class GroupMessageController { @GetMapping("/history") @ApiOperation(value = "查询聊天记录",notes="查询聊天记录") - public Result> recallMessage(@NotNull(message = "群聊id不能为空") @RequestParam Long groupId, + public Result> recallMessage(@NotNull(message = "群聊id不能为空") @RequestParam Long groupId, @NotNull(message = "页码不能为空") @RequestParam Long page, @NotNull(message = "size不能为空") @RequestParam Long size){ return ResultUtils.success( groupMessageService.findHistoryMessage(groupId,page,size)); diff --git a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java index 4e70554..3a09fed 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/LoginController.java @@ -1,6 +1,7 @@ package com.bx.implatform.controller; +import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.IUserService; @@ -45,4 +46,12 @@ public class LoginController { userService.register(dto); return ResultUtils.success(); } + + @PutMapping("/modifyPwd") + @ApiOperation(value = "修改密码",notes="修改用户密码") + public Result update(@Valid @RequestBody ModifyPwdDTO dto){ + userService.modifyPassword(dto); + return ResultUtils.success(); + } + } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java b/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java index 1b9a338..cde3c38 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java @@ -1,11 +1,11 @@ package com.bx.implatform.controller; -import com.bx.imcommon.model.PrivateMessageInfo; +import com.bx.implatform.vo.PrivateMessageVO; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; import com.bx.implatform.service.IPrivateMessageService; -import com.bx.implatform.vo.PrivateMessageVO; +import com.bx.implatform.dto.PrivateMessageDTO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +25,7 @@ public class PrivateMessageController { @PostMapping("/send") @ApiOperation(value = "发送消息",notes="发送私聊消息") - public Result sendMessage(@Valid @RequestBody PrivateMessageVO vo){ + public Result sendMessage(@Valid @RequestBody PrivateMessageDTO vo){ return ResultUtils.success(privateMessageService.sendMessage(vo)); } @@ -48,7 +48,7 @@ public class PrivateMessageController { @GetMapping("/history") @ApiOperation(value = "查询聊天记录",notes="查询聊天记录") - public Result> recallMessage(@NotNull(message = "好友id不能为空") @RequestParam Long friendId, + public Result> recallMessage(@NotNull(message = "好友id不能为空") @RequestParam Long friendId, @NotNull(message = "页码不能为空") @RequestParam Long page, @NotNull(message = "size不能为空") @RequestParam Long size){ return ResultUtils.success( privateMessageService.findHistoryMessage(friendId,page,size)); diff --git a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java index 3cc5cdf..8dc7bb6 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/UserController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/UserController.java @@ -1,5 +1,6 @@ package com.bx.implatform.controller; +import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.entity.User; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; @@ -36,9 +37,9 @@ public class UserController { @GetMapping("/self") @ApiOperation(value = "获取当前用户信息",notes="获取当前用户信息") - public Result findSelfInfo(){ + public Result findSelfInfo(){ UserSession session = SessionContext.getSession(); - User user = userService.getById(session.getId()); + User user = userService.getById(session.getUserId()); UserVO userVO = BeanUtils.copyProperties(user,UserVO.class); return ResultUtils.success(userVO); } @@ -61,11 +62,16 @@ public class UserController { - @GetMapping("/findByNickName") @ApiOperation(value = "查找用户",notes="根据昵称查找用户") - public Result findByNickName(@NotEmpty(message = "用户昵称不可为空") @RequestParam("nickName") String nickName){ + public Result> findByNickName(@NotEmpty(message = "用户昵称不可为空") @RequestParam("nickName") String nickName){ return ResultUtils.success( userService.findUserByNickName(nickName)); } + + @GetMapping("/findByName") + @ApiOperation(value = "查找用户",notes="根据用户名或昵称查找用户") + public Result> findByName(@NotEmpty(message = "用户名称不可为空") @RequestParam("name") String name){ + return ResultUtils.success( userService.findUserByName(name)); + } } diff --git a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java index b1fccd4..9fca97c 100644 --- a/im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java +++ b/im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java @@ -1,54 +1,35 @@ package com.bx.implatform.controller; - -import com.bx.imclient.IMClient; -import com.bx.imcommon.model.PrivateMessageInfo; -import com.bx.implatform.config.ICEServerConfig; -import com.bx.implatform.enums.MessageType; +import com.bx.implatform.config.ICEServer; import com.bx.implatform.result.Result; import com.bx.implatform.result.ResultUtils; -import com.bx.implatform.session.SessionContext; +import com.bx.implatform.service.IWebrtcService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Api(tags = "webrtc视频单人通话") @RestController @RequestMapping("/webrtc/private") public class WebrtcController { @Autowired - private IMClient imClient; - - @Autowired - private ICEServerConfig iceServerConfig; + private IWebrtcService webrtcService; @ApiOperation(httpMethod = "POST", value = "呼叫视频通话") @PostMapping("/call") public Result call(@RequestParam Long uid, @RequestBody String offer) { - Long userId = SessionContext.getSession().getId(); - - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_CALL.code()); - message.setRecvId(uid); - message.setSendId(userId); - message.setContent(offer); - imClient.sendPrivateMessage(uid,message); + webrtcService.call(uid,offer); return ResultUtils.success(); } @ApiOperation(httpMethod = "POST", value = "接受视频通话") @PostMapping("/accept") public Result accept(@RequestParam Long uid,@RequestBody String answer) { - Long userId = SessionContext.getSession().getId(); - - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_ACCEPT.code()); - message.setRecvId(uid); - message.setSendId(userId); - message.setContent(answer); - imClient.sendPrivateMessage(uid,message); + webrtcService.accept(uid,answer); return ResultUtils.success(); } @@ -56,71 +37,43 @@ public class WebrtcController { @ApiOperation(httpMethod = "POST", value = "拒绝视频通话") @PostMapping("/reject") public Result reject(@RequestParam Long uid) { - Long userId = SessionContext.getSession().getId(); - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_REJECT.code()); - message.setRecvId(uid); - message.setSendId(userId); - imClient.sendPrivateMessage(uid,message); + webrtcService.reject(uid); return ResultUtils.success(); } @ApiOperation(httpMethod = "POST", value = "取消呼叫") @PostMapping("/cancel") public Result cancel(@RequestParam Long uid) { - Long userId = SessionContext.getSession().getId(); - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_CANCEL.code()); - message.setRecvId(uid); - message.setSendId(userId); - imClient.sendPrivateMessage(uid,message); + webrtcService.cancel(uid); return ResultUtils.success(); } @ApiOperation(httpMethod = "POST", value = "呼叫失败") @PostMapping("/failed") public Result failed(@RequestParam Long uid,@RequestParam String reason) { - Long userId = SessionContext.getSession().getId(); - - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_FAILED.code()); - message.setRecvId(uid); - message.setSendId(userId); - message.setContent(reason); - imClient.sendPrivateMessage(uid,message); + webrtcService.failed(uid,reason); return ResultUtils.success(); } @ApiOperation(httpMethod = "POST", value = "挂断") @PostMapping("/handup") public Result leave(@RequestParam Long uid) { - Long userId = SessionContext.getSession().getId(); - - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_HANDUP.code()); - message.setRecvId(uid); - message.setSendId(userId); - imClient.sendPrivateMessage(uid,message); + webrtcService.leave(uid); return ResultUtils.success(); } @PostMapping("/candidate") @ApiOperation(httpMethod = "POST", value = "同步candidate") - public Result candidate(@RequestParam Long uid,@RequestBody String candidate ) { - Long userId = SessionContext.getSession().getId(); - PrivateMessageInfo message = new PrivateMessageInfo(); - message.setType(MessageType.RTC_CANDIDATE.code()); - message.setRecvId(uid); - message.setSendId(userId); - message.setContent(candidate); - imClient.sendPrivateMessage(uid,message); + public Result forwardCandidate(@RequestParam Long uid,@RequestBody String candidate ) { + webrtcService.candidate(uid,candidate); return ResultUtils.success(); } + @GetMapping("/iceservers") @ApiOperation(httpMethod = "GET", value = "获取iceservers") - public Result iceservers() { - return ResultUtils.success(iceServerConfig.getIceServers()); + public Result> iceservers() { + return ResultUtils.success(webrtcService.getIceServers()); } } diff --git a/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java new file mode 100644 index 0000000..2535784 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java @@ -0,0 +1,28 @@ +package com.bx.implatform.dto; + +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("群聊消息DTO") +public class GroupMessageDTO { + + @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/bx/implatform/dto/LoginDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java index 05a638d..0f16599 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java @@ -5,17 +5,26 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.hibernate.validator.constraints.Length; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; @Data -@ApiModel("用户登录VO") +@ApiModel("用户登录DTO") public class LoginDTO { - //@NotEmpty(message="用户名不可为空") + @Max(value = 1,message = "登录终端类型取值范围:0,1") + @Min(value = 0,message = "登录终端类型取值范围:0,1") + @NotNull(message="登录终端类型不可为空") + @ApiModelProperty(value = "登录终端 0:web 1:app") + private Integer terminal; + + @NotEmpty(message="用户名不可为空") @ApiModelProperty(value = "用户名") private String userName; - // @NotEmpty(message="用户密码不可为空") + @NotEmpty(message="用户密码不可为空") @ApiModelProperty(value = "用户密码") private String password; diff --git a/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java new file mode 100644 index 0000000..a4de7fe --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java @@ -0,0 +1,21 @@ +package com.bx.implatform.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Data +@ApiModel("修改密码DTO") +public class ModifyPwdDTO { + + @NotEmpty(message="旧用户密码不可为空") + @ApiModelProperty(value = "旧用户密码") + private String oldPassword; + + @NotEmpty(message="新用户密码不可为空") + @ApiModelProperty(value = "新用户密码") + private String newPassword; + +} diff --git a/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java new file mode 100644 index 0000000..9ae1a64 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java @@ -0,0 +1,31 @@ +package com.bx.implatform.dto; + + +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("私聊消息DTO") +public class PrivateMessageDTO { + + + @NotNull(message="接收用户id不可为空") + @ApiModelProperty(value = "接收用户id") + private Long recvId; + + + @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/bx/implatform/dto/RegisterDTO.java b/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java index 61255be..78f115c 100644 --- a/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java +++ b/im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java @@ -8,7 +8,7 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotEmpty; @Data -@ApiModel("用户注册VO") +@ApiModel("用户注册DTO") public class RegisterDTO { @Length(max = 64,message = "用户名不能大于64字符") diff --git a/im-platform/src/main/java/com/bx/implatform/entity/User.java b/im-platform/src/main/java/com/bx/implatform/entity/User.java index 1fa5ddd..ab6ff48 100644 --- a/im-platform/src/main/java/com/bx/implatform/entity/User.java +++ b/im-platform/src/main/java/com/bx/implatform/entity/User.java @@ -62,6 +62,11 @@ public class User extends Model { @TableField("head_image_thumb") private String headImageThumb; + /** + * 用户类型 1:普通用户 2:审核专用账户 + */ + @TableField("type") + private Integer type; /** * 个性签名 diff --git a/im-platform/src/main/java/com/bx/implatform/enums/FileType.java b/im-platform/src/main/java/com/bx/implatform/enums/FileType.java index 2e628e5..dc2071f 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/FileType.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/FileType.java @@ -9,24 +9,15 @@ public enum FileType { - private Integer code; + private final Integer code; - private String desc; + private final String desc; FileType(Integer index, String desc) { this.code =index; this.desc=desc; } - public static FileType fromCode(Integer code){ - for (FileType typeEnum:values()) { - if (typeEnum.code.equals(code)) { - return typeEnum; - } - } - return null; - } - public String description() { return desc; diff --git a/im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java b/im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java index 212c3eb..8a7968e 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java @@ -7,25 +7,15 @@ public enum MessageStatus { ALREADY_READ(1,"已读"), RECALL(2,"已撤回"); - private Integer code; + private final Integer code; - private String desc; + private final String desc; MessageStatus(Integer index, String desc) { this.code =index; this.desc=desc; } - public static MessageStatus fromCode(Integer code){ - for (MessageStatus typeEnum:values()) { - if (typeEnum.code.equals(code)) { - return typeEnum; - } - } - return null; - } - - public String description() { return desc; } diff --git a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java index cc7a07c..5e6d2e8 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/MessageType.java @@ -4,10 +4,11 @@ package com.bx.implatform.enums; public enum MessageType { TEXT(0,"文字"), - FILE(1,"文件"), - IMAGE(2,"图片"), - VIDEO(3,"视频"), - TIP(10,"系统提示"), + IMAGE(1,"图片"), + FILE(2,"文件"), + AUDIO(3,"音频"), + VIDEO(4,"视频"), + RECALL(10,"撤回"), RTC_CALL(101,"呼叫"), RTC_ACCEPT(102,"接受"), @@ -17,16 +18,15 @@ public enum MessageType { RTC_HANDUP(106,"挂断"), RTC_CANDIDATE(107,"同步candidate"); - private Integer code; + private final Integer code; - private String desc; + private final String desc; MessageType(Integer index, String desc) { this.code =index; this.desc=desc; } - public String description() { return desc; } diff --git a/im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java b/im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java index 4af3527..8b8a4b0 100644 --- a/im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java +++ b/im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java @@ -21,7 +21,6 @@ public enum ResultCode { private int code; private String msg; - // 构造方法 ResultCode(int code, String msg) { this.code = code; this.msg = msg; diff --git a/im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java b/im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java index 0c44af8..b7091a5 100644 --- a/im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java +++ b/im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java @@ -71,7 +71,7 @@ public class GlobalExceptionHandler { public Result handleValidationExceptionHandler(MethodArgumentNotValidException exception) { BindingResult bindResult = exception.getBindingResult(); String msg; - if (bindResult != null && bindResult.hasErrors()) { + if (bindResult.hasErrors()) { msg = bindResult.getAllErrors().get(0).getDefaultMessage(); if (msg.contains("NumberFormatException")) { msg = "参数类型错误!"; diff --git a/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java b/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java index 9353e0f..e7ff61d 100644 --- a/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java +++ b/im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java @@ -7,7 +7,6 @@ import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; -import java.util.List; @Component @ServletComponentScan diff --git a/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java b/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java index 761c743..9101015 100644 --- a/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java +++ b/im-platform/src/main/java/com/bx/implatform/filter/CacheHttpServletRequestWrapper.java @@ -10,9 +10,9 @@ import java.io.*; public class CacheHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] requestBody; - private HttpServletRequest request; + private final HttpServletRequest request; - public CacheHttpServletRequestWrapper(HttpServletRequest request) throws IOException { + public CacheHttpServletRequestWrapper(HttpServletRequest request) { super(request); this.request = request; } @@ -48,10 +48,6 @@ public class CacheHttpServletRequestWrapper extends HttpServletRequestWrapper { }; } - public byte[] getRequestBody() { - return requestBody; - } - @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); diff --git a/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java b/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java index c11e7e3..92fbd7e 100644 --- a/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java +++ b/im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java @@ -14,7 +14,6 @@ import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -; @Slf4j public class AuthInterceptor implements HandlerInterceptor { diff --git a/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java b/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java index fd384e1..96278fa 100644 --- a/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java +++ b/im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java @@ -17,7 +17,7 @@ public class XssInterceptor implements HandlerInterceptor { @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 检查参数 Map paramMap = request.getParameterMap(); for(String[] values:paramMap.values()){ diff --git a/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java index f9f5be2..a99522c 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java @@ -4,10 +4,9 @@ import com.bx.imclient.annotation.IMListener; import com.bx.imclient.listener.MessageListener; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; -import com.bx.imcommon.model.GroupMessageInfo; -import com.bx.imcommon.model.SendResult; +import com.bx.implatform.vo.GroupMessageVO; +import com.bx.imcommon.model.IMSendResult; import com.bx.implatform.contant.RedisKey; -import com.bx.implatform.enums.MessageType; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -15,22 +14,17 @@ import org.springframework.data.redis.core.RedisTemplate; @Slf4j @IMListener(type = IMListenerType.GROUP_MESSAGE) -public class GroupMessageListener implements MessageListener { +public class GroupMessageListener implements MessageListener { @Autowired private RedisTemplate redisTemplate; @Override - public void process(SendResult result){ - GroupMessageInfo messageInfo = (GroupMessageInfo) result.getMessageInfo(); - // 提示类数据不记录 - if(messageInfo.getType().equals(MessageType.TIP)){ - return; - } - + public void process(IMSendResult result){ + GroupMessageVO messageInfo = result.getData(); // 保存该用户已拉取的最大消息id - if(result.getCode().equals(IMSendCode.SUCCESS)) { - String key = RedisKey.IM_GROUP_READED_POSITION + messageInfo.getGroupId() + ":" + result.getRecvId(); + if(result.getCode().equals(IMSendCode.SUCCESS.code())) { + String key = String.join(":",RedisKey.IM_GROUP_READED_POSITION,messageInfo.getGroupId().toString(),result.getReceiver().getId().toString()); redisTemplate.opsForValue().set(key, messageInfo.getId()); } } diff --git a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java index 06fa83d..68a6f2b 100644 --- a/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java +++ b/im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java @@ -1,63 +1,38 @@ package com.bx.implatform.listener; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.bx.imclient.IMClient; import com.bx.imclient.annotation.IMListener; import com.bx.imclient.listener.MessageListener; import com.bx.imcommon.enums.IMListenerType; import com.bx.imcommon.enums.IMSendCode; -import com.bx.imcommon.model.PrivateMessageInfo; -import com.bx.imcommon.model.SendResult; +import com.bx.implatform.vo.PrivateMessageVO; +import com.bx.imcommon.model.IMSendResult; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; -import com.bx.implatform.enums.MessageType; import com.bx.implatform.service.IPrivateMessageService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Date; - @Slf4j @IMListener(type = IMListenerType.PRIVATE_MESSAGE) -public class PrivateMessageListener implements MessageListener { +public class PrivateMessageListener implements MessageListener { @Autowired private IPrivateMessageService privateMessageService; - @Autowired - private IMClient imClient; @Override - public void process(SendResult result){ - PrivateMessageInfo messageInfo = (PrivateMessageInfo) result.getMessageInfo(); - // 提示类数据不记录 - if(messageInfo.getType().equals(MessageType.TIP.code())){ - return; - } - // 视频通话信令不记录 - if(messageInfo.getType() >= MessageType.RTC_CALL.code() && messageInfo.getType()< MessageType.RTC_CANDIDATE.code()){ - // 通知用户呼叫失败了 - if(messageInfo.getType().equals(MessageType.RTC_CALL.code()) - && !result.getCode().equals(IMSendCode.SUCCESS)){ - PrivateMessageInfo sendMessage = new PrivateMessageInfo(); - sendMessage.setRecvId(messageInfo.getSendId()); - sendMessage.setSendId(messageInfo.getRecvId()); - sendMessage.setType(MessageType.RTC_FAILED.code()); - sendMessage.setContent(result.getCode().description()); - sendMessage.setSendTime(new Date()); - imClient.sendPrivateMessage(sendMessage.getRecvId(),sendMessage); - } - return; - } - // 更新消息状态 - if(result.getCode().equals(IMSendCode.SUCCESS)){ + public void process(IMSendResult result){ + PrivateMessageVO messageInfo = result.getData(); + // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态 + if(result.getCode().equals(IMSendCode.SUCCESS.code())){ UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.lambda().eq(PrivateMessage::getId,messageInfo.getId()) .eq(PrivateMessage::getStatus, MessageStatus.UNREAD.code()) .set(PrivateMessage::getStatus, MessageStatus.ALREADY_READ.code()); privateMessageService.update(updateWrapper); - log.info("消息已读,消息id:{},发送者:{},接收者:{}",messageInfo.getId(),messageInfo.getSendId(),messageInfo.getRecvId()); + log.info("消息已读,消息id:{},发送者:{},接收者:{},终端:{}",messageInfo.getId(),result.getSender().getId(),result.getReceiver().getId(),result.getReceiver().getTerminal()); } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java b/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java index ec5b339..cfde61c 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IFriendService.java @@ -11,7 +11,7 @@ public interface IFriendService extends IService { Boolean isFriend(Long userId1, Long userId2); - List findFriendByUserId(Long UserId); + List findFriendByUserId(Long userId); void addFriend(Long friendId); diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java b/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java index a4966c0..3611045 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java @@ -18,6 +18,7 @@ public interface IGroupMemberService extends IService { List findUserIdsByGroupId(Long groupId); + boolean saveOrUpdateBatch(Long groupId,List members); void removeByGroupId(Long groupId); diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java b/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java index 78a07ac..a003afe 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java @@ -1,9 +1,9 @@ package com.bx.implatform.service; import com.baomidou.mybatisplus.extension.service.IService; -import com.bx.imcommon.model.GroupMessageInfo; -import com.bx.implatform.entity.GroupMessage; import com.bx.implatform.vo.GroupMessageVO; +import com.bx.implatform.entity.GroupMessage; +import com.bx.implatform.dto.GroupMessageDTO; import java.util.List; @@ -11,11 +11,11 @@ import java.util.List; public interface IGroupMessageService extends IService { - Long sendMessage(GroupMessageVO vo); + Long sendMessage(GroupMessageDTO vo); void recallMessage(Long id); void pullUnreadMessage(); - List findHistoryMessage(Long groupId, Long page, Long size); + List findHistoryMessage(Long groupId, Long page, Long size); } diff --git a/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java b/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java index eeae9d5..40fb3c3 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IGroupService.java @@ -12,7 +12,7 @@ import java.util.List; public interface IGroupService extends IService { - GroupVO createGroup(String groupName); + GroupVO createGroup(GroupVO vo); GroupVO modifyGroup(GroupVO vo); @@ -26,7 +26,7 @@ public interface IGroupService extends IService { void invite(GroupInviteVO vo); - Group GetById(Long groupId); + Group getById(Long groupId); GroupVO findById(Long groupId); diff --git a/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java b/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java index be629d2..0b42d21 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java @@ -1,20 +1,20 @@ package com.bx.implatform.service; import com.baomidou.mybatisplus.extension.service.IService; -import com.bx.imcommon.model.PrivateMessageInfo; -import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.vo.PrivateMessageVO; +import com.bx.implatform.entity.PrivateMessage; +import com.bx.implatform.dto.PrivateMessageDTO; import java.util.List; public interface IPrivateMessageService extends IService { - Long sendMessage(PrivateMessageVO vo); + Long sendMessage(PrivateMessageDTO vo); void recallMessage(Long id); - List findHistoryMessage(Long friendId, Long page,Long size); + List findHistoryMessage(Long friendId, Long page,Long size); void pullUnreadMessage(); diff --git a/im-platform/src/main/java/com/bx/implatform/service/IUserService.java b/im-platform/src/main/java/com/bx/implatform/service/IUserService.java index 4e48398..d960165 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/IUserService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/IUserService.java @@ -1,6 +1,7 @@ package com.bx.implatform.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.entity.User; import com.bx.implatform.dto.LoginDTO; import com.bx.implatform.dto.RegisterDTO; @@ -14,16 +15,20 @@ public interface IUserService extends IService { LoginVO login(LoginDTO dto); + void modifyPassword(ModifyPwdDTO dto); + LoginVO refreshToken(String refreshToken); void register(RegisterDTO dto); - User findUserByName(String username); + User findUserByUserName(String username); void update(UserVO vo); List findUserByNickName(String nickname); + List findUserByName(String name); + List checkOnline(String userIds); } diff --git a/im-platform/src/main/java/com/bx/implatform/service/IWebrtcService.java b/im-platform/src/main/java/com/bx/implatform/service/IWebrtcService.java new file mode 100644 index 0000000..0b2e345 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/IWebrtcService.java @@ -0,0 +1,32 @@ +package com.bx.implatform.service; + +import com.bx.implatform.config.ICEServer; +import org.springframework.web.bind.annotation.RequestBody; +import java.util.List; + + +/** + * webrtc 通信服务 + * @author + */ +public interface IWebrtcService { + + void call(Long uid, String offer); + + void accept( Long uid,@RequestBody String answer); + + void reject( Long uid); + + void cancel( Long uid); + + void failed( Long uid, String reason); + + void leave( Long uid) ; + + void candidate( Long uid, String candidate); + + List getIceServers(); + + + +} diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java index f074d76..c40cf10 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java @@ -36,13 +36,13 @@ public class FriendServiceImpl extends ServiceImpl impleme /** * 查询用户的所有好友 * - * @param UserId 用户id + * @param userId 用户id * @return */ @Override - public List findFriendByUserId(Long UserId) { + public List findFriendByUserId(Long userId) { QueryWrapper queryWrapper = new QueryWrapper(); - queryWrapper.lambda().eq(Friend::getUserId,UserId); + queryWrapper.lambda().eq(Friend::getUserId,userId); List friends = this.list(queryWrapper); return friends; } @@ -57,7 +57,7 @@ public class FriendServiceImpl extends ServiceImpl impleme @Transactional @Override public void addFriend(Long friendId) { - long userId = SessionContext.getSession().getId(); + long userId = SessionContext.getSession().getUserId(); if(userId == friendId){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"不允许添加自己为好友"); } @@ -78,7 +78,7 @@ public class FriendServiceImpl extends ServiceImpl impleme @Transactional @Override public void delFriend(Long friendId) { - long userId = SessionContext.getSession().getId(); + long userId = SessionContext.getSession().getUserId(); // 互相解除好友关系 FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy(); proxy.unbindFriend(userId,friendId); @@ -113,7 +113,7 @@ public class FriendServiceImpl extends ServiceImpl impleme */ @Override public void update(FriendVO vo) { - long userId = SessionContext.getSession().getId(); + long userId = SessionContext.getSession().getUserId(); QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.lambda() .eq(Friend::getUserId,userId) @@ -186,7 +186,7 @@ public class FriendServiceImpl extends ServiceImpl impleme UserSession session = SessionContext.getSession(); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .eq(Friend::getUserId,session.getId()) + .eq(Friend::getUserId,session.getUserId()) .eq(Friend::getFriendId,friendId); Friend friend = this.getOne(wrapper); if(friend == null){ diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java index e62de44..ec70f53 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java @@ -1,7 +1,9 @@ package com.bx.implatform.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.GroupMember; @@ -71,8 +73,8 @@ public class GroupMemberServiceImpl extends ServiceImpl findByUserId(Long userId) { - QueryWrapper memberWrapper = new QueryWrapper(); - memberWrapper.lambda().eq(GroupMember::getUserId, userId) + LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery(); + memberWrapper.eq(GroupMember::getUserId, userId) .eq(GroupMember::getQuit,false); return this.list(memberWrapper); } @@ -86,8 +88,8 @@ public class GroupMemberServiceImpl extends ServiceImpl findByGroupId(Long groupId) { - QueryWrapper memberWrapper = new QueryWrapper(); - memberWrapper.lambda().eq(GroupMember::getGroupId, groupId); + LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery(); + memberWrapper.eq(GroupMember::getGroupId, groupId); return this.list(memberWrapper); } @@ -101,16 +103,16 @@ public class GroupMemberServiceImpl extends ServiceImpl findUserIdsByGroupId(Long groupId) { - QueryWrapper memberWrapper = new QueryWrapper(); - memberWrapper.lambda().eq(GroupMember::getGroupId, groupId) + LambdaQueryWrapper memberWrapper = Wrappers.lambdaQuery(); + memberWrapper.eq(GroupMember::getGroupId, groupId) .eq(GroupMember::getQuit,false); List members = this.list(memberWrapper); - return members.stream().map(m->m.getUserId()).collect(Collectors.toList()); + return members.stream().map(GroupMember::getUserId).collect(Collectors.toList()); } /** - *根据群聊id删除移除成员 + * 根据群聊id删除移除成员 * * @param groupId 群聊id * @return @@ -118,8 +120,8 @@ public class GroupMemberServiceImpl extends ServiceImpl wrapper = new UpdateWrapper(); - wrapper.lambda().eq(GroupMember::getGroupId,groupId) + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate(); + wrapper.eq(GroupMember::getGroupId,groupId) .set(GroupMember::getQuit,true); this.update(wrapper); } @@ -134,8 +136,8 @@ public class GroupMemberServiceImpl extends ServiceImpl wrapper = new UpdateWrapper<>(); - wrapper.lambda().eq(GroupMember::getGroupId,groupId) + LambdaUpdateWrapper wrapper = Wrappers.lambdaUpdate(); + wrapper.eq(GroupMember::getGroupId,groupId) .eq(GroupMember::getUserId,userId) .set(GroupMember::getQuit,true); this.update(wrapper); diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java index d09a6a9..c2f992a 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java @@ -1,10 +1,14 @@ package com.bx.implatform.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; -import com.bx.imcommon.contant.Constant; -import com.bx.imcommon.model.GroupMessageInfo; +import com.bx.imcommon.contant.IMConstant; +import com.bx.implatform.vo.GroupMessageVO; +import com.bx.imcommon.model.IMGroupMessage; +import com.bx.imcommon.model.IMUserInfo; import com.bx.implatform.contant.RedisKey; import com.bx.implatform.entity.Group; import com.bx.implatform.entity.GroupMember; @@ -18,8 +22,9 @@ import com.bx.implatform.service.IGroupMemberService; import com.bx.implatform.service.IGroupMessageService; import com.bx.implatform.service.IGroupService; import com.bx.implatform.session.SessionContext; +import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; -import com.bx.implatform.vo.GroupMessageVO; +import com.bx.implatform.dto.GroupMessageDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -27,37 +32,31 @@ import org.springframework.stereotype.Service; import java.util.Collections; import java.util.Date; -import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; @Slf4j @Service public class GroupMessageServiceImpl extends ServiceImpl implements IGroupMessageService { - - @Autowired private IGroupService groupService; - @Autowired private IGroupMemberService groupMemberService; - @Autowired private RedisTemplate redisTemplate; - @Autowired private IMClient imClient; /** * 发送群聊消息(与mysql所有交换都要进行缓存) * - * @param vo + * @param dto 群聊消息 * @return 群聊id */ @Override - public Long sendMessage(GroupMessageVO vo) { - Long userId = SessionContext.getSession().getId(); - Group group = groupService.getById(vo.getGroupId()); + public Long sendMessage(GroupMessageDTO dto) { + UserSession session = SessionContext.getSession(); + Group group = groupService.getById(dto.getGroupId()); if(group == null){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"群聊不存在"); } @@ -66,20 +65,24 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(group.getId()); - if(!userIds.contains(userId)){ + if(!userIds.contains(session.getUserId())){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您已不在群聊里面,无法发送消息"); } // 保存消息 - GroupMessage msg = BeanUtils.copyProperties(vo, GroupMessage.class); - msg.setSendId(userId); + GroupMessage msg = BeanUtils.copyProperties(dto, GroupMessage.class); + msg.setSendId(session.getUserId()); msg.setSendTime(new Date()); this.save(msg); // 不用发给自己 - userIds = userIds.stream().filter(id->!userId.equals(id)).collect(Collectors.toList()); + userIds = userIds.stream().filter(id->!session.getUserId().equals(id)).collect(Collectors.toList()); // 群发 - GroupMessageInfo msgInfo = BeanUtils.copyProperties(msg, GroupMessageInfo.class); - imClient.sendGroupMessage(userIds,msgInfo); - log.info("发送群聊消息,发送id:{},群聊id:{},内容:{}",userId,vo.getGroupId(),vo.getContent()); + GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvIds(userIds); + sendMessage.setData(msgInfo); + imClient.sendGroupMessage(sendMessage); + log.info("发送群聊消息,发送id:{},群聊id:{},内容:{}",session.getUserId(),dto.getGroupId(),dto.getContent()); return msg.getId(); } @@ -93,19 +96,19 @@ public class GroupMessageServiceImpl extends ServiceImpl Constant.ALLOW_RECALL_SECOND * 1000){ + if(System.currentTimeMillis() - msg.getSendTime().getTime() > IMConstant.ALLOW_RECALL_SECOND * 1000){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"消息已发送超过5分钟,无法撤回"); } // 判断是否在群里 - GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(),userId); + GroupMember member = groupMemberService.findByGroupAndUserId(msg.getGroupId(),session.getUserId()); if(member == null){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您已不在群聊里面,无法撤回消息"); } @@ -115,54 +118,69 @@ public class GroupMessageServiceImpl extends ServiceImpl userIds = groupMemberService.findUserIdsByGroupId(msg.getGroupId()); // 不用发给自己 - userIds = userIds.stream().filter(uid->userId.equals(uid)).collect(Collectors.toList()); - GroupMessageInfo msgInfo = BeanUtils.copyProperties(msg, GroupMessageInfo.class); - msgInfo.setType(MessageType.TIP.code()); + userIds = userIds.stream().filter(uid->!session.getUserId().equals(uid)).collect(Collectors.toList()); + GroupMessageVO msgInfo = BeanUtils.copyProperties(msg, GroupMessageVO.class); + msgInfo.setType(MessageType.RECALL.code()); String content = String.format("'%s'撤回了一条消息",member.getAliasName()); msgInfo.setContent(content); msgInfo.setSendTime(new Date()); - imClient.sendGroupMessage(userIds,msgInfo); - log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}",userId,msg.getGroupId(),msg.getContent()); + + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvIds(userIds); + sendMessage.setData(msgInfo); + sendMessage.setSendResult(false); + sendMessage.setSendToSelf(false); + imClient.sendGroupMessage(sendMessage); + + // 推给自己其他终端 + msgInfo.setContent("你撤回了一条消息"); + sendMessage.setSendToSelf(true); + sendMessage.setRecvIds(Collections.emptyList()); + sendMessage.setRecvTerminals(Collections.emptyList()); + imClient.sendGroupMessage(sendMessage); + log.info("撤回群聊消息,发送id:{},群聊id:{},内容:{}",session.getUserId(),msg.getGroupId(),msg.getContent()); } /** * 异步拉取群聊消息,通过websocket异步推送 * - * @return */ @Override public void pullUnreadMessage() { - Long userId = SessionContext.getSession().getId(); - List recvIds = new LinkedList(); - recvIds.add(userId); - List members = groupMemberService.findByUserId(userId); + UserSession session = SessionContext.getSession(); + List members = groupMemberService.findByUserId(session.getUserId()); for(GroupMember member:members){ // 获取群聊已读的最大消息id,只推送未读消息 - String key = RedisKey.IM_GROUP_READED_POSITION + member.getGroupId()+":"+userId; + String key = String.join(":",RedisKey.IM_GROUP_READED_POSITION,member.getGroupId().toString(),session.getUserId().toString()); Integer maxReadedId = (Integer)redisTemplate.opsForValue().get(key); - QueryWrapper wrapper = new QueryWrapper(); - wrapper.lambda().eq(GroupMessage::getGroupId,member.getGroupId()) + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GroupMessage::getGroupId,member.getGroupId()) .gt(GroupMessage::getSendTime,member.getCreatedTime()) - .ne(GroupMessage::getSendId, userId) + .ne(GroupMessage::getSendId, session.getUserId()) .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()); if(maxReadedId!=null){ - wrapper.lambda().gt(GroupMessage::getId,maxReadedId); + wrapper.gt(GroupMessage::getId,maxReadedId); } wrapper.last("limit 100"); List messages = this.list(wrapper); if(messages.isEmpty()){ continue; } - // 组装消息,准备推送 - List messageInfos = messages.stream().map(m->{ - GroupMessageInfo msgInfo = BeanUtils.copyProperties(m, GroupMessageInfo.class); - return msgInfo; - }).collect(Collectors.toList()); + // 推送 + for (GroupMessage message:messages ){ + GroupMessageVO msgInfo = BeanUtils.copyProperties(message, GroupMessageVO.class); + IMGroupMessage sendMessage = new IMGroupMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + // 只推给自己当前终端 + sendMessage.setRecvIds(Collections.singletonList(session.getUserId())); + sendMessage.setRecvTerminals(Collections.singletonList(session.getTerminal())); + sendMessage.setData(msgInfo); + imClient.sendGroupMessage(sendMessage); + } // 发送消息 - GroupMessageInfo[] infoArr = messageInfos.toArray(new GroupMessageInfo[messageInfos.size()]); - imClient.sendGroupMessage(Collections.singletonList(userId), infoArr); - log.info("拉取未读群聊消息,用户id:{},群聊id:{},数量:{}",userId,member.getGroupId(),messageInfos.size()); + log.info("拉取未读群聊消息,用户id:{},群聊id:{},数量:{}",session.getUserId(),member.getGroupId(),messages.size()); } } @@ -176,11 +194,11 @@ public class GroupMessageServiceImpl extends ServiceImpl findHistoryMessage(Long groupId, Long page, Long size) { + public List findHistoryMessage(Long groupId, Long page, Long size) { page = page > 0 ? page:1; size = size > 0 ? size:10; - Long userId = SessionContext.getSession().getId(); - Long stIdx = (page-1)* size; + Long userId = SessionContext.getSession().getUserId(); + long stIdx = (page-1)* size; // 群聊成员信息 GroupMember member = groupMemberService.findByGroupAndUserId(groupId,userId); if(member == null || member.getQuit()){ @@ -195,10 +213,7 @@ public class GroupMessageServiceImpl extends ServiceImpl messages = this.list(wrapper); - List messageInfos = messages.stream().map(m->{ - GroupMessageInfo info = BeanUtils.copyProperties(m, GroupMessageInfo.class); - return info; - }).collect(Collectors.toList()); + List messageInfos = messages.stream().map(m->BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList()); log.info("拉取群聊记录,用户id:{},群聊id:{},数量:{}",userId,groupId,messageInfos.size()); return messageInfos; } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java index 328f769..a72d9d0 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java @@ -1,6 +1,7 @@ package com.bx.implatform.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.implatform.contant.Constant; import com.bx.implatform.contant.RedisKey; @@ -30,8 +31,8 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Collections; import java.util.Date; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -51,46 +52,41 @@ public class GroupServiceImpl extends ServiceImpl implements @Autowired private IFriendService friendsService; - /** * 创建新群聊 * - * @Param groupName 群聊名称 - * @return + * @param vo 群聊信息 + * @return 群聊信息 **/ - @Transactional @Override - public GroupVO createGroup(String groupName) { + public GroupVO createGroup(GroupVO vo) { UserSession session = SessionContext.getSession(); - User user = userService.getById(session.getId()); + User user = userService.getById(session.getUserId()); // 保存群组数据 - Group group = new Group(); - group.setName(groupName); + Group group = BeanUtils.copyProperties(vo,Group.class); group.setOwnerId(user.getId()); - group.setHeadImage(user.getHeadImage()); - group.setHeadImageThumb(user.getHeadImageThumb()); this.save(group); // 把群主加入群 GroupMember groupMember = new GroupMember(); groupMember.setGroupId(group.getId()); groupMember.setUserId(user.getId()); - groupMember.setAliasName(user.getNickName()); - groupMember.setRemark(groupName); + groupMember.setAliasName(StringUtils.isEmpty(vo.getAliasName())?session.getNickName():vo.getAliasName()); + groupMember.setRemark(StringUtils.isEmpty(vo.getRemark())?group.getName():vo.getRemark()); groupMember.setHeadImage(user.getHeadImageThumb()); groupMemberService.save(groupMember); - GroupVO vo = BeanUtils.copyProperties(group, GroupVO.class); - vo.setAliasName(user.getNickName()); - vo.setRemark(groupName); + + vo.setId(group.getId()); + vo.setAliasName(groupMember.getAliasName()); + vo.setRemark(groupMember.getRemark()); log.info("创建群聊,群聊id:{},群聊名称:{}",group.getId(),group.getName()); return vo; } - /** * 修改群聊信息 * - * @Param GroupVO 群聊信息 - * @return + * @param vo 群聊信息 + * @return 群聊信息 **/ @CacheEvict(value = "#vo.getId()") @Transactional @@ -100,12 +96,12 @@ public class GroupServiceImpl extends ServiceImpl implements // 校验是不是群主,只有群主能改信息 Group group = this.getById(vo.getId()); // 群主有权修改群基本信息 - if(group.getOwnerId().equals(session.getId())){ + if(group.getOwnerId().equals(session.getUserId()) ){ group = BeanUtils.copyProperties(vo,Group.class); this.updateById(group); } // 更新成员信息 - GroupMember member = groupMemberService.findByGroupAndUserId(vo.getId(),session.getId()); + GroupMember member = groupMemberService.findByGroupAndUserId(vo.getId(),session.getUserId()); if(member == null){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您不是群聊的成员"); } @@ -120,8 +116,7 @@ public class GroupServiceImpl extends ServiceImpl implements /** * 删除群聊 * - * @Param groupId 群聊id - * @return + * @param groupId 群聊id **/ @Transactional @CacheEvict(value = "#groupId") @@ -129,7 +124,7 @@ public class GroupServiceImpl extends ServiceImpl implements public void deleteGroup(Long groupId) { UserSession session = SessionContext.getSession(); Group group = this.getById(groupId); - if(!group.getOwnerId().equals(session.getId())){ + if(!group.getOwnerId().equals(session.getUserId())){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"只有群主才有权限解除群聊"); } // 逻辑删除群数据 @@ -145,11 +140,10 @@ public class GroupServiceImpl extends ServiceImpl implements * 退出群聊 * * @param groupId 群聊id - * @return */ @Override public void quitGroup(Long groupId) { - Long userId = SessionContext.getSession().getId(); + Long userId = SessionContext.getSession().getUserId(); Group group = this.getById(groupId); if(group.getOwnerId().equals(userId)){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您是群主,不可退出群聊"); @@ -165,16 +159,15 @@ public class GroupServiceImpl extends ServiceImpl implements * * @param groupId 群聊id * @param userId 用户id - * @return */ @Override public void kickGroup(Long groupId, Long userId) { UserSession session = SessionContext.getSession(); Group group = this.getById(groupId); - if(!group.getOwnerId().equals(session.getId())){ + if(!group.getOwnerId().equals(session.getUserId()) ){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您不是群主,没有权限踢人"); } - if(userId.equals(session.getId())){ + if(userId.equals(session.getUserId())){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"亲,不能自己踢自己哟"); } // 删除群聊成员 @@ -186,7 +179,7 @@ public class GroupServiceImpl extends ServiceImpl implements public GroupVO findById(Long groupId) { UserSession session = SessionContext.getSession(); Group group = this.getById(groupId); - GroupMember member = groupMemberService.findByGroupAndUserId(groupId,session.getId()); + GroupMember member = groupMemberService.findByGroupAndUserId(groupId,session.getUserId()); if(member == null){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"您未加入群聊"); } @@ -200,11 +193,11 @@ public class GroupServiceImpl extends ServiceImpl implements * 根据id查找群聊,并进行缓存 * * @param groupId 群聊id - * @return + * @return 群聊实体 */ @Cacheable(value = "#groupId") @Override - public Group GetById(Long groupId){ + public Group getById(Long groupId){ Group group = super.getById(groupId); if(group == null){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"群组不存在"); @@ -220,37 +213,35 @@ public class GroupServiceImpl extends ServiceImpl implements /** * 查询当前用户的所有群聊 * - * @return + * @return 群聊信息列表 **/ @Override public List findGroups() { UserSession session = SessionContext.getSession(); // 查询当前用户的群id列表 - List groupMembers = groupMemberService.findByUserId(session.getId()); + List groupMembers = groupMemberService.findByUserId(session.getUserId()); if(groupMembers.isEmpty()){ - return Collections.EMPTY_LIST; + return new LinkedList<>(); } // 拉取群列表 - List ids = groupMembers.stream().map((gm -> gm.getGroupId())).collect(Collectors.toList()); - QueryWrapper groupWrapper = new QueryWrapper(); - groupWrapper.lambda().in(Group::getId, ids); + List ids = groupMembers.stream().map((GroupMember::getGroupId)).collect(Collectors.toList()); + LambdaQueryWrapper groupWrapper = Wrappers.lambdaQuery(); + groupWrapper.in(Group::getId, ids); List groups = this.list(groupWrapper); // 转vo - List vos = groups.stream().map(g -> { + return groups.stream().map(g -> { GroupVO vo = BeanUtils.copyProperties(g, GroupVO.class); GroupMember member = groupMembers.stream().filter(m -> g.getId().equals(m.getGroupId())).findFirst().get(); vo.setAliasName(member.getAliasName()); vo.setRemark(member.getRemark()); return vo; }).collect(Collectors.toList()); - return vos; } /** * 邀请好友进群 * * @Param GroupInviteVO 群id、好友id列表 - * @return **/ @Override public void invite(GroupInviteVO vo) { @@ -265,9 +256,8 @@ public class GroupServiceImpl extends ServiceImpl implements if(vo.getFriendIds().size() + size > Constant.MAX_GROUP_MEMBER){ throw new GlobalException(ResultCode.PROGRAM_ERROR, "群聊人数不能大于"+Constant.MAX_GROUP_MEMBER+"人"); } - // 找出好友信息 - List friends = friendsService.findFriendByUserId(session.getId()); + List friends = friendsService.findFriendByUserId(session.getUserId()); List friendsList = vo.getFriendIds().stream().map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get()).collect(Collectors.toList()); if (friendsList.size() != vo.getFriendIds().size()) { @@ -275,18 +265,18 @@ public class GroupServiceImpl extends ServiceImpl implements } // 批量保存成员数据 List groupMembers = friendsList.stream() - .map(f -> { - Optional optional = members.stream().filter(m-> m.getUserId().equals(f.getFriendId())).findFirst(); - GroupMember groupMember = optional.isPresent()? optional.get():new GroupMember(); - groupMember.setGroupId(vo.getGroupId()); - groupMember.setUserId(f.getFriendId()); - groupMember.setAliasName(f.getFriendNickName()); - groupMember.setRemark(group.getName()); - groupMember.setHeadImage(f.getFriendHeadImage()); - groupMember.setCreatedTime(new Date()); - groupMember.setQuit(false); - return groupMember; - }).collect(Collectors.toList()); + .map(f -> { + Optional optional = members.stream().filter(m->m.getUserId().equals(f.getFriendId())).findFirst(); + GroupMember groupMember = optional.orElseGet(GroupMember::new); + groupMember.setGroupId(vo.getGroupId()); + groupMember.setUserId(f.getFriendId()); + groupMember.setAliasName(f.getFriendNickName()); + groupMember.setRemark(group.getName()); + groupMember.setHeadImage(f.getFriendHeadImage()); + groupMember.setCreatedTime(new Date()); + groupMember.setQuit(false); + return groupMember; + }).collect(Collectors.toList()); if(!groupMembers.isEmpty()) { groupMemberService.saveOrUpdateBatch(group.getId(),groupMembers); } @@ -302,11 +292,7 @@ public class GroupServiceImpl extends ServiceImpl implements @Override public List findGroupMembers(Long groupId) { List members = groupMemberService.findByGroupId(groupId); - List vos = members.stream().map(m->{ - GroupMemberVO vo = BeanUtils.copyProperties(m,GroupMemberVO.class); - return vo; - }).collect(Collectors.toList()); - return vos; + return members.stream().map(m->BeanUtils.copyProperties(m,GroupMemberVO.class)).collect(Collectors.toList()); } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java index 83444e6..9fbbf6e 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java @@ -1,11 +1,14 @@ package com.bx.implatform.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; -import com.bx.imcommon.contant.Constant; -import com.bx.imcommon.contant.RedisKey; -import com.bx.imcommon.model.PrivateMessageInfo; +import com.bx.imcommon.contant.IMConstant; +import com.bx.imcommon.model.IMPrivateMessage; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.implatform.vo.PrivateMessageVO; import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.enums.MessageStatus; import com.bx.implatform.enums.MessageType; @@ -15,13 +18,14 @@ import com.bx.implatform.mapper.PrivateMessageMapper; import com.bx.implatform.service.IFriendService; import com.bx.implatform.service.IPrivateMessageService; import com.bx.implatform.session.SessionContext; +import com.bx.implatform.session.UserSession; import com.bx.implatform.util.BeanUtils; -import com.bx.implatform.vo.PrivateMessageVO; +import com.bx.implatform.dto.PrivateMessageDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -32,33 +36,37 @@ public class PrivateMessageServiceImpl extends ServiceImpl redisTemplate; + @Autowired private IMClient imClient; /** * 发送私聊消息 * - * @param vo 私聊消息vo + * @param dto 私聊消息 * @return 消息id */ @Override - public Long sendMessage(PrivateMessageVO vo) { - Long userId = SessionContext.getSession().getId(); - Boolean isFriends = friendService.isFriend(userId, vo.getRecvId()); + public Long sendMessage(PrivateMessageDTO dto) { + UserSession session = SessionContext.getSession(); + Boolean isFriends = friendService.isFriend(session.getUserId(), dto.getRecvId()); if (!isFriends) { throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不是对方好友,无法发送消息"); } // 保存消息 - PrivateMessage msg = BeanUtils.copyProperties(vo, PrivateMessage.class); - msg.setSendId(userId); + PrivateMessage msg = BeanUtils.copyProperties(dto, PrivateMessage.class); + msg.setSendId(session.getUserId()); msg.setStatus(MessageStatus.UNREAD.code()); msg.setSendTime(new Date()); this.save(msg); // 推送消息 - PrivateMessageInfo msgInfo = BeanUtils.copyProperties(msg, PrivateMessageInfo.class); - imClient.sendPrivateMessage(vo.getRecvId(),msgInfo); - log.info("发送私聊消息,发送id:{},接收id:{},内容:{}", userId, vo.getRecvId(), vo.getContent()); + PrivateMessageVO msgInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(msgInfo.getRecvId()); + sendMessage.setSendToSelf(true); + sendMessage.setData(msgInfo); + imClient.sendPrivateMessage(sendMessage); + log.info("发送私聊消息,发送id:{},接收id:{},内容:{}", session.getUserId(), dto.getRecvId(), dto.getContent()); return msg.getId(); } @@ -69,26 +77,39 @@ public class PrivateMessageServiceImpl extends ServiceImpl Constant.ALLOW_RECALL_SECOND * 1000) { + if (System.currentTimeMillis() - msg.getSendTime().getTime() > IMConstant.ALLOW_RECALL_SECOND * 1000) { throw new GlobalException(ResultCode.PROGRAM_ERROR, "消息已发送超过5分钟,无法撤回"); } // 修改消息状态 msg.setStatus(MessageStatus.RECALL.code()); this.updateById(msg); // 推送消息 - PrivateMessageInfo msgInfo = BeanUtils.copyProperties(msg, PrivateMessageInfo.class); - msgInfo.setType(MessageType.TIP.code()); + PrivateMessageVO msgInfo = BeanUtils.copyProperties(msg, PrivateMessageVO.class); + msgInfo.setType(MessageType.RECALL.code()); msgInfo.setSendTime(new Date()); msgInfo.setContent("对方撤回了一条消息"); - imClient.sendPrivateMessage(msgInfo.getRecvId(),msgInfo); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(msgInfo.getRecvId()); + sendMessage.setSendToSelf(false); + sendMessage.setData(msgInfo); + sendMessage.setSendResult(false); + imClient.sendPrivateMessage(sendMessage); + + // 推给自己其他终端 + msgInfo.setContent("你撤回了一条消息"); + sendMessage.setSendToSelf(true); + sendMessage.setRecvTerminals(Collections.emptyList()); + imClient.sendPrivateMessage(sendMessage); log.info("撤回私聊消息,发送id:{},接收id:{},内容:{}", msg.getSendId(), msg.getRecvId(), msg.getContent()); } @@ -102,11 +123,11 @@ public class PrivateMessageServiceImpl extends ServiceImpl findHistoryMessage(Long friendId, Long page, Long size) { + public List findHistoryMessage(Long friendId, Long page, Long size) { page = page > 0 ? page : 1; size = size > 0 ? size : 10; - Long userId = SessionContext.getSession().getId(); - Long stIdx = (page - 1) * size; + Long userId = SessionContext.getSession().getUserId(); + long stIdx = (page - 1) * size; QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().and(wrap -> wrap.and( wp -> wp.eq(PrivateMessage::getSendId, userId) @@ -118,10 +139,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl messages = this.list(wrapper); - List messageInfos = messages.stream().map(m -> { - PrivateMessageInfo info = BeanUtils.copyProperties(m, PrivateMessageInfo.class); - return info; - }).collect(Collectors.toList()); + List messageInfos = messages.stream().map(m -> BeanUtils.copyProperties(m, PrivateMessageVO.class)).collect(Collectors.toList()); log.info("拉取聊天记录,用户id:{},好友id:{},数量:{}", userId, friendId, messageInfos.size()); return messageInfos; } @@ -129,30 +147,32 @@ public class PrivateMessageServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(PrivateMessage::getRecvId, userId) + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(PrivateMessage::getRecvId, session.getUserId()) .eq(PrivateMessage::getStatus, MessageStatus.UNREAD); List messages = this.list(queryWrapper); // 上传至redis,等待推送 - if (!messages.isEmpty()) { - List messageInfos = messages.stream().map(m -> { - PrivateMessageInfo msgInfo = BeanUtils.copyProperties(m, PrivateMessageInfo.class); - return msgInfo; - }).collect(Collectors.toList()); + for(PrivateMessage message:messages){ + PrivateMessageVO msgInfo = BeanUtils.copyProperties(message, PrivateMessageVO.class); // 推送消息 - PrivateMessageInfo[] infoArr = messageInfos.toArray(new PrivateMessageInfo[messageInfos.size()]); - imClient.sendPrivateMessage(userId,infoArr); - log.info("拉取未读私聊消息,用户id:{},数量:{}", userId, infoArr.length); + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(session.getUserId()); + sendMessage.setRecvTerminals(Collections.singletonList(session.getTerminal())); + sendMessage.setSendToSelf(false); + sendMessage.setData(msgInfo); + imClient.sendPrivateMessage(sendMessage); } + log.info("拉取未读私聊消息,用户id:{},数量:{}", session.getUserId(), messages.size()); + } } diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java index 725204d..03e718f 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java @@ -1,11 +1,13 @@ package com.bx.implatform.service.impl; import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.bx.imclient.IMClient; -import com.bx.imcommon.contant.RedisKey; import com.bx.implatform.config.JwtProperties; +import com.bx.implatform.dto.ModifyPwdDTO; import com.bx.implatform.entity.Friend; import com.bx.implatform.entity.GroupMember; import com.bx.implatform.entity.User; @@ -65,7 +67,7 @@ public class UserServiceImpl extends ServiceImpl implements IU @Override public LoginVO login(LoginDTO dto) { - User user = findUserByName(dto.getUserName()); + User user = this.findUserByUserName(dto.getUserName()); if(null == user){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"用户不存在"); } @@ -74,6 +76,8 @@ public class UserServiceImpl extends ServiceImpl implements IU } // 生成token UserSession session = BeanUtils.copyProperties(user,UserSession.class); + session.setUserId(user.getId()); + session.setTerminal(dto.getTerminal()); String strJson = JSON.toJSONString(session); String accessToken = JwtUtil.sign(user.getId(),strJson,jwtProperties.getAccessTokenExpireIn(),jwtProperties.getAccessTokenSecret()); String refreshToken = JwtUtil.sign(user.getId(),strJson,jwtProperties.getRefreshTokenExpireIn(),jwtProperties.getRefreshTokenSecret()); @@ -85,6 +89,9 @@ public class UserServiceImpl extends ServiceImpl implements IU return vo; } + + + /** * 用refreshToken换取新 token * @@ -94,7 +101,7 @@ public class UserServiceImpl extends ServiceImpl implements IU @Override public LoginVO refreshToken(String refreshToken) { //验证 token - if(JwtUtil.checkSign(refreshToken, jwtProperties.getRefreshTokenSecret())){ + if(!JwtUtil.checkSign(refreshToken, jwtProperties.getRefreshTokenSecret())){ throw new GlobalException("refreshToken无效或已过期"); } String strJson = JwtUtil.getInfo(refreshToken); @@ -113,11 +120,10 @@ public class UserServiceImpl extends ServiceImpl implements IU * 用户注册 * * @param dto 注册dto - * @return */ @Override public void register(RegisterDTO dto) { - User user = findUserByName(dto.getUserName()); + User user = this.findUserByUserName(dto.getUserName()); if(null != user){ throw new GlobalException(ResultCode.USERNAME_ALREADY_REGISTER); } @@ -127,6 +133,19 @@ public class UserServiceImpl extends ServiceImpl implements IU log.info("注册用户,用户id:{},用户名:{},昵称:{}",user.getId(),dto.getUserName(),dto.getNickName()); } + + @Override + public void modifyPassword(ModifyPwdDTO dto) { + UserSession session = SessionContext.getSession(); + User user = this.getById(session.getUserId()); + if(!passwordEncoder.matches(dto.getOldPassword(),user.getPassword())){ + throw new GlobalException("旧密码不正确"); + } + user.setPassword(passwordEncoder.encode(dto.getNewPassword())); + this.updateById(user); + log.info("用户修改密码,用户id:{},用户名:{},昵称:{}",user.getId(),user.getUserName(),user.getNickName()); + } + /** * 根据用户名查询用户 * @@ -134,23 +153,23 @@ public class UserServiceImpl extends ServiceImpl implements IU * @return */ @Override - public User findUserByName(String username) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(User::getUserName,username); + public User findUserByUserName(String username) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(User::getUserName,username); return this.getOne(queryWrapper); } + /** * 更新用户信息,好友昵称和群聊昵称等冗余信息也会更新 * * @param vo 用户信息vo - * @return */ @Transactional @Override public void update(UserVO vo) { UserSession session = SessionContext.getSession(); - if(!session.getId().equals(vo.getId()) ){ + if(!session.getUserId().equals(vo.getId()) ){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"不允许修改其他用户的信息!"); } User user = this.getById(vo.getId()); @@ -160,7 +179,7 @@ public class UserServiceImpl extends ServiceImpl implements IU // 更新好友昵称和头像 if(!user.getNickName().equals(vo.getNickName()) || !user.getHeadImageThumb().equals(vo.getHeadImageThumb())){ QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(Friend::getFriendId,session.getId()); + queryWrapper.lambda().eq(Friend::getFriendId,session.getUserId()); List friends = friendService.list(queryWrapper); for(Friend friend: friends){ friend.setFriendNickName(vo.getNickName()); @@ -170,7 +189,7 @@ public class UserServiceImpl extends ServiceImpl implements IU } // 更新群聊中的头像 if(!user.getHeadImageThumb().equals(vo.getHeadImageThumb())){ - List members = groupMemberService.findByUserId(session.getId()); + List members = groupMemberService.findByUserId(session.getUserId()); for(GroupMember member:members){ member.setHeadImage(vo.getHeadImageThumb()); } @@ -183,7 +202,7 @@ public class UserServiceImpl extends ServiceImpl implements IU user.setHeadImage(vo.getHeadImage()); user.setHeadImageThumb(vo.getHeadImageThumb()); this.updateById(user); - log.info("用户信息更新,用户:{}}",user.toString()); + log.info("用户信息更新,用户:{}}", user); } @@ -195,19 +214,36 @@ public class UserServiceImpl extends ServiceImpl implements IU */ @Override public List findUserByNickName(String nickname) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda() - .like(User::getNickName,nickname) - .last("limit 20"); + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.like(User::getNickName,nickname).last("limit 20"); List users = this.list(queryWrapper); - List vos = users.stream().map(u-> { + return users.stream().map(u-> { UserVO vo = BeanUtils.copyProperties(u,UserVO.class); vo.setOnline(imClient.isOnline(u.getId())); return vo; }).collect(Collectors.toList()); - return vos; } + /** + * 根据用户昵称查询用户,最多返回20条数据 + * + * @param name 用户名或昵称 + * @return + */ + @Override + public List findUserByName(String name) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.like(User::getUserName,name) + .or() + .like(User::getNickName,name) + .last("limit 20"); + List users = this.list(queryWrapper); + return users.stream().map(u-> { + UserVO vo = BeanUtils.copyProperties(u,UserVO.class); + vo.setOnline(imClient.isOnline(u.getId())); + return vo; + }).collect(Collectors.toList()); + } /** * 判断用户是否在线,返回在线的用户id列表 diff --git a/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcServiceImpl.java b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcServiceImpl.java new file mode 100644 index 0000000..64177c2 --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcServiceImpl.java @@ -0,0 +1,245 @@ +package com.bx.implatform.service.impl; + +import com.bx.imclient.IMClient; +import com.bx.imcommon.model.IMPrivateMessage; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.implatform.vo.PrivateMessageVO; +import com.bx.implatform.config.ICEServer; +import com.bx.implatform.config.ICEServerConfig; +import com.bx.implatform.contant.RedisKey; +import com.bx.implatform.enums.MessageType; +import com.bx.implatform.exception.GlobalException; +import com.bx.implatform.service.IWebrtcService; +import com.bx.implatform.session.SessionContext; +import com.bx.implatform.session.UserSession; +import com.bx.implatform.session.WebrtcSession; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class WebrtcServiceImpl implements IWebrtcService { + + @Autowired + private IMClient imClient; + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private ICEServerConfig iceServerConfig; + + @Override + public void call(Long uid, String offer) { + UserSession session = SessionContext.getSession(); + if (!imClient.isOnline(uid)) { + throw new GlobalException("对方目前不在线"); + } + // 创建webrtc会话 + WebrtcSession webrtcSession = new WebrtcSession(); + webrtcSession.setCallerId(session.getUserId()); + webrtcSession.setCallerTerminal(session.getTerminal()); + String key = getSessionKey(session.getUserId(), uid); + redisTemplate.opsForValue().set(key, webrtcSession, 12, TimeUnit.HOURS); + // 向对方所有终端发起呼叫 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_CALL.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + messageInfo.setContent(offer); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + + } + + @Override + public void accept(Long uid, @RequestBody String answer) { + UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); + // 更新接受者信息 + webrtcSession.setAcceptorId(session.getUserId()); + webrtcSession.setAcceptorTerminal(session.getTerminal()); + String key = getSessionKey(session.getUserId(), uid); + redisTemplate.opsForValue().set(key, webrtcSession, 12, TimeUnit.HOURS); + // 向发起人推送接受通话信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_ACCEPT.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + messageInfo.setContent(answer); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + // 告知其他终端已经接受会话,中止呼叫 + sendMessage.setSendToSelf(true); + sendMessage.setSendResult(false); + sendMessage.setRecvTerminals((Collections.singletonList(webrtcSession.getCallerTerminal()))); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + } + + @Override + public void reject(Long uid) { + UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); + // 删除会话信息 + removeWebrtcSession(uid, session.getUserId()); + // 向发起人推送拒绝通话信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_REJECT.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + // 告知其他终端已经拒绝会话,中止呼叫 + sendMessage.setSendToSelf(true); + sendMessage.setSendResult(false); + sendMessage.setRecvTerminals(Collections.singletonList(webrtcSession.getCallerTerminal())); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + } + + @Override + public void cancel(Long uid) { + UserSession session = SessionContext.getSession(); + // 删除会话信息 + removeWebrtcSession(session.getUserId(), uid); + // 向对方所有终端推送取消通话信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_ACCEPT.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + sendMessage.setData(messageInfo); + // 通知对方取消会话 + imClient.sendPrivateMessage(sendMessage); + } + + @Override + public void failed(Long uid, String reason) { + UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); + // 删除会话信息 + removeWebrtcSession(uid, session.getUserId()); + // 向发起方推送通话失败信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_FAILED.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + // 告知其他终端已经会话失败,中止呼叫 + sendMessage.setSendToSelf(true); + sendMessage.setSendResult(false); + sendMessage.setRecvTerminals(Collections.singletonList(webrtcSession.getCallerTerminal())); + sendMessage.setData(messageInfo); + // 通知对方取消会话 + imClient.sendPrivateMessage(sendMessage); + + } + + @Override + public void leave(Long uid) { + UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); + // 删除会话信息 + removeWebrtcSession(uid, session.getUserId()); + // 向对方推送挂断通话信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_HANDUP.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + Integer terminal = getTerminalType(uid, webrtcSession); + sendMessage.setRecvTerminals(Collections.singletonList(terminal)); + sendMessage.setData(messageInfo); + // 通知对方取消会话 + imClient.sendPrivateMessage(sendMessage); + } + + @Override + public void candidate(Long uid, String candidate) { + UserSession session = SessionContext.getSession(); + // 查询webrtc会话 + WebrtcSession webrtcSession = getWebrtcSession(session.getUserId(), uid); + // 向发起方推送同步candidate信令 + PrivateMessageVO messageInfo = new PrivateMessageVO(); + messageInfo.setType(MessageType.RTC_CANDIDATE.code()); + messageInfo.setRecvId(uid); + messageInfo.setSendId(session.getUserId()); + messageInfo.setContent(candidate); + + IMPrivateMessage sendMessage = new IMPrivateMessage<>(); + sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); + sendMessage.setRecvId(uid); + sendMessage.setSendToSelf(false); + sendMessage.setSendResult(false); + Integer terminal = getTerminalType(uid, webrtcSession); + sendMessage.setRecvTerminals(Collections.singletonList(terminal)); + sendMessage.setData(messageInfo); + imClient.sendPrivateMessage(sendMessage); + } + + @Override + public List getIceServers() { + return iceServerConfig.getIceServers(); + } + + private WebrtcSession getWebrtcSession(Long userId, Long uid) { + String key = getSessionKey(userId, uid); + WebrtcSession webrtcSession = (WebrtcSession)redisTemplate.opsForValue().get(key); + if (webrtcSession == null) { + throw new GlobalException("视频通话已结束"); + } + return webrtcSession; + } + + private void removeWebrtcSession(Long userId, Long uid) { + String key = getSessionKey(userId, uid); + redisTemplate.delete(key); + } + + private String getSessionKey(Long id1, Long id2) { + Long minId = id1 > id2 ? id2 : id1; + Long maxId = id1 > id2 ? id1 : id2; + return String.join(":", RedisKey.IM_WEBRTC_SESSION, minId.toString(), maxId.toString()); + } + + private Integer getTerminalType(Long uid, WebrtcSession webrtcSession) { + if (uid.equals(webrtcSession.getCallerId())) { + return webrtcSession.getCallerTerminal(); + } + return webrtcSession.getAcceptorTerminal(); + } + +} diff --git a/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java index ada35c6..7fdb640 100644 --- a/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java +++ b/im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java @@ -54,7 +54,7 @@ public class FileService { public String uploadFile(MultipartFile file){ - Long userId = SessionContext.getSession().getId(); + Long userId = SessionContext.getSession().getUserId(); // 大小校验 if(file.getSize() > Constant.MAX_FILE_SIZE){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"文件大小不能超过10M"); @@ -71,7 +71,7 @@ public class FileService { public UploadImageVO uploadImage(MultipartFile file){ try { - Long userId = SessionContext.getSession().getId(); + Long userId = SessionContext.getSession().getUserId(); // 大小校验 if(file.getSize() > Constant.MAX_IMAGE_SIZE){ throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片大小不能超过5M"); diff --git a/im-platform/src/main/java/com/bx/implatform/session/UserSession.java b/im-platform/src/main/java/com/bx/implatform/session/UserSession.java index 0e7c81f..bf408da 100644 --- a/im-platform/src/main/java/com/bx/implatform/session/UserSession.java +++ b/im-platform/src/main/java/com/bx/implatform/session/UserSession.java @@ -1,11 +1,20 @@ package com.bx.implatform.session; +import com.bx.imcommon.model.IMSessionInfo; import lombok.Data; + + @Data -public class UserSession { +public class UserSession extends IMSessionInfo { - private Long id; + /* + * 用户名称 + */ private String userName; + + /* + * 用户昵称 + */ private String nickName; } diff --git a/im-platform/src/main/java/com/bx/implatform/session/WebrtcSession.java b/im-platform/src/main/java/com/bx/implatform/session/WebrtcSession.java new file mode 100644 index 0000000..fe4e08f --- /dev/null +++ b/im-platform/src/main/java/com/bx/implatform/session/WebrtcSession.java @@ -0,0 +1,32 @@ +package com.bx.implatform.session; + +import com.bx.imcommon.enums.IMTerminalType; +import io.swagger.models.auth.In; +import lombok.Data; + +/* + * webrtc 会话信息 + * @Author Blue + * @Date 2022/10/21 + */ +@Data +public class WebrtcSession { + /** + * 发起者id + */ + private Long callerId; + /** + * 发起者终端类型 + */ + private Integer callerTerminal; + + /** + * 接受者id + */ + private Long acceptorId; + + /** + * 接受者终端类型 + */ + private Integer acceptorTerminal; +} diff --git a/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java b/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java index 4cad011..83c36a5 100644 --- a/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java +++ b/im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java @@ -25,24 +25,8 @@ import java.util.*; public class DateTimeUtils extends DateUtils { public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; - public static final String FULL_DATE_FORMAT_CN = "yyyy年MM月dd日 HH时mm分ss秒"; public static final String PART_DATE_FORMAT = "yyyy-MM-dd"; - public static final String PART_DATE_FORMAT_TWO = "yyyy/MM/dd"; - public static final String PART_DATE_FORMAT_CN = "yyyy年MM月dd日"; public static final String PARTDATEFORMAT = "yyyyMMdd"; - public static final String YEAR_DATE_FORMAT = "yyyy"; - public static final String MONTH_DATE_FORMAT = "MM"; - public static final String DAY_DATE_FORMAT = "dd"; - public static final String WEEK_DATE_FORMAT = "week"; - - /** - * 星座 - */ - private final static int[] dayArr = new int[]{20, 19, 21, 20, 21, 22, 23, - 23, 23, 24, 23, 22}; - private final static String[] constellationArr = new String[]{"摩羯座", - "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", - "天蝎座", "射手座", "摩羯座"}; /** @@ -59,1070 +43,5 @@ public class DateTimeUtils extends DateUtils { return sdf.format(date); } - - /** - * 比较日期大小 - * - * @param dateX - * @param dateY - * @return x < y return [-1]; - * x = y return [0] ; - * x > y return [1] ; - */ - public static int compareDate(Date dateX, Date dateY) { - return dateX.compareTo(dateY); - } - - - /** - * 将日期字符串转换为日期格式类型 - * - * @param xDate - * @param xFormat 为NULL则转换如:2012-06-25 - * @return - */ - public static Date parseString2Date(String xDate, String xFormat) { - while (!isNotDate(xDate, xFormat)) { - xFormat = StringUtils.isEmpty(xFormat) == true ? PART_DATE_FORMAT : xFormat; - SimpleDateFormat sdf = new SimpleDateFormat(xFormat); - Date date = null; - try { - date = sdf.parse(xDate); - } catch (ParseException e) { - e.printStackTrace(); - return null; - } - return date; - } - return null; - } - - - /** - * 判断需要转换类型的日期字符串是否符合格式要求 - * - * @param xDate - * @return - */ - public static boolean isNotDate(String xDate, String format) { - SimpleDateFormat sdf; - try { - if (StringUtils.isEmpty(format)) { - sdf = new SimpleDateFormat(PART_DATE_FORMAT); - } else { - sdf = new SimpleDateFormat(format); - } - if (StringUtils.isEmpty(xDate)) { - return true; - } - sdf.parse(xDate); - return false; - } catch (ParseException e) { - e.printStackTrace(); - return true; - } - } - - public static boolean isDate(String xDate) { - return !isDate(xDate); - } - - - /** - * 获取俩个日期之间相差多少天 - * - * @param dateX - * @param dateY - * @return - */ - public static int getDiffDays(Date dateX, Date dateY) { - if ((dateX == null) || (dateY == null)) { - return 0; - } - - long dayX = dateX.getTime(); - long dayY = dateY.getTime(); - - return dayX > dayY ? (int) ((dayX - dayY) / (60 * 60 * 1000 * 24)) : (int) ((dayY - dayX) / (60 * 60 * 1000 * 24)); - } - - /** - * 获取俩个日期之间相差多少小时 - * - * @param dateX - * @param dateY - * @return - */ - public static int getDiffHours(Date dateX, Date dateY) { - if ((dateX == null) || (dateY == null)) { - return 0; - } - - long dayX = dateX.getTime(); - long dayY = dateY.getTime(); - - return dayX > dayY ? (int) ((dayX - dayY) / (60 * 60 * 1000)) : (int) ((dayY - dayX) / (60 * 60 * 1000)); - } - - /** - * 获取俩个日期之间相差多少小时 - * - * @param dateX - * @param dateY - * @return - */ - public static int getDiffMinute(Date dateX, Date dateY) { - if ((dateX == null) || (dateY == null)) { - return 0; - } - - long dayX = dateX.getTime(); - long dayY = dateY.getTime(); - - return dayX > dayY ? (int) ((dayX - dayY) / (60 * 1000)) : (int) ((dayY - dayX) / (60 * 1000)); - } - - /** - * 获取传值日期之后几天的日期并转换为字符串类型 - * - * @param date 需要转换的日期 date 可以为NULL 此条件下则获取当前日期 - * @param after 天数 - * @param xFormat 转换字符串类型 (可以为NULL) - * @return - */ - public static String getAfterCountDate(Date date, int after, String xFormat) { - date = date == null ? new Date() : date; - xFormat = StringUtils.isNotEmpty(xFormat) ? xFormat : PART_DATE_FORMAT; - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(Calendar.DAY_OF_MONTH, after); - return getFormatDate(calendar.getTime(), xFormat); - } - - /** - * 获取传值日期之前几天的日期并转换为字符串类型 - * - * @param date 需要转换的日期 date 可以为NULL 此条件下则获取当前日期 - * @param xFormat 转换字符串类型 (可以为NULL) - * @return - */ - public static String getBeforeCountDate(Date date, int before, String xFormat) { - date = date == null ? new Date() : date; - xFormat = StringUtils.isNotEmpty(xFormat) == true ? xFormat : PART_DATE_FORMAT; - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(Calendar.DAY_OF_MONTH, -before); - return getFormatDate(calendar.getTime(), xFormat); - } - - - /** - * 获取日期的参数 如:年 , 月 , 日 , 星期几 - * - * @param xDate 日期 可以为日期格式,可以是字符串格式; 为NULL或者其他格式时都判定为当前日期 - * @param xFormat 年 yyyy 月 MM 日 dd 星期 week ;其他条件下都返回0 - */ - public static int getDateTimeParam(Object xDate, String xFormat) { - xDate = xDate == null ? new Date() : xDate; - Date date = null; - if (xDate instanceof String) { - date = parseString2Date(xDate.toString(), null); - } else if (xDate instanceof Date) { - date = (Date) xDate; - } else { - date = new Date(); - } - date = date == null ? new Date() : date; - if (StringUtils.isNotEmpty(xFormat) - && (xFormat.equals(YEAR_DATE_FORMAT) - || xFormat.equals(MONTH_DATE_FORMAT) - || xFormat.equals(DAY_DATE_FORMAT))) { - return Integer.parseInt(getFormatDate(date, xFormat)); - } else if (StringUtils.isNotEmpty(xFormat) - && (WEEK_DATE_FORMAT.equals(xFormat))) { - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - int week = cal.get(Calendar.DAY_OF_WEEK) - 1 == 0 ? - 7 : cal.get(Calendar.DAY_OF_WEEK) - 1; - return week; - } else { - return 0; - } - } - - - /** - * 日期格式转换为时间戳 - * - * @param time - * @param format - * @return - */ - public static Long getLongTime(String time, String format) { - SimpleDateFormat sdf = new SimpleDateFormat(format); - Date date = null; - try { - date = sdf.parse(time); - return (date.getTime() / 1000); - } catch (ParseException e) { - e.printStackTrace(); - } - return null; - } - - - /** - * 获取星期字符串 - * - * @param xDate - * @return - */ - public static String getWeekString(Object xDate) { - int week = getDateTimeParam(xDate, WEEK_DATE_FORMAT); - switch (week) { - case 1: - return "星期一"; - case 2: - return "星期二"; - case 3: - return "星期三"; - case 4: - return "星期四"; - case 5: - return "星期五"; - case 6: - return "星期六"; - case 7: - return "星期日"; - default: - return ""; - } - } - - /** - * 获得十位时间 - */ - public static Long getTenBitTimestamp() { - return System.currentTimeMillis() / 1000; - } - - /** - * 获得某天的结束时间 - */ - public static Date getDateEnd(Date date) { - return new Date(date.getTime() + (86400 - 1) * 1000); - } - - /** - * 日期格式转换为毫秒 - * - * @param time - * @param format - * @return - */ - public static Long getLongDateTime(String time, String format) { - SimpleDateFormat sdf = new SimpleDateFormat(format); - Date date = null; - try { - date = sdf.parse(time); - return date.getTime(); - } catch (ParseException e) { - e.printStackTrace(); - } - return null; - } - - /** - * 获取某天开始时间戳_10位 - */ - public static Long getStartTimestamp(Date date) { - - Calendar calendar = Calendar.getInstance(); - date = date == null ? new Date() : date; - calendar.setTime(date); - - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - - return calendar.getTime().getTime() / 1000; - } - - /** - * 获取某天结束时间戳_10位 - */ - public static Long getEndTimestamp(Date date) { - - Calendar calendar = Calendar.getInstance(); - date = date == null ? new Date() : date; - calendar.setTime(date); - - calendar.set(Calendar.HOUR_OF_DAY, 23); - calendar.set(Calendar.MINUTE, 59); - calendar.set(Calendar.SECOND, 59); - calendar.set(Calendar.MILLISECOND, 999); - - return calendar.getTime().getTime() / 1000; - } - - /** - * 获取昨天日期 - * - * @param date - * @return - */ - public static Date getYesterday(Date date) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(Calendar.DAY_OF_MONTH, -1); - - calendar.set(Calendar.HOUR_OF_DAY, 9); - calendar.set(Calendar.MINUTE, 59); - calendar.set(Calendar.SECOND, 59); - calendar.set(Calendar.MILLISECOND, 999); - date = calendar.getTime(); - return date; - } - - /** - * 获取明天时间(参数时间+1天) - * - * @param date - * @return - */ - public static Date getTomorrowday(Date date) { - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.add(Calendar.DAY_OF_YEAR, +1); - return c.getTime(); - } - - /* 10位int型的时间戳转换为String(yyyy-MM-dd HH:mm:ss) - * - * @param time - * @return - */ - public static String timestampToString(Integer time, String format) { - // int转long时,先进行转型再进行计算,否则会是计算结束后在转型 - long temp = (long) time * 1000; - Timestamp ts = new Timestamp(temp); - String tsStr = ""; - DateFormat dateFormat = new SimpleDateFormat(format); - try { - // 方法一 - tsStr = dateFormat.format(ts); - } catch (Exception e) { - e.printStackTrace(); - } - return tsStr; - } - - /** - * 获取某天开始时间 - */ - public static Date getStartTime(Date date) { - - Calendar calendar = Calendar.getInstance(); - date = date == null ? new Date() : date; - calendar.setTime(date); - - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MILLISECOND, 0); - - return calendar.getTime(); - } - - /** - * 获取某天结束时间 - */ - public static Date getEndTime(Date date) { - - Calendar calendar = Calendar.getInstance(); - date = date == null ? new Date() : date; - calendar.setTime(date); - - calendar.set(Calendar.HOUR_OF_DAY, 23); - calendar.set(Calendar.MINUTE, 59); - calendar.set(Calendar.SECOND, 59); - calendar.set(Calendar.MILLISECOND, 999); - - return calendar.getTime(); - } - - /** - * Date类型转换为10位时间戳 - * - * @param time - * @return - */ - public static Integer DateToTimestamp(Date time) { - Timestamp ts = new Timestamp(time.getTime()); - - return (int) ((ts.getTime()) / 1000); - } - - /** - * 获取当前时间之前或之后几分钟 - * - * @param minute - * @return - */ - public static String getMinuteToString(int minute, Date time) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(time); - calendar.add(Calendar.MINUTE, minute); - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()); - } - - /** - * 获取当前时间之前或之后几分钟 - * - * @param minute - * @return - */ - public static Date getMinuteToTime(int minute, Date time) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(time); - calendar.add(Calendar.MINUTE, minute); - return calendar.getTime(); - } - - /** - * @return java.lang.String - * @Author 陈树森 - * @Description 将数据库里的timestamp转为指定日期数据格式字符串 - * @Date 16:11 2018/11/26 0026 - * @Param [timestamp, format] - **/ - public static String timestampToString(Timestamp timestamp, String format) { - return new SimpleDateFormat(format).format(timestamp); - } - - /** - * @return java.lang.String - * @Author 陈树森 - * @Description 将数据库里的timestamp转为默认格式 - * @Date 16:12 2018/11/26 0026 - * @Param [timestamp] - **/ - public static String timestampDefaultFormat(Timestamp timestamp) { - if (timestamp == null) { - return null; - } - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp); - } - - /** - * @return - * @Author 陈树森 - * @Description date默认格式yyyy-MM-dd HH:mm:ss - * @Date 11:48 2018/12/26 0026 - * @Param [date] - **/ - public static String dateDefaultFormat(Date date) { - if (date == null) { - return null; - } - return getFormatDate(date, "yyyy-MM-dd HH:mm:ss"); - } - - /** - * @return date - * @Description 获取当前时间N天后的时间 - * @Date 2019/01/09 13:58:00 - * @Param [day] - */ - public static Date getTimeByDay(int day) { - return getTimeByDay(new Date(), day); - } - - /** - * 获取指定时间N天后的时间 - * - * @param d1 - * @param day - * @return - */ - public static Date getTimeByDay(Date d1, int day) { - long temp1 = d1.getTime(); - temp1 = temp1 + day * 0x5265c00L; - return (new Date(temp1)); - } - - - /** - * 两个日期相差的分钟数 - * - * @param date1 - * @param date2 - * @return - */ - public static long getMinuteSpace(Date date1, Date date2) { - Calendar calendar1 = Calendar.getInstance(); - Calendar calendar2 = Calendar.getInstance(); - calendar1.setTime(date1); - calendar2.setTime(date2); - long milliseconds1 = calendar1.getTimeInMillis(); - long milliseconds2 = calendar2.getTimeInMillis(); - long diff = milliseconds2 - milliseconds1; - long diffDays = diff / (60 * 1000); - return Math.abs(diffDays); - } - - /** - * 获取当前时间的小时 - * - * @param date - * @return - */ - public static Integer getHourOfDate(Date date) { - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - return cal.get(Calendar.HOUR_OF_DAY); - } - - /** - * 获取指定时间,在每月的几号 - * - * @param date - * @return - */ - public static Integer getDayOfMonth(Date date) { - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - return cal.get(Calendar.DAY_OF_MONTH); - } - - /** - * 两个日期相差的天数 - * - * @param date1 - * @param date2 - * @return - */ - public static long getDateSpace(Date date1, Date date2) { - Calendar calendar1 = Calendar.getInstance(); - Calendar calendar2 = Calendar.getInstance(); - calendar1.setTime(date1); - calendar2.setTime(date2); - long milliseconds1 = calendar1.getTimeInMillis(); - long milliseconds2 = calendar2.getTimeInMillis(); - long diff = milliseconds2 - milliseconds1; - long diffDays = diff / (24 * 60 * 60 * 1000); - return Math.abs(diffDays); - } - - /** - * 获取今天还剩下多少秒 - * - * @return - */ - public static int getMiao(int num) { - Calendar curDate = Calendar.getInstance(); - //获取当前时间的第二天早上num点 - Calendar tommorowDate = new GregorianCalendar(curDate.get(Calendar.YEAR), curDate.get(Calendar.MONTH), curDate.get(Calendar.DATE) + 1, num, 0, 0); - return (int) (tommorowDate.getTimeInMillis() - curDate.getTimeInMillis()) / 1000; - } - - /** - * 时间相差多少秒 - */ - public static long secondsDifferen(Date d1, Date d2) { - long temp1 = d1.getTime(); - long temp2 = d2.getTime(); - return (long) ((temp2 - temp1) / 1000); - } - - /** - * 多少月后的时间 - */ - public static Date getTimeByMonth(int month) { - return getTimeByMonth(new Date(), month); - } - - public static Date getTimeByMonth(Date m1, int month) { - Calendar c = Calendar.getInstance(); - c.setTime(m1); - c.add(Calendar.MONTH, month); - Date m = c.getTime(); - return m; - } - - /** - * 天数转换为秒数 - */ - public static int dayConvertSecond(int day) { - //一天的秒数 - int secondOfDay = 60 * 60 * 24; - //计算N天的秒数 - return day * secondOfDay; - } - - /** - * 检查年月日是否合法 - * - * @param ymd - * @return - */ - public static boolean checkYearMonthDay(String ymd) { - if (ymd == null || ymd.length() == 0) { - return false; - } - String s = ymd.replaceAll("[/\\- ]", "/"); - SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd"); - try { - Date date = format.parse(s); - return true; - } catch (ParseException e) { - return false; - } - } - - - /** - * Java通过生日计算星座 生日格式必须为 yyyy-MM-dd - * - * @param birthday - * @return - */ - public static String getConstellation(String birthday) { - int month = 0; - int day = 0; - Date birthdayDateTime = DateTimeUtils.parseString2Date(birthday, "yyyy-MM-dd"); - if (null != birthdayDateTime) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(birthdayDateTime); - month = calendar.get(Calendar.MONTH) + 1; - day = calendar.get(Calendar.DAY_OF_MONTH); - } - return day < dayArr[month - 1] ? constellationArr[month - 1] - : constellationArr[month]; - } - - /** - * 通过生日计算属相 - * - * @param year - * @return - */ - public static String getYear(int year) { - if (year < 1900) { - return "未知"; - } - int start = 1900; - String[] years = new String[]{"鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", - "猴", "鸡", "狗", "猪"}; - return years[(year - start) % years.length]; - } - - /** - * 时分秒判断大小 - * - * @param s1 时间比较 - * @param s2 - * @return boolean true 大于 false 小于 - */ - public static boolean compareVehicle(String s1, String s2) { - boolean flag = true; - SimpleDateFormat sf = new SimpleDateFormat("HH:mm"); - try { - Date date1 = sf.parse(s1); - Date date2 = sf.parse(s2); - if (date1.getTime() > date2.getTime()) { - flag = true; - } else { - flag = false; - } - } catch (ParseException e) { - e.printStackTrace(); - } - return flag; - } - - /** - * 获得某天最大时间 2018-03-20 23:59:59 - * - * @param date - * @return - */ - public static String getEndOfDay(Date date) { - Calendar calendarEnd = Calendar.getInstance(); - calendarEnd.setTime(date); - calendarEnd.set(Calendar.HOUR_OF_DAY, 23); - calendarEnd.set(Calendar.MINUTE, 59); - calendarEnd.set(Calendar.SECOND, 59); - //防止mysql自动加一秒,毫秒设为0 - calendarEnd.set(Calendar.MILLISECOND, 0); - - return dateDefaultFormat(calendarEnd.getTime()); - } - - /** - * 获得某天最小时间 2018-03-20 00:00:00 - * - * @param date - * @return - */ - public static String getFirstOfDay(Date date) { - Calendar calendarStart = Calendar.getInstance(); - calendarStart.setTime(date); - calendarStart.set(Calendar.HOUR_OF_DAY, 0); - calendarStart.set(Calendar.MINUTE, 0); - calendarStart.set(Calendar.SECOND, 0); - calendarStart.set(Calendar.MILLISECOND, 0); - return dateDefaultFormat(calendarStart.getTime()); - } - - /** - * 两个时间相差距离多少天多少小时多少分多少秒 - * - * @param str1 时间参数 1 格式:1990-01-01 12:00:00 - * @param str2 时间参数 2 格式:2009-01-01 12:00:00 - * @return long[] 返回值为:{天, 时, 分, 秒} - */ - public static long[] getDistanceTimes(Date str1, Date str2) { - DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date one = str1; - Date two = str2; - long day = 0; - long hour = 0; - long min = 0; - long sec = 0; - long time1 = one.getTime(); - long time2 = two.getTime(); - long diff; - if (time1 < time2) { - diff = time2 - time1; - } else { - diff = time1 - time2; - } - day = diff / (24 * 60 * 60 * 1000); - hour = (diff / (60 * 60 * 1000) - day * 24); - min = ((diff / (60 * 1000)) - day * 24 * 60 - hour * 60); - sec = (diff / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60); - long[] times = {day, hour, min, sec}; - return times; - } - - /** - * 获取多少秒之后的日期 - * - * @param date - * @param second - * @return - */ - public static Date getLastDateBySecond(Date date, Integer second) { - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//24小时制 - //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//12小时制 - if (date == null) { - return null; - } - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.SECOND, second);//24小时制 - date = cal.getTime(); - cal = null; - return date; - } - - /** - * 根据年龄获取年份 - * - * @param age - * @return - */ - public static String getCalculateAge(int age) { - String toDay = DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.YEAR_DATE_FORMAT); - if (age > Integer.valueOf(toDay)) { - return null; - } - Integer year = Integer.valueOf(toDay) - age; - return year.toString(); - } - - /** - * 获取N天前的字符串格式日期 - * - * @param format 如:yyyy-MM-dd - * @param nDay - * @return - */ - public static String getNDayAgoByDay(String format, Integer nDay) { - Calendar calendar = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat(format); - calendar.add(Calendar.DATE, nDay); - String ndaysAgo = sdf.format(calendar.getTime()); - return ndaysAgo; - } - - /** - * 获取时间差,不考虑时分秒 - * - * @param dateBefore - * @param dateAfter - * @return int 1、昨天 2、近7天 3、近15天 4、近30天 - */ - public static Integer getTimeScope(Date dateBefore, Date dateAfter) { - int daysDifferent = compareDays(dateBefore, dateAfter);//1、昨天 2、近7天 3、近15天 4、近30天 - if (daysDifferent == 1) { - return 1; - } else if (daysDifferent >= 2 && daysDifferent <= 7) { - return 2; - } else if (daysDifferent >= 8 && daysDifferent <= 15) { - return 3; - } - return 4; - } - - public static int compareDays(Date datebefore, Date dateAfter) { - Calendar calendar1 = Calendar.getInstance(); - Calendar calendar2 = Calendar.getInstance(); - calendar1.setTime(datebefore); - calendar2.setTime(dateAfter); - int day1 = calendar1.get(Calendar.DAY_OF_YEAR); - int day2 = calendar2.get(Calendar.DAY_OF_YEAR); - int year1 = calendar1.get(Calendar.YEAR); - int year2 = calendar2.get(Calendar.YEAR); - if (year1 > year2) { - int tempyear = year1; - int tempday = day1; - day1 = day2; - day2 = tempday; - year1 = year2; - year2 = tempyear; - } - if (year1 == year2) { - return day2 - day1; - } else { - int DayCount = 0; - for (int i = year1; i < year2; i++) { - if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) { - DayCount += 366; - } else { - DayCount += 365; - } - } - return DayCount + (day2 - day1); - } - } - - public static Date asDate(LocalDateTime localDateTime) { - return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); - } - - /** - * 小于10 追加0 - * - * @param obj - * @return - */ - public static String appendZero(Integer obj) { - if (obj < 10) { - return '0' + String.valueOf(obj); - } else { - return String.valueOf(obj); - } - } - - /* - * 功能描述:
- * 获取时间与当前时间相差分钟数 - * @param: time - * @Return: int - * @Author: 97342 - * @Date: 2020/8/22 12:40 - */ - public static int getMinuteByNow(Date time) throws Exception { - Date date = new Date(); - long millsecond = date.getTime() - time.getTime(); - if (millsecond < 0) { - throw new Exception("时间超前异常"); - } - int minute = (int) millsecond / 60000; - return minute; - } - - /* - * 功能描述:
- * 时间戳转LocalDateTime - * @param: time - * @Return: java.time.LocalDateTime - * @Author: 97342 - * @Date: 2020/8/27 16:17 - */ - public static LocalDateTime longToLocalDateTime(Long time) { - LocalDateTime localDateTime = new Date(time).toInstant().atOffset(ZoneOffset.of("+08:00")).toLocalDateTime(); - return localDateTime; - } - - /** - * 获取 一天的开始时间 - * - * @param localDateTime - * @return java.time.LocalDateTime - * @author BNMZY - */ - public static LocalDateTime getTimeBegin(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - DateTime dateTime = DateUtil.beginOfDay(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取 一天结束的时间 - * - * @param localDateTime - * @return java.time.LocalDateTime - * @author BNMZY - */ - public static LocalDateTime getTimeEnd(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - DateTime dateTime = DateUtil.endOfDay(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 指定日期所在月的第一天 - * - * @param localDateTime - * @return - */ - public static LocalDateTime getMonthStart(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - DateTime dateTime = DateUtil.beginOfMonth(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 功能描述:
- * LocalDateTime 转String 格式 yyyy-MM-dd HH:mm:ss - * - * @param: time - * @Return: java.lang.String - * @Author: 97342 - * @Date: 2020/9/21 15:11 - */ - public static String LocalDateTimeToString(LocalDateTime time) { - - String format = time.format(DateTimeFormatter.ofPattern(FULL_DATE_FORMAT)); - return format; - - } - - /** - * 获取上周一的日期 - * - * @param localDateTime - * @return - */ - public static LocalDateTime getLastWeekMonday(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.DAY_OF_WEEK, -7); - date = cal.getTime(); - DateTime dateTime = DateUtil.beginOfWeek(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取本周一的日期 - * - * @param localDateTime - * @return - */ - public static LocalDateTime getThisWeekMonday(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - DateTime dateTime = DateUtil.beginOfWeek(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取上周最后一天的日期 - * - * @param localDateTime - * @return - */ - public static LocalDateTime getLastWeekSunday(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.DAY_OF_WEEK, -7); - date = cal.getTime(); - DateTime dateTime = DateUtil.endOfWeek(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取本月第一天的日期 - * - * @return - */ - public static LocalDateTime getFirstDayOfMonth(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - DateTime dateTime = DateUtil.beginOfMonth(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取上月第一天的日期 - * - * @return - */ - public static LocalDateTime getFirstDayLastMonth(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.MONTH, -1); - date = cal.getTime(); - DateTime dateTime = DateUtil.beginOfMonth(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * 获取上月最后一天的日期 - * - * @return - */ - public static LocalDateTime getLastDayLastMonth(LocalDateTime localDateTime) { - String format = DateUtil.formatLocalDateTime(localDateTime); - Date date = DateUtil.parse(format); - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.MONTH, -1); - date = cal.getTime(); - DateTime dateTime = DateUtil.endOfMonth(date); - return DateUtil.toLocalDateTime(dateTime); - } - - /** - * - * @param startDay 开始日期 - * @param endDay 结束日期 - * @return 返回包含开始结束日期的集合 - */ - public static List getDays(LocalDate startDay, LocalDate endDay){ - List days = new ArrayList<>(); - LocalDate start= ObjectUtil.clone(startDay); - LocalDate end= ObjectUtil.clone(endDay); - days.add(start); - while (start.isBefore(end)){ - start=start.plusDays(1L); - days.add(start); - } - Collections.reverse(days); - return days; - } - + } \ No newline at end of file diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java index ebfe425..72480e8 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupMessageVO.java @@ -1,28 +1,42 @@ package com.bx.implatform.vo; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import com.bx.imcommon.serializer.DateToLongSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Data; -import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import java.util.Date; @Data -@ApiModel("群聊消息VO") public class GroupMessageVO { - @NotNull(message="群聊id不可为空") - @ApiModelProperty(value = "群聊id") + /* + * 消息id + */ + private Long id; + + /* + * 群聊id + */ private Long groupId; + /* + * 发送者id + */ + private Long sendId; - @Length(max=1024,message = "内容长度不得大于1024") - @NotEmpty(message="发送内容不可为空") - @ApiModelProperty(value = "发送内容") + /* + * 消息内容 + */ private String content; - @NotNull(message="消息类型不可为空") - @ApiModelProperty(value = "消息类型") + /* + * 消息内容类型 具体枚举值由应用层定义 + */ private Integer type; + + /** + * 发送时间 + */ + @JsonSerialize(using = DateToLongSerializer.class) + private Date sendTime; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java b/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java index 9378fd1..3f98bed 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java @@ -12,7 +12,7 @@ import javax.validation.constraints.NotNull; @ApiModel("群信息VO") public class GroupVO { - @NotNull(message = "群id不可为空") + @ApiModelProperty(value = "群id") private Long id; @@ -21,7 +21,6 @@ public class GroupVO { @ApiModelProperty(value = "群名称") private String name; - @NotNull(message = "群主id不可为空") @ApiModelProperty(value = "群主id") private Long ownerId; diff --git a/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java b/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java index 500bb43..1b765bc 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/LoginVO.java @@ -19,4 +19,5 @@ public class LoginVO { @ApiModelProperty(value = "refreshToken过期时间(秒)") private Integer refreshTokenExpiresIn; + } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java b/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java index 7efdcc4..1b7c41a 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/PrivateMessageVO.java @@ -1,31 +1,42 @@ package com.bx.implatform.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import com.bx.imcommon.serializer.DateToLongSerializer; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.Data; -import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import java.util.Date; @Data -@ApiModel("私聊消息VO") public class PrivateMessageVO { + /* + * 消息id + */ + private long id; - @NotNull(message="接收用户id不可为空") - @ApiModelProperty(value = "接收用户id") - private Long recvId; + /* + * 发送者id + */ + private Long sendId; + /* + * 接收者id + */ + private Long recvId; - @Length(max=1024,message = "内容长度不得大于1024") - @NotEmpty(message="发送内容不可为空") - @ApiModelProperty(value = "发送内容") + /* + * 发送内容 + */ private String content; - @NotNull(message="消息类型不可为空") - @ApiModelProperty(value = "消息类型") + /* + * 消息内容类型 IMCmdType + */ private Integer type; + /** + * 发送时间 + */ + @JsonSerialize(using = DateToLongSerializer.class) + private Date sendTime; } diff --git a/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java b/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java index e114e73..13a5360 100644 --- a/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java +++ b/im-platform/src/main/java/com/bx/implatform/vo/UserVO.java @@ -30,7 +30,10 @@ public class UserVO { @ApiModelProperty(value = "性别") private Integer sex; - @Length(max = 64,message = "个性签名不能大于1024个字符") + @ApiModelProperty(value = "用户类型 1:普通用户 2:审核账户") + private Integer type; + + @Length(max = 1024,message = "个性签名不能大于1024个字符") @ApiModelProperty(value = "个性签名") private String signature; @@ -40,7 +43,6 @@ public class UserVO { @ApiModelProperty(value = "头像缩略图") private String headImageThumb; - @ApiModelProperty(value = "是否在线") private Boolean online; diff --git a/im-platform/src/main/resources/db/db.sql b/im-platform/src/main/resources/db/db.sql index 5e2365b..9cca837 100644 --- a/im-platform/src/main/resources/db/db.sql +++ b/im-platform/src/main/resources/db/db.sql @@ -6,7 +6,8 @@ create table `im_user`( `head_image` varchar(255) default '' comment '用户头像', `head_image_thumb` varchar(255) default '' comment '用户头像缩略图', `password` varchar(255) not null comment '密码(明文)', - `sex` tinyint(1) default 0 comment '性别 0:男 1::女', + `sex` tinyint(1) default 0 comment '性别 0:男 1:女', + `type` smallint default 1 comment '用户类型 1:普通用户 2:审核账户', `signature` varchar(1024) default '' comment '个性签名', `last_login_time` datetime DEFAULT null comment '最后登录时间', `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间', @@ -45,8 +46,8 @@ create table `im_group`( `head_image_thumb` varchar(255) default '' comment '群头像缩略图', `notice` varchar(1024) default '' comment '群公告', `remark` varchar(255) default '' comment '群备注', - `deleted` tinyint(1) DEFAULT 0 comment '是否已删除', - `created_time` datetime DEFAULT CURRENT_TIMESTAMP comment '创建时间' + `deleted` tinyint(1) default 0 comment '是否已删除', + `created_time` datetime default CURRENT_TIMESTAMP comment '创建时间' )ENGINE=InnoDB CHARSET=utf8mb3 comment '群'; create table `im_group_member`( diff --git a/im-server/src/main/java/com/bx/imserver/IMServerApp.java b/im-server/src/main/java/com/bx/imserver/IMServerApp.java index b938bf6..42373c5 100644 --- a/im-server/src/main/java/com/bx/imserver/IMServerApp.java +++ b/im-server/src/main/java/com/bx/imserver/IMServerApp.java @@ -19,5 +19,4 @@ public class IMServerApp { SpringApplication.run(IMServerApp.class,args); } - } diff --git a/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java b/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java index d2f946f..5ae1fbd 100644 --- a/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java +++ b/im-server/src/main/java/com/bx/imserver/config/RedisConfig.java @@ -1,5 +1,6 @@ package com.bx.imserver.config; +import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; @@ -26,9 +27,9 @@ public class RedisConfig { public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); - // 设置值(value)的序列化采用jackson2JsonRedisSerializer - redisTemplate.setValueSerializer(jackson2JsonRedisSerializer()); - redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer()); + // 设置值(value)的序列化采用FastJsonRedisSerializer + redisTemplate.setValueSerializer(fastJsonRedisSerializer()); + redisTemplate.setHashValueSerializer(fastJsonRedisSerializer()); // 设置键(key)的序列化采用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); @@ -36,17 +37,11 @@ public class RedisConfig { return redisTemplate; } - @Bean - public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer(){ - Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); - ObjectMapper om = new ObjectMapper(); - om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); - // 解决jackson2无法反序列化LocalDateTime的问题 - om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); - om.registerModule(new JavaTimeModule()); - om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); - jackson2JsonRedisSerializer.setObjectMapper(om); - return jackson2JsonRedisSerializer; + + public FastJsonRedisSerializer fastJsonRedisSerializer(){ + FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); + return fastJsonRedisSerializer; } + } diff --git a/im-server/src/main/java/com/bx/imserver/constant/ChannelAttrKey.java b/im-server/src/main/java/com/bx/imserver/constant/ChannelAttrKey.java new file mode 100644 index 0000000..7a4daee --- /dev/null +++ b/im-server/src/main/java/com/bx/imserver/constant/ChannelAttrKey.java @@ -0,0 +1,12 @@ +package com.bx.imserver.constant; + +public class ChannelAttrKey { + + // 用户ID + public static final String USER_ID = "USER_ID"; + // 终端类型 + public static final String TERMINAL_TYPE = "TERMINAL_TYPE"; + // 心跳次数 + public static final String HEARTBEAT_TIMES = "HEARTBEAt_TIMES"; + +} diff --git a/im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java b/im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java index 9a13f62..babd2a0 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java +++ b/im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java @@ -1,9 +1,10 @@ package com.bx.imserver.netty; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.model.IMSendInfo; -import com.bx.imserver.netty.processor.MessageProcessor; +import com.bx.imserver.constant.ChannelAttrKey; +import com.bx.imserver.netty.processor.AbstractMessageProcessor; import com.bx.imserver.netty.processor.ProcessorFactory; import com.bx.imserver.util.SpringContextHolder; import io.netty.channel.ChannelHandlerContext; @@ -33,7 +34,7 @@ public class IMChannelHandler extends SimpleChannelInboundHandler { @Override protected void channelRead0(ChannelHandlerContext ctx, IMSendInfo sendInfo) throws Exception { // 创建处理器进行处理 - MessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.fromCode(sendInfo.getCmd())); + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.fromCode(sendInfo.getCmd())); processor.process(ctx,processor.transForm(sendInfo.getData())); } @@ -64,18 +65,20 @@ public class IMChannelHandler extends SimpleChannelInboundHandler { @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { - AttributeKey attr = AttributeKey.valueOf("USER_ID"); - Long userId = ctx.channel().attr(attr).get(); - ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId); + AttributeKey userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID); + Long userId = ctx.channel().attr(userIdAttr).get(); + AttributeKey terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); + Integer terminal = ctx.channel().attr(terminalAttr).get(); + ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId,terminal); // 判断一下,避免异地登录导致的误删 if(context != null && ctx.channel().id().equals(context.channel().id())){ // 移除channel - UserChannelCtxMap.removeChannelCtx(userId); + UserChannelCtxMap.removeChannelCtx(userId,terminal); // 用户下线 RedisTemplate redisTemplate = SpringContextHolder.getBean("redisTemplate"); - String key = RedisKey.IM_USER_SERVER_ID + userId; + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID,userId.toString(), terminal.toString()); redisTemplate.delete(key); - log.info("断开连接,userId:{}",userId); + log.info("断开连接,userId:{},终端类型:{}",userId,terminal); } } @@ -87,7 +90,9 @@ public class IMChannelHandler extends SimpleChannelInboundHandler { // 在规定时间内没有收到客户端的上行数据, 主动断开连接 AttributeKey attr = AttributeKey.valueOf("USER_ID"); Long userId = ctx.channel().attr(attr).get(); - log.info("心跳超时,即将断开连接,用户id:{} ",userId); + AttributeKey terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); + Integer ternimal = ctx.channel().attr(terminalAttr).get(); + log.info("心跳超时,即将断开连接,用户id:{},终端类型:{} ",userId,ternimal); ctx.channel().close(); } } else { diff --git a/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java b/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java index 60c640e..619d770 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java +++ b/im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java @@ -1,6 +1,6 @@ package com.bx.imserver.netty; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; @@ -39,7 +39,7 @@ public class IMServerGroup implements CommandLineRunner { @Override public void run(String... args) throws Exception { // 初始化SERVER_ID - String key = RedisKey.IM_MAX_SERVER_ID; + String key = IMRedisKey.IM_MAX_SERVER_ID; serverId = redisTemplate.opsForValue().increment(key,1); // 启动服务 for(IMServer imServer:imServers){ diff --git a/im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java b/im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java index 8f5de0a..7bd3fcc 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java +++ b/im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java @@ -2,6 +2,7 @@ package com.bx.imserver.netty; import io.netty.channel.ChannelHandlerContext; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -9,21 +10,34 @@ import java.util.concurrent.ConcurrentHashMap; public class UserChannelCtxMap { /* - * 维护userId和ctx的关联关系,格式:Map + * 维护userId和ctx的关联关系,格式:Map> */ - private static Map channelMap = new ConcurrentHashMap(); + private static Map> channelMap = new ConcurrentHashMap(); - public static void addChannelCtx(Long userId,ChannelHandlerContext ctx){ - channelMap.put(userId,ctx); + public static void addChannelCtx(Long userId,Integer channel,ChannelHandlerContext ctx){ + channelMap.computeIfAbsent(userId,key -> new ConcurrentHashMap()).put(channel,ctx); } - public static void removeChannelCtx(Long userId){ - if(userId != null){ - channelMap.remove(userId); + public static void removeChannelCtx(Long userId,Integer terminal){ + if(userId != null && terminal != null && channelMap.containsKey(userId)){ + Map userChannelMap = channelMap.get(userId); + if(userChannelMap.containsKey(terminal)){ + userChannelMap.remove(terminal); + } } } - public static ChannelHandlerContext getChannelCtx(Long userId){ + public static ChannelHandlerContext getChannelCtx(Long userId,Integer terminal){ + if(userId != null && terminal != null && channelMap.containsKey(userId)){ + Map userChannelMap = channelMap.get(userId); + if(userChannelMap.containsKey(terminal)){ + return userChannelMap.get(terminal); + } + } + return null; + } + + public static Map getChannelCtx(Long userId){ if(userId == null){ return null; } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/MessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/AbstractMessageProcessor.java similarity index 83% rename from im-server/src/main/java/com/bx/imserver/netty/processor/MessageProcessor.java rename to im-server/src/main/java/com/bx/imserver/netty/processor/AbstractMessageProcessor.java index c600968..264edac 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/MessageProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/AbstractMessageProcessor.java @@ -3,7 +3,7 @@ package com.bx.imserver.netty.processor; import io.netty.channel.ChannelHandlerContext; -public abstract class MessageProcessor { +public abstract class AbstractMessageProcessor { public void process(ChannelHandlerContext ctx,T data){} diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java index 3b589b9..0446f05 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java @@ -1,12 +1,12 @@ package com.bx.imserver.netty.processor; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.enums.IMSendCode; -import com.bx.imcommon.model.GroupMessageInfo; import com.bx.imcommon.model.IMRecvInfo; import com.bx.imcommon.model.IMSendInfo; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.imcommon.model.IMSendResult; import com.bx.imserver.netty.UserChannelCtxMap; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; @@ -19,55 +19,53 @@ import java.util.List; @Slf4j @Component -public class GroupMessageProcessor extends MessageProcessor> { +public class GroupMessageProcessor extends AbstractMessageProcessor { @Autowired private RedisTemplate redisTemplate; @Async @Override - public void process(IMRecvInfo recvInfo) { - GroupMessageInfo messageInfo = recvInfo.getData(); - List recvIds = recvInfo.getRecvIds(); - log.info("接收到群消息,发送者:{},群id:{},接收id:{},内容:{}",messageInfo.getSendId(),messageInfo.getGroupId(),recvIds,messageInfo.getContent()); - for(Long recvId:recvIds){ + public void process(IMRecvInfo recvInfo) { + IMUserInfo sender = recvInfo.getSender(); + List receivers = recvInfo.getReceivers(); + log.info("接收到群消息,发送者:{},接收用户数量:{},内容:{}",sender.getId(),receivers.size(),recvInfo.getData()); + for(IMUserInfo receiver:receivers){ try { - ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(recvId); + ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(),receiver.getTerminal()); if(channelCtx != null){ // 推送消息到用户 IMSendInfo sendInfo = new IMSendInfo(); sendInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); - sendInfo.setData(messageInfo); + sendInfo.setData(recvInfo.getData()); channelCtx.channel().writeAndFlush(sendInfo); // 消息发送成功确认 - String key = RedisKey.IM_RESULT_GROUP_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.SUCCESS); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); + sendResult(recvInfo,receiver,IMSendCode.SUCCESS); }else { - // 消息发送失败确认 - String key = RedisKey.IM_RESULT_GROUP_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.NOT_FIND_CHANNEL); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); - log.error("未找到WS连接,发送者:{},群id:{},接收id:{},内容:{}",messageInfo.getSendId(),messageInfo.getGroupId(),recvIds,messageInfo.getContent()); + // 消息发送成功确认 + sendResult(recvInfo,receiver,IMSendCode.NOT_FIND_CHANNEL); + log.error("未找到channel,发送者:{},接收id:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); } }catch (Exception e){ // 消息发送失败确认 - String key = RedisKey.IM_RESULT_GROUP_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.UNKONW_ERROR); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); - log.error("发送消息异常,发送者:{},群id:{},接收id:{},内容:{}",messageInfo.getSendId(),messageInfo.getGroupId(),recvIds,messageInfo.getContent()); + sendResult(recvInfo,receiver,IMSendCode.UNKONW_ERROR); + log.error("发送消息异常,发送者:{},接收id:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); } } } + + private void sendResult(IMRecvInfo recvInfo,IMUserInfo receiver,IMSendCode sendCode){ + if(recvInfo.getSendResult()) { + IMSendResult result = new IMSendResult(); + result.setSender(recvInfo.getSender()); + result.setReceiver(receiver); + result.setCode(sendCode.code()); + result.setData(recvInfo.getData()); + // 推送到结果队列 + String key = IMRedisKey.IM_RESULT_GROUP_QUEUE; + redisTemplate.opsForList().rightPush(key, result); + } + } } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/HeartbeatProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/HeartbeatProcessor.java index f0001d0..b72bccd 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/HeartbeatProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/HeartbeatProcessor.java @@ -1,11 +1,12 @@ package com.bx.imserver.netty.processor; import cn.hutool.core.bean.BeanUtil; -import com.bx.imcommon.contant.Constant; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMConstant; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; -import com.bx.imcommon.model.HeartbeatInfo; +import com.bx.imcommon.model.IMHeartbeatInfo; import com.bx.imcommon.model.IMSendInfo; +import com.bx.imserver.constant.ChannelAttrKey; import com.bx.imserver.netty.ws.WebSocketServer; import io.netty.channel.ChannelHandlerContext; import io.netty.util.AttributeKey; @@ -19,40 +20,42 @@ import java.util.concurrent.TimeUnit; @Slf4j @Component -public class HeartbeatProcessor extends MessageProcessor { +public class HeartbeatProcessor extends AbstractMessageProcessor { @Autowired - private WebSocketServer WSServer; + private WebSocketServer wsServer; @Autowired RedisTemplate redisTemplate; @Override - public void process(ChannelHandlerContext ctx, HeartbeatInfo beatInfo) { + public void process(ChannelHandlerContext ctx, IMHeartbeatInfo beatInfo) { // 响应ws IMSendInfo sendInfo = new IMSendInfo(); sendInfo.setCmd(IMCmdType.HEART_BEAT.code()); ctx.channel().writeAndFlush(sendInfo); // 设置属性 - AttributeKey attr = AttributeKey.valueOf("HEARTBEAt_TIMES"); - Long heartbeatTimes = ctx.channel().attr(attr).get(); - ctx.channel().attr(attr).set(++heartbeatTimes); + AttributeKey heartBeatAttr = AttributeKey.valueOf(ChannelAttrKey.HEARTBEAT_TIMES); + Long heartbeatTimes = ctx.channel().attr(heartBeatAttr).get(); + ctx.channel().attr(heartBeatAttr).set(++heartbeatTimes); if(heartbeatTimes%10 == 0){ // 每心跳10次,用户在线状态续一次命 - attr = AttributeKey.valueOf("USER_ID"); - Long userId = ctx.channel().attr(attr).get(); - String key = RedisKey.IM_USER_SERVER_ID+userId; - redisTemplate.expire(key, Constant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS); + AttributeKey userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID); + Long userId = ctx.channel().attr(userIdAttr).get(); + AttributeKey terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); + Integer ternimal = ctx.channel().attr(terminalAttr).get(); + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID,userId.toString(),ternimal.toString()); + redisTemplate.expire(key, IMConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS); } } @Override - public HeartbeatInfo transForm(Object o) { + public IMHeartbeatInfo transForm(Object o) { HashMap map = (HashMap)o; - HeartbeatInfo heartbeatInfo = BeanUtil.fillBeanWithMap(map, new HeartbeatInfo(), false); + IMHeartbeatInfo heartbeatInfo = BeanUtil.fillBeanWithMap(map, new IMHeartbeatInfo(), false); return heartbeatInfo; } } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/LoginProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/LoginProcessor.java index 73b3a6e..fd3d3f9 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/LoginProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/LoginProcessor.java @@ -1,15 +1,17 @@ package com.bx.imserver.netty.processor; import cn.hutool.core.bean.BeanUtil; -import com.bx.imcommon.contant.Constant; -import com.bx.imcommon.contant.RedisKey; +import com.alibaba.fastjson.JSON; +import com.bx.imcommon.contant.IMConstant; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.model.IMSendInfo; -import com.bx.imcommon.model.LoginInfo; +import com.bx.imcommon.model.IMSessionInfo; +import com.bx.imcommon.model.IMLoginInfo; import com.bx.imcommon.util.JwtUtil; +import com.bx.imserver.constant.ChannelAttrKey; import com.bx.imserver.netty.IMServerGroup; import com.bx.imserver.netty.UserChannelCtxMap; -import com.bx.imserver.netty.ws.WebSocketServer; import io.netty.channel.ChannelHandlerContext; import io.netty.util.AttributeKey; import lombok.extern.slf4j.Slf4j; @@ -23,11 +25,7 @@ import java.util.concurrent.TimeUnit; @Slf4j @Component -public class LoginProcessor extends MessageProcessor { - - - @Autowired - private WebSocketServer WSServer; +public class LoginProcessor extends AbstractMessageProcessor { @Autowired RedisTemplate redisTemplate; @@ -36,14 +34,17 @@ public class LoginProcessor extends MessageProcessor { private String accessTokenSecret; @Override - synchronized public void process(ChannelHandlerContext ctx, LoginInfo loginInfo) { + synchronized public void process(ChannelHandlerContext ctx, IMLoginInfo loginInfo) { if(!JwtUtil.checkSign(loginInfo.getAccessToken(),accessTokenSecret)){ ctx.channel().close(); log.warn("用户token校验不通过,强制下线,token:{}",loginInfo.getAccessToken()); } - Long userId = JwtUtil.getUserId(loginInfo.getAccessToken()); + String strInfo = JwtUtil.getInfo(loginInfo.getAccessToken()); + IMSessionInfo sessionInfo = JSON.parseObject(strInfo,IMSessionInfo.class); + Long userId = sessionInfo.getUserId(); + Integer terminal = sessionInfo.getTerminal(); log.info("用户登录,userId:{}",userId); - ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId); + ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId,terminal); if(context != null && !ctx.channel().id().equals(context.channel().id())){ // 不允许多地登录,强制下线 IMSendInfo sendInfo = new IMSendInfo(); @@ -53,16 +54,19 @@ public class LoginProcessor extends MessageProcessor { log.info("异地登录,强制下线,userId:{}",userId); } // 绑定用户和channel - UserChannelCtxMap.addChannelCtx(userId,ctx); + UserChannelCtxMap.addChannelCtx(userId,terminal,ctx); // 设置用户id属性 - AttributeKey attr = AttributeKey.valueOf("USER_ID"); - ctx.channel().attr(attr).set(userId); - // 心跳次数 - attr = AttributeKey.valueOf("HEARTBEAt_TIMES"); - ctx.channel().attr(attr).set(0L); + AttributeKey userIdAttr = AttributeKey.valueOf(ChannelAttrKey.USER_ID); + ctx.channel().attr(userIdAttr).set(userId); + // 设置用户终端类型 + AttributeKey terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); + ctx.channel().attr(terminalAttr).set(terminal); + // 初始化心跳次数 + AttributeKey heartBeatAttr = AttributeKey.valueOf("HEARTBEAt_TIMES"); + ctx.channel().attr(heartBeatAttr).set(0L); // 在redis上记录每个user的channelId,15秒没有心跳,则自动过期 - String key = RedisKey.IM_USER_SERVER_ID+userId; - redisTemplate.opsForValue().set(key, IMServerGroup.serverId, Constant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS); + String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID,userId.toString(), terminal.toString()); + redisTemplate.opsForValue().set(key, IMServerGroup.serverId, IMConstant.ONLINE_TIMEOUT_SECOND, TimeUnit.SECONDS); // 响应ws IMSendInfo sendInfo = new IMSendInfo(); sendInfo.setCmd(IMCmdType.LOGIN.code()); @@ -71,9 +75,9 @@ public class LoginProcessor extends MessageProcessor { @Override - public LoginInfo transForm(Object o) { + public IMLoginInfo transForm(Object o) { HashMap map = (HashMap)o; - LoginInfo loginInfo = BeanUtil.fillBeanWithMap(map, new LoginInfo(), false); + IMLoginInfo loginInfo = BeanUtil.fillBeanWithMap(map, new IMLoginInfo(), false); return loginInfo; } } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java b/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java index 659412c..f65a635 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/PrivateMessageProcessor.java @@ -1,12 +1,12 @@ package com.bx.imserver.netty.processor; -import com.bx.imcommon.contant.RedisKey; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.enums.IMSendCode; import com.bx.imcommon.model.IMRecvInfo; import com.bx.imcommon.model.IMSendInfo; -import com.bx.imcommon.model.PrivateMessageInfo; -import com.bx.imcommon.model.SendResult; +import com.bx.imcommon.model.IMUserInfo; +import com.bx.imcommon.model.IMSendResult; import com.bx.imserver.netty.UserChannelCtxMap; import io.netty.channel.ChannelHandlerContext; import lombok.extern.slf4j.Slf4j; @@ -16,52 +16,49 @@ import org.springframework.stereotype.Component; @Slf4j @Component -public class PrivateMessageProcessor extends MessageProcessor> { +public class PrivateMessageProcessor extends AbstractMessageProcessor { @Autowired private RedisTemplate redisTemplate; @Override - public void process(IMRecvInfo recvInfo) { - PrivateMessageInfo messageInfo = recvInfo.getData(); - Long recvId = recvInfo.getRecvIds().get(0); - log.info("接收到消息,发送者:{},接收者:{},内容:{}",messageInfo.getSendId(),recvId,messageInfo.getContent()); + public void process(IMRecvInfo recvInfo) { + IMUserInfo sender = recvInfo.getSender(); + IMUserInfo receiver = recvInfo.getReceivers().get(0); + log.info("接收到消息,发送者:{},接收者:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); try{ - ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(recvId); + ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(),receiver.getTerminal()); if(channelCtx != null ){ // 推送消息到用户 IMSendInfo sendInfo = new IMSendInfo(); sendInfo.setCmd(IMCmdType.PRIVATE_MESSAGE.code()); - sendInfo.setData(messageInfo); + sendInfo.setData(recvInfo.getData()); channelCtx.channel().writeAndFlush(sendInfo); // 消息发送成功确认 - String key = RedisKey.IM_RESULT_PRIVATE_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.SUCCESS); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); + sendResult(recvInfo,IMSendCode.SUCCESS); }else{ // 消息推送失败确认 - String key = RedisKey.IM_RESULT_PRIVATE_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.NOT_FIND_CHANNEL); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); - log.error("未找到WS连接,发送者:{},接收者:{},内容:{}",messageInfo.getSendId(),recvId,messageInfo.getContent()); + sendResult(recvInfo,IMSendCode.NOT_FIND_CHANNEL); + log.error("未找到channel,发送者:{},接收者:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); } }catch (Exception e){ // 消息推送失败确认 - String key = RedisKey.IM_RESULT_PRIVATE_QUEUE; - SendResult sendResult = new SendResult(); - sendResult.setRecvId(recvId); - sendResult.setCode(IMSendCode.UNKONW_ERROR); - sendResult.setMessageInfo(messageInfo); - redisTemplate.opsForList().rightPush(key,sendResult); - log.error("发送异常,发送者:{},接收者:{},内容:{}",messageInfo.getSendId(),recvId,messageInfo.getContent(),e); + sendResult(recvInfo,IMSendCode.UNKONW_ERROR); + log.error("发送异常,发送者:{},接收者:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData(),e); } } + private void sendResult(IMRecvInfo recvInfo,IMSendCode sendCode){ + if(recvInfo.getSendResult()) { + IMSendResult result = new IMSendResult(); + result.setSender(recvInfo.getSender()); + result.setReceiver(recvInfo.getReceivers().get(0)); + result.setCode(sendCode.code()); + result.setData(recvInfo.getData()); + // 推送到结果队列 + String key = IMRedisKey.IM_RESULT_PRIVATE_QUEUE; + redisTemplate.opsForList().rightPush(key, result); + } + } } diff --git a/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java b/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java index c5e094b..b3c71d1 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java +++ b/im-server/src/main/java/com/bx/imserver/netty/processor/ProcessorFactory.java @@ -5,20 +5,20 @@ import com.bx.imserver.util.SpringContextHolder; public class ProcessorFactory { - public static MessageProcessor createProcessor(IMCmdType cmd){ - MessageProcessor processor = null; + public static AbstractMessageProcessor createProcessor(IMCmdType cmd){ + AbstractMessageProcessor processor = null; switch (cmd){ case LOGIN: - processor = (MessageProcessor) SpringContextHolder.getApplicationContext().getBean(LoginProcessor.class); + processor = (AbstractMessageProcessor) SpringContextHolder.getApplicationContext().getBean(LoginProcessor.class); break; case HEART_BEAT: - processor = (MessageProcessor) SpringContextHolder.getApplicationContext().getBean(HeartbeatProcessor.class); + processor = (AbstractMessageProcessor) SpringContextHolder.getApplicationContext().getBean(HeartbeatProcessor.class); break; case PRIVATE_MESSAGE: - processor = (MessageProcessor)SpringContextHolder.getApplicationContext().getBean(PrivateMessageProcessor.class); + processor = (AbstractMessageProcessor)SpringContextHolder.getApplicationContext().getBean(PrivateMessageProcessor.class); break; case GROUP_MESSAGE: - processor = (MessageProcessor)SpringContextHolder.getApplicationContext().getBean(GroupMessageProcessor.class); + processor = (AbstractMessageProcessor)SpringContextHolder.getApplicationContext().getBean(GroupMessageProcessor.class); break; default: break; diff --git a/im-server/src/main/java/com/bx/imserver/netty/tcp/TcpSocketServer.java b/im-server/src/main/java/com/bx/imserver/netty/tcp/TcpSocketServer.java index 6143e4d..1e89d73 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/tcp/TcpSocketServer.java +++ b/im-server/src/main/java/com/bx/imserver/netty/tcp/TcpSocketServer.java @@ -59,7 +59,7 @@ public class TcpSocketServer implements IMServer { protected void initChannel(Channel ch) throws Exception { // 获取职责链 ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new IdleStateHandler(15, 0, 0, TimeUnit.SECONDS)); + pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS)); pipeline.addLast("encode",new MessageProtocolEncoder()); pipeline.addLast("decode",new MessageProtocolDecoder()); pipeline.addLast("handler", new IMChannelHandler()); diff --git a/im-server/src/main/java/com/bx/imserver/netty/ws/WebSocketServer.java b/im-server/src/main/java/com/bx/imserver/netty/ws/WebSocketServer.java index 2d51ab8..efd4d6e 100644 --- a/im-server/src/main/java/com/bx/imserver/netty/ws/WebSocketServer.java +++ b/im-server/src/main/java/com/bx/imserver/netty/ws/WebSocketServer.java @@ -63,7 +63,7 @@ public class WebSocketServer implements IMServer { protected void initChannel(Channel ch) throws Exception { // 获取职责链 ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new IdleStateHandler(15, 0, 0, TimeUnit.SECONDS)); + pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS)); pipeline.addLast("http-codec", new HttpServerCodec()); pipeline.addLast("aggregator", new HttpObjectAggregator(65535)); pipeline.addLast("http-chunked", new ChunkedWriteHandler()); diff --git a/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java index d5dafe4..8b1acdc 100644 --- a/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java +++ b/im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java @@ -7,11 +7,10 @@ import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.*; @Slf4j -public abstract class AbstractPullMessageTask{ +public abstract class AbstractPullMessageTask { private int threadNum = 1; private ExecutorService executorService; @@ -19,34 +18,33 @@ public abstract class AbstractPullMessageTask{ @Autowired private IMServerGroup serverGroup; - public AbstractPullMessageTask(){ + public AbstractPullMessageTask() { this.threadNum = 1; } - public AbstractPullMessageTask(int threadNum){ + public AbstractPullMessageTask(int threadNum) { this.threadNum = threadNum; } @PostConstruct - public void init(){ + public void init() { // 初始化定时器 executorService = Executors.newFixedThreadPool(threadNum); - for(int i=0;i redisTemplate; - - @Override public void pullMessage() { // 从redis拉取未读消息 - String key = RedisKey.IM_UNREAD_GROUP_QUEUE + IMServerGroup.serverId; - List messageInfos = redisTemplate.opsForList().range(key,0,-1); - for(Object o: messageInfos){ - redisTemplate.opsForList().leftPop(key); - IMRecvInfo recvInfo = (IMRecvInfo)o; - MessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); + String key = String.join(":", IMRedisKey.IM_UNREAD_GROUP_QUEUE,IMServerGroup.serverId+""); + JSONObject jsonObject = (JSONObject)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); + if(jsonObject != null){ + IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class); + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE); processor.process(recvInfo); } } - - } diff --git a/im-server/src/main/java/com/bx/imserver/task/PullUnreadPrivateMessageTask.java b/im-server/src/main/java/com/bx/imserver/task/PullUnreadPrivateMessageTask.java index 50bb8b2..4ba5048 100644 --- a/im-server/src/main/java/com/bx/imserver/task/PullUnreadPrivateMessageTask.java +++ b/im-server/src/main/java/com/bx/imserver/task/PullUnreadPrivateMessageTask.java @@ -1,28 +1,23 @@ package com.bx.imserver.task; -import com.bx.imcommon.contant.RedisKey; +import com.alibaba.fastjson.JSONObject; +import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.model.IMRecvInfo; -import com.bx.imcommon.model.PrivateMessageInfo; import com.bx.imserver.netty.IMServerGroup; -import com.bx.imserver.netty.processor.MessageProcessor; +import com.bx.imserver.netty.processor.AbstractMessageProcessor; import com.bx.imserver.netty.processor.ProcessorFactory; -import com.bx.imserver.netty.ws.WebSocketServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; - -import java.util.List; - +import java.util.concurrent.TimeUnit; @Slf4j @Component public class PullUnreadPrivateMessageTask extends AbstractPullMessageTask { - @Autowired - private WebSocketServer WSServer; @Autowired private RedisTemplate redisTemplate; @@ -30,14 +25,12 @@ public class PullUnreadPrivateMessageTask extends AbstractPullMessageTask { @Override public void pullMessage() { // 从redis拉取未读消息 - String key = RedisKey.IM_UNREAD_PRIVATE_QUEUE + IMServerGroup.serverId; - List messageInfos = redisTemplate.opsForList().range(key,0,-1); - for(Object o: messageInfos){ - redisTemplate.opsForList().leftPop(key); - IMRecvInfo recvInfo = (IMRecvInfo)o; - MessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE); + String key = String.join(":", IMRedisKey.IM_UNREAD_PRIVATE_QUEUE ,IMServerGroup.serverId+""); + JSONObject jsonObject = (JSONObject)redisTemplate.opsForList().leftPop(key,10, TimeUnit.SECONDS); + if(jsonObject!=null){ + IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class); + AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE); processor.process(recvInfo); - } } diff --git a/im-ui/public/favicon.ico b/im-ui/public/favicon.ico deleted file mode 100644 index df36fcf..0000000 Binary files a/im-ui/public/favicon.ico and /dev/null differ diff --git a/im-ui/public/index.html b/im-ui/public/index.html index 5ae1079..724a362 100644 --- a/im-ui/public/index.html +++ b/im-ui/public/index.html @@ -4,7 +4,7 @@ - + 盒子IM diff --git a/im-ui/public/logo.png b/im-ui/public/logo.png new file mode 100644 index 0000000..8cd39d4 Binary files /dev/null and b/im-ui/public/logo.png differ diff --git a/im-ui/src/api/enums.js b/im-ui/src/api/enums.js index ec05b4a..eb41941 100644 --- a/im-ui/src/api/enums.js +++ b/im-ui/src/api/enums.js @@ -1,5 +1,11 @@ const MESSAGE_TYPE = { + TEXT: 0, + IMAGE:1, + FILE:2, + AUDIO:3, + VIDEO:4, + RECALL:10, RTC_CALL: 101, RTC_ACCEPT: 102, RTC_REJECT: 103, diff --git a/im-ui/src/api/httpRequest.js b/im-ui/src/api/httpRequest.js index 7f8f376..aacc0a5 100644 --- a/im-ui/src/api/httpRequest.js +++ b/im-ui/src/api/httpRequest.js @@ -47,6 +47,8 @@ http.interceptors.response.use(async response => { headers: { refreshToken: refreshToken } + }).catch(()=>{ + router.replace("/login"); }) // 保存token sessionStorage.setItem("accessToken", data.accessToken); diff --git a/im-ui/src/api/wssocket.js b/im-ui/src/api/wssocket.js index eb3b715..fbe4222 100644 --- a/im-ui/src/api/wssocket.js +++ b/im-ui/src/api/wssocket.js @@ -18,8 +18,9 @@ let createWebSocket = (url, id,token) => { let initWebSocket = () => { try { console.log("初始化WebSocket"); + closeWebSocket(); hasLogin = false; - websock = new WebSocket(wsurl); + websock = new WebSocket(wsurl); websock.onmessage = function(e) { let sendInfo = JSON.parse(e.data) if (sendInfo.cmd == 0) { @@ -39,6 +40,7 @@ let initWebSocket = () => { websock.onclose = function(e) { console.log('WebSocket连接关闭') isConnect = false; //断开后修改标识 + reConnect(); } websock.onopen = function() { console.log("WebSocket连接成功"); @@ -77,7 +79,7 @@ let reConnect = () => { }; //设置关闭连接 let closeWebSocket = () => { - websock.close(); + websock && websock.close(); }; @@ -147,4 +149,4 @@ export { sendMessage, onmessage, onopen -} +} diff --git a/im-ui/src/assets/logo.png b/im-ui/src/assets/logo.png deleted file mode 100644 index f3d2503..0000000 Binary files a/im-ui/src/assets/logo.png and /dev/null differ diff --git a/im-ui/src/components/chat/ChatBox.vue b/im-ui/src/components/chat/ChatBox.vue index 99047e6..4918033 100644 --- a/im-ui/src/components/chat/ChatBox.vue +++ b/im-ui/src/components/chat/ChatBox.vue @@ -134,7 +134,7 @@ loadStatus: "loading" } // 填充对方id - this.setTargetId(msgInfo, this.chat.targetId); + this.fillTargetId(msgInfo, this.chat.targetId); // 插入消息 this.$store.commit("insertMessage", msgInfo); // 滚动到底部 @@ -182,7 +182,7 @@ loadStatus: "loading" } // 填充对方id - this.setTargetId(msgInfo, this.chat.targetId); + this.fillTargetId(msgInfo, this.chat.targetId); // 插入消息 this.$store.commit("insertMessage", msgInfo); // 滚动到底部 @@ -232,7 +232,7 @@ type: 3 } // 填充对方id - this.setTargetId(msgInfo, this.chat.targetId); + this.fillTargetId(msgInfo, this.chat.targetId); this.$http({ url: this.messageAction, method: 'post', @@ -252,7 +252,7 @@ this.showVoice = false; }) }, - setTargetId(msgInfo, targetId) { + fillTargetId(msgInfo, targetId) { if (this.chat.type == "GROUP") { msgInfo.groupId = targetId; } else { @@ -269,7 +269,7 @@ type: 0 } // 填充对方id - this.setTargetId(msgInfo, this.chat.targetId); + this.fillTargetId(msgInfo, this.chat.targetId); this.lockMessage = true; this.$http({ url: this.messageAction, diff --git a/im-ui/src/components/chat/ChatMessageItem.vue b/im-ui/src/components/chat/ChatMessageItem.vue index eb4cdc1..72039ae 100644 --- a/im-ui/src/components/chat/ChatMessageItem.vue +++ b/im-ui/src/components/chat/ChatMessageItem.vue @@ -1,7 +1,7 @@