feat: (REQ-3057) 获取历史消息记录

This commit is contained in:
xudawei 2024-11-19 18:40:22 +08:00
parent f3a914563d
commit db3b6b7d43
9 changed files with 422 additions and 4 deletions

View File

@ -5,13 +5,16 @@ import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupChangeOwnerReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupJoinTeamsReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.GroupHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.KickChatGroupReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ListCrowTypesReq;
import cn.axzo.im.center.api.vo.req.chatgroup.PrivateHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.UserAddChatGroupReq;
import cn.axzo.im.center.api.vo.resp.ChatGroupCreateResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupCrowTypeResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupJoinTeamsResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupQueryResp;
import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
@ -65,9 +68,20 @@ public interface ChatGroupApi {
ApiResult<Set<ChatGroupCrowTypeResp>> listCrowType(@RequestBody @Validated ListCrowTypesReq req);
/**
* 获取用户已加入的群组信息
* 加入群聊
*/
@PostMapping("api/im/chat/group/joinTeams")
ApiResult<ChatGroupJoinTeamsResp> joinTeams(@RequestBody @Validated ChatGroupJoinTeamsReq req);
/**
* 私聊-历史消息查询
*/
@PostMapping("api/im/chat/private/historyMsgQuery")
ApiResult<HistoryMsgQueryResp> privateHistoryMsgQuery(@RequestBody @Validated PrivateHistoryMsgQueryReq req);
/**
* 群聊-历史消息查询
*/
@PostMapping("api/im/chat/group/historyMsgQuery")
ApiResult<HistoryMsgQueryResp> groupHistoryMsgQuery(@RequestBody @Validated GroupHistoryMsgQueryReq req);
}

View File

@ -0,0 +1,88 @@
package cn.axzo.im.center.api.vo.req.chatgroup;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 历史消息查询
* @author xudawei
* @date 2024/11/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GroupHistoryMsgQueryReq implements Serializable {
/**
* 群id
*/
@NotEmpty(message = "群id不能为空")
private String tid;
/**
* 查询用户对应的accid.
*/
@NotEmpty(message = "用户对应的accid不能为空")
private String accid;
/**
* 开始时间毫秒级
*/
@NotEmpty(message = "群头像不能为空")
private String begintime;
/**
* 截止时间毫秒级
*/
@NotNull(message = "项目Id不能为空")
private String endtime;
/**
* 本次查询的消息条数上限(最多100条),小于等于0或者大于100会提示参数错误
*/
@NotNull(message = "本次查询的消息条数上限(最多100条),小于等于0或者大于100会提示参数错误")
private Integer limit;
/**
* 1按时间正序排列2按时间降序排列其它返回参数414错误.默认是按降序排列即时间戳最晚的消息排在最前面
*/
private Integer reverse;
/**
* 查询指定的多个消息类型类型之间用","分割不设置该参数则查询全部类型消息格式示例 0,1,2,3
* 类型支持0:文本1:图片2:语音3:视频4:地理位置5:通知6:文件10:提示11:Robot100:自定义
*/
private String type;
/**
* 查询结果中是否需要包含无感知消息true包含false不包含默认为 false
* 无感知消息具体包括
* 发送消息时被设置为发送方无感知的消息 msgSenderNoSense=1
* 发送消息时被设置为接收方无感知的消息 msgReceiverNoSense=1
* 被单向撤回的消息
* 被单向删除的消息
* 以下消息不属于无感知消息
* 被双向撤回的消息
* 被双向删除的消息
*/
private String includeNoSenseMsg;
/**
* 结束查询的最后一条消息的 msgid不包含在查询结果中用于定位锚点
* 为了保证极端场景下两条消息的时间戳一致不丢失消息建议每次查询时填写该字段定位最后一次查询到的消息
*/
private String excludeMsgid;
/**
* true(默认值)表示需要检查群是否有效,accid是否为有效的群成员设置为false则仅检测群是否存在accid是否曾经为群成员
*/
private Boolean checkTeamValid;
}

