Commit 77f3131ef3a174dc77e5e4c8fc6ad46364801c9c

Authored by 安浩浩
1 parent 2d052ea7

修改:私聊消息判断发送状态

yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.enums.message;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +@RequiredArgsConstructor
  10 +@Getter
  11 +public enum ImMessageStatusEnum implements IntArrayValuable {
  12 +
  13 + SENDING(1, "发送中"),
  14 + SUCCESS(2, "发送成功"),
  15 + FAILURE(3, "发送失败"),
  16 + DELETED(4, "已删除"),
  17 + RECALL(5, "已撤回");
  18 +
  19 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray();
  20 + private final Integer status;
  21 + private final String name;
  22 +
  23 + @Override
  24 + public int[] array() {
  25 + return ARRAYS;
  26 + }
  27 +
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java
1 package cn.iocoder.yudao.module.im.enums.message; 1 package cn.iocoder.yudao.module.im.enums.message;
2 2
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Getter; 5 import lombok.Getter;
5 6
  7 +import java.util.Arrays;
  8 +
6 /** 9 /**
7 * IM 消息的类型枚举 10 * IM 消息的类型枚举
8 - * 11 + * <p>
9 * 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">“消息类型”</a> 文档 12 * 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">“消息类型”</a> 文档
10 * 13 *
11 * @author 芋道源码 14 * @author 芋道源码
12 */ 15 */
13 @Getter 16 @Getter
14 @AllArgsConstructor 17 @AllArgsConstructor
15 -public enum ImMessageTypeEnum { 18 +public enum ImMessageTypeEnum implements IntArrayValuable {
16 19
17 TEXT(1, "文本"), // 消息内容为普通文本 20 TEXT(1, "文本"), // 消息内容为普通文本
18 IMAGE(2, "图片"), // 消息内容为图片 URL 地址、尺寸、图片大小等信息 21 IMAGE(2, "图片"), // 消息内容为图片 URL 地址、尺寸、图片大小等信息
@@ -25,6 +28,7 @@ public enum ImMessageTypeEnum { @@ -25,6 +28,7 @@ public enum ImMessageTypeEnum {
25 NOTIFICATION(8, "通知"), // 主要用于群组、聊天室和超大群的事件通知,由服务端下发,客户端无法发送事件通知消息。通知类消息有在线、离线、漫游机制;没有通知栏提醒 28 NOTIFICATION(8, "通知"), // 主要用于群组、聊天室和超大群的事件通知,由服务端下发,客户端无法发送事件通知消息。通知类消息有在线、离线、漫游机制;没有通知栏提醒
26 ; 29 ;
27 30
  31 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageTypeEnum::getType).toArray();
28 /** 32 /**
29 * 类型 33 * 类型
30 */ 34 */
@@ -34,4 +38,8 @@ public enum ImMessageTypeEnum { @@ -34,4 +38,8 @@ public enum ImMessageTypeEnum {
34 */ 38 */
35 private final String name; 39 private final String name;
36 40
  41 + @Override
  42 + public int[] array() {
  43 + return ARRAYS;
  44 + }
37 } 45 }
38 \ No newline at end of file 46 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java
1 package cn.iocoder.yudao.module.im.controller.admin.message.vo; 1 package cn.iocoder.yudao.module.im.controller.admin.message.vo;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
4 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
5 import lombok.Data; 6 import lombok.Data;
6 import lombok.EqualsAndHashCode; 7 import lombok.EqualsAndHashCode;
@@ -55,4 +56,7 @@ public class ImMessagePageReqVO extends PageParam { @@ -55,4 +56,7 @@ public class ImMessagePageReqVO extends PageParam {
55 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 56 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
56 private LocalDateTime[] createTime; 57 private LocalDateTime[] createTime;
57 58
  59 + @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
  60 + private Integer messageStatus;
  61 +
58 } 62 }
59 \ No newline at end of file 63 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageRespVO.java
1 package cn.iocoder.yudao.module.im.controller.admin.message.vo; 1 package cn.iocoder.yudao.module.im.controller.admin.message.vo;
2 2
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
  5 +import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum;
3 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; 6 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
4 import com.alibaba.excel.annotation.ExcelProperty; 7 import com.alibaba.excel.annotation.ExcelProperty;
5 import io.swagger.v3.oas.annotations.media.Schema; 8 import io.swagger.v3.oas.annotations.media.Schema;
  9 +import jakarta.validation.constraints.NotNull;
6 import lombok.Data; 10 import lombok.Data;
7 11
8 import java.time.LocalDateTime; 12 import java.time.LocalDateTime;
@@ -46,6 +50,7 @@ public class ImMessageRespVO { @@ -46,6 +50,7 @@ public class ImMessageRespVO {
46 50
47 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 51 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
48 @ExcelProperty("消息类型") 52 @ExcelProperty("消息类型")
  53 + @InEnum(ImMessageTypeEnum.class)
49 private Integer contentType; 54 private Integer contentType;
50 55
51 @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) 56 @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -64,4 +69,9 @@ public class ImMessageRespVO { @@ -64,4 +69,9 @@ public class ImMessageRespVO {
64 @ExcelProperty("创建时间") 69 @ExcelProperty("创建时间")
65 private LocalDateTime createTime; 70 private LocalDateTime createTime;
66 71
  72 + @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
  73 + @ExcelProperty("消息状态")
  74 + @InEnum(ImMessageStatusEnum.class)
  75 + private Integer messageStatus;
  76 +
67 } 77 }
68 \ No newline at end of file 78 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageSaveReqVO.java
@@ -38,7 +38,7 @@ public class ImMessageSaveReqVO { @@ -38,7 +38,7 @@ public class ImMessageSaveReqVO {
38 @NotNull(message = "会话类型不能为空") 38 @NotNull(message = "会话类型不能为空")
39 private Integer conversationType; 39 private Integer conversationType;
40 40
41 - @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED) 41 + @Schema(description = "会话标志 conversation_no = a_b", requiredMode = Schema.RequiredMode.REQUIRED)
42 @NotEmpty(message = "会话标志不能为空") 42 @NotEmpty(message = "会话标志不能为空")
43 private String conversationNo; 43 private String conversationNo;
44 44
@@ -57,4 +57,7 @@ public class ImMessageSaveReqVO { @@ -57,4 +57,7 @@ public class ImMessageSaveReqVO {
57 @NotNull(message = "消息来源 100-用户发送;200-系统发送(一般是通知);不能为空") 57 @NotNull(message = "消息来源 100-用户发送;200-系统发送(一般是通知);不能为空")
58 private Integer sendFrom; 58 private Integer sendFrom;
59 59
  60 + @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
  61 + @NotNull(message = "消息状态不能为空")
  62 + private Integer messageStatus;
60 } 63 }
61 \ No newline at end of file 64 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImMessageDO.java
@@ -73,4 +73,9 @@ public class ImMessageDO extends BaseDO { @@ -73,4 +73,9 @@ public class ImMessageDO extends BaseDO {
73 */ 73 */
74 private Integer sendFrom; 74 private Integer sendFrom;
75 75
  76 + /**
  77 + * 消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回
  78 + */
  79 + private Integer messageStatus;
  80 +
76 } 81 }
77 \ No newline at end of file 82 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java
@@ -61,4 +61,12 @@ public interface ImMessageService { @@ -61,4 +61,12 @@ public interface ImMessageService {
61 * @return id 61 * @return id
62 */ 62 */
63 Long savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId); 63 Long savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId);
  64 +
  65 + /**
  66 + * 更新消息状态
  67 + *
  68 + * @param messageId 消息id
  69 + * @param messageStatus 消息状态
  70 + */
  71 + void updateMessageStatus(Long messageId, Integer messageStatus);
64 } 72 }
65 \ No newline at end of file 73 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java
@@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO @@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO
6 import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO;
7 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; 7 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;
8 import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper; 8 import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper;
  9 +import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
9 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; 10 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
10 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 11 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
11 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 12 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
12 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
  14 +import org.dromara.hutool.core.date.TimeUtil;
13 import org.springframework.stereotype.Service; 15 import org.springframework.stereotype.Service;
14 import org.springframework.validation.annotation.Validated; 16 import org.springframework.validation.annotation.Validated;
15 17
@@ -74,22 +76,35 @@ public class ImMessageServiceImpl implements ImMessageService { @@ -74,22 +76,35 @@ public class ImMessageServiceImpl implements ImMessageService {
74 76
75 77
76 @Override 78 @Override
77 - public Long savePrivateMessage(ImSendMessage message, Long fromUserId) { 79 + public Long savePrivateMessage(ImSendMessage message, Long senderId) {
78 ImMessageSaveReqVO imMessageSaveReqVO = new ImMessageSaveReqVO(); 80 ImMessageSaveReqVO imMessageSaveReqVO = new ImMessageSaveReqVO();
79 imMessageSaveReqVO.setClientMessageId(message.getClientMessageId()); 81 imMessageSaveReqVO.setClientMessageId(message.getClientMessageId());
80 - imMessageSaveReqVO.setSenderId(fromUserId); 82 + imMessageSaveReqVO.setSenderId(senderId);
81 imMessageSaveReqVO.setReceiverId(message.getReceiverId()); 83 imMessageSaveReqVO.setReceiverId(message.getReceiverId());
82 //查询发送人昵称和发送人头像 84 //查询发送人昵称和发送人头像
83 - AdminUserRespDTO user = adminUserApi.getUser(fromUserId); 85 + AdminUserRespDTO user = adminUserApi.getUser(senderId);
84 imMessageSaveReqVO.setSenderNickname(user.getNickname()); 86 imMessageSaveReqVO.setSenderNickname(user.getNickname());
85 imMessageSaveReqVO.setSenderAvatar(user.getAvatar()); 87 imMessageSaveReqVO.setSenderAvatar(user.getAvatar());
86 imMessageSaveReqVO.setConversationType(message.getConversationType()); 88 imMessageSaveReqVO.setConversationType(message.getConversationType());
87 imMessageSaveReqVO.setContentType(message.getContentType()); 89 imMessageSaveReqVO.setContentType(message.getContentType());
88 - imMessageSaveReqVO.setConversationNo("1"); 90 + imMessageSaveReqVO.setConversationNo(senderId + "_" + message.getReceiverId());
89 imMessageSaveReqVO.setContent(message.getContent()); 91 imMessageSaveReqVO.setContent(message.getContent());
90 //消息来源 100-用户发送;200-系统发送(一般是通知);不能为空 92 //消息来源 100-用户发送;200-系统发送(一般是通知);不能为空
91 imMessageSaveReqVO.setSendFrom(100); 93 imMessageSaveReqVO.setSendFrom(100);
  94 + imMessageSaveReqVO.setSendTime(TimeUtil.now());
  95 + imMessageSaveReqVO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus());
92 return createMessage(imMessageSaveReqVO); 96 return createMessage(imMessageSaveReqVO);
93 } 97 }
94 98
  99 + @Override
  100 + public void updateMessageStatus(Long messageId, Integer messageStatus) {
  101 + //校验 id 是否存在
  102 + validateMessageExists(messageId);
  103 + //更新消息状态
  104 + ImMessageDO imMessageDO = new ImMessageDO();
  105 + imMessageDO.setId(messageId);
  106 + imMessageDO.setMessageStatus(messageStatus);
  107 + imMessageMapper.updateById(imMessageDO);
  108 + }
  109 +
95 } 110 }
96 \ No newline at end of file 111 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java
@@ -3,25 +3,31 @@ package cn.iocoder.yudao.module.im.websocket; @@ -3,25 +3,31 @@ package cn.iocoder.yudao.module.im.websocket;
3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; 4 import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
5 import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; 5 import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
  6 +import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
6 import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; 7 import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
7 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; 8 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;
8 import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao; 9 import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao;
9 import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; 10 import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum;
  11 +import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
10 import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; 12 import cn.iocoder.yudao.module.im.service.conversation.ImConversationService;
11 import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; 13 import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
12 import cn.iocoder.yudao.module.im.service.message.ImMessageService; 14 import cn.iocoder.yudao.module.im.service.message.ImMessageService;
13 import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage; 15 import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage;
14 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; 16 import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
15 import jakarta.annotation.Resource; 17 import jakarta.annotation.Resource;
  18 +import lombok.extern.slf4j.Slf4j;
16 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
17 import org.springframework.web.socket.WebSocketSession; 20 import org.springframework.web.socket.WebSocketSession;
18 21
  22 +import java.util.List;
  23 +
19 /** 24 /**
20 - * WebSocket 示例:单发消息 25 + * WebSocket im
21 * 26 *
22 * @author 芋道源码 27 * @author 芋道源码
23 */ 28 */
24 @Component 29 @Component
  30 +@Slf4j
25 public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> { 31 public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> {
26 32
27 @Resource 33 @Resource
@@ -34,6 +40,8 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe @@ -34,6 +40,8 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe
34 private ImInboxService imInboxService; 40 private ImInboxService imInboxService;
35 @Resource 41 @Resource
36 private SequenceGeneratorRedisDao sequenceGeneratorRedisDao; 42 private SequenceGeneratorRedisDao sequenceGeneratorRedisDao;
  43 + @Resource
  44 + private WebSocketSessionManager webSocketSessionManager;
37 45
38 @Override 46 @Override
39 public void onMessage(WebSocketSession session, ImSendMessage message) { 47 public void onMessage(WebSocketSession session, ImSendMessage message) {
@@ -48,6 +56,14 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe @@ -48,6 +56,14 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe
48 imInboxService.createInbox(new ImInboxSaveReqVO(fromUserId, messageId, sequenceGeneratorRedisDao.generateSequence(fromUserId))); 56 imInboxService.createInbox(new ImInboxSaveReqVO(fromUserId, messageId, sequenceGeneratorRedisDao.generateSequence(fromUserId)));
49 57
50 //3、推送消息 58 //3、推送消息
  59 + // 3.1判断是否在线
  60 + List<WebSocketSession> sessions = (List<WebSocketSession>) webSocketSessionManager.getSessionList(UserTypeEnum.ADMIN.getValue(), message.getReceiverId());
  61 + if (sessions.isEmpty()) {
  62 + //更新消息状态,为发送失败
  63 + imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.FAILURE.getStatus());
  64 + return;
  65 + }
  66 + //3.2发送
51 ImReceiveMessage toMessage = new ImReceiveMessage(); 67 ImReceiveMessage toMessage = new ImReceiveMessage();
52 toMessage.setFromId(fromUserId); 68 toMessage.setFromId(fromUserId);
53 toMessage.setConversationType(ImConversationTypeEnum.PRIVATE.getType()); 69 toMessage.setConversationType(ImConversationTypeEnum.PRIVATE.getType());
@@ -55,6 +71,9 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe @@ -55,6 +71,9 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener&lt;ImSe
55 toMessage.setContent(message.getContent()); 71 toMessage.setContent(message.getContent());
56 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), // 给指定用户 72 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), // 给指定用户
57 "im-message-receive", toMessage); 73 "im-message-receive", toMessage);
  74 + //4、更新消息状态,为发送成功
  75 + imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.SUCCESS.getStatus());
  76 +
58 } 77 }
59 } 78 }
60 79