Browse Source

过滤html标签

master
Andrews 2 years ago
parent
commit
a442ac2f80
  1. 2
      im-client/src/main/java/com/bx/imclient/IMClient.java
  2. 3
      im-client/src/main/java/com/bx/imclient/config/RedisConfig.java
  3. 12
      im-client/src/main/java/com/bx/imclient/sender/IMSender.java
  4. 41
      im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java
  5. 2
      im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java
  6. 4
      im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java
  7. 12
      im-commom/src/main/java/com/bx/imcommon/contant/IMConstant.java
  8. 40
      im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java
  9. 32
      im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java
  10. 21
      im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java
  11. 22
      im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java
  12. 18
      im-commom/src/main/java/com/bx/imcommon/enums/IMTerminalType.java
  13. 4
      im-commom/src/main/java/com/bx/imcommon/model/IMGroupMessage.java
  14. 2
      im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java
  15. 2
      im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java
  16. 16
      im-commom/src/main/java/com/bx/imcommon/model/IMSendInfo.java
  17. 2
      im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java
  18. 43
      im-commom/src/main/java/com/bx/imcommon/util/JwtUtil.java
  19. 100
      im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java
  20. 5
      im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java
  21. 2
      im-platform/src/main/java/com/bx/implatform/config/ICEServer.java
  22. 2
      im-platform/src/main/java/com/bx/implatform/config/ICEServerConfig.java
  23. 7
      im-platform/src/main/java/com/bx/implatform/config/JwtProperties.java
  24. 3
      im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java
  25. 5
      im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java
  26. 6
      im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java
  27. 1
      im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java
  28. 21
      im-platform/src/main/java/com/bx/implatform/contant/Constant.java
  29. 41
      im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java
  30. 13
      im-platform/src/main/java/com/bx/implatform/controller/FileController.java
  31. 33
      im-platform/src/main/java/com/bx/implatform/controller/FriendController.java
  32. 45
      im-platform/src/main/java/com/bx/implatform/controller/GroupController.java
  33. 37
      im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java
  34. 24
      im-platform/src/main/java/com/bx/implatform/controller/LoginController.java
  35. 35
      im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java
  36. 33
      im-platform/src/main/java/com/bx/implatform/controller/UserController.java
  37. 22
      im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java
  38. 10
      im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java
  39. 10
      im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java
  40. 4
      im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java
  41. 10
      im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java
  42. 12
      im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java
  43. 1
      im-platform/src/main/java/com/bx/implatform/entity/Group.java
  44. 5
      im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java
  45. 2
      im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java
  46. 4
      im-platform/src/main/java/com/bx/implatform/entity/User.java
  47. 24
      im-platform/src/main/java/com/bx/implatform/enums/FileType.java
  48. 22
      im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java
  49. 68
      im-platform/src/main/java/com/bx/implatform/enums/MessageType.java
  50. 41
      im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java
  51. 17
      im-platform/src/main/java/com/bx/implatform/exception/GlobalException.java
  52. 41
      im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java
  53. 8
      im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java
  54. 15
      im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java
  55. 15
      im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java
  56. 10
      im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java
  57. 9
      im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java
  58. 1
      im-platform/src/main/java/com/bx/implatform/mapper/FriendMapper.java
  59. 1
      im-platform/src/main/java/com/bx/implatform/mapper/GroupMapper.java
  60. 1
      im-platform/src/main/java/com/bx/implatform/mapper/GroupMemberMapper.java
  61. 1
      im-platform/src/main/java/com/bx/implatform/mapper/GroupMessageMapper.java
  62. 1
      im-platform/src/main/java/com/bx/implatform/mapper/PrivateMessageMapper.java
  63. 1
      im-platform/src/main/java/com/bx/implatform/mapper/UserMapper.java
  64. 2
      im-platform/src/main/java/com/bx/implatform/result/Result.java
  65. 35
      im-platform/src/main/java/com/bx/implatform/result/ResultUtils.java
  66. 5
      im-platform/src/main/java/com/bx/implatform/service/IFriendService.java
  67. 20
      im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java
  68. 6
      im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java
  69. 13
      im-platform/src/main/java/com/bx/implatform/service/IGroupService.java
  70. 3
      im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java
  71. 3
      im-platform/src/main/java/com/bx/implatform/service/IUserService.java
  72. 19
      im-platform/src/main/java/com/bx/implatform/service/IWebrtcService.java
  73. 84
      im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java
  74. 27
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java
  75. 35
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java
  76. 13
      im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java
  77. 8
      im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java
  78. 6
      im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java
  79. 20
      im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcServiceImpl.java
  80. 69
      im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java
  81. 9
      im-platform/src/main/java/com/bx/implatform/session/SessionContext.java
  82. 8
      im-platform/src/main/java/com/bx/implatform/session/UserSession.java
  83. 77
      im-platform/src/main/java/com/bx/implatform/util/BeanUtils.java
  84. 5
      im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java
  85. 15
      im-platform/src/main/java/com/bx/implatform/util/FileUtil.java
  86. 8
      im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java
  87. 71
      im-platform/src/main/java/com/bx/implatform/util/MinioUtil.java
  88. 7
      im-platform/src/main/java/com/bx/implatform/util/XssUtil.java
  89. 1
      im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java
  90. 1
      im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java
  91. 9
      im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java
  92. 7
      im-platform/src/main/java/com/bx/implatform/vo/UserVO.java
  93. 7
      im-server/src/main/java/com/bx/imserver/IMServerApp.java
  94. 2
      im-server/src/main/java/com/bx/imserver/config/RedisConfig.java
  95. 17
      im-server/src/main/java/com/bx/imserver/constant/ChannelAttrKey.java
  96. 29
      im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java
  97. 22
      im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java
  98. 33
      im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java
  99. 13
      im-server/src/main/java/com/bx/imserver/netty/processor/AbstractMessageProcessor.java
  100. 32
      im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java

2
im-client/src/main/java/com/bx/imclient/IMClient.java