View File

@ -0,0 +1,90 @@
package cn.axzo.im.center.api.vo.req.chatgroup;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 历史消息查询
* @author xudawei
* @date 2024/11/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PrivateHistoryMsgQueryReq implements Serializable {
/**
* 发送者accid
* 实际查询结果包含双向的消息不仅包含 from 发送给 to 的消息也包含 to 发给 from 的消息
*/
@NotEmpty(message = "发送者accid不能为空")
private String from;
/**
* 接收者accid
* 实际查询结果包含双向的消息不仅包含 from 发送给 to 的消息也包含 to 发给 from 的消息
*/
@NotEmpty(message = "接收者accid不能为空")
private String to;
/**
* 开始时间毫秒级
*/
@NotEmpty(message = "群头像不能为空")
private String begintime;
/**
* 截止时间毫秒级
*/
@NotNull(message = "项目Id不能为空")
private String endtime;
/**
* 本次查询的消息条数上限(最多100条),小于等于0或者大于100会提示参数错误
*/
@NotNull(message = "本次查询的消息条数上限(最多100条),小于等于0或者大于100会提示参数错误")
private Integer limit;
/**
* 1按时间正序排列2按时间降序排列其它返回参数414错误.默认是按降序排列即时间戳最晚的消息排在最前面
*/
private Integer reverse;
/**
* 查询指定的多个消息类型类型之间用","分割不设置该参数则查询全部类型消息格式示例 0,1,2,3
* 类型支持0:文本1:图片2:语音3:视频4:地理位置5:通知6:文件10:提示11:Robot100:自定义
*/
private String type;
/**
* 查询结果中是否需要包含无感知消息true包含false不包含默认为 false
* 无感知消息具体包括
* 发送消息时被设置为发送方无感知的消息 msgSenderNoSense=1
* 发送消息时被设置为接收方无感知的消息 msgReceiverNoSense=1
* 被单向撤回的消息
* 被单向删除的消息
* 以下消息不属于无感知消息
* 被双向撤回的消息
* 被双向删除的消息
*/
private String includeNoSenseMsg;
/**
* 结束查询的最后一条消息的 msgid不包含在查询结果中用于定位锚点
* 为了保证极端场景下两条消息的时间戳一致不丢失消息建议每次查询时填写该字段定位最后一次查询到的消息
*/
private String excludeMsgid;
/**
* true(默认值)表示需要检查群是否有效,accid是否为有效的群成员设置为false则仅检测群是否存在accid是否曾经为群成员
*/
private Boolean checkTeamValid;
}

View File

@ -0,0 +1,23 @@
package cn.axzo.im.center.api.vo.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 私聊历史消息查询
* @author xudawei@axzo.cn
* @date 2024/11/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HistoryMsgQueryResp {
private List<String> msgs;
}

View File

