修改:私聊消息判断发送状态
This commit is contained in:
parent
2d052ea752
commit
77f3131ef3
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -73,4 +73,9 @@ public class ImMessageDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private Integer sendFrom;
|
private Integer sendFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回
|
||||||
|
*/
|
||||||
|
private Integer messageStatus;
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue