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

This commit is contained in:
安浩浩 2024-03-13 23:57:34 +08:00
parent 2d052ea752
commit 77f3131ef3
9 changed files with 108 additions and 8 deletions

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.im.enums.message;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
@RequiredArgsConstructor
@Getter
public enum ImMessageStatusEnum implements IntArrayValuable {
SENDING(1, "发送中"),
SUCCESS(2, "发送成功"),
FAILURE(3, "发送失败"),
DELETED(4, "已删除"),
RECALL(5, "已撤回");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray();
private final Integer status;
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -1,18 +1,21 @@
package cn.iocoder.yudao.module.im.enums.message; package cn.iocoder.yudao.module.im.enums.message;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import java.util.Arrays;
/** /**
* IM 消息的类型枚举 * IM 消息的类型枚举
* * <p>
* 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">消息类型</a> 文档 * 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">消息类型</a> 文档
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum ImMessageTypeEnum { public enum ImMessageTypeEnum implements IntArrayValuable {
TEXT(1, "文本"), // 消息内容为普通文本 TEXT(1, "文本"), // 消息内容为普通文本
IMAGE(2, "图片"), // 消息内容为图片 URL 地址尺寸图片大小等信息 IMAGE(2, "图片"), // 消息内容为图片 URL 地址尺寸图片大小等信息
@ -25,6 +28,7 @@ public enum ImMessageTypeEnum {
NOTIFICATION(8, "通知"), // 主要用于群组聊天室和超大群的事件通知由服务端下发客户端无法发送事件通知消息通知类消息有在线离线漫游机制没有通知栏提醒 NOTIFICATION(8, "通知"), // 主要用于群组聊天室和超大群的事件通知由服务端下发客户端无法发送事件通知消息通知类消息有在线离线漫游机制没有通知栏提醒
; ;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageTypeEnum::getType).toArray();
/** /**
* 类型 * 类型
*/ */
@ -34,4 +38,8 @@ public enum ImMessageTypeEnum {
*/ */
private final String name; private final String name;
@Override
public int[] array() {
return ARRAYS;
}
} }

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.im.controller.admin.message.vo; package cn.iocoder.yudao.module.im.controller.admin.message.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -55,4 +56,7 @@ public class ImMessagePageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer messageStatus;
} }

View File

@ -1,8 +1,12 @@
package cn.iocoder.yudao.module.im.controller.admin.message.vo; package cn.iocoder.yudao.module.im.controller.admin.message.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -46,6 +50,7 @@ public class ImMessageRespVO {
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("消息类型") @ExcelProperty("消息类型")
@InEnum(ImMessageTypeEnum.class)
private Integer contentType; private Integer contentType;
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
@ -64,4 +69,9 @@ public class ImMessageRespVO {
@ExcelProperty("创建时间") @ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("消息状态")
@InEnum(ImMessageStatusEnum.class)
private Integer messageStatus;
} }

View File

@ -38,7 +38,7 @@ public class ImMessageSaveReqVO {
@NotNull(message = "会话类型不能为空") @NotNull(message = "会话类型不能为空")
private Integer conversationType; private Integer conversationType;
@Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "会话标志 conversation_no = a_b", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "会话标志不能为空") @NotEmpty(message = "会话标志不能为空")
private String conversationNo; private String conversationNo;
@ -57,4 +57,7 @@ public class ImMessageSaveReqVO {
@NotNull(message = "消息来源 100-用户发送200-系统发送(一般是通知);不能为空") @NotNull(message = "消息来源 100-用户发送200-系统发送(一般是通知);不能为空")
private Integer sendFrom; private Integer sendFrom;
@Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "消息状态不能为空")
private Integer messageStatus;
} }

View File

@ -73,4 +73,9 @@ public class ImMessageDO extends BaseDO {
*/ */
private Integer sendFrom; private Integer sendFrom;
/**
* 消息状态 1 发送中2 发送成功3 发送失败4 已删除5 已撤回
*/
private Integer messageStatus;
} }

View File

@ -61,4 +61,12 @@ public interface ImMessageService {
* @return id * @return id
*/ */
Long savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId); Long savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId);
/**
* 更新消息状态
*
* @param messageId 消息id
* @param messageStatus 消息状态
*/
void updateMessageStatus(Long messageId, Integer messageStatus);
} }

View File