@ -2,6 +2,8 @@ package cn.axzo.im.channel.netease;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.im.center.api.vo.req.chatgroup.GroupHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.PrivateHistoryMsgQueryReq;
import cn.axzo.im.channel.IMChannelProvider;
import cn.axzo.im.channel.netease.dto.ChangeOwnerRequest;
import cn.axzo.im.channel.netease.dto.ChangeOwnerResponse;
@ -9,6 +11,7 @@ import cn.axzo.im.channel.netease.dto.ChatGroupCreateRequest;
import cn.axzo.im.channel.netease.dto.ChatGroupCreateResponse;
import cn.axzo.im.channel.netease.dto.ChatGroupJoinTeamsResponse;
import cn.axzo.im.channel.netease.dto.ChatGroupQueryResponse;
import cn.axzo.im.channel.netease.dto.HistoryMsgQueryResponse;
import cn.axzo.im.channel.netease.dto.KickChatGroupRequest;
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchRequest;
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse;
@ -96,6 +99,16 @@ public class NimChannelService implements IMChannelProvider {
*/
private static final String JOIN_TEAM = "https://api.netease.im/nimserver/team/joinTeams.action";
/**
* 私聊-历史消息查询
*/
private static final String PRIVATE_HISTORY_MSG_QUERY = "https://api.netease.im/nimserver/history/querySessionMsg.action";
/**
* 群聊-历史消息查询
*/
private static final String GROUP_HISTORY_MSG_QUERY = "https://api.netease.im/nimserver/history/queryTeamMsg.action";
public static final int SUCCESS_CODE = 200;
public static final int RATE_LIMITED_CODE = 416;
@ -622,6 +635,105 @@ public class NimChannelService implements IMChannelProvider {
return chatGroupJoinTeamsResponse;
}
/**
* 获取用户已加入的群组信息
*/
public HistoryMsgQueryResponse privateHistoryMsgQuery(PrivateHistoryMsgQueryReq req) {
//构建创建群聊对象
HashMap<String, Object> paramMap = this.buildPrivateHistoryMsgQuery(req);
Map<String, String> authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret());
log.info("privateHistoryMsgQuery-请求网易云信,URL:{},Header:{},请求参数:{}", PRIVATE_HISTORY_MSG_QUERY,
JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap));
HttpResponse response = HttpRequest.post(PRIVATE_HISTORY_MSG_QUERY).addHeaders(authHeaderMap)
.form(paramMap).timeout(5000).execute();
String result = response.body();
log.info("privateHistoryMsgQuery-请求网易云信,result:{}", result);
if (response.getStatus() != SUCCESS_CODE) {
log.warn("privateHistoryMsgQuery-请求网易云信Server:{},异常:{}", PRIVATE_HISTORY_MSG_QUERY, result);
}
HistoryMsgQueryResponse historyMsgQueryResp = JSONUtil.toBean(result, HistoryMsgQueryResponse.class);
if (historyMsgQueryResp == null) {
log.warn("privateHistoryMsgQuery-请求网易云信Server:{},异常:{}", PRIVATE_HISTORY_MSG_QUERY, result);
}
if (historyMsgQueryResp.getCode() != SUCCESS_CODE) {
log.warn("privateHistoryMsgQuery-请求网易云信Server:{},异常:{}", PRIVATE_HISTORY_MSG_QUERY, result);
}
return historyMsgQueryResp;
}
/**
* 私聊-查询历史数据
*/
private HashMap<String, Object> buildPrivateHistoryMsgQuery(PrivateHistoryMsgQueryReq req) {
HashMap<String, Object> paramMap = Maps.newHashMap();
paramMap.put("from", req.getFrom());
paramMap.put("to", req.getTo());
paramMap.put("begintime", req.getBegintime());
paramMap.put("endtime", req.getEndtime());
paramMap.put("limit", req.getLimit());
paramMap.put("reverse", req.getReverse());
paramMap.put("type", req.getType());
paramMap.put("includeNoSenseMsg", req.getIncludeNoSenseMsg());
paramMap.put("excludeMsgid", req.getExcludeMsgid());
return paramMap;
}
/**
* 获取用户已加入的群组信息
*/
public HistoryMsgQueryResponse groupHistoryMsgQuery(GroupHistoryMsgQueryReq req) {
//构建创建群聊对象
HashMap<String, Object> paramMap = this.buildGroupHistoryMsgQuery(req);
Map<String, String> authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret());
log.info("groupHistoryMsgQuery-请求网易云信,URL:{},Header:{},请求参数:{}", GROUP_HISTORY_MSG_QUERY,
JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap));
HttpResponse response = HttpRequest.post(GROUP_HISTORY_MSG_QUERY).addHeaders(authHeaderMap)
.form(paramMap).timeout(5000).execute();
String result = response.body();
log.info("groupHistoryMsgQuery-请求网易云信,result:{}", result);
if (response.getStatus() != SUCCESS_CODE) {
log.warn("groupHistoryMsgQuery-请求网易云信Server:{},异常:{}", GROUP_HISTORY_MSG_QUERY, result);
}
HistoryMsgQueryResponse historyMsgQueryResp = JSONUtil.toBean(result, HistoryMsgQueryResponse.class);
if (historyMsgQueryResp == null) {
log.warn("groupHistoryMsgQuery-请求网易云信Server:{},异常:{}", GROUP_HISTORY_MSG_QUERY, result);
}
if (historyMsgQueryResp.getCode() != SUCCESS_CODE) {
log.warn("groupHistoryMsgQuery-请求网易云信Server:{},异常:{}", GROUP_HISTORY_MSG_QUERY, result);
}
return historyMsgQueryResp;
}
/**
* 私聊-查询历史数据
*/
private HashMap<String, Object> buildGroupHistoryMsgQuery(GroupHistoryMsgQueryReq req) {
HashMap<String, Object> paramMap = Maps.newHashMap();
paramMap.put("tid", req.getTid());
paramMap.put("accid", req.getAccid());
paramMap.put("begintime", req.getBegintime());
paramMap.put("endtime", req.getEndtime());
paramMap.put("limit", req.getLimit());
paramMap.put("reverse", req.getReverse());
paramMap.put("type", req.getType());
paramMap.put("checkTeamValid", req.getCheckTeamValid());
paramMap.put("includeNoSenseMsg", req.getIncludeNoSenseMsg());
paramMap.put("excludeMsgid", req.getExcludeMsgid());
return paramMap;
}
/**
* 群聊-查询历史数据
*/
private HashMap<String, Object> buildGroupHistoryMsgQuery(String accid) {
HashMap<String, Object> paramMap = Maps.newHashMap();
paramMap.put("accid", accid);
return paramMap;
}
/**
* 构建-获取用户已加入的群组信息
*/

