Merge branch 'feature/REQ-1405'

# Conflicts:
#	im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UserAccountResp.java
This commit is contained in:
songyuanlun 2024-01-04 15:10:41 +08:00
commit 1d24adfb06
17 changed files with 537 additions and 36 deletions

View File

@ -1,15 +1,16 @@
package cn.axzo.im.center.api.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
import cn.axzo.im.center.api.vo.req.MessageInfo;
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* IM消息管理API
*
@ -34,4 +35,10 @@ public interface MessageApi {
@PostMapping("api/im/message/dispatch")
ApiResult<List<MessageDispatchResp>> sendMessage(@RequestBody @Validated MessageInfo messageInfo);
/**
* 发送自定义消息
*/
@PostMapping("api/im/custom-message/send")
ApiResult<List<MessageCustomResp>> sendCustomMessage(@RequestBody @Validated CustomMessageInfo messageInfo);
}

View File

@ -0,0 +1,50 @@
package cn.axzo.im.center.api.vo.req;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.BizTypeEnum;
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author syl
* @date 2023/12/21
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CustomMessageInfo {
/**
* 发送消息到App端
* 工人端企业端服务器
* CMCMPSYSTEM
*
* @See cn.axzo.im.center.common.enums.AppTypeEnum
*/
@NotEmpty(message = "消息接收端类型appTypeList不能为空")
private List<AppTypeEnum> appTypeList;
/**
* 接收用户自然人Id
*/
@NotBlank(message = "接收用户自然人Id不能为空")
private String toPersonId;
/**
* 业务类型
*/
@NotNull(message = "业务类型不能为空")
private BizTypeEnum bizType;
/**
* 推送内容 - 业务数据json格式
*/
private String payload;
}

View File

@ -1,9 +1,11 @@
package cn.axzo.im.center.api.vo.req;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Map;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 账户信息
@ -13,6 +15,9 @@ import java.util.Map;
* @date 2023/10/9 16:01
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserAccountReq {
/**
@ -45,4 +50,5 @@ public class UserAccountReq {
* 用户账户扩展信息
*/
private Map<String, String> attachments;
}

View File

@ -0,0 +1,38 @@
package cn.axzo.im.center.api.vo.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author syl
* @date 2023/12/21
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MessageCustomResp {
/**
* 接收消息端类型
*/
private String appType;
/**
* 接收人IM账户
*/
private String toImAccount;
/**
* 接收人personId
*/
private String personId;
/**
* true - 发送成功
* false - 发送失败
*/
private Boolean isSuccess;
}

View File

@ -1,6 +1,5 @@
package cn.axzo.im.center.api.vo.resp;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

View File