@ -14,7 +14,7 @@ import java.util.Map;
@AllArgsConstructor @AllArgsConstructor
public class IMClient { public class IMClient {
private IMSender imSender; private final IMSender imSender;
/** /**
* 判断用户是否在线 * 判断用户是否在线

3
im-client/src/main/java/com/bx/imclient/config/RedisConfig.java

@ -25,8 +25,7 @@ public class RedisConfig {
} }
public FastJsonRedisSerializer fastJsonRedisSerializer(){ public FastJsonRedisSerializer fastJsonRedisSerializer(){
FastJsonRedisSerializer <Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); return new FastJsonRedisSerializer<>(Object.class);
return fastJsonRedisSerializer;
} }
} }

12
im-client/src/main/java/com/bx/imclient/sender/IMSender.java

@ -1,6 +1,6 @@
package com.bx.imclient.sender; package com.bx.imclient.sender;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollUtil;
import com.bx.imclient.listener.MessageListenerMulticaster; import com.bx.imclient.listener.MessageListenerMulticaster;
import com.bx.imcommon.contant.IMRedisKey; import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMCmdType; import com.bx.imcommon.enums.IMCmdType;
@ -79,7 +79,7 @@ public class IMSender {
// 根据群聊每个成员所连的IM-server,进行分组 // 根据群聊每个成员所连的IM-server,进行分组
Map<String, IMUserInfo> sendMap = new HashMap<>(); Map<String, IMUserInfo> sendMap = new HashMap<>();
for (Integer terminal : message.getRecvTerminals()) { for (Integer terminal : message.getRecvTerminals()) {
message.getRecvIds().stream().forEach(id -> { message.getRecvIds().forEach(id -> {
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString()); String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, id.toString(), terminal.toString());
sendMap.put(key,new IMUserInfo(id, terminal)); sendMap.put(key,new IMUserInfo(id, terminal));
}); });
@ -99,7 +99,7 @@ public class IMSender {
// 加入离线列表 // 加入离线列表
offLineUsers.add(entry.getValue()); offLineUsers.add(entry.getValue());
} }
}; }
// 逐个server发送 // 逐个server发送
for (Map.Entry<Integer, List<IMUserInfo>> entry : serverMap.entrySet()) { for (Map.Entry<Integer, List<IMUserInfo>> entry : serverMap.entrySet()) {
IMRecvInfo recvInfo = new IMRecvInfo(); IMRecvInfo recvInfo = new IMRecvInfo();
@ -149,8 +149,8 @@ public class IMSender {
} }
public Map<Long,List<IMTerminalType>> getOnlineTerminal(List<Long> userIds){ public Map<Long,List<IMTerminalType>> getOnlineTerminal(List<Long> userIds){
if(CollectionUtil.isEmpty(userIds)){ if(CollUtil.isEmpty(userIds)){
return Collections.EMPTY_MAP; return Collections.emptyMap();
} }
// 把所有用户的key都存起来 // 把所有用户的key都存起来
Map<String,IMUserInfo> userMap = new HashMap<>(); Map<String,IMUserInfo> userMap = new HashMap<>();
@ -178,7 +178,7 @@ public class IMSender {
public Boolean isOnline(Long userId) { public Boolean isOnline(Long userId) {
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*"); String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), "*");
return !redisTemplate.keys(key).isEmpty(); return !Objects.requireNonNull(redisTemplate.keys(key)).isEmpty();
} }
public List<Long> getOnlineUser(List<Long> userIds){ public List<Long> getOnlineUser(List<Long> userIds){

41
im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java

@ -1,48 +1,43 @@
package com.bx.imclient.task; package com.bx.imclient.task;
import com.bx.imcommon.util.ThreadPoolExecutorFactory;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j @Slf4j
public abstract class AbstractMessageResultTask implements CommandLineRunner { public abstract class AbstractMessageResultTask implements CommandLineRunner {
private int threadNum = 8; private static final ExecutorService EXECUTOR_SERVICE = ThreadPoolExecutorFactory.getThreadPoolExecutor();
private ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
@Override @Override
public void run(String... args) throws Exception { public void run(String... args) {
// 初始化定时器 // 初始化定时器
for(int i=0;i<threadNum;i++){ EXECUTOR_SERVICE.execute(new Runnable() {
executorService.execute(new Runnable() { @SneakyThrows
@SneakyThrows @Override
@Override public void run() {
public void run() { try{
try{ pullMessage();
pullMessage(); }catch (Exception e){
}catch (Exception e){ log.error("任务调度异常",e);
log.error("任务调度异常",e); Thread.sleep(200);
Thread.sleep(200); }
} if(!EXECUTOR_SERVICE.isShutdown()){
if(!executorService.isShutdown()){ EXECUTOR_SERVICE.execute(this);
executorService.execute(this);
}
} }
}); }
} });
} }
@PreDestroy @PreDestroy
public void destroy(){ public void destroy(){
log.info("{}线程任务关闭",this.getClass().getSimpleName()); log.info("{}线程任务关闭",this.getClass().getSimpleName());
executorService.shutdown(); EXECUTOR_SERVICE.shutdown();
} }
public abstract void pullMessage(); public abstract void pullMessage();

2
im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java

@ -19,7 +19,7 @@ public class GroupMessageResultResultTask extends AbstractMessageResultTask {
@Resource(name = "IMRedisTemplate") @Resource(name = "IMRedisTemplate")
private RedisTemplate<String,Object> redisTemplate; private RedisTemplate<String,Object> redisTemplate;
private MessageListenerMulticaster listenerMulticaster; private final MessageListenerMulticaster listenerMulticaster;
@Override @Override
public void pullMessage() { public void pullMessage() {

4
im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java

@ -13,8 +13,6 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
;
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
@ -24,7 +22,7 @@ public class PrivateMessageResultResultTask extends AbstractMessageResultTask {
@Resource(name = "IMRedisTemplate") @Resource(name = "IMRedisTemplate")
private RedisTemplate<String,Object> redisTemplate; private RedisTemplate<String,Object> redisTemplate;
private MessageListenerMulticaster listenerMulticaster; private final MessageListenerMulticaster listenerMulticaster;
@Override @Override
public void pullMessage() { public void pullMessage() {

12
im-commom/src/main/java/com/bx/imcommon/contant/IMConstant.java

@ -1,11 +1,17 @@
package com.bx.imcommon.contant; package com.bx.imcommon.contant;
public final class IMConstant {
public class IMConstant { private IMConstant() {
}
// 在线状态过期时间 600s /**
* 在线状态过期时间 600s
*/
public static final long ONLINE_TIMEOUT_SECOND = 600; public static final long ONLINE_TIMEOUT_SECOND = 600;
// 消息允许撤回时间 300s /**
* 消息允许撤回时间 300s
*/
public static final long ALLOW_RECALL_SECOND = 300; public static final long ALLOW_RECALL_SECOND = 300;

40
im-commom/src/main/java/com/bx/imcommon/contant/IMRedisKey.java

@ -1,18 +1,32 @@
package com.bx.imcommon.contant; package com.bx.imcommon.contant;
public class IMRedisKey { public final class IMRedisKey {
// im-server最大id,从0开始递增 private IMRedisKey() {}
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"; * im-server最大id,从0开始递增
// 未读私聊消息队列 */
public final static String IM_MESSAGE_PRIVATE_QUEUE = "im:message:private"; public static final String IM_MAX_SERVER_ID = "im:max_server_id";
// 未读群聊消息队列 /**
public final static String IM_MESSAGE_GROUP_QUEUE = "im:message:group"; * 用户ID所连接的IM-server的ID
// 私聊消息发送结果队列 */
public final static String IM_RESULT_PRIVATE_QUEUE = "im:result:private"; public static final String IM_USER_SERVER_ID = "im:user:server_id";
// 群聊消息发送结果队列 /**
public final static String IM_RESULT_GROUP_QUEUE = "im:result:group"; * 未读私聊消息队列
*/
public static final String IM_MESSAGE_PRIVATE_QUEUE = "im:message:private";
/**
* 未读群聊消息队列
*/
public static final String IM_MESSAGE_GROUP_QUEUE = "im:message:group";
/**
* 私聊消息发送结果队列
*/
public static final String IM_RESULT_PRIVATE_QUEUE = "im:result:private";
/**
* 群聊消息发送结果队列
*/
public static final String IM_RESULT_GROUP_QUEUE = "im:result:group";
} }

32
im-commom/src/main/java/com/bx/imcommon/enums/IMCmdType.java

@ -1,16 +1,30 @@
package com.bx.imcommon.enums; package com.bx.imcommon.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum IMCmdType { public enum IMCmdType {
LOGIN(0,"登陆"), /**
HEART_BEAT(1,"心跳"), * 登陆
FORCE_LOGUT(2,"强制下线"), */
PRIVATE_MESSAGE(3,"私聊消息"), LOGIN(0, "登陆"),
GROUP_MESSAGE(4,"群发消息"); /**
* 心跳
*/
HEART_BEAT(1, "心跳"),
/**
* 强制下线
*/
FORCE_LOGUT(2, "强制下线"),
/**
* 私聊消息
*/
PRIVATE_MESSAGE(3, "私聊消息"),
/**
* 群发消息
*/
GROUP_MESSAGE(4, "群发消息");
private final Integer code; private final Integer code;
@ -18,8 +32,8 @@ public enum IMCmdType {
private final String desc; private final String desc;
public static IMCmdType fromCode(Integer code){ public static IMCmdType fromCode(Integer code) {
for (IMCmdType typeEnum:values()) { for (IMCmdType typeEnum : values()) {
if (typeEnum.code.equals(code)) { if (typeEnum.code.equals(code)) {
return typeEnum; return typeEnum;
} }
@ -28,7 +42,7 @@ public enum IMCmdType {
} }
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }

21
im-commom/src/main/java/com/bx/imcommon/enums/IMListenerType.java

@ -3,18 +3,25 @@ package com.bx.imcommon.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum IMListenerType{ public enum IMListenerType {
ALL(0,"全部消息"), /**
PRIVATE_MESSAGE(1,"私聊消息"), * 全部消息
GROUP_MESSAGE(2,"群聊消息"); */
ALL(0, "全部消息"),
/**
* 私聊消息
*/
PRIVATE_MESSAGE(1, "私聊消息"),
/**
* 群聊消息
*/
GROUP_MESSAGE(2, "群聊消息");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public Integer code() {
public Integer code(){
return this.code; return this.code;
} }

22
im-commom/src/main/java/com/bx/imcommon/enums/IMSendCode.java

@ -5,15 +5,27 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum IMSendCode { public enum IMSendCode {
SUCCESS(0,"发送成功"), /**
NOT_ONLINE(1,"对方当前不在线"), * 发送成功
NOT_FIND_CHANNEL(2,"未找到对方的channel"), */
UNKONW_ERROR(9999,"未知异常"); SUCCESS(0, "发送成功"),
/**
* 对方当前不在线
*/
NOT_ONLINE(1, "对方当前不在线"),
/**
* 未找到对方的channel
*/
NOT_FIND_CHANNEL(2, "未找到对方的channel"),
/**
* 未知异常
*/
UNKONW_ERROR(9999, "未知异常");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }

18
im-commom/src/main/java/com/bx/imcommon/enums/IMTerminalType.java

@ -9,16 +9,22 @@ import java.util.stream.Collectors;
@AllArgsConstructor @AllArgsConstructor
public enum IMTerminalType { public enum IMTerminalType {
WEB(0,"web"), /**
APP(1,"app"); * web
*/
WEB(0, "web"),
/**
* app
*/
APP(1, "app");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public static IMTerminalType fromCode(Integer code){ public static IMTerminalType fromCode(Integer code) {
for (IMTerminalType typeEnum:values()) { for (IMTerminalType typeEnum : values()) {
if (typeEnum.code.equals(code)) { if (typeEnum.code.equals(code)) {
return typeEnum; return typeEnum;
} }
@ -26,11 +32,11 @@ public enum IMTerminalType {
return null; return null;
} }
public static List<Integer> codes(){ public static List<Integer> codes() {
return Arrays.stream(values()).map(IMTerminalType::code).collect(Collectors.toList()); return Arrays.stream(values()).map(IMTerminalType::code).collect(Collectors.toList());
} }
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }

4
im-commom/src/main/java/com/bx/imcommon/model/IMGroupMessage.java

@ -17,7 +17,7 @@ public class IMGroupMessage<T> {
/** /**
* 接收者id列表(群成员列表,为空则不会推送) * 接收者id列表(群成员列表,为空则不会推送)
*/ */
private List<Long> recvIds = new LinkedList<>(); private List<Long> recvIds = new LinkedList<>();
/** /**
@ -36,7 +36,7 @@ public class IMGroupMessage<T> {
private Boolean sendResult = true; private Boolean sendResult = true;
/** /**
* 消息内容 * 消息内容
*/ */
private T data; private T data;

2
im-commom/src/main/java/com/bx/imcommon/model/IMPrivateMessage.java

@ -36,7 +36,7 @@ public class IMPrivateMessage<T> {
private Boolean sendResult = true; private Boolean sendResult = true;
/** /**
* 消息内容 * 消息内容
*/ */
private T data; private T data;

2
im-commom/src/main/java/com/bx/imcommon/model/IMRecvInfo.java

@ -23,7 +23,7 @@ public class IMRecvInfo {
List<IMUserInfo> receivers; List<IMUserInfo> receivers;
/** /**
* 是否需要回调发送结果 * 是否需要回调发送结果
*/ */
private Boolean sendResult; private Boolean sendResult;

16
im-commom/src/main/java/com/bx/imcommon/model/IMSendInfo.java

@ -5,14 +5,14 @@ import lombok.Data;
@Data @Data
public class IMSendInfo<T> { public class IMSendInfo<T> {
/** /**
* 命令 * 命令
*/ */
private Integer cmd; private Integer cmd;
/** /**
* 推送消息体 * 推送消息体
*/ */
private T data; private T data;
} }

2
im-commom/src/main/java/com/bx/imcommon/model/IMSendResult.java

@ -21,7 +21,7 @@ public class IMSendResult<T> {
private Integer code; private Integer code;
/** /**
* 消息内容 * 消息内容
*/ */
private T data; private T data;

43
im-commom/src/main/java/com/bx/imcommon/util/JwtUtil.java

@ -8,19 +8,23 @@ import com.auth0.jwt.exceptions.JWTVerificationException;
import java.util.Date; import java.util.Date;
public class JwtUtil { public final class JwtUtil {
private JwtUtil() {
}
/** /**
* 生成jwt字符串 JWT(json web token) * 生成jwt字符串 JWT(json web token)
* @param userId 用户id *
* @param info 用户细腻系 * @param userId 用户id
* @param info 用户细腻系
* @param expireIn 过期时间 * @param expireIn 过期时间
* @param secret 秘钥 * @param secret 秘钥
* @return token * @return token
* */ */
public static String sign(Long userId, String info,long expireIn,String secret) { public static String sign(Long userId, String info, long expireIn, String secret) {
try { try {
Date date = new Date(System.currentTimeMillis() + expireIn*1000); Date date = new Date(System.currentTimeMillis() + expireIn * 1000);
Algorithm algorithm = Algorithm.HMAC256(secret); Algorithm algorithm = Algorithm.HMAC256(secret);
return JWT.create() return JWT.create()
//将userId保存到token里面 //将userId保存到token里面
@ -38,44 +42,47 @@ public class JwtUtil {
/** /**
* 根据token获取userId * 根据token获取userId
* @param token 登录token *
* @param token 登录token
* @return 用户id * @return 用户id
* */ */
public static Long getUserId(String token) { public static Long getUserId(String token) {
try { try {
String userId = JWT.decode(token).getAudience().get(0); String userId = JWT.decode(token).getAudience().get(0);
return Long.parseLong(userId); return Long.parseLong(userId);
}catch (JWTDecodeException e) { } catch (JWTDecodeException e) {
return null; return null;
} }
} }
/** /**
* 根据token获取用户数据 * 根据token获取用户数据
*
* @param token 用户登录token * @param token 用户登录token
* @return 用户数据 * @return 用户数据
* */ */
public static String getInfo(String token) { public static String getInfo(String token) {
try { try {
return JWT.decode(token).getClaim("info").asString(); return JWT.decode(token).getClaim("info").asString();
}catch (JWTDecodeException e) { } catch (JWTDecodeException e) {
return null; return null;
} }
} }
/** /**
* 校验token * 校验token
* @param token 用户登录token *
* @param token 用户登录token
* @param secret 秘钥 * @param secret 秘钥
* @return true/false * @return true/false
* */ */
public static Boolean checkSign(String token,String secret) { public static Boolean checkSign(String token, String secret) {
try{ try {
Algorithm algorithm = Algorithm.HMAC256(secret); Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).build(); JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token); verifier.verify(token);
return true; return true;
}catch (JWTVerificationException e) { } catch (JWTVerificationException e) {
return false; return false;
} }
} }

100
im-commom/src/main/java/com/bx/imcommon/util/ThreadPoolExecutorFactory.java

@ -0,0 +1,100 @@
package com.bx.imcommon.util;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 创建单例线程池
* @author Andrews
* @date 2023/11/30 11:12
*/
public final class ThreadPoolExecutorFactory {
/**
* 机器的CPU核数:Runtime.getRuntime().availableProcessors()
* corePoolSize 池中所保存的线程数包括空闲线程
* CPU 密集型核心线程数 = CPU核数 + 1
* IO 密集型核心线程数 = CPU核数 * 2
*/
private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
/**
* maximumPoolSize - 池中允许的最大线程数(采用LinkedBlockingQueue时没有作用)
*/
private static final int MAX_IMUM_POOL_SIZE = 100;
/**
* keepAliveTime -当线程数大于核心时此为终止前多余的空闲线程等待新任务的最长时间线程池维护线程所允许的空闲时间
*/
private static final int KEEP_ALIVE_TIME = 1000;
/**
* 等待队列的大小默认是无界的性能损耗的关键
*/
private static final int QUEUE_SIZE = 200;
/**
* 线程池对象
*/
private static volatile ThreadPoolExecutor threadPoolExecutor = null;
/**
* 构造方法私有化
*/
private ThreadPoolExecutorFactory() {
if (null == threadPoolExecutor) {
threadPoolExecutor = ThreadPoolExecutorFactory.getThreadPoolExecutor();
}
}
/**
* 重写readResolve方法
*/
private Object readResolve() {
//重写readResolve方法,防止序列化破坏单例
return ThreadPoolExecutorFactory.getThreadPoolExecutor();
}
/**
* 双检锁创建线程安全的单例
*/
public static ThreadPoolExecutor getThreadPoolExecutor() {
if (null == threadPoolExecutor) {
synchronized (ThreadPoolExecutorFactory.class) {
if (null == threadPoolExecutor) {
threadPoolExecutor = new ThreadPoolExecutor(
//核心线程数
CORE_POOL_SIZE,
//最大线程数,包含临时线程
MAX_IMUM_POOL_SIZE,
//临时线程的存活时间
KEEP_ALIVE_TIME,
//时间单位(毫秒)
TimeUnit.MILLISECONDS,
//等待队列
new LinkedBlockingQueue<>(QUEUE_SIZE),
//拒绝策略
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
}
return threadPoolExecutor;
}
/**
* 关闭线程池
*/
public void shutDown() {
if (threadPoolExecutor != null) {
threadPoolExecutor.shutdown();
}
}
public void execute(Runnable runnable) {
if (runnable == null) {
return;
}
threadPoolExecutor.execute(runnable);
}
}

5
im-platform/src/main/java/com/bx/implatform/IMPlatformApp.java

@ -7,14 +7,13 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Slf4j @Slf4j
@EnableAspectJAutoProxy(exposeProxy = true) @EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan(basePackages = {"com.bx.implatform.mapper"}) @MapperScan(basePackages = {"com.bx.implatform.mapper"})
@SpringBootApplication(exclude= {SecurityAutoConfiguration.class })// 禁用secrity @SpringBootApplication(exclude = {SecurityAutoConfiguration.class})// 禁用secrity
public class IMPlatformApp { public class IMPlatformApp {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(IMPlatformApp.class,args); SpringApplication.run(IMPlatformApp.class, args);
} }
} }

2
im-platform/src/main/java/com/bx/implatform/config/ICEServer.java

@ -1,9 +1,7 @@
package com.bx.implatform.config; package com.bx.implatform.config;
import lombok.Data; import lombok.Data;
@Data @Data
public class ICEServer { public class ICEServer {
private String urls; private String urls;

2
im-platform/src/main/java/com/bx/implatform/config/ICEServerConfig.java

@ -9,7 +9,7 @@ import java.util.List;
@Data @Data
@Component @Component
@ConfigurationProperties(prefix="webrtc") @ConfigurationProperties(prefix = "webrtc")
public class ICEServerConfig { public class ICEServerConfig {
private List<ICEServer> iceServers = new ArrayList<>(); private List<ICEServer> iceServers = new ArrayList<>();

7
im-platform/src/main/java/com/bx/implatform/config/JwtProperties.java

@ -1,6 +1,5 @@
package com.bx.implatform.config; package com.bx.implatform.config;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -10,13 +9,13 @@ import org.springframework.stereotype.Component;
public class JwtProperties { public class JwtProperties {
@Value("${jwt.accessToken.expireIn}") @Value("${jwt.accessToken.expireIn}")
private Integer accessTokenExpireIn; private Integer accessTokenExpireIn;
@Value("${jwt.accessToken.secret}") @Value("${jwt.accessToken.secret}")
private String accessTokenSecret; private String accessTokenSecret;
@Value("${jwt.refreshToken.expireIn}") @Value("${jwt.refreshToken.expireIn}")
private Integer refreshTokenExpireIn ; private Integer refreshTokenExpireIn;
@Value("${jwt.refreshToken.secret}") @Value("${jwt.refreshToken.secret}")
private String refreshTokenSecret; private String refreshTokenSecret;

3
im-platform/src/main/java/com/bx/implatform/config/MinIoClientConfig.java

@ -5,7 +5,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
public class MinIoClientConfig { public class MinIoClientConfig {
@ -18,7 +17,7 @@ public class MinIoClientConfig {
@Bean @Bean
public MinioClient minioClient(){ public MinioClient minioClient() {
// 注入minio 客户端 // 注入minio 客户端
return MinioClient.builder() return MinioClient.builder()
.endpoint(endpoint) .endpoint(endpoint)

5
im-platform/src/main/java/com/bx/implatform/config/MvcConfig.java

@ -10,7 +10,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
@AllArgsConstructor @AllArgsConstructor
public class MvcConfig implements WebMvcConfigurer { public class MvcConfig implements WebMvcConfigurer {
@ -24,12 +23,12 @@ public class MvcConfig implements WebMvcConfigurer {
.addPathPatterns("/**"); .addPathPatterns("/**");
registry.addInterceptor(authInterceptor) registry.addInterceptor(authInterceptor)
.addPathPatterns("/**") .addPathPatterns("/**")
.excludePathPatterns("/login","/logout","/register","/refreshToken", .excludePathPatterns("/login", "/logout", "/register", "/refreshToken",
"/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**"); "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
} }
@Bean @Bean
public PasswordEncoder passwordEncoder(){ public PasswordEncoder passwordEncoder() {
// 使用BCrypt加密密码 // 使用BCrypt加密密码
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
} }

6
im-platform/src/main/java/com/bx/implatform/config/RedisConfig.java

@ -26,7 +26,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.Duration; import java.time.Duration;
import java.util.Objects;
@EnableCaching @EnableCaching
@Configuration @Configuration
@ -52,7 +52,7 @@ public class RedisConfig extends CachingConfigurerSupport {
} }
@Bean @Bean
public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer(){ public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
@ -68,7 +68,7 @@ public class RedisConfig extends CachingConfigurerSupport {
@Bean @Bean
@Override @Override
public CacheResolver cacheResolver() { public CacheResolver cacheResolver() {
return new SimpleCacheResolver(cacheManager()); return new SimpleCacheResolver(Objects.requireNonNull(cacheManager()));
} }
@Bean @Bean

1
im-platform/src/main/java/com/bx/implatform/config/SwaggerConfig.java

@ -11,7 +11,6 @@ import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2; import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2
public class SwaggerConfig { public class SwaggerConfig {

21
im-platform/src/main/java/com/bx/implatform/contant/Constant.java

@ -1,12 +1,21 @@
package com.bx.implatform.contant; package com.bx.implatform.contant;
public final class Constant {
public class Constant { private Constant() {
// 最大图片上传大小 }
public static final long MAX_IMAGE_SIZE = 5*1024*1024;
// 最大上传文件大小 /**
public static final long MAX_FILE_SIZE = 10*1024*1024; * 最大图片上传大小
// 群聊最大人数 */
public static final long MAX_IMAGE_SIZE = 5 * 1024 * 1024;
/**
* 最大上传文件大小
*/
public static final long MAX_FILE_SIZE = 10 * 1024 * 1024;
/**
* 群聊最大人数
*/
public static final long MAX_GROUP_MEMBER = 500; public static final long MAX_GROUP_MEMBER = 500;
} }

41
im-platform/src/main/java/com/bx/implatform/contant/RedisKey.java

@ -1,18 +1,33 @@
package com.bx.implatform.contant; package com.bx.implatform.contant;
public class RedisKey { public final class RedisKey {
// 已读群聊消息位置(已读最大id) private RedisKey() {
public final static String IM_GROUP_READED_POSITION = "im:readed:group:position"; }
// webrtc 会话信息
public final static String IM_WEBRTC_SESSION = "im:webrtc:session"; /**
// 缓存前缀 * 已读群聊消息位置(已读最大id)
public final static String IM_CACHE = "im:cache:"; */
// 缓存是否好友:bool public static final String IM_GROUP_READED_POSITION = "im:readed:group:position";
public final static String IM_CACHE_FRIEND = IM_CACHE+"friend"; /**
// 缓存群聊信息 * webrtc 会话信息
public final static String IM_CACHE_GROUP = IM_CACHE+"group"; */
// 缓存群聊成员id public static final String IM_WEBRTC_SESSION = "im:webrtc:session";
public final static String IM_CACHE_GROUP_MEMBER_ID = IM_CACHE+"group_member_ids"; /**
* 缓存前缀
*/
public static final String IM_CACHE = "im:cache:";
/**
* 缓存是否好友bool
*/
public static final String IM_CACHE_FRIEND = IM_CACHE + "friend";
/**
* 缓存群聊信息
*/
public static final String IM_CACHE_GROUP = IM_CACHE + "group";
/**
* 缓存群聊成员id
*/
public static final String IM_CACHE_GROUP_MEMBER_ID = IM_CACHE + "group_member_ids";
} }

13
im-platform/src/main/java/com/bx/implatform/controller/FileController.java

@ -6,31 +6,30 @@ import com.bx.implatform.service.thirdparty.FileService;
import com.bx.implatform.vo.UploadImageVO; import com.bx.implatform.vo.UploadImageVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@Slf4j @Slf4j
@RestController @RestController
@Api(tags = "文件上传") @Api(tags = "文件上传")
@AllArgsConstructor @RequiredArgsConstructor
public class FileController { public class FileController {
private FileService fileService; private final FileService fileService;
@ApiOperation(value = "上传图片",notes="上传图片,上传后返回原图和缩略图的url") @ApiOperation(value = "上传图片", notes = "上传图片,上传后返回原图和缩略图的url")
@PostMapping("/image/upload") @PostMapping("/image/upload")
public Result<UploadImageVO> uploadImage(MultipartFile file) { public Result<UploadImageVO> uploadImage(MultipartFile file) {
return ResultUtils.success(fileService.uploadImage(file)); return ResultUtils.success(fileService.uploadImage(file));
} }
@ApiOperation(value = "上传文件",notes="上传文件,上传后返回文件url") @ApiOperation(value = "上传文件", notes = "上传文件,上传后返回文件url")
@PostMapping("/file/upload") @PostMapping("/file/upload")
public Result<String> uploadFile(MultipartFile file) { public Result<String> uploadFile(MultipartFile file) {
return ResultUtils.success(fileService.uploadFile(file),""); return ResultUtils.success(fileService.uploadFile(file), "");
} }
} }

33
im-platform/src/main/java/com/bx/implatform/controller/FriendController.java

@ -8,7 +8,7 @@ import com.bx.implatform.session.SessionContext;
import com.bx.implatform.vo.FriendVO; import com.bx.implatform.vo.FriendVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
@ -19,16 +19,16 @@ import java.util.stream.Collectors;
@Api(tags = "好友") @Api(tags = "好友")
@RestController @RestController
@RequestMapping("/friend") @RequestMapping("/friend")
@AllArgsConstructor @RequiredArgsConstructor
public class FriendController { public class FriendController {
private IFriendService friendService; private final IFriendService friendService;
@GetMapping("/list") @GetMapping("/list")
@ApiOperation(value = "好友列表",notes="获取好友列表") @ApiOperation(value = "好友列表", notes = "获取好友列表")
public Result< List<FriendVO>> findFriends(){ public Result<List<FriendVO>> findFriends() {
List<Friend> friends = friendService.findFriendByUserId(SessionContext.getSession().getUserId()); List<Friend> friends = friendService.findFriendByUserId(SessionContext.getSession().getUserId());
List<FriendVO> vos = friends.stream().map(f->{ List<FriendVO> vos = friends.stream().map(f -> {
FriendVO vo = new FriendVO(); FriendVO vo = new FriendVO();
vo.setId(f.getFriendId()); vo.setId(f.getFriendId());
vo.setHeadImage(f.getFriendHeadImage()); vo.setHeadImage(f.getFriendHeadImage());
@ -39,31 +39,30 @@ public class FriendController {
} }
@PostMapping("/add") @PostMapping("/add")
@ApiOperation(value = "添加好友",notes="双方建立好友关系") @ApiOperation(value = "添加好友", notes = "双方建立好友关系")
public Result addFriend(@NotEmpty(message = "好友id不可为空") @RequestParam("friendId") Long friendId){ public Result addFriend(@NotEmpty(message = "好友id不可为空") @RequestParam("friendId") Long friendId) {
friendService.addFriend(friendId); friendService.addFriend(friendId);
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/find/{friendId}") @GetMapping("/find/{friendId}")
@ApiOperation(value = "查找好友信息",notes="查找好友信息") @ApiOperation(value = "查找好友信息", notes = "查找好友信息")
public Result<FriendVO> findFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId){ public Result<FriendVO> findFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId) {
return ResultUtils.success(friendService.findFriend(friendId)); return ResultUtils.success(friendService.findFriend(friendId));
} }
@DeleteMapping("/delete/{friendId}") @DeleteMapping("/delete/{friendId}")
@ApiOperation(value = "删除好友",notes="解除好友关系") @ApiOperation(value = "删除好友", notes = "解除好友关系")
public Result delFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId){ public Result delFriend(@NotEmpty(message = "好友id不可为空") @PathVariable("friendId") Long friendId) {
friendService.delFriend(friendId); friendService.delFriend(friendId);
return ResultUtils.success(); return ResultUtils.success();
} }
@PutMapping("/update") @PutMapping("/update")
@ApiOperation(value = "更新好友信息",notes="更新好友头像或昵称") @ApiOperation(value = "更新好友信息", notes = "更新好友头像或昵称")
public Result modifyFriend(@Valid @RequestBody FriendVO vo){ public Result modifyFriend(@Valid @RequestBody FriendVO vo) {
friendService.update(vo); friendService.update(vo);
return ResultUtils.success(); return ResultUtils.success();
} }

45
im-platform/src/main/java/com/bx/implatform/controller/GroupController.java

@ -8,78 +8,77 @@ import com.bx.implatform.vo.GroupMemberVO;
import com.bx.implatform.vo.GroupVO; import com.bx.implatform.vo.GroupVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@Api(tags = "群聊") @Api(tags = "群聊")
@RestController @RestController
@RequestMapping("/group") @RequestMapping("/group")
@AllArgsConstructor @RequiredArgsConstructor
public class GroupController { public class GroupController {
private IGroupService groupService; private final IGroupService groupService;
@ApiOperation(value = "创建群聊",notes="创建群聊") @ApiOperation(value = "创建群聊", notes = "创建群聊")
@PostMapping("/create") @PostMapping("/create")
public Result<GroupVO> createGroup(@Valid @RequestBody GroupVO vo){ public Result<GroupVO> createGroup(@Valid @RequestBody GroupVO vo) {
return ResultUtils.success(groupService.createGroup(vo)); return ResultUtils.success(groupService.createGroup(vo));
} }
@ApiOperation(value = "修改群聊信息",notes="修改群聊信息") @ApiOperation(value = "修改群聊信息", notes = "修改群聊信息")
@PutMapping("/modify") @PutMapping("/modify")
public Result<GroupVO> modifyGroup(@Valid @RequestBody GroupVO vo){ public Result<GroupVO> modifyGroup(@Valid @RequestBody GroupVO vo) {
return ResultUtils.success(groupService.modifyGroup(vo)); return ResultUtils.success(groupService.modifyGroup(vo));
} }
@ApiOperation(value = "解散群聊",notes="解散群聊") @ApiOperation(value = "解散群聊", notes = "解散群聊")
@DeleteMapping("/delete/{groupId}") @DeleteMapping("/delete/{groupId}")
public Result deleteGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){ public Result deleteGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) {
groupService.deleteGroup(groupId); groupService.deleteGroup(groupId);
return ResultUtils.success(); return ResultUtils.success();
} }
@ApiOperation(value = "查询群聊",notes="查询单个群聊信息") @ApiOperation(value = "查询群聊", notes = "查询单个群聊信息")
@GetMapping("/find/{groupId}") @GetMapping("/find/{groupId}")
public Result<GroupVO> findGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){ public Result<GroupVO> findGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) {
return ResultUtils.success(groupService.findById(groupId)); return ResultUtils.success(groupService.findById(groupId));
} }
@ApiOperation(value = "查询群聊列表",notes="查询群聊列表") @ApiOperation(value = "查询群聊列表", notes = "查询群聊列表")
@GetMapping("/list") @GetMapping("/list")
public Result<List<GroupVO>> findGroups(){ public Result<List<GroupVO>> findGroups() {
return ResultUtils.success(groupService.findGroups()); return ResultUtils.success(groupService.findGroups());
} }
@ApiOperation(value = "邀请进群",notes="邀请好友进群") @ApiOperation(value = "邀请进群", notes = "邀请好友进群")
@PostMapping("/invite") @PostMapping("/invite")
public Result invite(@Valid @RequestBody GroupInviteVO vo){ public Result invite(@Valid @RequestBody GroupInviteVO vo) {
groupService.invite(vo); groupService.invite(vo);
return ResultUtils.success(); return ResultUtils.success();
} }
@ApiOperation(value = "查询群聊成员",notes="查询群聊成员") @ApiOperation(value = "查询群聊成员", notes = "查询群聊成员")
@GetMapping("/members/{groupId}") @GetMapping("/members/{groupId}")
public Result<List<GroupMemberVO>> findGroupMembers(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){ public Result<List<GroupMemberVO>> findGroupMembers(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) {
return ResultUtils.success(groupService.findGroupMembers(groupId)); return ResultUtils.success(groupService.findGroupMembers(groupId));
} }
@ApiOperation(value = "退出群聊",notes="退出群聊") @ApiOperation(value = "退出群聊", notes = "退出群聊")
@DeleteMapping("/quit/{groupId}") @DeleteMapping("/quit/{groupId}")
public Result quitGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId){ public Result quitGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId) {
groupService.quitGroup(groupId); groupService.quitGroup(groupId);
return ResultUtils.success(); return ResultUtils.success();
} }
@ApiOperation(value = "踢出群聊",notes="将用户踢出群聊") @ApiOperation(value = "踢出群聊", notes = "将用户踢出群聊")
@DeleteMapping("/kick/{groupId}") @DeleteMapping("/kick/{groupId}")
public Result kickGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId, public Result kickGroup(@NotNull(message = "群聊id不能为空") @PathVariable Long groupId,
@NotNull(message = "用户id不能为空") @RequestParam Long userId){ @NotNull(message = "用户id不能为空") @RequestParam Long userId) {
groupService.kickGroup(groupId,userId); groupService.kickGroup(groupId, userId);
return ResultUtils.success(); return ResultUtils.success();
} }

37
im-platform/src/main/java/com/bx/implatform/controller/GroupMessageController.java

@ -7,66 +7,63 @@ import com.bx.implatform.service.IGroupMessageService;
import com.bx.implatform.vo.GroupMessageVO; import com.bx.implatform.vo.GroupMessageVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@Api(tags = "群聊消息") @Api(tags = "群聊消息")
@RestController @RestController
@RequestMapping("/message/group") @RequestMapping("/message/group")
@AllArgsConstructor @RequiredArgsConstructor
public class GroupMessageController { public class GroupMessageController {
private IGroupMessageService groupMessageService; private final IGroupMessageService groupMessageService;
@PostMapping("/send") @PostMapping("/send")
@ApiOperation(value = "发送群聊消息",notes="发送群聊消息") @ApiOperation(value = "发送群聊消息", notes = "发送群聊消息")
public Result<Long> sendMessage(@Valid @RequestBody GroupMessageDTO vo){ public Result<Long> sendMessage(@Valid @RequestBody GroupMessageDTO vo) {
return ResultUtils.success(groupMessageService.sendMessage(vo)); return ResultUtils.success(groupMessageService.sendMessage(vo));
} }
@DeleteMapping("/recall/{id}") @DeleteMapping("/recall/{id}")
@ApiOperation(value = "撤回消息",notes="撤回群聊消息") @ApiOperation(value = "撤回消息", notes = "撤回群聊消息")
public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id){ public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) {
groupMessageService.recallMessage(id); groupMessageService.recallMessage(id);
return ResultUtils.success(); return ResultUtils.success();
} }
// todo 删除 // todo 删除
@PostMapping("/pullUnreadMessage") @PostMapping("/pullUnreadMessage")
@ApiOperation(value = "拉取未读消息",notes="拉取未读消息") @ApiOperation(value = "拉取未读消息", notes = "拉取未读消息")
public Result pullUnreadMessage(){ public Result pullUnreadMessage() {
groupMessageService.pullUnreadMessage(); groupMessageService.pullUnreadMessage();
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/loadMessage") @GetMapping("/loadMessage")
@ApiOperation(value = "拉取消息",notes="拉取消息,一次最多拉取100条") @ApiOperation(value = "拉取消息", notes = "拉取消息,一次最多拉取100条")
public Result<List<GroupMessageVO>> loadMessage(@RequestParam Long minId){ public Result<List<GroupMessageVO>> loadMessage(@RequestParam Long minId) {
return ResultUtils.success(groupMessageService.loadMessage(minId)); return ResultUtils.success(groupMessageService.loadMessage(minId));
} }
@PutMapping("/readed") @PutMapping("/readed")
@ApiOperation(value = "消息已读",notes="将群聊中的消息状态置为已读") @ApiOperation(value = "消息已读", notes = "将群聊中的消息状态置为已读")
public Result readedMessage(@RequestParam Long groupId){ public Result readedMessage(@RequestParam Long groupId) {
groupMessageService.readedMessage(groupId); groupMessageService.readedMessage(groupId);
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/history") @GetMapping("/history")
@ApiOperation(value = "查询聊天记录",notes="查询聊天记录") @ApiOperation(value = "查询聊天记录", notes = "查询聊天记录")
public Result<List<GroupMessageVO>> recallMessage(@NotNull(message = "群聊id不能为空") @RequestParam Long groupId, public Result<List<GroupMessageVO>> recallMessage(@NotNull(message = "群聊id不能为空") @RequestParam Long groupId,
@NotNull(message = "页码不能为空") @RequestParam Long page, @NotNull(message = "页码不能为空") @RequestParam Long page,
@NotNull(message = "size不能为空") @RequestParam Long size){ @NotNull(message = "size不能为空") @RequestParam Long size) {
return ResultUtils.success( groupMessageService.findHistoryMessage(groupId,page,size)); return ResultUtils.success(groupMessageService.findHistoryMessage(groupId, page, size));
} }
} }

24
im-platform/src/main/java/com/bx/implatform/controller/LoginController.java

@ -9,46 +9,44 @@ import com.bx.implatform.service.IUserService;
import com.bx.implatform.vo.LoginVO; import com.bx.implatform.vo.LoginVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
@Api(tags = "用户登录和注册") @Api(tags = "用户登录和注册")
@RestController @RestController
@AllArgsConstructor @RequiredArgsConstructor
public class LoginController { public class LoginController {
private IUserService userService; private final IUserService userService;
@PostMapping("/login") @PostMapping("/login")
@ApiOperation(value = "用户注册",notes="用户注册") @ApiOperation(value = "用户注册", notes = "用户注册")
public Result register(@Valid @RequestBody LoginDTO dto){ public Result register(@Valid @RequestBody LoginDTO dto) {
LoginVO vo = userService.login(dto); LoginVO vo = userService.login(dto);
return ResultUtils.success(vo); return ResultUtils.success(vo);
} }
@PutMapping("/refreshToken") @PutMapping("/refreshToken")
@ApiOperation(value = "刷新token",notes="用refreshtoken换取新的token") @ApiOperation(value = "刷新token", notes = "用refreshtoken换取新的token")
public Result refreshToken(@RequestHeader("refreshToken")String refreshToken){ public Result refreshToken(@RequestHeader("refreshToken") String refreshToken) {
LoginVO vo = userService.refreshToken(refreshToken); LoginVO vo = userService.refreshToken(refreshToken);
return ResultUtils.success(vo); return ResultUtils.success(vo);
} }
@PostMapping("/register") @PostMapping("/register")
@ApiOperation(value = "用户注册",notes="用户注册") @ApiOperation(value = "用户注册", notes = "用户注册")
public Result register(@Valid @RequestBody RegisterDTO dto){ public Result register(@Valid @RequestBody RegisterDTO dto) {
userService.register(dto); userService.register(dto);
return ResultUtils.success(); return ResultUtils.success();
} }
@PutMapping("/modifyPwd") @PutMapping("/modifyPwd")
@ApiOperation(value = "修改密码",notes="修改用户密码") @ApiOperation(value = "修改密码", notes = "修改用户密码")
public Result update(@Valid @RequestBody ModifyPwdDTO dto){ public Result update(@Valid @RequestBody ModifyPwdDTO dto) {
userService.modifyPassword(dto); userService.modifyPassword(dto);
return ResultUtils.success(); return ResultUtils.success();
} }

35
im-platform/src/main/java/com/bx/implatform/controller/PrivateMessageController.java

@ -7,7 +7,7 @@ import com.bx.implatform.service.IPrivateMessageService;
import com.bx.implatform.vo.PrivateMessageVO; import com.bx.implatform.vo.PrivateMessageVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
@ -17,53 +17,52 @@ import java.util.List;
@Api(tags = "私聊消息") @Api(tags = "私聊消息")
@RestController @RestController
@RequestMapping("/message/private") @RequestMapping("/message/private")
@AllArgsConstructor @RequiredArgsConstructor
public class PrivateMessageController { public class PrivateMessageController {
private IPrivateMessageService privateMessageService; private final IPrivateMessageService privateMessageService;
@PostMapping("/send") @PostMapping("/send")
@ApiOperation(value = "发送消息",notes="发送私聊消息") @ApiOperation(value = "发送消息", notes = "发送私聊消息")
public Result<Long> sendMessage(@Valid @RequestBody PrivateMessageDTO vo){ public Result<Long> sendMessage(@Valid @RequestBody PrivateMessageDTO vo) {
return ResultUtils.success(privateMessageService.sendMessage(vo)); return ResultUtils.success(privateMessageService.sendMessage(vo));
} }
@DeleteMapping("/recall/{id}") @DeleteMapping("/recall/{id}")
@ApiOperation(value = "撤回消息",notes="撤回私聊消息") @ApiOperation(value = "撤回消息", notes = "撤回私聊消息")
public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id){ public Result<Long> recallMessage(@NotNull(message = "消息id不能为空") @PathVariable Long id) {
privateMessageService.recallMessage(id); privateMessageService.recallMessage(id);
return ResultUtils.success(); return ResultUtils.success();
} }
// todo 删除
@PostMapping("/pullUnreadMessage") @PostMapping("/pullUnreadMessage")
@ApiOperation(value = "拉取未读消息",notes="拉取未读消息") @ApiOperation(value = "拉取未读消息", notes = "拉取未读消息")
public Result pullUnreadMessage(){ public Result pullUnreadMessage() {
privateMessageService.pullUnreadMessage(); privateMessageService.pullUnreadMessage();
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/loadMessage") @GetMapping("/loadMessage")
@ApiOperation(value = "拉取消息",notes="拉取消息,一次最多拉取100条") @ApiOperation(value = "拉取消息", notes = "拉取消息,一次最多拉取100条")
public Result<List<PrivateMessageVO>> loadMessage(@RequestParam Long minId){ public Result<List<PrivateMessageVO>> loadMessage(@RequestParam Long minId) {
return ResultUtils.success(privateMessageService.loadMessage(minId)); return ResultUtils.success(privateMessageService.loadMessage(minId));
} }
@PutMapping("/readed") @PutMapping("/readed")
@ApiOperation(value = "消息已读",notes="将会话中接收的消息状态置为已读") @ApiOperation(value = "消息已读", notes = "将会话中接收的消息状态置为已读")
public Result readedMessage(@RequestParam Long friendId){ public Result readedMessage(@RequestParam Long friendId) {
privateMessageService.readedMessage(friendId); privateMessageService.readedMessage(friendId);
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/history") @GetMapping("/history")
@ApiOperation(value = "查询聊天记录",notes="查询聊天记录") @ApiOperation(value = "查询聊天记录", notes = "查询聊天记录")
public Result<List<PrivateMessageVO>> recallMessage(@NotNull(message = "好友id不能为空") @RequestParam Long friendId, public Result<List<PrivateMessageVO>> recallMessage(@NotNull(message = "好友id不能为空") @RequestParam Long friendId,
@NotNull(message = "页码不能为空") @RequestParam Long page, @NotNull(message = "页码不能为空") @RequestParam Long page,
@NotNull(message = "size不能为空") @RequestParam Long size){ @NotNull(message = "size不能为空") @RequestParam Long size) {
return ResultUtils.success( privateMessageService.findHistoryMessage(friendId,page,size)); return ResultUtils.success(privateMessageService.findHistoryMessage(friendId, page, size));
} }
} }

33
im-platform/src/main/java/com/bx/implatform/controller/UserController.java

@ -11,58 +11,55 @@ import com.bx.implatform.vo.OnlineTerminalVO;
import com.bx.implatform.vo.UserVO; import com.bx.implatform.vo.UserVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
@Api(tags = "用户") @Api(tags = "用户")
@RestController @RestController
@RequestMapping("/user") @RequestMapping("/user")
@AllArgsConstructor @RequiredArgsConstructor
public class UserController { public class UserController {
private IUserService userService; private final IUserService userService;
@GetMapping("/terminal/online") @GetMapping("/terminal/online")
@ApiOperation(value = "判断用户哪个终端在线",notes="返回在线的用户id的终端集合") @ApiOperation(value = "判断用户哪个终端在线", notes = "返回在线的用户id的终端集合")
public Result<List<OnlineTerminalVO>> getOnlineTerminal(@NotEmpty @RequestParam("userIds") String userIds){ public Result<List<OnlineTerminalVO>> getOnlineTerminal(@NotEmpty @RequestParam("userIds") String userIds) {
return ResultUtils.success(userService.getOnlineTerminals(userIds)); return ResultUtils.success(userService.getOnlineTerminals(userIds));
} }
@GetMapping("/self") @GetMapping("/self")
@ApiOperation(value = "获取当前用户信息",notes="获取当前用户信息") @ApiOperation(value = "获取当前用户信息", notes = "获取当前用户信息")
public Result<UserVO> findSelfInfo(){ public Result<UserVO> findSelfInfo() {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
User user = userService.getById(session.getUserId()); User user = userService.getById(session.getUserId());
UserVO userVO = BeanUtils.copyProperties(user,UserVO.class); UserVO userVO = BeanUtils.copyProperties(user, UserVO.class);
return ResultUtils.success(userVO); return ResultUtils.success(userVO);
} }
@GetMapping("/find/{id}") @GetMapping("/find/{id}")
@ApiOperation(value = "查找用户",notes="根据id查找用户") @ApiOperation(value = "查找用户", notes = "根据id查找用户")
public Result<UserVO> findById(@NotEmpty @PathVariable("id") Long id){ public Result<UserVO> findById(@NotEmpty @PathVariable("id") Long id) {
return ResultUtils.success(userService.findUserById(id)); return ResultUtils.success(userService.findUserById(id));
} }
@PutMapping("/update") @PutMapping("/update")
@ApiOperation(value = "修改用户信息",notes="修改用户信息,仅允许修改登录用户信息") @ApiOperation(value = "修改用户信息", notes = "修改用户信息,仅允许修改登录用户信息")
public Result update(@Valid @RequestBody UserVO vo){ public Result update(@Valid @RequestBody UserVO vo) {
userService.update(vo); userService.update(vo);
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/findByName") @GetMapping("/findByName")
@ApiOperation(value = "查找用户",notes="根据用户名或昵称查找用户") @ApiOperation(value = "查找用户", notes = "根据用户名或昵称查找用户")
public Result<List<UserVO>> findByName(@RequestParam("name") String name){ public Result<List<UserVO>> findByName(@RequestParam("name") String name) {
return ResultUtils.success( userService.findUserByName(name)); return ResultUtils.success(userService.findUserByName(name));
} }
} }

22
im-platform/src/main/java/com/bx/implatform/controller/WebrtcController.java

@ -6,7 +6,7 @@ import com.bx.implatform.result.ResultUtils;
import com.bx.implatform.service.IWebrtcService; import com.bx.implatform.service.IWebrtcService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@ -14,22 +14,22 @@ import java.util.List;
@Api(tags = "webrtc视频单人通话") @Api(tags = "webrtc视频单人通话")
@RestController @RestController
@RequestMapping("/webrtc/private") @RequestMapping("/webrtc/private")
@AllArgsConstructor @RequiredArgsConstructor
public class WebrtcController { public class WebrtcController {
private IWebrtcService webrtcService; private final IWebrtcService webrtcService;
@ApiOperation(httpMethod = "POST", value = "呼叫视频通话") @ApiOperation(httpMethod = "POST", value = "呼叫视频通话")
@PostMapping("/call") @PostMapping("/call")
public Result call(@RequestParam Long uid, @RequestBody String offer) { public Result call(@RequestParam Long uid, @RequestBody String offer) {
webrtcService.call(uid,offer); webrtcService.call(uid, offer);
return ResultUtils.success(); return ResultUtils.success();
} }
@ApiOperation(httpMethod = "POST", value = "接受视频通话") @ApiOperation(httpMethod = "POST", value = "接受视频通话")
@PostMapping("/accept") @PostMapping("/accept")
public Result accept(@RequestParam Long uid,@RequestBody String answer) { public Result accept(@RequestParam Long uid, @RequestBody String answer) {
webrtcService.accept(uid,answer); webrtcService.accept(uid, answer);
return ResultUtils.success(); return ResultUtils.success();
} }
@ -50,8 +50,8 @@ public class WebrtcController {
@ApiOperation(httpMethod = "POST", value = "呼叫失败") @ApiOperation(httpMethod = "POST", value = "呼叫失败")
@PostMapping("/failed") @PostMapping("/failed")
public Result failed(@RequestParam Long uid,@RequestParam String reason) { public Result failed(@RequestParam Long uid, @RequestParam String reason) {
webrtcService.failed(uid,reason); webrtcService.failed(uid, reason);
return ResultUtils.success(); return ResultUtils.success();
} }
@ -65,15 +65,15 @@ public class WebrtcController {
@PostMapping("/candidate") @PostMapping("/candidate")
@ApiOperation(httpMethod = "POST", value = "同步candidate") @ApiOperation(httpMethod = "POST", value = "同步candidate")
public Result forwardCandidate(@RequestParam Long uid,@RequestBody String candidate ) { public Result forwardCandidate(@RequestParam Long uid, @RequestBody String candidate) {
webrtcService.candidate(uid,candidate); webrtcService.candidate(uid, candidate);
return ResultUtils.success(); return ResultUtils.success();
} }
@GetMapping("/iceservers") @GetMapping("/iceservers")
@ApiOperation(httpMethod = "GET", value = "获取iceservers") @ApiOperation(httpMethod = "GET", value = "获取iceservers")
public Result<List<ICEServer>> iceservers() { public Result<List<ICEServer>> iceservers() {
return ResultUtils.success(webrtcService.getIceServers()); return ResultUtils.success(webrtcService.getIceServers());
} }
} }

10
im-platform/src/main/java/com/bx/implatform/dto/GroupMessageDTO.java

@ -14,20 +14,20 @@ import java.util.List;
@ApiModel("群聊消息DTO") @ApiModel("群聊消息DTO")
public class GroupMessageDTO { public class GroupMessageDTO {
@NotNull(message="群聊id不可为空") @NotNull(message = "群聊id不可为空")
@ApiModelProperty(value = "群聊id") @ApiModelProperty(value = "群聊id")
private Long groupId; private Long groupId;
@Length(max=1024,message = "发送内容长度不得大于1024") @Length(max = 1024, message = "发送内容长度不得大于1024")
@NotEmpty(message="发送内容不可为空") @NotEmpty(message = "发送内容不可为空")
@ApiModelProperty(value = "发送内容") @ApiModelProperty(value = "发送内容")
private String content; private String content;
@NotNull(message="消息类型不可为空") @NotNull(message = "消息类型不可为空")
@ApiModelProperty(value = "消息类型") @ApiModelProperty(value = "消息类型")
private Integer type; private Integer type;
@Size(max = 20,message = "一次最多只能@20个小伙伴哦") @Size(max = 20, message = "一次最多只能@20个小伙伴哦")
@ApiModelProperty(value = "被@用户列表") @ApiModelProperty(value = "被@用户列表")
private List<Long> atUserIds; private List<Long> atUserIds;
} }

10
im-platform/src/main/java/com/bx/implatform/dto/LoginDTO.java

@ -13,17 +13,17 @@ import javax.validation.constraints.NotNull;
@ApiModel("用户登录DTO") @ApiModel("用户登录DTO")
public class LoginDTO { public class LoginDTO {
@Max(value = 1,message = "登录终端类型取值范围:0,1") @Max(value = 1, message = "登录终端类型取值范围:0,1")
@Min(value = 0,message = "登录终端类型取值范围:0,1") @Min(value = 0, message = "登录终端类型取值范围:0,1")
@NotNull(message="登录终端类型不可为空") @NotNull(message = "登录终端类型不可为空")
@ApiModelProperty(value = "登录终端 0:web 1:app") @ApiModelProperty(value = "登录终端 0:web 1:app")
private Integer terminal; private Integer terminal;
@NotEmpty(message="用户名不可为空") @NotEmpty(message = "用户名不可为空")
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
private String userName; private String userName;
@NotEmpty(message="用户密码不可为空") @NotEmpty(message = "用户密码不可为空")
@ApiModelProperty(value = "用户密码") @ApiModelProperty(value = "用户密码")
private String password; private String password;

4
im-platform/src/main/java/com/bx/implatform/dto/ModifyPwdDTO.java

@ -10,11 +10,11 @@ import javax.validation.constraints.NotEmpty;
@ApiModel("修改密码DTO") @ApiModel("修改密码DTO")
public class ModifyPwdDTO { public class ModifyPwdDTO {
@NotEmpty(message="旧用户密码不可为空") @NotEmpty(message = "旧用户密码不可为空")
@ApiModelProperty(value = "旧用户密码") @ApiModelProperty(value = "旧用户密码")
private String oldPassword; private String oldPassword;
@NotEmpty(message="新用户密码不可为空") @NotEmpty(message = "新用户密码不可为空")
@ApiModelProperty(value = "新用户密码") @ApiModelProperty(value = "新用户密码")
private String newPassword; private String newPassword;

10
im-platform/src/main/java/com/bx/implatform/dto/PrivateMessageDTO.java

@ -1,6 +1,5 @@
package com.bx.implatform.dto; package com.bx.implatform.dto;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -13,18 +12,17 @@ import javax.validation.constraints.NotNull;
@ApiModel("私聊消息DTO") @ApiModel("私聊消息DTO")
public class PrivateMessageDTO { public class PrivateMessageDTO {
@NotNull(message = "接收用户id不可为空")
@NotNull(message="接收用户id不可为空")
@ApiModelProperty(value = "接收用户id") @ApiModelProperty(value = "接收用户id")
private Long recvId; private Long recvId;
@Length(max=1024,message = "内容长度不得大于1024") @Length(max = 1024, message = "内容长度不得大于1024")
@NotEmpty(message="发送内容不可为空") @NotEmpty(message = "发送内容不可为空")
@ApiModelProperty(value = "发送内容") @ApiModelProperty(value = "发送内容")
private String content; private String content;
@NotNull(message="消息类型不可为空") @NotNull(message = "消息类型不可为空")
@ApiModelProperty(value = "消息类型") @ApiModelProperty(value = "消息类型")
private Integer type; private Integer type;

12
im-platform/src/main/java/com/bx/implatform/dto/RegisterDTO.java

@ -11,18 +11,18 @@ import javax.validation.constraints.NotEmpty;
@ApiModel("用户注册DTO") @ApiModel("用户注册DTO")
public class RegisterDTO { public class RegisterDTO {
@Length(max = 64,message = "用户名不能大于64字符") @Length(max = 64, message = "用户名不能大于64字符")
@NotEmpty(message="用户名不可为空") @NotEmpty(message = "用户名不可为空")
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
private String userName; private String userName;
@Length(min=5,max = 20,message = "密码长度必须在5-20个字符之间") @Length(min = 5, max = 20, message = "密码长度必须在5-20个字符之间")
@NotEmpty(message="用户密码不可为空") @NotEmpty(message = "用户密码不可为空")
@ApiModelProperty(value = "用户密码") @ApiModelProperty(value = "用户密码")
private String password; private String password;
@Length(max = 64,message = "昵称不能大于64字符") @Length(max = 64, message = "昵称不能大于64字符")
@NotEmpty(message="用户昵称不可为空") @NotEmpty(message = "用户昵称不可为空")
@ApiModelProperty(value = "用户昵称") @ApiModelProperty(value = "用户昵称")
private String nickName; private String nickName;

1
im-platform/src/main/java/com/bx/implatform/entity/Group.java

@ -13,6 +13,7 @@ import java.util.Date;
/** /**
* *
*
* @author blue * @author blue
* @since 2022-10-31 * @since 2022-10-31
*/ */

5
im-platform/src/main/java/com/bx/implatform/entity/GroupMember.java

@ -45,19 +45,18 @@ public class GroupMember extends Model<GroupMember> {
private Long userId; private Long userId;
/** /**
* 群内显示名称 * 群内显示名称
*/ */
@TableField("alias_name") @TableField("alias_name")
private String aliasName; private String aliasName;
/** /**
* 头像 * 头像
*/ */
@TableField("head_image") @TableField("head_image")
private String headImage; private String headImage;
/** /**
* 备注 * 备注
*/ */

2
im-platform/src/main/java/com/bx/implatform/entity/PrivateMessage.java

@ -24,7 +24,7 @@ import java.util.Date;
@TableName("im_private_message") @TableName("im_private_message")
public class PrivateMessage extends Model<PrivateMessage> { public class PrivateMessage extends Model<PrivateMessage> {
private static final long serialVersionUID=1L; private static final long serialVersionUID = 1L;
/** /**
* id * id

4
im-platform/src/main/java/com/bx/implatform/entity/User.java

@ -13,7 +13,7 @@ import java.util.Date;
/** /**
* <p> * <p>
* 用户 * 用户
* </p> * </p>
* *
* @author blue * @author blue
@ -24,7 +24,7 @@ import java.util.Date;
@TableName("im_user") @TableName("im_user")
public class User extends Model<User> { public class User extends Model<User> {
private static final long serialVersionUID=1L; private static final long serialVersionUID = 1L;
/** /**
* id * id

24
im-platform/src/main/java/com/bx/implatform/enums/FileType.java

@ -5,19 +5,29 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum FileType { public enum FileType {
FILE(0,"文件"), /**
IMAGE(1,"图片"), * 文件
VIDEO(2,"视频"), */
AUDIO(3,"声音"); FILE(0, "文件"),
/**
* 图片
*/
IMAGE(1, "图片"),
/**
* 视频
*/
VIDEO(2, "视频"),
/**
* 声音
*/
AUDIO(3, "声音");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }

22
im-platform/src/main/java/com/bx/implatform/enums/MessageStatus.java

@ -5,17 +5,29 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum MessageStatus { public enum MessageStatus {
UNSEND(0,"未送达"), /**
SENDED(1,"送达"), * 文件
RECALL(2,"撤回"), */
READED(3,"已读"); UNSEND(0, "未送达"),
/**
* 文件
*/
SENDED(1, "送达"),
/**
* 撤回
*/
RECALL(2, "撤回"),
/**
* 已读
*/
READED(3, "已读");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }
} }

68
im-platform/src/main/java/com/bx/implatform/enums/MessageType.java

@ -5,28 +5,70 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum MessageType { public enum MessageType {
TEXT(0,"文字"), /**
IMAGE(1,"图片"), * 文字
FILE(2,"文件"), */
AUDIO(3,"音频"), TEXT(0, "文字"),
VIDEO(4,"视频"), /**
RECALL(10,"撤回"), * 图片
*/
IMAGE(1, "图片"),
/**
* 文件
*/
FILE(2, "文件"),
/**
* 音频
*/
AUDIO(3, "音频"),
/**
* 视频
*/
VIDEO(4, "视频"),
/**
* 撤回
*/
RECALL(10, "撤回"),
/**
* 已读
*/
READED(11, "已读"), READED(11, "已读"),
RTC_CALL(101,"呼叫"), /**
RTC_ACCEPT(102,"接受"), * 呼叫
*/
RTC_CALL(101, "呼叫"),
/**
* 接受
*/
RTC_ACCEPT(102, "接受"),
/**
* 拒绝
*/
RTC_REJECT(103, "拒绝"), RTC_REJECT(103, "拒绝"),
RTC_CANCEL(104,"取消呼叫"), /**
RTC_FAILED(105,"呼叫失败"), * 取消呼叫
RTC_HANDUP(106,"挂断"), */
RTC_CANDIDATE(107,"同步candidate"); RTC_CANCEL(104, "取消呼叫"),
/**
* 呼叫失败
*/
RTC_FAILED(105, "呼叫失败"),
/**
* 挂断
*/
RTC_HANDUP(106, "挂断"),
/**
* 同步candidate
*/
RTC_CANDIDATE(107, "同步candidate");
private final Integer code; private final Integer code;
private final String desc; private final String desc;
public Integer code(){ public Integer code() {
return this.code; return this.code;
} }
} }

41
im-platform/src/main/java/com/bx/implatform/enums/ResultCode.java

@ -8,23 +8,42 @@ import lombok.Getter;
* *
* @author Blue * @author Blue
* @date 2020/10/19 * @date 2020/10/19
*
**/ **/
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum ResultCode { public enum ResultCode {
SUCCESS(200,"成功"), /**
NO_LOGIN(400,"未登录"), * 成功
INVALID_TOKEN(401,"token无效或已过期"), */
PROGRAM_ERROR(500,"系统繁忙,请稍后再试"), SUCCESS(200, "成功"),
PASSWOR_ERROR(10001,"密码不正确"), /**
USERNAME_ALREADY_REGISTER(10003,"该用户名已注册"), * 未登录
XSS_PARAM_ERROR(10004,"请不要输入非法内容"), */
; NO_LOGIN(400, "未登录"),
/**
* token无效或已过期
*/
INVALID_TOKEN(401, "token无效或已过期"),
/**
* 系统繁忙请稍后再试
*/
PROGRAM_ERROR(500, "系统繁忙,请稍后再试"),
/**
* 密码不正确
*/
PASSWOR_ERROR(10001, "密码不正确"),
/**
* 该用户名已注册
*/
USERNAME_ALREADY_REGISTER(10003, "该用户名已注册"),
/**
* 请不要输入非法内容
*/
XSS_PARAM_ERROR(10004, "请不要输入非法内容");
private int code; private final int code;
private String msg; private final String msg;
} }

17
im-platform/src/main/java/com/bx/implatform/exception/GlobalException.java

@ -5,21 +5,20 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data @Data
public class GlobalException extends RuntimeException implements Serializable { public class GlobalException extends RuntimeException implements Serializable {
private static final long serialVersionUID = 8134030011662574394L; private static final long serialVersionUID = 8134030011662574394L;
private Integer code; private Integer code;
private String message; private String message;
public GlobalException(Integer code, String message){ public GlobalException(Integer code, String message) {
this.code=code; this.code = code;
this.message=message; this.message = message;
} }
public GlobalException(ResultCode resultCode, String message){ public GlobalException(ResultCode resultCode, String message) {
this.code = resultCode.getCode(); this.code = resultCode.getCode();
this.message=message; this.message = message;
} }
public GlobalException(ResultCode resultCode) { public GlobalException(ResultCode resultCode) {
@ -27,9 +26,9 @@ public class GlobalException extends RuntimeException implements Serializable {
this.message = resultCode.getMsg(); this.message = resultCode.getMsg();
} }
public GlobalException(String message){ public GlobalException(String message) {
this.code= ResultCode.PROGRAM_ERROR.getCode(); this.code = ResultCode.PROGRAM_ERROR.getCode();
this.message=message; this.message = message;
} }
} }

41
im-platform/src/main/java/com/bx/implatform/exception/GlobalExceptionHandler.java

@ -20,53 +20,52 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.List; import java.util.List;
@ControllerAdvice @ControllerAdvice
@ResponseBody @ResponseBody
@Slf4j @Slf4j
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class) @ExceptionHandler(value = Exception.class)
public Result handleException(Exception e){ public Result handleException(Exception e) {
if(e instanceof GlobalException) { if (e instanceof GlobalException) {
GlobalException ex = (GlobalException)e; GlobalException ex = (GlobalException) e;
log.error("全局异常捕获:msg:{},log:{},{}" , ex.getMessage(), e); log.error("全局异常捕获:msg:{},log:{},{}", ex.getMessage(), e);
return ResultUtils.error(ex.getCode(), ex.getMessage()); return ResultUtils.error(ex.getCode(), ex.getMessage());
} } else if (e instanceof UndeclaredThrowableException) {
else if(e instanceof UndeclaredThrowableException) {
GlobalException ex = (GlobalException) e.getCause(); GlobalException ex = (GlobalException) e.getCause();
log.error("全局异常捕获:msg:{},log:{},{}" , ex.getMessage(), e); log.error("全局异常捕获:msg:{},log:{},{}", ex.getMessage(), e);
return ResultUtils.error(ex.getCode(), ex.getMessage()); return ResultUtils.error(ex.getCode(), ex.getMessage());
}else{ } else {
log.error("全局异常捕获:msg:{},{}" , e.getMessage(), e); log.error("全局异常捕获:msg:{},{}", e.getMessage(), e);
return ResultUtils.error(ResultCode.PROGRAM_ERROR); return ResultUtils.error(ResultCode.PROGRAM_ERROR);
} }
} }
/** /**
* 数据解析错误 * 数据解析错误
**/ **/
@ExceptionHandler(value = HttpMessageNotReadableException.class) @ExceptionHandler(value = HttpMessageNotReadableException.class)
public Result handleMessageNotReadableException(HttpMessageNotReadableException e){ public Result handleMessageNotReadableException(HttpMessageNotReadableException e) {
log.error("全局异常捕获:msg:{}" , e.getMessage()); log.error("全局异常捕获:msg:{}", e.getMessage());
Throwable t = e.getCause(); Throwable t = e.getCause();
if(t instanceof JSONException){ if (t instanceof JSONException) {
t = t.getCause(); t = t.getCause();
if(t instanceof DateTimeParseException){ if (t instanceof DateTimeParseException) {
return ResultUtils.error(ResultCode.PROGRAM_ERROR, "日期格式不正确"); return ResultUtils.error(ResultCode.PROGRAM_ERROR, "日期格式不正确");
} }
return ResultUtils.error(ResultCode.PROGRAM_ERROR, "数据格式不正确"); return ResultUtils.error(ResultCode.PROGRAM_ERROR, "数据格式不正确");
} }
return ResultUtils.error(ResultCode.PROGRAM_ERROR); return ResultUtils.error(ResultCode.PROGRAM_ERROR);
} }
/** /**
* 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常 * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常
*
* @param exception * @param exception
* @return * @return
*/ */
@ExceptionHandler(value = { MethodArgumentNotValidException.class}) @ExceptionHandler(value = {MethodArgumentNotValidException.class})
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public Result handleValidationExceptionHandler(MethodArgumentNotValidException exception) { public Result handleValidationExceptionHandler(MethodArgumentNotValidException exception) {
BindingResult bindResult = exception.getBindingResult(); BindingResult bindResult = exception.getBindingResult();
@ -76,23 +75,23 @@ public class GlobalExceptionHandler {
if (msg.contains("NumberFormatException")) { if (msg.contains("NumberFormatException")) {
msg = "参数类型错误!"; msg = "参数类型错误!";
} }
}else { } else {
msg = "系统繁忙,请稍后重试..."; msg = "系统繁忙,请稍后重试...";
} }
return ResultUtils.error(ResultCode.PROGRAM_ERROR,msg); return ResultUtils.error(ResultCode.PROGRAM_ERROR, msg);
} }
@ExceptionHandler(BindException.class) @ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
public Result handleBindException(BindException e){ public Result handleBindException(BindException e) {
//抛出异常可能不止一个 输出为一个List集合 //抛出异常可能不止一个 输出为一个List集合
List<ObjectError> errors = e.getAllErrors(); List<ObjectError> errors = e.getAllErrors();
//取第一个异常 //取第一个异常
ObjectError error = errors.get(0); ObjectError error = errors.get(0);
//获取异常信息 //获取异常信息
String errorMsg = error.getDefaultMessage(); String errorMsg = error.getDefaultMessage();
return ResultUtils.error(ResultCode.PROGRAM_ERROR,errorMsg); return ResultUtils.error(ResultCode.PROGRAM_ERROR, errorMsg);
} }
} }

8
im-platform/src/main/java/com/bx/implatform/filter/CacheFilter.java

@ -10,14 +10,16 @@ import java.io.IOException;
@Component @Component
@ServletComponentScan @ServletComponentScan
@WebFilter(urlPatterns = "/*",filterName = "xssFilter") @WebFilter(urlPatterns = "/*", filterName = "xssFilter")
public class CacheFilter implements Filter { public class CacheFilter implements Filter {
@Override @Override
public void init(FilterConfig filterConfig) {} public void init(FilterConfig filterConfig) {
}
@Override @Override
public void destroy() {} public void destroy() {
}
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

15
im-platform/src/main/java/com/bx/implatform/interceptor/AuthInterceptor.java

@ -9,6 +9,7 @@ import com.bx.implatform.exception.GlobalException;
import com.bx.implatform.session.UserSession; import com.bx.implatform.session.UserSession;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
@ -24,7 +25,7 @@ public class AuthInterceptor implements HandlerInterceptor {
private final JwtProperties jwtProperties; private final JwtProperties jwtProperties;
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
//如果不是映射到方法直接通过 //如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod)) { if (!(handler instanceof HandlerMethod)) {
return true; return true;
@ -32,18 +33,18 @@ public class AuthInterceptor implements HandlerInterceptor {
//从 http 请求头中取出 token //从 http 请求头中取出 token
String token = request.getHeader("accessToken"); String token = request.getHeader("accessToken");
if (StrUtil.isEmpty(token)) { if (StrUtil.isEmpty(token)) {
log.error("未登陆,url:{}",request.getRequestURI()); log.error("未登陆,url:{}", request.getRequestURI());
throw new GlobalException(ResultCode.NO_LOGIN); throw new GlobalException(ResultCode.NO_LOGIN);
} }
//验证 token //验证 token
if(!JwtUtil.checkSign(token, jwtProperties.getAccessTokenSecret())){ if (!JwtUtil.checkSign(token, jwtProperties.getAccessTokenSecret())) {
log.error("token已失效,url:{}",request.getRequestURI()); log.error("token已失效,url:{}", request.getRequestURI());
throw new GlobalException(ResultCode.INVALID_TOKEN); throw new GlobalException(ResultCode.INVALID_TOKEN);
} }
// 存放session // 存放session
String strJson = JwtUtil.getInfo(token); String strJson = JwtUtil.getInfo(token);
UserSession userSession = JSON.parseObject(strJson,UserSession.class); UserSession userSession = JSON.parseObject(strJson, UserSession.class);
request.setAttribute("session",userSession); request.setAttribute("session", userSession);
return true; return true;
} }
} }

15
im-platform/src/main/java/com/bx/implatform/interceptor/XssInterceptor.java

@ -5,6 +5,7 @@ import com.bx.implatform.exception.GlobalException;
import com.bx.implatform.util.XssUtil; import com.bx.implatform.util.XssUtil;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
@ -18,26 +19,26 @@ import java.util.Map;
public class XssInterceptor implements HandlerInterceptor { public class XssInterceptor implements HandlerInterceptor {
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
// 检查参数 // 检查参数
Map<String, String[]> paramMap = request.getParameterMap(); Map<String, String[]> paramMap = request.getParameterMap();
for(String[] values:paramMap.values()){ for (String[] values : paramMap.values()) {
for(String value:values){ for (String value : values) {
if(XssUtil.checkXss(value)){ if (XssUtil.checkXss(value)) {
throw new GlobalException(ResultCode.XSS_PARAM_ERROR); throw new GlobalException(ResultCode.XSS_PARAM_ERROR);
} }
} }
} }
// 检查body // 检查body
String body = getBody(request); String body = getBody(request);
if(XssUtil.checkXss(body)){ if (XssUtil.checkXss(body)) {
throw new GlobalException(ResultCode.XSS_PARAM_ERROR); throw new GlobalException(ResultCode.XSS_PARAM_ERROR);
} }
return true; return true;
} }
@SneakyThrows @SneakyThrows
private String getBody(HttpServletRequest request){ private String getBody(HttpServletRequest request) {
BufferedReader reader = request.getReader(); BufferedReader reader = request.getReader();
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
String line; String line;

10
im-platform/src/main/java/com/bx/implatform/listener/GroupMessageListener.java

@ -11,21 +11,19 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
@Slf4j @Slf4j
@IMListener(type = IMListenerType.GROUP_MESSAGE) @IMListener(type = IMListenerType.GROUP_MESSAGE)
@AllArgsConstructor @AllArgsConstructor
public class GroupMessageListener implements MessageListener<GroupMessageVO> { public class GroupMessageListener implements MessageListener<GroupMessageVO> {
private RedisTemplate<String,Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
@Override @Override
public void process(IMSendResult<GroupMessageVO> result){ public void process(IMSendResult<GroupMessageVO> result) {
GroupMessageVO messageInfo = result.getData(); GroupMessageVO messageInfo = result.getData();
// todo 删除
// 保存该用户已拉取的最大消息id // 保存该用户已拉取的最大消息id
if(result.getCode().equals(IMSendCode.SUCCESS.code())) { if (result.getCode().equals(IMSendCode.SUCCESS.code())) {
String key = String.join(":",RedisKey.IM_GROUP_READED_POSITION,messageInfo.getGroupId().toString(),result.getReceiver().getId().toString()); String key = String.join(":", RedisKey.IM_GROUP_READED_POSITION, messageInfo.getGroupId().toString(), result.getReceiver().getId().toString());
redisTemplate.opsForValue().set(key, messageInfo.getId()); redisTemplate.opsForValue().set(key, messageInfo.getId());
} }
} }

9
im-platform/src/main/java/com/bx/implatform/listener/PrivateMessageListener.java

@ -14,7 +14,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@Slf4j @Slf4j
@IMListener(type = IMListenerType.PRIVATE_MESSAGE) @IMListener(type = IMListenerType.PRIVATE_MESSAGE)
public class PrivateMessageListener implements MessageListener<PrivateMessageVO> { public class PrivateMessageListener implements MessageListener<PrivateMessageVO> {
@ -24,16 +23,16 @@ public class PrivateMessageListener implements MessageListener<PrivateMessageVO>
private IPrivateMessageService privateMessageService; private IPrivateMessageService privateMessageService;
@Override @Override
public void process(IMSendResult<PrivateMessageVO> result){ public void process(IMSendResult<PrivateMessageVO> result) {
PrivateMessageVO messageInfo = result.getData(); PrivateMessageVO messageInfo = result.getData();
// 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态 // 更新消息状态,这里只处理成功消息,失败的消息继续保持未读状态
if(result.getCode().equals(IMSendCode.SUCCESS.code())){ if (result.getCode().equals(IMSendCode.SUCCESS.code())) {
UpdateWrapper<PrivateMessage> updateWrapper = new UpdateWrapper<>(); UpdateWrapper<PrivateMessage> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(PrivateMessage::getId,messageInfo.getId()) updateWrapper.lambda().eq(PrivateMessage::getId, messageInfo.getId())
.eq(PrivateMessage::getStatus, MessageStatus.UNSEND.code()) .eq(PrivateMessage::getStatus, MessageStatus.UNSEND.code())
.set(PrivateMessage::getStatus, MessageStatus.SENDED.code()); .set(PrivateMessage::getStatus, MessageStatus.SENDED.code());
privateMessageService.update(updateWrapper); privateMessageService.update(updateWrapper);
log.info("消息已读,消息id:{},发送者:{},接收者:{},终端:{}",messageInfo.getId(),result.getSender().getId(),result.getReceiver().getId(),result.getReceiver().getTerminal()); log.info("消息已读,消息id:{},发送者:{},接收者:{},终端:{}", messageInfo.getId(), result.getSender().getId(), result.getReceiver().getId(), result.getReceiver().getTerminal());
} }
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/FriendMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.Friend; import com.bx.implatform.entity.Friend;
public interface FriendMapper extends BaseMapper<Friend> { public interface FriendMapper extends BaseMapper<Friend> {
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/GroupMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.Group; import com.bx.implatform.entity.Group;
public interface GroupMapper extends BaseMapper<Group> { public interface GroupMapper extends BaseMapper<Group> {
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/GroupMemberMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.GroupMember; import com.bx.implatform.entity.GroupMember;
public interface GroupMemberMapper extends BaseMapper<GroupMember> { public interface GroupMemberMapper extends BaseMapper<GroupMember> {
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/GroupMessageMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.GroupMessage; import com.bx.implatform.entity.GroupMessage;
public interface GroupMessageMapper extends BaseMapper<GroupMessage> { public interface GroupMessageMapper extends BaseMapper<GroupMessage> {
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/PrivateMessageMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.PrivateMessage; import com.bx.implatform.entity.PrivateMessage;
public interface PrivateMessageMapper extends BaseMapper<PrivateMessage> { public interface PrivateMessageMapper extends BaseMapper<PrivateMessage> {
} }

1
im-platform/src/main/java/com/bx/implatform/mapper/UserMapper.java

@ -3,7 +3,6 @@ package com.bx.implatform.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bx.implatform.entity.User; import com.bx.implatform.entity.User;
public interface UserMapper extends BaseMapper<User> { public interface UserMapper extends BaseMapper<User> {
} }

2
im-platform/src/main/java/com/bx/implatform/result/Result.java

@ -2,11 +2,9 @@ package com.bx.implatform.result;
import lombok.Data; import lombok.Data;
@Data @Data
public class Result<T> { public class Result<T> {
private int code; private int code;
private String message; private String message;

35
im-platform/src/main/java/com/bx/implatform/result/ResultUtils.java

@ -1,62 +1,63 @@
package com.bx.implatform.result; package com.bx.implatform.result;
import com.bx.implatform.enums.ResultCode; import com.bx.implatform.enums.ResultCode;
public class ResultUtils { public final class ResultUtils {
private ResultUtils() {
}
public static <T> Result<T> success(){ public static <T> Result<T> success() {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode()); result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(ResultCode.SUCCESS.getMsg()); result.setMessage(ResultCode.SUCCESS.getMsg());
return result; return result;
} }
public static <T> Result<T> success(T data){ public static <T> Result<T> success(T data) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode()); result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(ResultCode.SUCCESS.getMsg()); result.setMessage(ResultCode.SUCCESS.getMsg());
result.setData(data); result.setData(data);
return result; return result;
} }
public static <T> Result<T> success(T data, String messsage){ public static <T> Result<T> success(T data, String messsage) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode()); result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(messsage); result.setMessage(messsage);
result.setData(data); result.setData(data);
return result; return result;
} }
public static <T> Result<T> success(String messsage){ public static <T> Result<T> success(String messsage) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(ResultCode.SUCCESS.getCode()); result.setCode(ResultCode.SUCCESS.getCode());
result.setMessage(messsage); result.setMessage(messsage);
return result; return result;
} }
public static <T> Result<T> error(Integer code, String messsage){ public static <T> Result<T> error(Integer code, String messsage) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(code); result.setCode(code);
result.setMessage(messsage); result.setMessage(messsage);
return result; return result;
} }
public static <T> Result<T> error(ResultCode resultCode, String messsage){ public static <T> Result<T> error(ResultCode resultCode, String messsage) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(resultCode.getCode()); result.setCode(resultCode.getCode());
result.setMessage(messsage); result.setMessage(messsage);
return result; return result;
} }
public static <T> Result<T> error(ResultCode resultCode){ public static <T> Result<T> error(ResultCode resultCode) {
Result<T> result=new Result<>(); Result<T> result = new Result<>();
result.setCode(resultCode.getCode()); result.setCode(resultCode.getCode());
result.setMessage(resultCode.getMsg()); result.setMessage(resultCode.getMsg());
return result; return result;
} }
} }

5
im-platform/src/main/java/com/bx/implatform/service/IFriendService.java

@ -6,7 +6,6 @@ import com.bx.implatform.vo.FriendVO;
import java.util.List; import java.util.List;
public interface IFriendService extends IService<Friend> { public interface IFriendService extends IService<Friend> {
/** /**
@ -22,7 +21,7 @@ public interface IFriendService extends IService<Friend> {
/** /**
* 查询用户的所有好友 * 查询用户的所有好友
* *
* @param userId 用户id * @param userId 用户id
* @return 好友列表 * @return 好友列表
*/ */
List<Friend> findFriendByUserId(Long userId); List<Friend> findFriendByUserId(Long userId);
@ -44,7 +43,7 @@ public interface IFriendService extends IService<Friend> {
/** /**
* 更新好友信息主要是头像和昵称 * 更新好友信息主要是头像和昵称
* *
* @param vo 好友vo * @param vo 好友vo
*/ */
void update(FriendVO vo); void update(FriendVO vo);

20
im-platform/src/main/java/com/bx/implatform/service/IGroupMemberService.java

@ -5,18 +5,16 @@ import com.bx.implatform.entity.GroupMember;
import java.util.List; import java.util.List;
public interface IGroupMemberService extends IService<GroupMember> { public interface IGroupMemberService extends IService<GroupMember> {
/** /**
* 根据群聊id和用户id查询群聊成员 * 根据群聊id和用户id查询群聊成员
* *
* @param groupId 群聊id * @param groupId 群聊id
* @param userId 用户id * @param userId 用户id
* @return 群聊成员信息 * @return 群聊成员信息
*/ */
GroupMember findByGroupAndUserId(Long groupId,Long userId); GroupMember findByGroupAndUserId(Long groupId, Long userId);
/** /**
* 根据用户id查询群聊成员 * 根据用户id查询群聊成员
@ -24,7 +22,7 @@ public interface IGroupMemberService extends IService<GroupMember> {
* @param userId 用户id * @param userId 用户id
* @return 成员列表 * @return 成员列表
*/ */
List<GroupMember> findByUserId(Long userId); List<GroupMember> findByUserId(Long userId);
/** /**
* 根据群聊id查询群聊成员包括已退出 * 根据群聊id查询群聊成员包括已退出
@ -32,7 +30,7 @@ public interface IGroupMemberService extends IService<GroupMember> {
* @param groupId 群聊id * @param groupId 群聊id
* @return 群聊成员列表 * @return 群聊成员列表
*/ */
List<GroupMember> findByGroupId(Long groupId); List<GroupMember> findByGroupId(Long groupId);
/** /**
* 根据群聊id查询没有退出的群聊成员id * 根据群聊id查询没有退出的群聊成员id
@ -49,20 +47,20 @@ public interface IGroupMemberService extends IService<GroupMember> {
* @param members 成员列表 * @param members 成员列表
* @return 成功或失败 * @return 成功或失败
*/ */
boolean saveOrUpdateBatch(Long groupId,List<GroupMember> members); boolean saveOrUpdateBatch(Long groupId, List<GroupMember> members);
/** /**
* 根据群聊id删除移除成员 * 根据群聊id删除移除成员
* *
* @param groupId 群聊id * @param groupId 群聊id
*/ */
void removeByGroupId(Long groupId); void removeByGroupId(Long groupId);
/** /**
*根据群聊id和用户id移除成员 * 根据群聊id和用户id移除成员
* *
* @param groupId 群聊id * @param groupId 群聊id
* @param userId 用户id * @param userId 用户id
*/ */
void removeByGroupAndUserId(Long groupId,Long userId); void removeByGroupAndUserId(Long groupId, Long userId);
} }

6
im-platform/src/main/java/com/bx/implatform/service/IGroupMessageService.java

@ -7,7 +7,6 @@ import com.bx.implatform.vo.GroupMessageVO;
import java.util.List; import java.util.List;
public interface IGroupMessageService extends IService<GroupMessage> { public interface IGroupMessageService extends IService<GroupMessage> {
/** /**
@ -26,7 +25,6 @@ public interface IGroupMessageService extends IService<GroupMessage> {
void recallMessage(Long id); void recallMessage(Long id);
/** /**
*
* 异步拉取群聊消息通过websocket异步推送 * 异步拉取群聊消息通过websocket异步推送
*/ */
void pullUnreadMessage(); void pullUnreadMessage();
@ -34,7 +32,7 @@ public interface IGroupMessageService extends IService<GroupMessage> {
/** /**
* 拉取消息只能拉取最近1个月的消息一次拉取100条 * 拉取消息只能拉取最近1个月的消息一次拉取100条
* *
* @param minId 消息起始id * @param minId 消息起始id
* @return 聊天消息列表 * @return 聊天消息列表
*/ */
List<GroupMessageVO> loadMessage(Long minId); List<GroupMessageVO> loadMessage(Long minId);
@ -42,7 +40,7 @@ public interface IGroupMessageService extends IService<GroupMessage> {
/** /**
* 消息已读,同步其他终端清空未读数量 * 消息已读,同步其他终端清空未读数量
* *
* @param groupId 群聊 * @param groupId 群聊
*/ */
void readedMessage(Long groupId); void readedMessage(Long groupId);

13
im-platform/src/main/java/com/bx/implatform/service/IGroupService.java

@ -8,13 +8,12 @@ import com.bx.implatform.vo.GroupVO;
import java.util.List; import java.util.List;
public interface IGroupService extends IService<Group> { public interface IGroupService extends IService<Group> {
/** /**
* 创建新群聊 * 创建新群聊
* *
* @param vo 群聊信息 * @param vo 群聊信息
* @return 群聊信息 * @return 群聊信息
**/ **/
GroupVO createGroup(GroupVO vo); GroupVO createGroup(GroupVO vo);
@ -22,7 +21,7 @@ public interface IGroupService extends IService<Group> {
/** /**
* 修改群聊信息 * 修改群聊信息
* *
* @param vo 群聊信息 * @param vo 群聊信息
* @return 群聊信息 * @return 群聊信息
**/ **/
GroupVO modifyGroup(GroupVO vo); GroupVO modifyGroup(GroupVO vo);
@ -45,21 +44,21 @@ public interface IGroupService extends IService<Group> {
* 将用户踢出群聊 * 将用户踢出群聊
* *
* @param groupId 群聊id * @param groupId 群聊id
* @param userId 用户id * @param userId 用户id
*/ */
void kickGroup(Long groupId,Long userId); void kickGroup(Long groupId, Long userId);
/** /**
* 查询当前用户的所有群聊 * 查询当前用户的所有群聊
* *
* @return 群聊信息列表 * @return 群聊信息列表
**/ **/
List<GroupVO> findGroups(); List<GroupVO> findGroups();
/** /**
* 邀请好友进群 * 邀请好友进群
* *
* @param vo 群id好友id列表 * @param vo 群id好友id列表
**/ **/
void invite(GroupInviteVO vo); void invite(GroupInviteVO vo);

3
im-platform/src/main/java/com/bx/implatform/service/IPrivateMessageService.java

@ -7,7 +7,6 @@ import com.bx.implatform.vo.PrivateMessageVO;
import java.util.List; import java.util.List;
public interface IPrivateMessageService extends IService<PrivateMessage> { public interface IPrivateMessageService extends IService<PrivateMessage> {
/** /**
@ -34,7 +33,7 @@ public interface IPrivateMessageService extends IService<PrivateMessage> {
* @param size 页码大小 * @param size 页码大小
* @return 聊天记录列表 * @return 聊天记录列表
*/ */
List<PrivateMessageVO> findHistoryMessage(Long friendId, Long page,Long size); List<PrivateMessageVO> findHistoryMessage(Long friendId, Long page, Long size);
/** /**
* 异步拉取私聊消息通过websocket异步推送 * 异步拉取私聊消息通过websocket异步推送

3
im-platform/src/main/java/com/bx/implatform/service/IUserService.java

@ -11,7 +11,6 @@ import com.bx.implatform.vo.UserVO;
import java.util.List; import java.util.List;
public interface IUserService extends IService<User> { public interface IUserService extends IService<User> {
/** /**
@ -32,7 +31,7 @@ public interface IUserService extends IService<User> {
/** /**
* 用refreshToken换取新 token * 用refreshToken换取新 token
* *
* @param refreshToken 刷新token * @param refreshToken 刷新token
* @return 登录token * @return 登录token
*/ */
LoginVO refreshToken(String refreshToken); LoginVO refreshToken(String refreshToken);

19
im-platform/src/main/java/com/bx/implatform/service/IWebrtcService.java

@ -5,29 +5,28 @@ import org.springframework.web.bind.annotation.RequestBody;
import java.util.List; import java.util.List;
/** /**
* webrtc 通信服务 * webrtc 通信服务
*
* @author * @author
*/ */
public interface IWebrtcService { public interface IWebrtcService {
void call(Long uid, String offer); void call(Long uid, String offer);
void accept( Long uid,@RequestBody String answer);
void reject( Long uid); void accept(Long uid, @RequestBody String answer);
void cancel( Long uid); void reject(Long uid);
void failed( Long uid, String reason); void cancel(Long uid);
void leave( Long uid) ; void failed(Long uid, String reason);
void candidate( Long uid, String candidate); void leave(Long uid);
List<ICEServer> getIceServers(); void candidate(Long uid, String candidate);
List<ICEServer> getIceServers();
} }

84
im-platform/src/main/java/com/bx/implatform/service/impl/FriendServiceImpl.java

@ -15,7 +15,7 @@ import com.bx.implatform.service.IFriendService;
import com.bx.implatform.session.SessionContext; import com.bx.implatform.session.SessionContext;
import com.bx.implatform.session.UserSession; import com.bx.implatform.session.UserSession;
import com.bx.implatform.vo.FriendVO; import com.bx.implatform.vo.FriendVO;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext; import org.springframework.aop.framework.AopContext;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
@ -26,76 +26,71 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
@CacheConfig(cacheNames= RedisKey.IM_CACHE_FRIEND) @CacheConfig(cacheNames = RedisKey.IM_CACHE_FRIEND)
public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements IFriendService { public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements IFriendService {
private final UserMapper userMapper; private final UserMapper userMapper;
@Override @Override
public List<Friend> findFriendByUserId(Long userId) { public List<Friend> findFriendByUserId(Long userId) {
LambdaQueryWrapper<Friend> queryWrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<Friend> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(Friend::getUserId,userId); queryWrapper.eq(Friend::getUserId, userId);
return this.list(queryWrapper); return this.list(queryWrapper);
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public void addFriend(Long friendId) { public void addFriend(Long friendId) {
long userId = SessionContext.getSession().getUserId(); long userId = SessionContext.getSession().getUserId();
if(userId == friendId){ if (userId == friendId) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"不允许添加自己为好友"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "不允许添加自己为好友");
} }
// 互相绑定好友关系 // 互相绑定好友关系
FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy(); FriendServiceImpl proxy = (FriendServiceImpl) AopContext.currentProxy();
proxy.bindFriend(userId,friendId); proxy.bindFriend(userId, friendId);
proxy.bindFriend(friendId,userId); proxy.bindFriend(friendId, userId);
log.info("添加好友,用户id:{},好友id:{}",userId,friendId); log.info("添加好友,用户id:{},好友id:{}", userId, friendId);
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public void delFriend(Long friendId) { public void delFriend(Long friendId) {
long userId = SessionContext.getSession().getUserId(); long userId = SessionContext.getSession().getUserId();
// 互相解除好友关系,走代理清理缓存 // 互相解除好友关系,走代理清理缓存
FriendServiceImpl proxy = (FriendServiceImpl)AopContext.currentProxy(); FriendServiceImpl proxy = (FriendServiceImpl) AopContext.currentProxy();
proxy.unbindFriend(userId,friendId); proxy.unbindFriend(userId, friendId);
proxy.unbindFriend(friendId,userId); proxy.unbindFriend(friendId, userId);
log.info("删除好友,用户id:{},好友id:{}",userId,friendId); log.info("删除好友,用户id:{},好友id:{}", userId, friendId);
} }
@Cacheable(key = "#userId1+':'+#userId2")
@Cacheable(key="#userId1+':'+#userId2")
@Override @Override
public Boolean isFriend(Long userId1, Long userId2) { public Boolean isFriend(Long userId1, Long userId2) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId1) .eq(Friend::getUserId, userId1)
.eq(Friend::getFriendId,userId2); .eq(Friend::getFriendId, userId2);
return this.count(queryWrapper) > 0; return this.count(queryWrapper) > 0;
} }
@Override @Override
public void update(FriendVO vo) { public void update(FriendVO vo) {
long userId = SessionContext.getSession().getUserId(); long userId = SessionContext.getSession().getUserId();
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId) .eq(Friend::getUserId, userId)
.eq(Friend::getFriendId,vo.getId()); .eq(Friend::getFriendId, vo.getId());
Friend f = this.getOne(queryWrapper); Friend f = this.getOne(queryWrapper);
if(f == null){ if (f == null) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"对方不是您的好友"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "对方不是您的好友");
} }
f.setFriendHeadImage(vo.getHeadImage()); f.setFriendHeadImage(vo.getHeadImage());
@ -107,16 +102,16 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
/** /**
* 单向绑定好友关系 * 单向绑定好友关系
* *
* @param userId 用户id * @param userId 用户id
* @param friendId 好友的用户id * @param friendId 好友的用户id
*/ */
@CacheEvict(key="#userId+':'+#friendId") @CacheEvict(key = "#userId+':'+#friendId")
public void bindFriend(Long userId, Long friendId) { public void bindFriend(Long userId, Long friendId) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId) .eq(Friend::getUserId, userId)
.eq(Friend::getFriendId,friendId); .eq(Friend::getFriendId, friendId);
if(this.count(queryWrapper)==0){ if (this.count(queryWrapper) == 0) {
Friend friend = new Friend(); Friend friend = new Friend();
friend.setUserId(userId); friend.setUserId(userId);
friend.setFriendId(friendId); friend.setFriendId(friendId);
@ -131,36 +126,35 @@ public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> impleme
/** /**
* 单向解除好友关系 * 单向解除好友关系
* *
* @param userId 用户id * @param userId 用户id
* @param friendId 好友的用户id * @param friendId 好友的用户id
*/ */
@CacheEvict(key="#userId+':'+#friendId") @CacheEvict(key = "#userId+':'+#friendId")
public void unbindFriend(Long userId, Long friendId) { public void unbindFriend(Long userId, Long friendId) {
QueryWrapper<Friend> queryWrapper = new QueryWrapper<>(); QueryWrapper<Friend> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda() queryWrapper.lambda()
.eq(Friend::getUserId,userId) .eq(Friend::getUserId, userId)
.eq(Friend::getFriendId,friendId); .eq(Friend::getFriendId, friendId);
List<Friend> friends = this.list(queryWrapper); List<Friend> friends = this.list(queryWrapper);
friends.forEach(friend -> this.removeById(friend.getId())); friends.forEach(friend -> this.removeById(friend.getId()));
} }
@Override @Override
public FriendVO findFriend(Long friendId) { public FriendVO findFriend(Long friendId) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
QueryWrapper<Friend> wrapper = new QueryWrapper<>(); QueryWrapper<Friend> wrapper = new QueryWrapper<>();
wrapper.lambda() wrapper.lambda()
.eq(Friend::getUserId,session.getUserId()) .eq(Friend::getUserId, session.getUserId())
.eq(Friend::getFriendId,friendId); .eq(Friend::getFriendId, friendId);
Friend friend = this.getOne(wrapper); Friend friend = this.getOne(wrapper);
if(friend == null){ if (friend == null) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"对方不是您的好友"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "对方不是您的好友");
} }
FriendVO vo = new FriendVO(); FriendVO vo = new FriendVO();
vo.setId(friend.getFriendId()); vo.setId(friend.getFriendId());
vo.setHeadImage(friend.getFriendHeadImage()); vo.setHeadImage(friend.getFriendHeadImage());
vo.setNickName(friend.getFriendNickName()); vo.setNickName(friend.getFriendNickName());
return vo; return vo;
} }
} }

27
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMemberServiceImpl.java

@ -17,19 +17,18 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER_ID) @CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP_MEMBER_ID)
public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, GroupMember> implements IGroupMemberService { public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, GroupMember> implements IGroupMemberService {
@CacheEvict(key="#member.getGroupId()") @CacheEvict(key = "#member.getGroupId()")
@Override @Override
public boolean save(GroupMember member) { public boolean save(GroupMember member) {
return super.save(member); return super.save(member);
} }
@CacheEvict(key="#groupId") @CacheEvict(key = "#groupId")
@Override @Override
public boolean saveOrUpdateBatch(Long groupId,List<GroupMember> members) { public boolean saveOrUpdateBatch(Long groupId, List<GroupMember> members) {
return super.saveOrUpdateBatch(members); return super.saveOrUpdateBatch(members);
} }
@ -37,8 +36,8 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
@Override @Override
public GroupMember findByGroupAndUserId(Long groupId, Long userId) { public GroupMember findByGroupAndUserId(Long groupId, Long userId) {
QueryWrapper<GroupMember> wrapper = new QueryWrapper<>(); QueryWrapper<GroupMember> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(GroupMember::getGroupId,groupId) wrapper.lambda().eq(GroupMember::getGroupId, groupId)
.eq(GroupMember::getUserId,userId); .eq(GroupMember::getUserId, userId);
return this.getOne(wrapper); return this.getOne(wrapper);
} }
@ -46,7 +45,7 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
public List<GroupMember> findByUserId(Long userId) { public List<GroupMember> findByUserId(Long userId) {
LambdaQueryWrapper<GroupMember> memberWrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMember> memberWrapper = Wrappers.lambdaQuery();
memberWrapper.eq(GroupMember::getUserId, userId) memberWrapper.eq(GroupMember::getUserId, userId)
.eq(GroupMember::getQuit,false); .eq(GroupMember::getQuit, false);
return this.list(memberWrapper); return this.list(memberWrapper);
} }
@ -57,12 +56,12 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
return this.list(memberWrapper); return this.list(memberWrapper);
} }
@Cacheable(key="#groupId") @Cacheable(key = "#groupId")
@Override @Override
public List<Long> findUserIdsByGroupId(Long groupId) { public List<Long> findUserIdsByGroupId(Long groupId) {
LambdaQueryWrapper<GroupMember> memberWrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMember> memberWrapper = Wrappers.lambdaQuery();
memberWrapper.eq(GroupMember::getGroupId, groupId) memberWrapper.eq(GroupMember::getGroupId, groupId)
.eq(GroupMember::getQuit,false); .eq(GroupMember::getQuit, false);
List<GroupMember> members = this.list(memberWrapper); List<GroupMember> members = this.list(memberWrapper);
return members.stream().map(GroupMember::getUserId).collect(Collectors.toList()); return members.stream().map(GroupMember::getUserId).collect(Collectors.toList());
} }
@ -71,8 +70,8 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
@Override @Override
public void removeByGroupId(Long groupId) { public void removeByGroupId(Long groupId) {
LambdaUpdateWrapper<GroupMember> wrapper = Wrappers.lambdaUpdate(); LambdaUpdateWrapper<GroupMember> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(GroupMember::getGroupId,groupId) wrapper.eq(GroupMember::getGroupId, groupId)
.set(GroupMember::getQuit,true); .set(GroupMember::getQuit, true);
this.update(wrapper); this.update(wrapper);
} }
@ -80,9 +79,9 @@ public class GroupMemberServiceImpl extends ServiceImpl<GroupMemberMapper, Group
@Override @Override
public void removeByGroupAndUserId(Long groupId, Long userId) { public void removeByGroupAndUserId(Long groupId, Long userId) {
LambdaUpdateWrapper<GroupMember> wrapper = Wrappers.lambdaUpdate(); LambdaUpdateWrapper<GroupMember> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(GroupMember::getGroupId,groupId) wrapper.eq(GroupMember::getGroupId, groupId)
.eq(GroupMember::getUserId,userId) .eq(GroupMember::getUserId, userId)
.set(GroupMember::getQuit,true); .set(GroupMember::getQuit, true);
this.update(wrapper); this.update(wrapper);
} }
} }

35
im-platform/src/main/java/com/bx/implatform/service/impl/GroupMessageServiceImpl.java

@ -1,7 +1,8 @@
package com.bx.implatform.service.impl; package com.bx.implatform.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -28,8 +29,10 @@ import com.bx.implatform.session.UserSession;
import com.bx.implatform.util.BeanUtils; import com.bx.implatform.util.BeanUtils;
import com.bx.implatform.util.DateTimeUtils; import com.bx.implatform.util.DateTimeUtils;
import com.bx.implatform.vo.GroupMessageVO; import com.bx.implatform.vo.GroupMessageVO;
import lombok.AllArgsConstructor; import com.google.common.base.Splitter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -38,7 +41,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, GroupMessage> implements IGroupMessageService { public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, GroupMessage> implements IGroupMessageService {
private final IGroupService groupService; private final IGroupService groupService;
private final IGroupMemberService groupMemberService; private final IGroupMemberService groupMemberService;
@ -69,8 +72,8 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
msg.setSendId(session.getUserId()); msg.setSendId(session.getUserId());
msg.setSendTime(new Date()); msg.setSendTime(new Date());
msg.setSendNickName(member.getAliasName()); msg.setSendNickName(member.getAliasName());
if (CollectionUtil.isNotEmpty(dto.getAtUserIds())) { if (CollUtil.isNotEmpty(dto.getAtUserIds())) {
msg.setAtUserIds(StrUtil.join(",", dto.getAtUserIds())); msg.setAtUserIds(CharSequenceUtil.join(",", dto.getAtUserIds()));
} }
this.save(msg); this.save(msg);
// 群发 // 群发
@ -140,10 +143,10 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
for (GroupMember member : members) { for (GroupMember member : members) {
// 获取群聊已读的最大消息id,只推送未读消息 // 获取群聊已读的最大消息id,只推送未读消息
String key = String.join(":", RedisKey.IM_GROUP_READED_POSITION, member.getGroupId().toString(), session.getUserId().toString()); String key = String.join(":", RedisKey.IM_GROUP_READED_POSITION, member.getGroupId().toString(), session.getUserId().toString());
Integer maxReadedId = (Integer)redisTemplate.opsForValue().get(key); Integer maxReadedId = (Integer) redisTemplate.opsForValue().get(key);
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
wrapper.eq(GroupMessage::getGroupId, member.getGroupId()).gt(GroupMessage::getSendTime, member.getCreatedTime()) wrapper.eq(GroupMessage::getGroupId, member.getGroupId()).gt(GroupMessage::getSendTime, member.getCreatedTime())
.ne(GroupMessage::getSendId, session.getUserId()).ne(GroupMessage::getStatus, MessageStatus.RECALL.code()); .ne(GroupMessage::getSendId, session.getUserId()).ne(GroupMessage::getStatus, MessageStatus.RECALL.code());
if (maxReadedId != null) { if (maxReadedId != null) {
wrapper.gt(GroupMessage::getId, maxReadedId); wrapper.gt(GroupMessage::getId, maxReadedId);
} }
@ -181,25 +184,27 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
Date minDate = DateTimeUtils.addMonths(new Date(), -1); Date minDate = DateTimeUtils.addMonths(new Date(), -1);
LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery(); LambdaQueryWrapper<GroupMessage> wrapper = Wrappers.lambdaQuery();
wrapper.gt(GroupMessage::getId, minId).gt(GroupMessage::getSendTime, minDate).in(GroupMessage::getGroupId, ids) wrapper.gt(GroupMessage::getId, minId).gt(GroupMessage::getSendTime, minDate).in(GroupMessage::getGroupId, ids)
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByAsc(GroupMessage::getId).last("limit 100"); .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByAsc(GroupMessage::getId).last("limit 100");
List<GroupMessage> messages = this.list(wrapper); List<GroupMessage> messages = this.list(wrapper);
// 转成vo // 转成vo
List<GroupMessageVO> vos = messages.stream().map(m -> { List<GroupMessageVO> vos = messages.stream().map(m -> {
GroupMessageVO vo = BeanUtils.copyProperties(m, GroupMessageVO.class); GroupMessageVO vo = BeanUtils.copyProperties(m, GroupMessageVO.class);
// 被@用户列表 // 被@用户列表
List<String> atIds = Arrays.asList(StrUtil.split(m.getAtUserIds(), ",")); if (StringUtils.isNotBlank(m.getAtUserIds())) {
vo.setAtUserIds(atIds.stream().map(Long::parseLong).collect(Collectors.toList())); List<String> atIds = Splitter.on(",").trimResults().splitToList(m.getAtUserIds());
vo.setAtUserIds(atIds.stream().map(Long::parseLong).collect(Collectors.toList()));
}
return vo; return vo;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
// 消息状态,数据库没有存群聊的消息状态,需要从redis取 // 消息状态,数据库没有存群聊的消息状态,需要从redis取
List<String> keys = ids.stream().map(id -> String.join(":", RedisKey.IM_GROUP_READED_POSITION, id.toString(), session.getUserId().toString())) List<String> keys = ids.stream().map(id -> String.join(":", RedisKey.IM_GROUP_READED_POSITION, id.toString(), session.getUserId().toString()))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<Object> sendPos = redisTemplate.opsForValue().multiGet(keys); List<Object> sendPos = redisTemplate.opsForValue().multiGet(keys);
int idx = 0; int idx = 0;
for (Long id : ids) { for (Long id : ids) {
Object o = sendPos.get(idx); Object o = sendPos.get(idx);
Integer sendMaxId = Objects.isNull(o) ? -1 : (Integer)o; Integer sendMaxId = Objects.isNull(o) ? -1 : (Integer) o;
vos.stream().filter(vo -> vo.getGroupId().equals(id)).forEach(vo -> { vos.stream().filter(vo -> vo.getGroupId().equals(id)).forEach(vo -> {
if (vo.getId() <= sendMaxId) { if (vo.getId() <= sendMaxId) {
// 已读 // 已读
@ -237,7 +242,7 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
imClient.sendGroupMessage(sendMessage); imClient.sendGroupMessage(sendMessage);
// 记录已读消息位置 // 记录已读消息位置
String key = StrUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId, session.getUserId()); String key = CharSequenceUtil.join(":", RedisKey.IM_GROUP_READED_POSITION, groupId, session.getUserId());
redisTemplate.opsForValue().set(key, message.getId()); redisTemplate.opsForValue().set(key, message.getId());
} }
@ -256,11 +261,11 @@ public class GroupMessageServiceImpl extends ServiceImpl<GroupMessageMapper, Gro
// 查询聊天记录,只查询加入群聊时间之后的消息 // 查询聊天记录,只查询加入群聊时间之后的消息
QueryWrapper<GroupMessage> wrapper = new QueryWrapper<>(); QueryWrapper<GroupMessage> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(GroupMessage::getGroupId, groupId).gt(GroupMessage::getSendTime, member.getCreatedTime()) wrapper.lambda().eq(GroupMessage::getGroupId, groupId).gt(GroupMessage::getSendTime, member.getCreatedTime())
.ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(GroupMessage::getId).last("limit " + stIdx + "," + size); .ne(GroupMessage::getStatus, MessageStatus.RECALL.code()).orderByDesc(GroupMessage::getId).last("limit " + stIdx + "," + size);
List<GroupMessage> messages = this.list(wrapper); List<GroupMessage> messages = this.list(wrapper);
List<GroupMessageVO> messageInfos = List<GroupMessageVO> messageInfos =
messages.stream().map(m -> BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList()); messages.stream().map(m -> BeanUtils.copyProperties(m, GroupMessageVO.class)).collect(Collectors.toList());
log.info("拉取群聊记录,用户id:{},群聊id:{},数量:{}", userId, groupId, messageInfos.size()); log.info("拉取群聊记录,用户id:{},群聊id:{},数量:{}", userId, groupId, messageInfos.size());
return messageInfos; return messageInfos;
} }

13
im-platform/src/main/java/com/bx/implatform/service/impl/GroupServiceImpl.java

@ -23,7 +23,7 @@ import com.bx.implatform.util.BeanUtils;
import com.bx.implatform.vo.GroupInviteVO; import com.bx.implatform.vo.GroupInviteVO;
import com.bx.implatform.vo.GroupMemberVO; import com.bx.implatform.vo.GroupMemberVO;
import com.bx.implatform.vo.GroupVO; import com.bx.implatform.vo.GroupVO;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheConfig;
@ -32,16 +32,13 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date; import java.util.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP) @CacheConfig(cacheNames = RedisKey.IM_CACHE_GROUP)
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService { public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService {
private final IUserService userService; private final IUserService userService;
private final IGroupMemberService groupMemberService; private final IGroupMemberService groupMemberService;
@ -90,7 +87,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
throw new GlobalException(ResultCode.PROGRAM_ERROR, "您不是群聊的成员"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "您不是群聊的成员");
} }
member.setAliasName(StringUtils.isEmpty(vo.getAliasName()) ? session.getNickName() : vo.getAliasName()); member.setAliasName(StringUtils.isEmpty(vo.getAliasName()) ? session.getNickName() : vo.getAliasName());
member.setRemark(StringUtils.isEmpty(vo.getRemark()) ? group.getName() : vo.getRemark()); member.setRemark(StringUtils.isEmpty(vo.getRemark()) ? Objects.requireNonNull(group).getName() : vo.getRemark());
groupMemberService.updateById(member); groupMemberService.updateById(member);
log.info("修改群聊,群聊id:{},群聊名称:{}", group.getId(), group.getName()); log.info("修改群聊,群聊id:{},群聊名称:{}", group.getId(), group.getName());
return vo; return vo;
@ -206,7 +203,7 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements
// 找出好友信息 // 找出好友信息
List<Friend> friends = friendsService.findFriendByUserId(session.getUserId()); List<Friend> friends = friendsService.findFriendByUserId(session.getUserId());
List<Friend> friendsList = vo.getFriendIds().stream().map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get()) List<Friend> friendsList = vo.getFriendIds().stream().map(id -> friends.stream().filter(f -> f.getFriendId().equals(id)).findFirst().get())
.collect(Collectors.toList()); .collect(Collectors.toList());
if (friendsList.size() != vo.getFriendIds().size()) { if (friendsList.size() != vo.getFriendIds().size()) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "部分用户不是您的好友,邀请失败"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "部分用户不是您的好友,邀请失败");
} }

8
im-platform/src/main/java/com/bx/implatform/service/impl/PrivateMessageServiceImpl.java

@ -25,6 +25,7 @@ import com.bx.implatform.util.BeanUtils;
import com.bx.implatform.util.DateTimeUtils; import com.bx.implatform.util.DateTimeUtils;
import com.bx.implatform.vo.PrivateMessageVO; import com.bx.implatform.vo.PrivateMessageVO;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -37,7 +38,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper, PrivateMessage> implements IPrivateMessageService { public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper, PrivateMessage> implements IPrivateMessageService {
private final IFriendService friendService; private final IFriendService friendService;
@ -47,7 +48,7 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
public Long sendMessage(PrivateMessageDTO dto) { public Long sendMessage(PrivateMessageDTO dto) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
Boolean isFriends = friendService.isFriend(session.getUserId(), dto.getRecvId()); Boolean isFriends = friendService.isFriend(session.getUserId(), dto.getRecvId());
if (!isFriends) { if (Boolean.FALSE.equals(isFriends)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不是对方好友,无法发送消息"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "您已不是对方好友,无法发送消息");
} }
// 保存消息 // 保存消息
@ -107,7 +108,6 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
} }
@Override @Override
public List<PrivateMessageVO> findHistoryMessage(Long friendId, Long page, Long size) { public List<PrivateMessageVO> findHistoryMessage(Long friendId, Long page, Long size) {
page = page > 0 ? page : 1; page = page > 0 ? page : 1;
@ -167,7 +167,6 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
} }
@Override @Override
public List<PrivateMessageVO> loadMessage(Long minId) { public List<PrivateMessageVO> loadMessage(Long minId) {
UserSession session = SessionContext.getSession(); UserSession session = SessionContext.getSession();
@ -208,7 +207,6 @@ public class PrivateMessageServiceImpl extends ServiceImpl<PrivateMessageMapper,
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public void readedMessage(Long friendId) { public void readedMessage(Long friendId) {

6
im-platform/src/main/java/com/bx/implatform/service/impl/UserServiceImpl.java

@ -27,9 +27,8 @@ import com.bx.implatform.util.BeanUtils;
import com.bx.implatform.vo.LoginVO; import com.bx.implatform.vo.LoginVO;
import com.bx.implatform.vo.OnlineTerminalVO; import com.bx.implatform.vo.OnlineTerminalVO;
import com.bx.implatform.vo.UserVO; import com.bx.implatform.vo.UserVO;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -39,10 +38,9 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
private final RedisTemplate<String, Object> redisTemplate;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final IGroupMemberService groupMemberService; private final IGroupMemberService groupMemberService;
private final IFriendService friendService; private final IFriendService friendService;

20
im-platform/src/main/java/com/bx/implatform/service/impl/WebrtcServiceImpl.java

@ -13,7 +13,7 @@ import com.bx.implatform.session.SessionContext;
import com.bx.implatform.session.UserSession; import com.bx.implatform.session.UserSession;
import com.bx.implatform.session.WebrtcSession; import com.bx.implatform.session.WebrtcSession;
import com.bx.implatform.vo.PrivateMessageVO; import com.bx.implatform.vo.PrivateMessageVO;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Service @Service
@AllArgsConstructor @RequiredArgsConstructor
public class WebrtcServiceImpl implements IWebrtcService { public class WebrtcServiceImpl implements IWebrtcService {
private final IMClient imClient; private final IMClient imClient;
@ -52,7 +52,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setContent(offer); messageInfo.setContent(offer);
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
sendMessage.setSendToSelf(false); sendMessage.setSendToSelf(false);
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
@ -79,7 +79,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setContent(answer); messageInfo.setContent(answer);
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
// 告知其他终端已经接受会话,中止呼叫 // 告知其他终端已经接受会话,中止呼叫
sendMessage.setSendToSelf(true); sendMessage.setSendToSelf(true);
@ -103,7 +103,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setSendId(session.getUserId()); messageInfo.setSendId(session.getUserId());
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
// 告知其他终端已经拒绝会话,中止呼叫 // 告知其他终端已经拒绝会话,中止呼叫
sendMessage.setSendToSelf(true); sendMessage.setSendToSelf(true);
@ -125,7 +125,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setSendId(session.getUserId()); messageInfo.setSendId(session.getUserId());
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
sendMessage.setSendToSelf(false); sendMessage.setSendToSelf(false);
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
@ -148,7 +148,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setSendId(session.getUserId()); messageInfo.setSendId(session.getUserId());
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
// 告知其他终端已经会话失败,中止呼叫 // 告知其他终端已经会话失败,中止呼叫
sendMessage.setSendToSelf(true); sendMessage.setSendToSelf(true);
@ -174,7 +174,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setSendId(session.getUserId()); messageInfo.setSendId(session.getUserId());
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
sendMessage.setSendToSelf(false); sendMessage.setSendToSelf(false);
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
@ -198,7 +198,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
messageInfo.setContent(candidate); messageInfo.setContent(candidate);
IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>(); IMPrivateMessage<PrivateMessageVO> sendMessage = new IMPrivateMessage<>();
sendMessage.setSender(new IMUserInfo(session.getUserId(),session.getTerminal())); sendMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
sendMessage.setRecvId(uid); sendMessage.setRecvId(uid);
sendMessage.setSendToSelf(false); sendMessage.setSendToSelf(false);
sendMessage.setSendResult(false); sendMessage.setSendResult(false);
@ -215,7 +215,7 @@ public class WebrtcServiceImpl implements IWebrtcService {
private WebrtcSession getWebrtcSession(Long userId, Long uid) { private WebrtcSession getWebrtcSession(Long userId, Long uid) {
String key = getSessionKey(userId, uid); String key = getSessionKey(userId, uid);
WebrtcSession webrtcSession = (WebrtcSession)redisTemplate.opsForValue().get(key); WebrtcSession webrtcSession = (WebrtcSession) redisTemplate.opsForValue().get(key);
if (webrtcSession == null) { if (webrtcSession == null) {
throw new GlobalException("视频通话已结束"); throw new GlobalException("视频通话已结束");
} }

69
im-platform/src/main/java/com/bx/implatform/service/thirdparty/FileService.java

@ -18,19 +18,20 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.io.IOException; import java.io.IOException;
import java.util.Objects;
/** /**
* todo 通过校验文件MD5实现重复文件秒传 * 通过校验文件MD5实现重复文件秒传
* 文件上传服务 * 文件上传服务
*
* @author Blue * @author Blue
* @date 2022/10/28 * @date 2022/10/28
*
*/ */
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class FileService { public class FileService {
private final MinioUtil minioUtil; private final MinioUtil minioUtil;
@Value("${minio.public}") @Value("${minio.public}")
private String minIoServer; private String minIoServer;
@Value("${minio.bucketName}") @Value("${minio.bucketName}")
@ -42,8 +43,8 @@ public class FileService {
@PostConstruct @PostConstruct
public void init(){ public void init() {
if(!minioUtil.bucketExists(bucketName)){ if (!minioUtil.bucketExists(bucketName)) {
// 创建bucket // 创建bucket
minioUtil.makeBucket(bucketName); minioUtil.makeBucket(bucketName);
// 公开bucket // 公开bucket
@ -52,61 +53,61 @@ public class FileService {
} }
public String uploadFile(MultipartFile file){ public String uploadFile(MultipartFile file) {
Long userId = SessionContext.getSession().getUserId(); Long userId = SessionContext.getSession().getUserId();
// 大小校验 // 大小校验
if(file.getSize() > Constant.MAX_FILE_SIZE){ if (file.getSize() > Constant.MAX_FILE_SIZE) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"文件大小不能超过10M"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "文件大小不能超过10M");
} }
// 上传 // 上传
String fileName = minioUtil.upload(bucketName,filePath,file); String fileName = minioUtil.upload(bucketName, filePath, file);
if(StringUtils.isEmpty(fileName)){ if (StringUtils.isEmpty(fileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"文件上传失败"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "文件上传失败");
} }
String url = generUrl(FileType.FILE,fileName); String url = generUrl(FileType.FILE, fileName);
log.info("文件文件成功,用户id:{},url:{}",userId,url); log.info("文件文件成功,用户id:{},url:{}", userId, url);
return url; return url;
} }
public UploadImageVO uploadImage(MultipartFile file){ public UploadImageVO uploadImage(MultipartFile file) {
try { try {
Long userId = SessionContext.getSession().getUserId(); Long userId = SessionContext.getSession().getUserId();
// 大小校验 // 大小校验
if(file.getSize() > Constant.MAX_IMAGE_SIZE){ if (file.getSize() > Constant.MAX_IMAGE_SIZE) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片大小不能超过5M"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片大小不能超过5M");
} }
// 图片格式校验 // 图片格式校验
if(!FileUtil.isImage(file.getOriginalFilename())){ if (!FileUtil.isImage(file.getOriginalFilename())) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片格式不合法"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片格式不合法");
} }
// 上传原图 // 上传原图
UploadImageVO vo = new UploadImageVO(); UploadImageVO vo = new UploadImageVO();
String fileName = minioUtil.upload(bucketName,imagePath,file); String fileName = minioUtil.upload(bucketName, imagePath, file);
if(StringUtils.isEmpty(fileName)){ if (StringUtils.isEmpty(fileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片上传失败"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片上传失败");
} }
vo.setOriginUrl(generUrl(FileType.IMAGE,fileName)); vo.setOriginUrl(generUrl(FileType.IMAGE, fileName));
// 大于30K的文件需上传缩略图 // 大于30K的文件需上传缩略图
if(file.getSize() > 30 * 1024){ if (file.getSize() > 30 * 1024) {
byte[] imageByte = ImageUtil.compressForScale(file.getBytes(),30); byte[] imageByte = ImageUtil.compressForScale(file.getBytes(), 30);
fileName = minioUtil.upload(bucketName,imagePath,file.getOriginalFilename(),imageByte,file.getContentType()); fileName = minioUtil.upload(bucketName, imagePath, Objects.requireNonNull(file.getOriginalFilename()), imageByte, file.getContentType());
if(StringUtils.isEmpty(fileName)){ if (StringUtils.isEmpty(fileName)) {
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片上传失败"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片上传失败");
} }
} }
vo.setThumbUrl(generUrl(FileType.IMAGE,fileName)); vo.setThumbUrl(generUrl(FileType.IMAGE, fileName));
log.info("文件图片成功,用户id:{},url:{}",userId,vo.getOriginUrl()); log.info("文件图片成功,用户id:{},url:{}", userId, vo.getOriginUrl());
return vo; return vo;
} catch (IOException e) { } catch (IOException e) {
log.error("上传图片失败,{}",e.getMessage(),e); log.error("上传图片失败,{}", e.getMessage(), e);
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片上传失败"); throw new GlobalException(ResultCode.PROGRAM_ERROR, "图片上传失败");
} }
} }
public String generUrl(FileType fileTypeEnum, String fileName){ public String generUrl(FileType fileTypeEnum, String fileName) {
String url = minIoServer +"/"+bucketName; String url = minIoServer + "/" + bucketName;
switch (fileTypeEnum){ switch (fileTypeEnum) {
case FILE: case FILE:
url += "/file/"; url += "/file/";
break; break;

9
im-platform/src/main/java/com/bx/implatform/session/SessionContext.java

@ -12,14 +12,11 @@ import javax.servlet.http.HttpServletRequest;
*/ */
public class SessionContext { public class SessionContext {
public static UserSession getSession() {
public static UserSession getSession(){
// 从请求上下文里获取Request对象 // 从请求上下文里获取Request对象
ServletRequestAttributes requestAttributes = ServletRequestAttributes.class. ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
cast(RequestContextHolder.getRequestAttributes());
HttpServletRequest request = requestAttributes.getRequest(); HttpServletRequest request = requestAttributes.getRequest();
UserSession userSession = (UserSession) request.getAttribute("session"); return (UserSession) request.getAttribute("session");
return userSession;
} }
} }

8
im-platform/src/main/java/com/bx/implatform/session/UserSession.java

@ -2,18 +2,18 @@ package com.bx.implatform.session;
import com.bx.imcommon.model.IMSessionInfo; import com.bx.imcommon.model.IMSessionInfo;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data @Data
public class UserSession extends IMSessionInfo { public class UserSession extends IMSessionInfo {
/* /**
* 用户名称 * 用户名称
*/ */
private String userName; private String userName;
/* /**
* 用户昵称 * 用户昵称
*/ */
private String nickName; private String nickName;

77
im-platform/src/main/java/com/bx/implatform/util/BeanUtils.java

@ -1,42 +1,45 @@
package com.bx.implatform.util; package com.bx.implatform.util;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils;
public class BeanUtils { public final class BeanUtils {
private BeanUtils() {
private static void handleReflectionException(Exception e) { }
ReflectionUtils.handleReflectionException(e);
} private static void handleReflectionException(Exception e) {
ReflectionUtils.handleReflectionException(e);
}
/**
* 属性拷贝
* @param orig 源对象 /**
* @param destClass 目标 * 属性拷贝
* @return T *
*/ * @param orig 源对象
public static <T> T copyProperties(Object orig, Class<T> destClass) { * @param destClass 目标
try { * @return T
Object target = destClass.newInstance(); */
if(orig == null) { public static <T> T copyProperties(Object orig, Class<T> destClass) {
return null; try {
} T target = destClass.newInstance();
copyProperties(orig, target); if (orig == null) {
return (T) target; return null;
}catch(Exception e) { }
handleReflectionException(e); copyProperties(orig, target);
return null; return target;
} } catch (Exception e) {
} handleReflectionException(e);
return null;
}
public static void copyProperties(Object orig, Object dest) { }
try {
org.springframework.beans.BeanUtils.copyProperties(orig, dest);
} catch (Exception e) { public static void copyProperties(Object orig, Object dest) {
handleReflectionException(e); try {
} org.springframework.beans.BeanUtils.copyProperties(orig, dest);
} } catch (Exception e) {
handleReflectionException(e);
}
}
} }

5
im-platform/src/main/java/com/bx/implatform/util/DateTimeUtils.java

@ -11,7 +11,10 @@ import java.util.Date;
* *
* @version 1.0 * @version 1.0
*/ */
public class DateTimeUtils extends DateUtils { public final class DateTimeUtils extends DateUtils {
private DateTimeUtils() {
}
public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String FULL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String PARTDATEFORMAT = "yyyyMMdd"; public static final String PARTDATEFORMAT = "yyyyMMdd";

15
im-platform/src/main/java/com/bx/implatform/util/FileUtil.java

@ -1,11 +1,14 @@
package com.bx.implatform.util; package com.bx.implatform.util;
public class FileUtil { public final class FileUtil {
private FileUtil() {
}
/** /**
* 获取文件后缀 * 获取文件后缀
* *
* @param fileName 文件名 * @param fileName 文件名
* @return boolean * @return boolean
*/ */
public static String getFileExtension(String fileName) { public static String getFileExtension(String fileName) {
@ -15,13 +18,13 @@ public class FileUtil {
/** /**
* 判断文件是否图片类型 * 判断文件是否图片类型
* *
* @param fileName 文件名 * @param fileName 文件名
* @return boolean * @return boolean
*/ */
public static boolean isImage(String fileName) { public static boolean isImage(String fileName) {
String extension = getFileExtension(fileName); String extension = getFileExtension(fileName);
String[] imageExtension = new String[]{"jpeg", "jpg", "bmp", "png","webp","gif"}; String[] imageExtension = new String[]{"jpeg", "jpg", "bmp", "png", "webp", "gif"};
for (String e : imageExtension){ for (String e : imageExtension) {
if (extension.toLowerCase().equals(e)) { if (extension.toLowerCase().equals(e)) {
return true; return true;
} }

8
im-platform/src/main/java/com/bx/implatform/util/ImageUtil.java

@ -1,6 +1,5 @@
package com.bx.implatform.util; package com.bx.implatform.util;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails; import net.coobird.thumbnailator.Thumbnails;
@ -8,7 +7,10 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@Slf4j @Slf4j
public class ImageUtil { public final class ImageUtil {
private ImageUtil() {
}
//以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值 //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
private static final Integer ZERO = 0; private static final Integer ZERO = 0;
@ -53,8 +55,6 @@ public class ImageUtil {
} }
/** /**
* 自动调节精度(经验数值) * 自动调节精度(经验数值)
* *

71
im-platform/src/main/java/com/bx/implatform/util/MinioUtil.java

@ -1,8 +1,7 @@
package com.bx.implatform.util; package com.bx.implatform.util;
import io.minio.*; import io.minio.*;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -14,20 +13,21 @@ import java.util.Date;
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @RequiredArgsConstructor
public class MinioUtil { public class MinioUtil {
private final MinioClient minioClient; private final MinioClient minioClient;
/** /**
* 查看存储bucket是否存在 * 查看存储bucket是否存在
*
* @return boolean * @return boolean
*/ */
public Boolean bucketExists(String bucketName) { public Boolean bucketExists(String bucketName) {
try { try {
return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) { } catch (Exception e) {
log.error("查询bucket失败",e); log.error("查询bucket失败", e);
return false; return false;
} }
} }
@ -41,7 +41,7 @@ public class MinioUtil {
.bucket(bucketName) .bucket(bucketName)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
log.error("创建bucket失败,",e); log.error("创建bucket失败,", e);
} }
} }
@ -64,34 +64,35 @@ public class MinioUtil {
.config(sb) .config(sb)
.build()); .build());
} catch (Exception e) { } catch (Exception e) {
log.error("创建bucket失败,",e); log.error("创建bucket失败,", e);
} }
} }
/** /**
* 文件上传 * 文件上传
*
* @param bucketName bucket名称 * @param bucketName bucket名称
* @param path 路径 * @param path 路径
* @param file 文件 * @param file 文件
* @return Boolean * @return Boolean
*/ */
public String upload(String bucketName,String path,MultipartFile file) { public String upload(String bucketName, String path, MultipartFile file) {
String originalFilename = file.getOriginalFilename(); String originalFilename = file.getOriginalFilename();
if (StringUtils.isBlank(originalFilename)){ if (StringUtils.isBlank(originalFilename)) {
throw new RuntimeException(); throw new RuntimeException();
} }
String fileName = System.currentTimeMillis()+""; String fileName = System.currentTimeMillis() + "";
if(originalFilename.lastIndexOf(".") >= 0){ if (originalFilename.lastIndexOf(".") >= 0) {
fileName +=originalFilename.substring(originalFilename.lastIndexOf(".")); fileName += originalFilename.substring(originalFilename.lastIndexOf("."));
} }
String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName; String objectName = DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
try { try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName) PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path + "/" + objectName)
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build(); .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
//文件名称相同会覆盖 //文件名称相同会覆盖
minioClient.putObject(objectArgs); minioClient.putObject(objectArgs);
} catch (Exception e) { } catch (Exception e) {
log.error("上传图片失败,",e); log.error("上传图片失败,", e);
return null; return null;
} }
return objectName; return objectName;
@ -99,25 +100,26 @@ public class MinioUtil {
/** /**
* 文件上传 * 文件上传
* @param bucketName bucket名称 *
* @param path 路径 * @param bucketName bucket名称
* @param name 文件名 * @param path 路径
* @param fileByte 文件内容 * @param name 文件名
* @param contentType contentType * @param fileByte 文件内容
* @return objectName * @param contentType contentType
* @return objectName
*/ */
public String upload(String bucketName,String path,String name,byte[] fileByte,String contentType) { public String upload(String bucketName, String path, String name, byte[] fileByte, String contentType) {
String fileName = System.currentTimeMillis() + name.substring(name.lastIndexOf(".")); String fileName = System.currentTimeMillis() + name.substring(name.lastIndexOf("."));
String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName; String objectName = DateTimeUtils.getFormatDate(new Date(), DateTimeUtils.PARTDATEFORMAT) + "/" + fileName;
try { try {
InputStream stream = new ByteArrayInputStream(fileByte); InputStream stream = new ByteArrayInputStream(fileByte);
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName) PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path + "/" + objectName)
.stream(stream, fileByte.length, -1).contentType(contentType).build(); .stream(stream, fileByte.length, -1).contentType(contentType).build();
//文件名称相同会覆盖 //文件名称相同会覆盖
minioClient.putObject(objectArgs); minioClient.putObject(objectArgs);
} catch (Exception e) { } catch (Exception e) {
log.error("上传文件失败,",e); log.error("上传文件失败,", e);
return null; return null;
} }
return objectName; return objectName;
@ -126,16 +128,17 @@ public class MinioUtil {
/** /**
* 删除 * 删除
*
* @param bucketName bucket名称 * @param bucketName bucket名称
* @param path 路径 * @param path 路径
* @param fileName 文件名 * @param fileName 文件名
* @return true/false * @return true/false
*/ */
public boolean remove(String bucketName,String path,String fileName){ public boolean remove(String bucketName, String path, String fileName) {
try { try {
minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(path+fileName).build()); minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(path + fileName).build());
}catch (Exception e){ } catch (Exception e) {
log.error("删除文件失败,",e); log.error("删除文件失败,", e);
return false; return false;
} }
return true; return true;

7
im-platform/src/main/java/com/bx/implatform/util/XssUtil.java

@ -3,13 +3,16 @@ package com.bx.implatform.util;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class XssUtil { public final class XssUtil {
private XssUtil() {
}
private static final String XSS_PATTERN = "((?i)<script.*?>)|((?i)alert\\s*\\()|((?i)prompt\\s*\\()|((?i)document\\.cookie)|((?i)location\\.href)|((?i)window\\.location)|((?i)onerror\\s*\\()|((?i)eval\\s*\\()|((?i)window\\.open\\s*\\()|((?i)innerHTML)|((?i)onclick\\s*\\()|((?i)onmouseover\\s*\\()|((?i)onsubmit\\s*\\()|((?i)onload\\s*\\()|((?i)onfocus\\s*\\()|((?i)onblur\\s*\\()|((?i)onkeyup\\s*\\()|((?i)onkeydown\\s*\\()|((?i)onkeypress\\s*\\()|((?i)onmouseout\\s*\\()|((?i)src=)|((?i)href=)|((?i)style=)|((?i)background=)|((?i)expression\\s*\\()|((?i)XMLHttpRequest\\s*\\()|((?i)ActiveXObject\\s*\\()|((?i)iframe)|((?i)document\\.write\\s*\\()|((?i)document\\.writeln\\s*\\()|((?i)setTimeout\\s*\\()|((?i)setInterval\\s*\\()|((?i)onreadystatechange\\s*\\()|((?i)appendChild\\s*\\()|((?i)createTextNode\\s*\\()|((?i)createElement\\s*\\()|((?i)getElementsByTagName\\s*\\()|((?i)getElementsByClassName\\s*\\()|((?i)querySelector\\s*\\()|((?i)querySelectorAll\\s*\\()|((?i)document\\.location)|((?i)document\\.body\\.innerHTML)|((?i)document\\.forms)|((?i)document\\.images)|((?i)document\\.links)|((?i)document\\.URL)|((?i)document\\.domain)|((?i)document\\.referrer)|((?i)history\\.back\\s*\\()"; private static final String XSS_PATTERN = "((?i)<script.*?>)|((?i)alert\\s*\\()|((?i)prompt\\s*\\()|((?i)document\\.cookie)|((?i)location\\.href)|((?i)window\\.location)|((?i)onerror\\s*\\()|((?i)eval\\s*\\()|((?i)window\\.open\\s*\\()|((?i)innerHTML)|((?i)onclick\\s*\\()|((?i)onmouseover\\s*\\()|((?i)onsubmit\\s*\\()|((?i)onload\\s*\\()|((?i)onfocus\\s*\\()|((?i)onblur\\s*\\()|((?i)onkeyup\\s*\\()|((?i)onkeydown\\s*\\()|((?i)onkeypress\\s*\\()|((?i)onmouseout\\s*\\()|((?i)src=)|((?i)href=)|((?i)style=)|((?i)background=)|((?i)expression\\s*\\()|((?i)XMLHttpRequest\\s*\\()|((?i)ActiveXObject\\s*\\()|((?i)iframe)|((?i)document\\.write\\s*\\()|((?i)document\\.writeln\\s*\\()|((?i)setTimeout\\s*\\()|((?i)setInterval\\s*\\()|((?i)onreadystatechange\\s*\\()|((?i)appendChild\\s*\\()|((?i)createTextNode\\s*\\()|((?i)createElement\\s*\\()|((?i)getElementsByTagName\\s*\\()|((?i)getElementsByClassName\\s*\\()|((?i)querySelector\\s*\\()|((?i)querySelectorAll\\s*\\()|((?i)document\\.location)|((?i)document\\.body\\.innerHTML)|((?i)document\\.forms)|((?i)document\\.images)|((?i)document\\.links)|((?i)document\\.URL)|((?i)document\\.domain)|((?i)document\\.referrer)|((?i)history\\.back\\s*\\()";
private static final Pattern PATTERN = Pattern.compile(XSS_PATTERN); private static final Pattern PATTERN = Pattern.compile(XSS_PATTERN);
public static boolean checkXss(String inputString) { public static boolean checkXss(String inputString) {
if (inputString!=null) { if (inputString != null) {
Matcher matcher = PATTERN.matcher(inputString); Matcher matcher = PATTERN.matcher(inputString);
return matcher.find(); return matcher.find();
} }

1
im-platform/src/main/java/com/bx/implatform/vo/FriendVO.java

@ -1,6 +1,5 @@
package com.bx.implatform.vo; package com.bx.implatform.vo;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;

1
im-platform/src/main/java/com/bx/implatform/vo/GroupMemberVO.java

@ -1,6 +1,5 @@
package com.bx.implatform.vo; package com.bx.implatform.vo;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;

9
im-platform/src/main/java/com/bx/implatform/vo/GroupVO.java

@ -11,11 +11,10 @@ import javax.validation.constraints.NotEmpty;
@ApiModel("群信息VO") @ApiModel("群信息VO")
public class GroupVO { public class GroupVO {
@ApiModelProperty(value = "群id") @ApiModelProperty(value = "群id")
private Long id; private Long id;
@Length(max=20,message = "群名称长度不能大于20") @Length(max = 20, message = "群名称长度不能大于20")
@NotEmpty(message = "群名称不可为空") @NotEmpty(message = "群名称不可为空")
@ApiModelProperty(value = "群名称") @ApiModelProperty(value = "群名称")
private String name; private String name;
@ -29,15 +28,15 @@ public class GroupVO {
@ApiModelProperty(value = "头像缩略图") @ApiModelProperty(value = "头像缩略图")
private String headImageThumb; private String headImageThumb;
@Length(max=1024,message = "群聊显示长度不能大于1024") @Length(max = 1024, message = "群聊显示长度不能大于1024")
@ApiModelProperty(value = "群公告") @ApiModelProperty(value = "群公告")
private String notice; private String notice;
@Length(max=20,message = "群聊显示长度不能大于20") @Length(max = 20, message = "群聊显示长度不能大于20")
@ApiModelProperty(value = "用户在群显示昵称") @ApiModelProperty(value = "用户在群显示昵称")
private String aliasName; private String aliasName;
@Length(max=20,message = "群聊显示长度不能大于20") @Length(max = 20, message = "群聊显示长度不能大于20")
@ApiModelProperty(value = "群聊显示备注") @ApiModelProperty(value = "群聊显示备注")
private String remark; private String remark;

7
im-platform/src/main/java/com/bx/implatform/vo/UserVO.java

@ -1,6 +1,5 @@
package com.bx.implatform.vo; package com.bx.implatform.vo;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -18,12 +17,12 @@ public class UserVO {
private Long id; private Long id;
@NotEmpty(message = "用户名不能为空") @NotEmpty(message = "用户名不能为空")
@Length(max = 64,message = "用户名不能大于64字符") @Length(max = 64, message = "用户名不能大于64字符")
@ApiModelProperty(value = "用户名") @ApiModelProperty(value = "用户名")
private String userName; private String userName;
@NotEmpty(message = "用户昵称不能为空") @NotEmpty(message = "用户昵称不能为空")
@Length(max = 64,message = "昵称不能大于64字符") @Length(max = 64, message = "昵称不能大于64字符")
@ApiModelProperty(value = "用户昵称") @ApiModelProperty(value = "用户昵称")
private String nickName; private String nickName;
@ -33,7 +32,7 @@ public class UserVO {
@ApiModelProperty(value = "用户类型 1:普通用户 2:审核账户") @ApiModelProperty(value = "用户类型 1:普通用户 2:审核账户")
private Integer type; private Integer type;
@Length(max = 1024,message = "个性签名不能大于1024个字符") @Length(max = 1024, message = "个性签名不能大于1024个字符")
@ApiModelProperty(value = "个性签名") @ApiModelProperty(value = "个性签名")
private String signature; private String signature;

7
im-server/src/main/java/com/bx/imserver/IMServerApp.java

@ -1,22 +1,19 @@
package com.bx.imserver; package com.bx.imserver;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
@EnableAsync @EnableAsync
@EnableScheduling @EnableScheduling
@ComponentScan(basePackages={"com.bx"}) @ComponentScan(basePackages = {"com.bx"})
@SpringBootApplication @SpringBootApplication
public class IMServerApp { public class IMServerApp {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(IMServerApp.class,args); SpringApplication.run(IMServerApp.class, args);
} }
} }

2
im-server/src/main/java/com/bx/imserver/config/RedisConfig.java

@ -25,7 +25,7 @@ public class RedisConfig {
} }
public FastJsonRedisSerializer fastJsonRedisSerializer(){ public FastJsonRedisSerializer fastJsonRedisSerializer() {
return new FastJsonRedisSerializer<>(Object.class); return new FastJsonRedisSerializer<>(Object.class);
} }

17
im-server/src/main/java/com/bx/imserver/constant/ChannelAttrKey.java

@ -1,12 +1,21 @@
package com.bx.imserver.constant; package com.bx.imserver.constant;
public class ChannelAttrKey { public final class ChannelAttrKey {
// 用户ID private ChannelAttrKey() {
}
/**
* 用户ID
*/
public static final String USER_ID = "USER_ID"; public static final String USER_ID = "USER_ID";
// 终端类型 /**
* 终端类型
*/
public static final String TERMINAL_TYPE = "TERMINAL_TYPE"; public static final String TERMINAL_TYPE = "TERMINAL_TYPE";
// 心跳次数 /**
* 心跳次数
*/
public static final String HEARTBEAT_TIMES = "HEARTBEAt_TIMES"; public static final String HEARTBEAT_TIMES = "HEARTBEAt_TIMES";
} }

29
im-server/src/main/java/com/bx/imserver/netty/IMChannelHandler.java

@ -15,7 +15,6 @@ import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
/** /**
* WebSocket 长连接下 文本帧的处理器 * WebSocket 长连接下 文本帧的处理器
* 实现浏览器发送文本回写 * 实现浏览器发送文本回写
@ -27,24 +26,24 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
/** /**
* 读取到消息后进行处理 * 读取到消息后进行处理
* *
* @param ctx channel上下文 * @param ctx channel上下文
* @param sendInfo 发送消息 * @param sendInfo 发送消息
*/ */
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, IMSendInfo sendInfo) { protected void channelRead0(ChannelHandlerContext ctx, IMSendInfo sendInfo) {
// 创建处理器进行处理 // 创建处理器进行处理
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.fromCode(sendInfo.getCmd())); AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.fromCode(sendInfo.getCmd()));
processor.process(ctx,processor.transForm(sendInfo.getData())); processor.process(ctx, processor.transForm(sendInfo.getData()));
} }
/** /**
* 出现异常的处理 打印报错日志 * 出现异常的处理 打印报错日志
* *
* @param ctx channel上下文 * @param ctx channel上下文
* @param cause 异常信息 * @param cause 异常信息
*/ */
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error(cause.getMessage()); log.error(cause.getMessage());
//关闭上下文 //关闭上下文
//ctx.close(); //ctx.close();
@ -53,10 +52,10 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
/** /**
* 监控浏览器上线 * 监控浏览器上线
* *
* @param ctx channel上下文 * @param ctx channel上下文
*/ */
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) { public void handlerAdded(ChannelHandlerContext ctx) {
log.info(ctx.channel().id().asLongText() + "连接"); log.info(ctx.channel().id().asLongText() + "连接");
} }
@ -66,16 +65,16 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
Long userId = ctx.channel().attr(userIdAttr).get(); Long userId = ctx.channel().attr(userIdAttr).get();
AttributeKey<Integer> terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); AttributeKey<Integer> terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE);
Integer terminal = ctx.channel().attr(terminalAttr).get(); Integer terminal = ctx.channel().attr(terminalAttr).get();
ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId,terminal); ChannelHandlerContext context = UserChannelCtxMap.getChannelCtx(userId, terminal);
// 判断一下,避免异地登录导致的误删 // 判断一下,避免异地登录导致的误删
if(context != null && ctx.channel().id().equals(context.channel().id())){ if (context != null && ctx.channel().id().equals(context.channel().id())) {
// 移除channel // 移除channel
UserChannelCtxMap.removeChannelCtx(userId,terminal); UserChannelCtxMap.removeChannelCtx(userId, terminal);
// 用户下线 // 用户下线
RedisTemplate<String,Object> redisTemplate = SpringContextHolder.getBean("redisTemplate"); RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");
String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID,userId.toString(), terminal.toString()); String key = String.join(":", IMRedisKey.IM_USER_SERVER_ID, userId.toString(), terminal.toString());
redisTemplate.delete(key); redisTemplate.delete(key);
log.info("断开连接,userId:{},终端类型:{}",userId,terminal); log.info("断开连接,userId:{},终端类型:{}", userId, terminal);
} }
} }
@ -89,7 +88,7 @@ public class IMChannelHandler extends SimpleChannelInboundHandler<IMSendInfo> {
Long userId = ctx.channel().attr(attr).get(); Long userId = ctx.channel().attr(attr).get();
AttributeKey<Integer> terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE); AttributeKey<Integer> terminalAttr = AttributeKey.valueOf(ChannelAttrKey.TERMINAL_TYPE);
Integer terminal = ctx.channel().attr(terminalAttr).get(); Integer terminal = ctx.channel().attr(terminalAttr).get();
log.info("心跳超时,即将断开连接,用户id:{},终端类型:{} ",userId,terminal); log.info("心跳超时,即将断开连接,用户id:{},终端类型:{} ", userId, terminal);
ctx.channel().close(); ctx.channel().close();
} }
} else { } else {

22
im-server/src/main/java/com/bx/imserver/netty/IMServerGroup.java

@ -13,23 +13,23 @@ import java.util.List;
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @AllArgsConstructor
public class IMServerGroup implements CommandLineRunner { public class IMServerGroup implements CommandLineRunner {
public static volatile long serverId = 0; public static volatile long serverId = 0;
RedisTemplate<String,Object> redisTemplate; RedisTemplate<String, Object> redisTemplate;
private List<IMServer> imServers; private final List<IMServer> imServers;
/*** /***
* 判断服务器是否就绪 * 判断服务器是否就绪
* *
* @return * @return
**/ **/
public boolean isReady(){ public boolean isReady() {
for(IMServer imServer:imServers){ for (IMServer imServer : imServers) {
if(!imServer.isReady()){ if (!imServer.isReady()) {
return false; return false;
} }
} }
return true; return true;
@ -39,17 +39,17 @@ public class IMServerGroup implements CommandLineRunner {
public void run(String... args) throws Exception { public void run(String... args) throws Exception {
// 初始化SERVER_ID // 初始化SERVER_ID
String key = IMRedisKey.IM_MAX_SERVER_ID; String key = IMRedisKey.IM_MAX_SERVER_ID;
serverId = redisTemplate.opsForValue().increment(key,1); serverId = redisTemplate.opsForValue().increment(key, 1);
// 启动服务 // 启动服务
for(IMServer imServer:imServers){ for (IMServer imServer : imServers) {
imServer.start(); imServer.start();
} }
} }
@PreDestroy @PreDestroy
public void destroy(){ public void destroy() {
// 停止服务 // 停止服务
for(IMServer imServer:imServers){ for (IMServer imServer : imServers) {
imServer.stop(); imServer.stop();
} }
} }

33
im-server/src/main/java/com/bx/imserver/netty/UserChannelCtxMap.java

@ -5,40 +5,37 @@ import io.netty.channel.ChannelHandlerContext;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class UserChannelCtxMap { public class UserChannelCtxMap {
/* /**
* 维护userId和ctx的关联关系格式:Map<userId,map<terminalctx>> * 维护userId和ctx的关联关系格式:Map<userId,map<terminalctx>>
*/ */
private static Map<Long, Map<Integer,ChannelHandlerContext>> channelMap = new ConcurrentHashMap(); private static Map<Long, Map<Integer, ChannelHandlerContext>> channelMap = new ConcurrentHashMap();
public static void addChannelCtx(Long userId,Integer channel,ChannelHandlerContext ctx){ public static void addChannelCtx(Long userId, Integer channel, ChannelHandlerContext ctx) {
channelMap.computeIfAbsent(userId,key -> new ConcurrentHashMap()).put(channel,ctx); channelMap.computeIfAbsent(userId, key -> new ConcurrentHashMap()).put(channel, ctx);
} }
public static void removeChannelCtx(Long userId,Integer terminal){ public static void removeChannelCtx(Long userId, Integer terminal) {
if(userId != null && terminal != null && channelMap.containsKey(userId)){ if (userId != null && terminal != null && channelMap.containsKey(userId)) {
Map<Integer,ChannelHandlerContext> userChannelMap = channelMap.get(userId); Map<Integer, ChannelHandlerContext> userChannelMap = channelMap.get(userId);
if(userChannelMap.containsKey(terminal)){ userChannelMap.remove(terminal);
userChannelMap.remove(terminal);
}
} }
} }
public static ChannelHandlerContext getChannelCtx(Long userId,Integer terminal){ public static ChannelHandlerContext getChannelCtx(Long userId, Integer terminal) {
if(userId != null && terminal != null && channelMap.containsKey(userId)){ if (userId != null && terminal != null && channelMap.containsKey(userId)) {
Map<Integer,ChannelHandlerContext> userChannelMap = channelMap.get(userId); Map<Integer, ChannelHandlerContext> userChannelMap = channelMap.get(userId);
if(userChannelMap.containsKey(terminal)){ if (userChannelMap.containsKey(terminal)) {
return userChannelMap.get(terminal); return userChannelMap.get(terminal);
} }
} }
return null; return null;
} }
public static Map<Integer,ChannelHandlerContext> getChannelCtx(Long userId){ public static Map<Integer, ChannelHandlerContext> getChannelCtx(Long userId) {
if(userId == null){ if (userId == null) {
return null; return null;
} }
return channelMap.get(userId); return channelMap.get(userId);
} }

13
im-server/src/main/java/com/bx/imserver/netty/processor/AbstractMessageProcessor.java

@ -1,17 +1,18 @@
package com.bx.imserver.netty.processor; package com.bx.imserver.netty.processor;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
public abstract class AbstractMessageProcessor<T> { public abstract class AbstractMessageProcessor<T> {
public void process(ChannelHandlerContext ctx,T data){} public void process(ChannelHandlerContext ctx, T data) {
}
public void process(T data){} public void process(T data) {
}
public T transForm(Object o){ public T transForm(Object o) {
return (T)o; return (T) o;
} }
} }

32
im-server/src/main/java/com/bx/imserver/netty/processor/GroupMessageProcessor.java

@ -9,7 +9,7 @@ import com.bx.imcommon.model.IMSendResult;
import com.bx.imcommon.model.IMUserInfo; import com.bx.imcommon.model.IMUserInfo;
import com.bx.imserver.netty.UserChannelCtxMap; import com.bx.imserver.netty.UserChannelCtxMap;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
@ -19,45 +19,45 @@ import java.util.List;
@Slf4j @Slf4j
@Component @Component
@AllArgsConstructor @RequiredArgsConstructor
public class GroupMessageProcessor extends AbstractMessageProcessor<IMRecvInfo> { public class GroupMessageProcessor extends AbstractMessageProcessor<IMRecvInfo> {
private final RedisTemplate<String,Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
@Async @Async
@Override @Override
public void process(IMRecvInfo recvInfo) { public void process(IMRecvInfo recvInfo) {
IMUserInfo sender = recvInfo.getSender(); IMUserInfo sender = recvInfo.getSender();
List<IMUserInfo> receivers = recvInfo.getReceivers(); List<IMUserInfo> receivers = recvInfo.getReceivers();
log.info("接收到群消息,发送者:{},接收用户数量:{},内容:{}",sender.getId(),receivers.size(),recvInfo.getData()); log.info("接收到群消息,发送者:{},接收用户数量:{},内容:{}", sender.getId(), receivers.size(), recvInfo.getData());
for(IMUserInfo receiver:receivers){ for (IMUserInfo receiver : receivers) {
try { try {
ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(),receiver.getTerminal()); ChannelHandlerContext channelCtx = UserChannelCtxMap.getChannelCtx(receiver.getId(), receiver.getTerminal());
if(channelCtx != null){ if (channelCtx != null) {
// 推送消息到用户 // 推送消息到用户
IMSendInfo sendInfo = new IMSendInfo(); IMSendInfo sendInfo = new IMSendInfo();
sendInfo.setCmd(IMCmdType.GROUP_MESSAGE.code()); sendInfo.setCmd(IMCmdType.GROUP_MESSAGE.code());
sendInfo.setData(recvInfo.getData()); sendInfo.setData(recvInfo.getData());
channelCtx.channel().writeAndFlush(sendInfo); channelCtx.channel().writeAndFlush(sendInfo);
// 消息发送成功确认 // 消息发送成功确认
sendResult(recvInfo,receiver,IMSendCode.SUCCESS); sendResult(recvInfo, receiver, IMSendCode.SUCCESS);
}else { } else {
// 消息发送成功确认 // 消息发送成功确认
sendResult(recvInfo,receiver,IMSendCode.NOT_FIND_CHANNEL); sendResult(recvInfo, receiver, IMSendCode.NOT_FIND_CHANNEL);
log.error("未找到channel,发送者:{},接收id:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); log.error("未找到channel,发送者:{},接收id:{},内容:{}", sender.getId(), receiver.getId(), recvInfo.getData());
} }
}catch (Exception e){ } catch (Exception e) {
// 消息发送失败确认 // 消息发送失败确认
sendResult(recvInfo,receiver,IMSendCode.UNKONW_ERROR); sendResult(recvInfo, receiver, IMSendCode.UNKONW_ERROR);
log.error("发送消息异常,发送者:{},接收id:{},内容:{}",sender.getId(),receiver.getId(),recvInfo.getData()); log.error("发送消息异常,发送者:{},接收id:{},内容:{}", sender.getId(), receiver.getId(), recvInfo.getData());
} }
} }
} }
private void sendResult(IMRecvInfo recvInfo,IMUserInfo receiver,IMSendCode sendCode){ private void sendResult(IMRecvInfo recvInfo, IMUserInfo receiver, IMSendCode sendCode) {
if(recvInfo.getSendResult()) { if (recvInfo.getSendResult()) {
IMSendResult result = new IMSendResult(); IMSendResult result = new IMSendResult();
result.setSender(recvInfo.getSender()); result.setSender(recvInfo.getSender());
result.setReceiver(receiver); result.setReceiver(receiver);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save