View File

@ -0,0 +1,36 @@
package cn.axzo.im.channel.netease.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 私聊历史消息查询
* @author xudawei@axzo.cn
* @date 2024/11/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HistoryMsgQueryResponse {
/**
* 状态码
*/
private Integer code;
/**
* 描述
*/
private String desc;
/**
* 消息
*/
private List<String> msgs;
}

View File

@ -6,13 +6,16 @@ import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupChangeOwnerReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupJoinTeamsReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.GroupHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.KickChatGroupReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ListCrowTypesReq;
import cn.axzo.im.center.api.vo.req.chatgroup.PrivateHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.UserAddChatGroupReq;
import cn.axzo.im.center.api.vo.resp.ChatGroupCreateResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupCrowTypeResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupJoinTeamsResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupQueryResp;
import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp;
import cn.axzo.im.service.ChatGroupService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -90,10 +93,27 @@ public class ChatGroupController implements ChatGroupApi {
}
/**
* 人群列表
* 加入群
*/
@Override
public ApiResult<ChatGroupJoinTeamsResp> joinTeams(@RequestBody @Validated ChatGroupJoinTeamsReq req) {
return ApiResult.ok(chatGroupService.joinTeams(req.getAccid()));
}
/**
* 私聊-历史消息查询
*/
@Override
public ApiResult<HistoryMsgQueryResp> privateHistoryMsgQuery(@RequestBody @Validated PrivateHistoryMsgQueryReq req) {
return ApiResult.ok(chatGroupService.privateHistoryMsgQuery(req));
}
/**
* 群聊-历史消息查询
*/
@Override
public ApiResult<HistoryMsgQueryResp> groupHistoryMsgQuery(@RequestBody @Validated GroupHistoryMsgQueryReq req) {
return ApiResult.ok(chatGroupService.groupHistoryMsgQuery(req));
}
}

View File