@ -1,7 +1,9 @@
package cn.axzo.im.center.api.vo.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* IM账户信息
@ -11,6 +13,9 @@ import lombok.Data;
* @date 2023/10/9 16:01
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserAccountResp {
/**
* 用户userId

View File

@ -20,7 +20,12 @@ public enum AccountTypeEnum {
/**
* 普通用户
*/
USER("user", "普通用户");
USER("user", "普通用户"),
/**
* 自定义用户
*/
CUSTOM("custom", "自定义用户"),
;
private final String code;

View File

@ -0,0 +1,28 @@
package cn.axzo.im.center.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 业务类型
*/
@Getter
@AllArgsConstructor
public enum BizTypeEnum {
/**
* 积分
*/
POINTS("POINTS", "积分"),
/**
* 待办
*/
PENDING("PENDING", "待办"),
;
private final String code;
private final String message;
}

View File

@ -36,6 +36,12 @@ public interface IMChannelProvider {
*/
MessageBatchDispatchResponse dispatchBatchMessage(@Valid MessageBatchDispatchRequest messageInfo);
/**
* IM 发送自定义系统通知
*
*/
MessageCustomDispatchResponse dispatchCustomMessage(@Valid MessageCustomDispatchRequest param);
/**
* 获取AppKey
*

View File

@ -1,8 +1,10 @@
package cn.axzo.im.channel.netease;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.im.channel.IMChannelProvider;
import cn.axzo.im.channel.netease.dto.*;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
@ -41,6 +43,8 @@ public class NimChannelService implements IMChannelProvider {
private static final String NIM_MESSAGE_BATCH_DISPATCH_URL = "https://api.netease.im/nimserver/msg/sendBatchMsg.action";
private static final String NIM_MESSAGE_ATTACH_URL = "https://api.netease.im/nimserver/msg/sendAttachMsg.action";
private static final int SUCCESS_CODE = 200;
private static final int NIM_ACCOUNT_ALREADY_REGISTER = 414;
@ -214,6 +218,40 @@ public class NimChannelService implements IMChannelProvider {
return MessageBatchDispatchResponse.builder().desc("请求网易云信Server异常,请联系管理员!").build();
}
@Override
public MessageCustomDispatchResponse dispatchCustomMessage(MessageCustomDispatchRequest param) {
AssertUtil.notNull(param, "dispatchCustomMessage param cannot null");
//目前支持 0-点对点自定义通知
param.setMsgtype(0);
HashMap<String, Object> paramMap = Maps.newHashMap();
paramMap.put("from", param.getFrom());
paramMap.put("msgtype", param.getMsgtype());
paramMap.put("to", param.getTo());
paramMap.put("attach", param.getAttach());
paramMap.put("pushcontent", param.getPushcontent());
paramMap.put("payload", param.getPayload());
paramMap.put("isForcePush", ObjectUtil.defaultIfNull(param.getIsForcePush(), false));
Map<String, String> authHeaderMap = buildAuthHeader(getProviderAppKey(), getProviderAppSecret());
log.info("invoke yunxin dispatchCustomMessage,URL: {}, Header:{}, param:{}", NIM_MESSAGE_ATTACH_URL,
JSONUtil.toJsonStr(authHeaderMap), JSONUtil.toJsonStr(paramMap));
HttpResponse response = HttpRequest.post(NIM_MESSAGE_ATTACH_URL).addHeaders(authHeaderMap)
.form(paramMap).timeout(5000).execute();
log.info("yunxin dispatchMessage return,URL:{} , Header:{}, response:{}", NIM_MESSAGE_ATTACH_URL,
JSONUtil.toJsonStr(authHeaderMap), response.body());
if (response.getStatus() == SUCCESS_CODE) {
MessageCustomDispatchResponse registerResponse = JSONUtil.toBean(response.body(),
MessageCustomDispatchResponse.class);
if (registerResponse.getCode() != SUCCESS_CODE) {
log.warn("invoke yunxin server: {}, biz exception:{}", NIM_MESSAGE_ATTACH_URL, response.body());
}
return registerResponse;
} else {
log.error("invoke yunxin server :{}, error:{}", NIM_MESSAGE_ATTACH_URL, response.body());
}
return null;
}
@Override
public RegisterResponse updateAccountProfile(@Valid RegisterUpdateRequest updateRequest) {
HashMap<String, Object> paramMap = Maps.newHashMap();

View File

@ -0,0 +1,40 @@
package cn.axzo.im.channel.netease.dto;
import cn.axzo.im.center.common.enums.BizTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author syl
* @date 2023/12/21
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MessageCustomBody {
/**
* 接收人IM账户
*/
private String toImAccount;
/**
* 接收用户自然人Id
*/
private String personId;
/**
* 业务类型
*/
private BizTypeEnum bizType;
/**
* 推送内容 - 业务数据json格式
*/
private String payload;
}

View File

@ -0,0 +1,62 @@
package cn.axzo.im.channel.netease.dto;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 文档地址:https://doc.yunxin.163.com/messaging/docs/DQ2NTg4ODE?platform=server
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MessageCustomDispatchRequest {
/**
* 发送者的云信 IM 账号accid最大 32 字符
* 必须保证一个应用内唯一
*/
@NotBlank
private String from;
/**
* 仅可传入 0 1
* 0点对点自定义通知
* 1群消息自定义通知传入其他值都将报错状态码414
*/
@NotNull
private Integer msgtype;
/**
* msgtype=0 时需填入接收系统通知的用户的的云信 IM 账号accid
* msgtype=1 时需填入接收系统通知的群的 ID tid最大 32 字符
*/
@NotBlank
private String to;
/**
* 自定义系统通知的具体内容json
*/
@NotBlank
private String attach;
/**
* 推送文案
*/
private String pushcontent;
/**
* 推送对应的 payload必须是 JSON 格式不能超过 2048 字符
*/
private String payload;
/**
* 发自定义系统通知时是否强制推送默认 false
*/
private Boolean isForcePush;
}

View File

@ -0,0 +1,28 @@
package cn.axzo.im.channel.netease.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
/**
* 消息返回响应
* 示例
* {
* "code":200
* }
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MessageCustomDispatchResponse {
private Integer code;
public boolean isSuccess () {
return code == HttpStatus.OK.value();
}
}

View File

@ -2,18 +2,24 @@ package cn.axzo.im.controller;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.feign.AccountApi;
import cn.axzo.im.center.api.vo.req.*;
import cn.axzo.im.center.api.vo.req.AccountAbsentQuery;
import cn.axzo.im.center.api.vo.req.AccountQuery;
import cn.axzo.im.center.api.vo.req.BatchAccountReq;
import cn.axzo.im.center.api.vo.req.RobotAccountReq;
import cn.axzo.im.center.api.vo.req.UserAccountReq;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.axzo.im.channel.netease.INotifyService;
import cn.axzo.im.service.AccountService;
import com.google.common.collect.Lists;
import java.util.List;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* IM账户相关设计
*
@ -71,4 +77,17 @@ public class AccountController implements AccountApi {
}
return ApiResult.ok(respList);
}
/**
* 自定义用户生成IM账户
* 例如 因多终端场景同一个普通用户会申请多个网易云信账户用于不同的app终端
* 例如工人端一个IM账户企业端一个IM账户,根据不同的appType来区分
*
* @return 返回云信IM账户
*/
@PostMapping(value = "/api/im/custom-account/generate")
public ApiResult<UserAccountResp> initRelationTemplateMap(@RequestBody @Validated UserAccountReq userAccountReq) {
UserAccountResp userAccountResp = accountService.registerCustomAccount(userAccountReq, iNotifyService);
return ApiResult.ok(userAccountResp);
}
}