@ -6,10 +6,12 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO
import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO; import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO;
import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;
import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper; import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper;
import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.dromara.hutool.core.date.TimeUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -74,22 +76,35 @@ public class ImMessageServiceImpl implements ImMessageService {
@Override @Override
public Long savePrivateMessage(ImSendMessage message, Long fromUserId) { public Long savePrivateMessage(ImSendMessage message, Long senderId) {
ImMessageSaveReqVO imMessageSaveReqVO = new ImMessageSaveReqVO(); ImMessageSaveReqVO imMessageSaveReqVO = new ImMessageSaveReqVO();
imMessageSaveReqVO.setClientMessageId(message.getClientMessageId()); imMessageSaveReqVO.setClientMessageId(message.getClientMessageId());
imMessageSaveReqVO.setSenderId(fromUserId); imMessageSaveReqVO.setSenderId(senderId);
imMessageSaveReqVO.setReceiverId(message.getReceiverId()); imMessageSaveReqVO.setReceiverId(message.getReceiverId());
//查询发送人昵称和发送人头像 //查询发送人昵称和发送人头像
AdminUserRespDTO user = adminUserApi.getUser(fromUserId); AdminUserRespDTO user = adminUserApi.getUser(senderId);
imMessageSaveReqVO.setSenderNickname(user.getNickname()); imMessageSaveReqVO.setSenderNickname(user.getNickname());
imMessageSaveReqVO.setSenderAvatar(user.getAvatar()); imMessageSaveReqVO.setSenderAvatar(user.getAvatar());
imMessageSaveReqVO.setConversationType(message.getConversationType()); imMessageSaveReqVO.setConversationType(message.getConversationType());
imMessageSaveReqVO.setContentType(message.getContentType()); imMessageSaveReqVO.setContentType(message.getContentType());
imMessageSaveReqVO.setConversationNo("1"); imMessageSaveReqVO.setConversationNo(senderId + "_" + message.getReceiverId());
imMessageSaveReqVO.setContent(message.getContent()); imMessageSaveReqVO.setContent(message.getContent());
//消息来源 100-用户发送200-系统发送一般是通知不能为空 //消息来源 100-用户发送200-系统发送一般是通知不能为空
imMessageSaveReqVO.setSendFrom(100); imMessageSaveReqVO.setSendFrom(100);
imMessageSaveReqVO.setSendTime(TimeUtil.now());
imMessageSaveReqVO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus());
return createMessage(imMessageSaveReqVO); return createMessage(imMessageSaveReqVO);
} }
@Override
public void updateMessageStatus(Long messageId, Integer messageStatus) {
//校验 id 是否存在
validateMessageExists(messageId);
//更新消息状态
ImMessageDO imMessageDO = new ImMessageDO();
imMessageDO.setId(messageId);
imMessageDO.setMessageStatus(messageStatus);
imMessageMapper.updateById(imMessageDO);
}
} }

View File

@ -3,25 +3,31 @@ package cn.iocoder.yudao.module.im.websocket;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;
import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao; import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao;
import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum;
import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;
import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; import cn.iocoder.yudao.module.im.service.conversation.ImConversationService;
import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
import cn.iocoder.yudao.module.im.service.message.ImMessageService; import cn.iocoder.yudao.module.im.service.message.ImMessageService;
import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage; import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage;
import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import java.util.List;
/** /**
* WebSocket 示例单发消息 * WebSocket im
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@Component @Component
@Slf4j
public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> { public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> {
@Resource @Resource
@ -34,6 +40,8 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
private ImInboxService imInboxService; private ImInboxService imInboxService;
@Resource @Resource
private SequenceGeneratorRedisDao sequenceGeneratorRedisDao; private SequenceGeneratorRedisDao sequenceGeneratorRedisDao;
@Resource
private WebSocketSessionManager webSocketSessionManager;
@Override @Override
public void onMessage(WebSocketSession session, ImSendMessage message) { public void onMessage(WebSocketSession session, ImSendMessage message) {
@ -48,6 +56,14 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
imInboxService.createInbox(new ImInboxSaveReqVO(fromUserId, messageId, sequenceGeneratorRedisDao.generateSequence(fromUserId))); imInboxService.createInbox(new ImInboxSaveReqVO(fromUserId, messageId, sequenceGeneratorRedisDao.generateSequence(fromUserId)));
//3推送消息 //3推送消息
// 3.1判断是否在线
List<WebSocketSession> sessions = (List<WebSocketSession>) webSocketSessionManager.getSessionList(UserTypeEnum.ADMIN.getValue(), message.getReceiverId());
if (sessions.isEmpty()) {
//更新消息状态,为发送失败
imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.FAILURE.getStatus());
return;
}
//3.2发送
ImReceiveMessage toMessage = new ImReceiveMessage(); ImReceiveMessage toMessage = new ImReceiveMessage();
toMessage.setFromId(fromUserId); toMessage.setFromId(fromUserId);
toMessage.setConversationType(ImConversationTypeEnum.PRIVATE.getType()); toMessage.setConversationType(ImConversationTypeEnum.PRIVATE.getType());
@ -55,6 +71,9 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
toMessage.setContent(message.getContent()); toMessage.setContent(message.getContent());
webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), // 给指定用户 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), message.getReceiverId(), // 给指定用户
"im-message-receive", toMessage); "im-message-receive", toMessage);
//4更新消息状态,为发送成功
imMessageService.updateMessageStatus(messageId, ImMessageStatusEnum.SUCCESS.getStatus());
} }
} }