@ -5,11 +5,14 @@ import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupChangeOwnerReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupGenericSearchReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.GroupHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.KickChatGroupReq;
import cn.axzo.im.center.api.vo.req.chatgroup.PrivateHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.UserAddChatGroupReq;
import cn.axzo.im.center.api.vo.resp.ChatGroupCreateResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupJoinTeamsResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupQueryResp;
import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp;
import cn.axzo.im.center.common.enums.ChatGroupUserDataSourceEnum;
import cn.axzo.im.entity.ChatGroup;
import cn.axzo.maokai.api.vo.response.OrganizationalNodeUserVO;
@ -113,6 +116,16 @@ public interface ChatGroupService extends IService<ChatGroup> {
*/
ChatGroupJoinTeamsResp joinTeams(String accid);
/**
* 私聊-历史消息查询
*/
HistoryMsgQueryResp privateHistoryMsgQuery(PrivateHistoryMsgQueryReq req);
/**
* 群聊-历史消息查询
*/
HistoryMsgQueryResp groupHistoryMsgQuery(GroupHistoryMsgQueryReq req);
/**
* 注册IM账号(支持幂等性)
*/

View File

@ -11,11 +11,14 @@ import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupCreateReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupGenericSearchReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.ChatGroupUserGenericSearchReq;
import cn.axzo.im.center.api.vo.req.chatgroup.GroupHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.KickChatGroupReq;
import cn.axzo.im.center.api.vo.req.chatgroup.PrivateHistoryMsgQueryReq;
import cn.axzo.im.center.api.vo.req.chatgroup.UserAddChatGroupReq;
import cn.axzo.im.center.api.vo.resp.ChatGroupCreateResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupJoinTeamsResp;
import cn.axzo.im.center.api.vo.resp.ChatGroupQueryResp;
import cn.axzo.im.center.api.vo.resp.HistoryMsgQueryResp;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.ChatGroupStatusEnum;
@ -30,6 +33,7 @@ import cn.axzo.im.channel.netease.dto.ChatGroupCreateRequest;
import cn.axzo.im.channel.netease.dto.ChatGroupCreateResponse;
import cn.axzo.im.channel.netease.dto.ChatGroupJoinTeamsResponse;
import cn.axzo.im.channel.netease.dto.ChatGroupQueryResponse;
import cn.axzo.im.channel.netease.dto.HistoryMsgQueryResponse;
import cn.axzo.im.channel.netease.dto.KickChatGroupRequest;
import cn.axzo.im.channel.netease.dto.UserAddChatGroupRequest;
import cn.axzo.im.config.BizResultCode;
@ -580,7 +584,7 @@ public class ChatGroupServiceImpl extends ServiceImpl<ChatGroupMapper, ChatGrou
}
/**
* 获取用户已加入组信息
* 加入群
*/
@Override
public ChatGroupJoinTeamsResp joinTeams(String accid) {
@ -589,6 +593,24 @@ public class ChatGroupServiceImpl extends ServiceImpl<ChatGroupMapper, ChatGrou
return ChatGroupJoinTeamsResp.builder().infos(joinTeams).build();
}
/**
* 私聊-历史消息查询
*/
@Override
public HistoryMsgQueryResp privateHistoryMsgQuery(PrivateHistoryMsgQueryReq req) {
HistoryMsgQueryResponse historyMsgQueryResponse = nimChannelService.privateHistoryMsgQuery(req);
return HistoryMsgQueryResp.builder().msgs(historyMsgQueryResponse.getMsgs()).build();
}
/**
* 群聊-历史消息查询
*/
@Override
public HistoryMsgQueryResp groupHistoryMsgQuery(GroupHistoryMsgQueryReq req) {
HistoryMsgQueryResponse historyMsgQueryResponse = nimChannelService.groupHistoryMsgQuery(req);
return HistoryMsgQueryResp.builder().msgs(historyMsgQueryResponse.getMsgs()).build();
}
/**
* 注册IM账号(支持幂等性)
*/