View File

@ -2,10 +2,14 @@ package cn.axzo.im.controller;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.im.center.api.feign.MessageApi;
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
import cn.axzo.im.center.api.vo.req.MessageInfo;
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
import cn.axzo.im.service.MessageService;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
import java.util.List;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@ -13,9 +17,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* IM消息派发相关
*
@ -37,6 +38,12 @@ public class MessageController implements MessageApi {
return ApiResult.ok(messageRespList);
}
@Override
public ApiResult<List<MessageCustomResp>> sendCustomMessage(CustomMessageInfo customMessage) {
List<MessageCustomResp> messageRespList = messageService.sendCustomMessage(customMessage);
return ApiResult.ok(messageRespList);
}
@ExceptionHandler({ RequestNotPermitted.class })
@ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
public ApiResult<String> handleRequestNotPermitted() {

View File

@ -2,37 +2,38 @@ package cn.axzo.im.service;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.im.center.api.vo.req.*;
import cn.axzo.im.center.api.vo.req.AccountAbsentQuery;
import cn.axzo.im.center.api.vo.req.AccountQuery;
import cn.axzo.im.center.api.vo.req.RobotAccountReq;
import cn.axzo.im.center.api.vo.req.UserAccountReq;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.axzo.im.center.common.enums.AccountTypeEnum;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.RobotStatusEnum;
import cn.axzo.im.channel.IMChannelProvider;
import cn.axzo.im.channel.netease.INotifyService;
import cn.axzo.im.channel.netease.dto.NimAccountInfo;
import cn.axzo.im.channel.netease.dto.RegisterRequest;
import cn.axzo.im.channel.netease.dto.RegisterResponse;
import cn.axzo.im.dao.repository.AccountRegisterDao;
import cn.axzo.im.dao.repository.RobotInfoDao;
import cn.axzo.im.entity.AccountRegister;
import cn.axzo.im.channel.netease.dto.RegisterResponse;
import cn.axzo.im.channel.netease.dto.RegisterRequest;
import cn.axzo.im.channel.netease.dto.NimAccountInfo;
import cn.axzo.im.center.common.enums.AccountTypeEnum;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.entity.RobotInfo;
import com.google.common.collect.Lists;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* IM账户服务
*
@ -90,6 +91,52 @@ public class AccountService {
}
/**
* 创建IM账户 - 用于自定义通知
*/
@Transactional(rollbackFor = Exception.class)
public UserAccountResp registerCustomAccount(@Valid UserAccountReq userAccountReq, INotifyService iNotifyService) {
String appType = userAccountReq.getAppType();
AppTypeEnum appTypeEnum = AppTypeEnum.isValidAppType(appType);
if (appTypeEnum == null) {
throw new ServiceException("当前appType,服务器不支持该类型!!");
}
String env = environment.getProperty("spring.profiles.active");
String userIdWrapper = env + userAccountReq.getUserId() + "_" + appTypeEnum.getCode();
String appKey = imChannelProvider.getProviderAppKey();
AccountRegister customAccountRegister = queryCustomAccount(AccountTypeEnum.CUSTOM,
AppTypeEnum.SYSTEM, appKey);
if (Objects.nonNull(customAccountRegister)) {
log.info("generateCustomAccount exists custom account ");
return UserAccountResp.builder()
.userId(customAccountRegister.getAccountId())
.imAccount(customAccountRegister.getImAccount())
.token(customAccountRegister.getToken())
.appType(customAccountRegister.getAppType())
.build();
}
UserAccountResp userAccountResp = createAccountRegister(userAccountReq.getUserId(), userIdWrapper, appType,
AccountTypeEnum.CUSTOM.getCode(), userAccountReq.getHeadImageUrl(), userAccountReq.getNickName());
if (iNotifyService != null && userAccountResp != null && StringUtils.isNotBlank(userAccountResp.getImAccount())) {
iNotifyService.notifyUserAccountChange(userAccountResp.getImAccount(), userAccountReq.getNickName(), null);
}
return userAccountResp;
}
public AccountRegister queryCustomAccount(AccountTypeEnum accountType, AppTypeEnum appType, String appKey) {
return accountRegisterDao.lambdaQuery()
.eq(AccountRegister::getIsDelete, 0)
.eq(AccountRegister::getAccountType, accountType.getCode())
.eq(AccountRegister::getAppType, appType.getCode())
.eq(AccountRegister::getAppKey, appKey)
.last(" LIMIT 1 ")
.one();
}
@Transactional(rollbackFor = Exception.class)
public UserAccountResp generateRobotAccount(@Valid RobotAccountReq robotAccountReq, INotifyService iNotifyService) {
//后续AppKey可能会更换机器人通过robotIdappKey维度来保证唯一性

View File

@ -2,14 +2,25 @@ package cn.axzo.im.service;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.im.center.api.vo.req.AccountQuery;
import cn.axzo.im.center.api.vo.req.CustomMessageInfo;
import cn.axzo.im.center.api.vo.req.MessageInfo;
import cn.axzo.im.center.api.vo.resp.MessageCustomResp;
import cn.axzo.im.center.api.vo.resp.MessageDispatchResp;
import cn.axzo.im.center.api.vo.resp.UserAccountResp;
import cn.axzo.im.center.common.enums.AccountTypeEnum;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.channel.IMChannelProvider;
import cn.axzo.im.channel.netease.NimMsgTypeEnum;
import cn.axzo.im.channel.netease.dto.*;
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchRequest;
import cn.axzo.im.channel.netease.dto.MessageBatchDispatchResponse;
import cn.axzo.im.channel.netease.dto.MessageBody;
import cn.axzo.im.channel.netease.dto.MessageCustomBody;
import cn.axzo.im.channel.netease.dto.MessageCustomDispatchRequest;
import cn.axzo.im.channel.netease.dto.MessageCustomDispatchResponse;
import cn.axzo.im.channel.netease.dto.MessageDispatchRequest;
import cn.axzo.im.channel.netease.dto.MessageDispatchResponse;
import cn.axzo.im.dao.repository.AccountRegisterDao;
import cn.axzo.im.dao.repository.MessageHistoryDao;
import cn.axzo.im.entity.AccountRegister;
@ -17,6 +28,15 @@ import cn.axzo.im.entity.MessageHistory;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -29,13 +49,6 @@ import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* im-center
*
@ -343,4 +356,107 @@ public class MessageService {
}
}));
}
@Transactional(rollbackFor = Exception.class)
public List<MessageCustomResp> sendCustomMessage(CustomMessageInfo customMessage) {
MessageCustomDispatchRequest messageRequest = new MessageCustomDispatchRequest();
String appKey = imChannel.getProviderAppKey();
AccountRegister customSendAccount = accountService.queryCustomAccount(
AccountTypeEnum.CUSTOM, AppTypeEnum.SYSTEM, appKey);
AssertUtil.notNull(customSendAccount, String.format("appKey=%s自定义用户没有注册im账号", appKey));
messageRequest.setFrom(customSendAccount.getImAccount());
//如果消息模板是针对多App端则分开进行发送消息
List<AppTypeEnum> appTypeList = customMessage.getAppTypeList();
List<MessageCustomResp> messageCustomRespList = Lists.newArrayList();
appTypeList.forEach(appType -> {
if (appType == null || AppTypeEnum.isValidAppType(appType.getCode()) == null) {
throw new ServiceException("当前服务器不支持该appType类型!");
}
String personId = customMessage.getToPersonId();
//进行接收用户IM账户校验
List<AccountRegister> accountRegisterList = accountRegisterDao.lambdaQuery()
.eq(AccountRegister::getIsDelete, 0)
.eq(AccountRegister::getAccountId, personId)
.eq(AccountRegister::getAppKey, imChannel.getProviderAppKey())
.isNotNull(AccountRegister::getToken)
.eq(AccountRegister::getAppType, appType.getCode()).list();
if (CollectionUtils.isEmpty(accountRegisterList)) {
//返回未注册的IM账户信息
MessageCustomResp messageDispatchResp = MessageCustomResp.builder()
.appType(appType.getCode())
.personId(personId)
.toImAccount(null)
.isSuccess(false)
.build();
log.warn("user personId=[" + personId + "],appType[" + appType.getCode() + "],"
+ " Do not send messages if you have not registered an IM account!");
return;
}
accountRegisterList.stream()
.filter(a -> StringUtils.isNoneBlank(a.getImAccount(), a.getToken()))
.forEach(a -> {
messageRequest.setTo(a.getImAccount());
String body = JSONUtil.toJsonStr(wrapperCustomMessage(a.getImAccount(),
customMessage));
messageRequest.setAttach(body);
messageRequest.setPayload(body);
MessageCustomDispatchResponse response = imChannel.dispatchCustomMessage(messageRequest);
MessageCustomResp customResp = MessageCustomResp.builder()
.appType(appType.getCode())
.personId(personId)
.toImAccount(a.getImAccount())
.isSuccess(response.isSuccess())
.build();
messageCustomRespList.add(customResp);
});
});
insertImCustomMessage(messageCustomRespList, messageRequest, customSendAccount.getImAccount());
return messageCustomRespList;
}
private void insertImCustomMessage(List<MessageCustomResp> messageRespList,
MessageCustomDispatchRequest messageRequest, String fromImAccount) {
if (CollectionUtils.isEmpty(messageRespList)) {
return;
}
String requestId = UUID.randomUUID().toString().replace("-", "");
log.info("IM custom message sent successfully insert DB: {}, param payload: {}",
JSONUtil.toJsonStr(messageRespList), messageRequest.getAttach());
CompletableFuture.runAsync(() -> {
List<MessageHistory> histories = messageRespList.stream().map(messageDispatchResp -> {
MessageHistory messageHistory = new MessageHistory();
messageHistory.setBizId(requestId);
messageHistory.setFromAccount(fromImAccount);
if (StringUtils.isNotBlank(messageDispatchResp.getToImAccount())) {
messageHistory.setToAccount(messageDispatchResp.getToImAccount());
} else {
messageHistory.setToAccount("unregistered");
}
messageHistory.setChannel(imChannel.getProviderType());
messageHistory.setAppType(messageDispatchResp.getAppType());
messageHistory.setMessageBody(messageRequest.getPayload());
messageHistory.setCreateAt(new Date());
messageHistory.setUpdateAt(new Date());
return messageHistory;
}).collect(Collectors.toList());
try {
messageHistoryDao.saveOrUpdateBatch(histories);
} catch (Exception e) {
log.error("custom message sent successfully insert failed :{},",
JSONUtil.toJsonStr(histories), e);
}
});
}
public static MessageCustomBody wrapperCustomMessage(String toImAccount,
CustomMessageInfo customMessage) {
return MessageCustomBody.builder()
.toImAccount(toImAccount)
.personId(customMessage.getToPersonId())
.bizType(customMessage.getBizType())
.payload(Optional.ofNullable(customMessage.getPayload()).orElse("{}"))
.build();
}
}