REQ-3201: push

This commit is contained in:
yanglin 2024-12-16 14:44:10 +08:00
parent 4375d6478e
commit de49f0ea09
25 changed files with 774 additions and 74 deletions

View File

@ -59,7 +59,7 @@ public class CustomMessageInfo {
*/
private Map<String, Object> personId2BizInfo = new HashMap<>();
private boolean isPush = false;
private PushContent pushContent;
public void addBizInfo(String personId, Object bizInfo) {
if (personId2BizInfo == null)

View File

@ -0,0 +1,58 @@
package cn.axzo.im.center.api.vo.req;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
/**
* @author yanglin
*/
@Setter
@Getter
public class PushContent {
/**
* 主标题
*/
private String title;
/**
* 推送内容
*/
private String content;
/**
* android点击push的跳转链接
*/
private String androidPushUrl;
/**
* ios点击push的跳转链接
*/
private String iosPushUrl;
/**
* push消息类型. SYSTEM: 系统消息, OP: 运营消息
*/
private PushMessageTye messageTye;
/**
* 自定义提示音
*/
private String customSoundFile;
private Map<String, String> intent = new HashMap<>();
public void addIntent(String key, String value) {
intent.put(key, value);
}
public String determineAndroidCategory() {
return messageTye == PushMessageTye.OP
? "MARKETING"
: "IM";
}
}

View File

@ -0,0 +1,24 @@
package cn.axzo.im.center.api.vo.req;
import cn.axzo.basics.common.constant.enums.CodeDefinition;
import lombok.RequiredArgsConstructor;
/**
* @author yanglin
*/
@RequiredArgsConstructor
public enum PushMessageTye implements CodeDefinition<String> {
SYSTEM("system", "系统消息"),
OP("op", "运营消息"),
;
private final String code;
private final String description;
@Override
public String getCode() {
return code;
}
}

View File

@ -78,10 +78,7 @@ public class SendTemplateMessageParam {
return sender == null;
}
/**
* 推送消息
*/
private String payload;
private PushContent pushContent;
private List<ExcludePushPayload> excludePushPayloads;

View File

@ -136,7 +136,6 @@ public class MessageController implements MessageApi {
// 全员发送是不常用的场景不应该由业务处理所以把配置放在bizData里面
.allPerson(sendMessageParam.isAllPerson())
.appTypes(sendMessageParam.getAppTypes())
.payload(sendMessageParam.getPayload())
.build();
Date now = new Date();
MessageTask messageTask = messageTaskService.create(MessageTask.builder()
@ -197,7 +196,7 @@ public class MessageController implements MessageApi {
MessageTask.BizData bizData = MessageTask.BizData.builder()
.msgTemplateContent(request.getMsgTemplateContent())
.msgTemplateId(request.getMsgTemplateId())
.payload(request.getPayload())
.pushContent(request.getPushContent())
.excludePushPayloads(request.getExcludePushPayloads())
.templatedMsgType(request.getTemplatedMsgType())
.isSenderRobot(request.isSendByRobot())

View File

@ -2,6 +2,7 @@ package cn.axzo.im.entity;
import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.api.vo.req.ExcludePushPayload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.center.api.vo.req.SendMessageParam;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.center.common.enums.BizTypeEnum;
@ -134,11 +135,7 @@ public class MessageTask {
*/
private BizTypeEnum bizType;
/**
* 网易云信-自定义消息使用
* 推送内容 - 业务数据json格式
*/
private String payload;
private PushContent pushContent;
/**
* 跳转信息

View File

@ -1,29 +0,0 @@
package cn.axzo.im.gateway;
import cn.axzo.maokai.api.client.OrganizationalNodeApi;
import cn.axzo.maokai.api.vo.request.OrganizationalNodeBatchQueryVO;
import cn.axzo.maokai.api.vo.response.OrganizationalNodeVO;
import cn.axzo.pokonyan.util.RpcUtil;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("organizationalNodeApiGateway")
@Slf4j
@RequiredArgsConstructor
public class OrganizationalNodeApiGateway {
private final OrganizationalNodeApi organizationalNodeApi;
public List<OrganizationalNodeVO> fetchNodesByNodeIds(List<Long> nodeIdList) {
OrganizationalNodeBatchQueryVO organizationalNodeBatchQueryVO = new OrganizationalNodeBatchQueryVO();
organizationalNodeBatchQueryVO.setNodeIds(nodeIdList);
organizationalNodeBatchQueryVO.setContainsDeleted(false);
List<OrganizationalNodeVO> nodeVOList = organizationalNodeApi.listNode(organizationalNodeBatchQueryVO).getData();
return RpcUtil.rpcApiResultProcessor(() -> organizationalNodeApi.listNode(organizationalNodeBatchQueryVO), "fetchNodesByNodeIds", JSON.toJSONString(nodeVOList));
}
}

View File

@ -0,0 +1,61 @@
package cn.axzo.im.push;
import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.payload.PushPayloadBuilder;
import cn.axzo.im.push.payload.intent.Intent;
import cn.axzo.im.push.payload.intent.IntentValue;
import cn.axzo.im.utils.BizAssertions;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.function.Consumer;
/**
* @author yanglin
*/
@Service
public class NimPushService {
private final PushPayloadBuilder<?>[] payloadBuilders;
@SuppressWarnings("rawtypes")
public NimPushService(ObjectProvider<PushPayloadBuilder[]> payloadBuilders) {
this.payloadBuilders = payloadBuilders.getIfAvailable();
}
@SuppressWarnings({"rawtypes", "unchecked"})
public String buildPayload(PushContent content, PushPeer peer) {
Consumer<Intent<?>> intentPopulator = intent -> {
intent.setValue(Intent.INTENT_TYPE,
peer.getApiChannel() == ApiChannel.CUSTOM_MESSAGE
? IntentValue.TYPE_SERVER
: IntentValue.TYPE_IM);
intent.setValue(Intent.INTENT_SESSION_TYPE, IntentValue.CONSTANT_SESSION_TYPE);
intent.setValue(Intent.INTENT_SESSION_ID, IntentValue.create(peer.getSenderImAccount()));
if (peer.getOuId() != null && peer.getOuId() != 0L)
intent.setValue(Intent.INTENT_OU_ID, IntentValue.create(peer.getOuId()));
if (peer.getWorkspaceId() != null && peer.getWorkspaceId() != 0L)
intent.setValue(Intent.INTENT_WORKSPACE_ID, IntentValue.create(peer.getWorkspaceId()));
if (StringUtils.isNotBlank(content.getCustomSoundFile()))
intent.setValue(Intent.INTENT_SOUND, IntentValue.create(content.getCustomSoundFile()));
for (Map.Entry<String, String> e : content.getIntent().entrySet()) {
if (e.getValue() == null) continue;
intent.setValue(e.getKey(), IntentValue.create(e.getValue()));
}
};
JSONObject payload = new JSONObject();
payload.put("pushTitle", content.getTitle());
for (PushPayloadBuilder builder : payloadBuilders) {
Intent intent = builder.createIntent(content);
BizAssertions.assertNotNull(intent, "intent can't be null");
intentPopulator.accept(intent);
builder.build(peer, content, intent, payload);
}
return payload.toJSONString();
}
}

View File

@ -0,0 +1,33 @@
package cn.axzo.im.push;
import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.center.api.vo.req.PushMessageTye;
import cn.axzo.im.center.common.enums.AppTypeEnum;
import cn.axzo.im.push.PushProps.ChannelConfig;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class PushPeer {
private Long ouId;
private Long workspaceId;
private String senderImAccount;
private AppTypeEnum appType;
private ApiChannel apiChannel;
public String determineChannelId(ChannelConfig config,
PushContent content) {
PushProps.ChannelIds channelIds = appType == AppTypeEnum.CM
? config.getWorkerIds()
: config.getManagerIds();
return content.getMessageTye() == PushMessageTye.OP
? channelIds.getOpMessageChannelId()
: channelIds.getWorkMessageChannelId();
}
}

View File

@ -0,0 +1,96 @@
package cn.axzo.im.push;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
* @author yanglin
*/
@Data
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "upush.channels")
public class PushProps {
/**
* oppo渠道配置
*/
private ChannelConfig oppoChannelConfig = new ChannelConfig(
"oppo渠道配置",
// 管理端
//new ChannelIds("cmp", "67a686e9", "38a2db69"),
// 工人端
//new ChannelIds("cm", "203be53b", "3163b193"),
new ChannelIds("cm", "12a12b80", "12a12b80"),
new ChannelIds("cm", "12a12b80", "12a12b80"));
/**
* 小米渠道配置
*/
private ChannelConfig xiaomiChannelConfig = new ChannelConfig(
"小米渠道配置",
// 管理端
new ChannelIds("cmp", "122345", "122346"),
// 工人端
new ChannelIds("cm", "122431", "122432"));
/**
* 不同app的渠道配置
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class ChannelConfig {
/**
* 渠道名称
*/
private String channelName;
/**
* 管理端配置
*/
private ChannelIds managerIds;
/**
* 工人端配置
*/
private ChannelIds workerIds;
public String toString() {
return JSON.toJSONString(this);
}
}
/**
* 不同渠道的channelId配置
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class ChannelIds {
private String appType;
/**
* 个人工作信息渠道
*/
private String workMessageChannelId;
/**
* 推广信息运营信息渠道
*/
private String opMessageChannelId;
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
}

View File

@ -0,0 +1,28 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.payload.intent.Intent;
import cn.axzo.im.push.payload.intent.IntentValue;
import cn.axzo.im.utils.BizAssertions;
import org.apache.commons.lang3.StringUtils;
/**
* @author yanglin
*/
abstract class AndroidPushPayloadBuilder<T extends Intent<?>>
implements PushPayloadBuilder<T> {
@Override
public final T createIntent(PushContent content) {
T intent = createIntent();
BizAssertions.assertNotNull(intent, "intent can't be null");
if (StringUtils.isNotBlank(content.getAndroidPushUrl()))
Intent.setRouter(intent, IntentValue
.create(content.getAndroidPushUrl())
.urlEncode());
return intent;
}
abstract T createIntent();
}

View File

@ -0,0 +1,45 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.payload.intent.UriIntent;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
/**
* 华为
*
* @author yanglin
*/
@Component
class HWPushPayloadBuilder extends AndroidPushPayloadBuilder<UriIntent> {
@Override
UriIntent createIntent() {
return new UriIntent();
}
@Override
public void build(PushPeer peer, PushContent content,
UriIntent intent, JSONObject payload) {
// 点击事件的内容
JSONObject clickAction = new JSONObject();
clickAction.put("type", 1);
clickAction.put("intent", intent.build());
// 通知的内容
JSONObject androidConfig = new JSONObject();
androidConfig.put("category", content.determineAndroidCategory());
JSONObject hwField = new JSONObject();
hwField.put("android", androidConfig);
hwField.put("style", 1);
hwField.put("big_title", content.getTitle());
hwField.put("big_body", content.getContent());
hwField.put("click_action", clickAction);
payload.put("hwField", hwField);
}
}

View File

@ -0,0 +1,40 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.PushProps;
import cn.axzo.im.push.payload.intent.JsonIntent;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Component
@RequiredArgsConstructor
class OppoPushPayloadBuilder extends AndroidPushPayloadBuilder<JsonIntent> {
private final PushProps pushProps;
@Override
public JsonIntent createIntent() {
return new JsonIntent();
}
@Override
public void build(PushPeer peer, PushContent content,
JsonIntent intent, JSONObject payload) {
PushProps.ChannelConfig xmCfg = pushProps.getOppoChannelConfig();
JSONObject oppoField = new JSONObject();
oppoField.put("channel_id", peer.determineChannelId(xmCfg, content));
oppoField.put("category", content.determineAndroidCategory());
oppoField.put("notify_level", 2);
oppoField.put("click_action_type", 1);
oppoField.put("click_action_activity", "com.oppo.codelabpush.intent.action.test");
oppoField.put("action_parameters", intent.build().toJSONString());
payload.put("oppoField", oppoField);
}
}

View File

@ -0,0 +1,46 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.payload.intent.Intent;
import cn.axzo.im.push.payload.intent.IntentValue;
import cn.axzo.im.push.payload.intent.JsonIntent;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
/**
* 苹果
*
* @author yanglin
*/
@Component
class PGPushPayloadBuilder implements PushPayloadBuilder<JsonIntent> {
@Override
public JsonIntent createIntent(PushContent content) {
JsonIntent intent = new JsonIntent();
if (StringUtils.isNotBlank(content.getIosPushUrl()))
Intent.setRouter(intent, IntentValue
.create(content.getIosPushUrl()));
return intent;
}
@Override
public void build(PushPeer peer, PushContent content,
JsonIntent intent, JSONObject payload) {
JSONObject userInfo = new JSONObject();
userInfo.putAll(intent.build());
JSONObject alert = new JSONObject();
alert.put("title", content.getTitle());
alert.put("body", content.getContent());
alert.put("userInfo", userInfo);
JSONObject apsField = new JSONObject();
apsField.put("alert", alert);
payload.put("apsField", apsField);
}
}

View File

@ -0,0 +1,23 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.payload.intent.Intent;
import com.alibaba.fastjson.JSONObject;
/**
* <a href="https://doc.yunxin.163.com/messaging/server-apis/DQyNjc5NjE?platform=server#apns%E6%8E%A8%E9%80%81%E6%B6%88%E6%81%AF">云信推送</a>
* <a href="https://doc.yunxin.163.com/messaging/guide/TY4MzU5MDc?platform=android#%E8%AE%BE%E7%BD%AE%E6%8E%A8%E9%80%81%E9%80%9A%E7%9F%A5%E6%A0%8F%E8%B7%B3%E8%BD%AC%E6%96%B9%E5%BC%8F">各端推送配置</a>
* <p/>
* 文字, 链接声音
*
* @author yanglin
*/
public interface PushPayloadBuilder<T extends Intent<?>> {
T createIntent(PushContent content);
void build(PushPeer peer, PushContent content,
T intent, JSONObject payload);
}

View File

@ -0,0 +1,45 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.center.api.vo.req.PushMessageTye;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.payload.intent.UriIntent;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
/**
* 荣耀
*
* @author yanglin
*/
@Component
class RYPushPayloadBuilder extends AndroidPushPayloadBuilder<UriIntent> {
@Override
public UriIntent createIntent() {
return new UriIntent();
}
@Override
public void build(PushPeer peer, PushContent content,
UriIntent intent, JSONObject payload) {
// 点击事件的内容
JSONObject clickAction = new JSONObject();
clickAction.put("type", 1);
clickAction.put("intent", intent.build());
// 通知的内容
JSONObject notification = new JSONObject();
notification.put("title", content.getTitle());
notification.put("body", content.getContent());
notification.put("clickAction", clickAction);
notification.put("importance",
content.getMessageTye() == PushMessageTye.OP ? "LOW" : "NORMAL");
JSONObject honorField = new JSONObject();
honorField.put("notification", notification);
payload.put("honorField", honorField);
}
}

View File

@ -0,0 +1,41 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.center.api.vo.req.PushMessageTye;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.payload.intent.UriIntent;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
/**
* VIVO
*
* @author yanglin
*/
@Component
class VivoPushPayloadBuilder extends AndroidPushPayloadBuilder<UriIntent> {
@Override
public UriIntent createIntent() {
return new UriIntent();
}
/**
* 没找到自定义声音相关的字段
*/
@Override
public void build(PushPeer peer, PushContent content,
UriIntent intent, JSONObject payload) {
JSONObject vivoField = new JSONObject();
vivoField.put("content", content.getContent());
vivoField.put("classification",
content.getMessageTye() == PushMessageTye.OP ? 0 : 1);
vivoField.put("skipType", 4);
vivoField.put("networkType", -1);
vivoField.put("category", content.determineAndroidCategory());
vivoField.put("skipContent", intent.build());
payload.put("vivoField", vivoField);
}
}

View File

@ -0,0 +1,37 @@
package cn.axzo.im.push.payload;
import cn.axzo.im.center.api.vo.req.PushContent;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.push.PushProps;
import cn.axzo.im.push.payload.intent.UriIntent;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 小米
*
* @author yanglin
*/
@Component
@RequiredArgsConstructor
class XMPushPayloadBuilder extends AndroidPushPayloadBuilder<UriIntent> {
private final PushProps pushProps;
@Override
public UriIntent createIntent() {
return new UriIntent();
}
@Override
public void build(PushPeer peer, PushContent content,
UriIntent intent, JSONObject payload) {
PushProps.ChannelConfig xmCfg = pushProps.getXiaomiChannelConfig();
payload.put("channel_id", peer.determineChannelId(xmCfg, content));
payload.put("notify_foreground", "1");
payload.put("notify_effect", "2");
payload.put("intent_uri", intent.build());
}
}

View File

@ -0,0 +1,26 @@
package cn.axzo.im.push.payload.intent;
/**
* @author yanglin
*/
public interface Intent<T> {
String INTENT_ROUTER = "router";
String INTENT_SOUND = "sound";
String INTENT_TYPE = "type";
String INTENT_SESSION_TYPE = "sessionType";
String INTENT_SESSION_ID = "sessionId";
String INTENT_WORKSPACE_ID = "workspaceId";
String INTENT_OU_ID = "ouId";
void setValue(String key, IntentValue value);
T build();
// !! helper
static void setRouter(Intent<?> intent, IntentValue router) {
intent.setValue(INTENT_ROUTER, router);
}
}

View File

@ -0,0 +1,52 @@
package cn.axzo.im.push.payload.intent;
import cn.axzo.basics.common.exception.ServiceException;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.function.Consumer;
/**
* @author yanglin
*/
@Slf4j
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class IntentValue {
private final Object value;
private static final IntentValue NULL = new IntentValue(null);
public static final IntentValue CONSTANT_SESSION_TYPE = new IntentValue("0");
public static final IntentValue TYPE_SERVER = new IntentValue("server");
public static final IntentValue TYPE_IM = new IntentValue("im");
public static IntentValue create(Object value) {
if (value == null) return NULL;
return new IntentValue(value);
}
/**
* 和app约定好了, intent里面都使用string类型的值
*/
public void consume(Consumer<String> consumer) {
if (value == null) return;
consumer.accept(String.valueOf(value));
}
public IntentValue urlEncode() {
if (value == null) return NULL;
try {
if (value instanceof String)
return create(URLEncoder.encode((String) value, "UTF-8"));
else
throw new ServiceException("only string can be url encoded");
} catch (UnsupportedEncodingException e) {
log.warn("url encode failed, intent value: {}", value, e);
throw new ServiceException(String.format("url encode failed, intent value: %s", value), e);
}
}
}

View File

@ -0,0 +1,25 @@
package cn.axzo.im.push.payload.intent;
import cn.axzo.im.utils.BizAssertions;
import com.alibaba.fastjson.JSONObject;
/**
* @author yanglin
*/
public class JsonIntent implements Intent<JSONObject> {
private final JSONObject values = new JSONObject();
@Override
public void setValue(String key, IntentValue value) {
BizAssertions.assertNotBlank(key, "key is required");
BizAssertions.assertNotNull(value, "value is required");
value.consume(stringValue -> values.put(key, stringValue));
}
@Override
public JSONObject build() {
return values;
}
}

View File

@ -0,0 +1,41 @@
package cn.axzo.im.push.payload.intent;
import cn.axzo.im.utils.BizAssertions;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author yanglin
*/
public class UriIntent implements Intent<String> {
private static final String INTENT_PREFIX =
"intent://cn.axzo.codelabpush/deeplink?#Intent;scheme=pushschema;launchFlags=0x4000000;";
private final LinkedHashMap<String, IntentValue> values = new LinkedHashMap<>();
@Override
public void setValue(String key, IntentValue value) {
BizAssertions.assertNotBlank(key, "key is required");
BizAssertions.assertNotNull(value, "value is required");
values.put(key, value);
}
@Override
public String build() {
StringBuilder buf = new StringBuilder(INTENT_PREFIX);
for (Map.Entry<String, IntentValue> entry : values.entrySet()) {
entry.getValue().consume(stringValue ->
buf.append("S.")
.append(entry.getKey())
.append("=")
.append(stringValue)
.append(";"));
}
buf.append("end");
return buf.toString();
}
}

View File

@ -13,6 +13,8 @@ import cn.axzo.im.dao.repository.MessageHistoryDao;
import cn.axzo.im.entity.AccountRegister;
import cn.axzo.im.entity.MessageHistory;
import cn.axzo.im.enums.MessageHistoryStatus;
import cn.axzo.im.push.NimPushService;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.utils.BizAssertions;
import cn.axzo.im.utils.UUIDUtil;
import com.alibaba.fastjson.JSON;
@ -44,6 +46,7 @@ public class CustomMessageService {
private final AccountService accountService;
private final AccountRegisterDao accountRegisterDao;
private final MessageHistoryDao messageHistoryDao;
private final NimPushService nimPushService;
@Transactional(rollbackFor = Exception.class)
public List<MessageCustomResp> saveAsHistoryRecords(CustomMessageInfo request) {
@ -126,10 +129,17 @@ public class CustomMessageService {
history.setToAccount(account.getImAccount());
history.setStatus(MessageHistoryStatus.PENDING);
}
if (request.isPush()) {
history.setMessageBody(request.getPayload());
history.getOrCreateRecordExt().setPayload(request.getPayload());
history.getOrCreateRecordExt().setSound(request.getSound());
if (request.getPushContent() != null) {
PushPeer peer = new PushPeer();
peer.setOuId(request.getOuId());
peer.setWorkspaceId(null);
peer.setSenderImAccount(customSendAccount.getImAccount());
peer.setAppType(appType);
peer.setApiChannel(ApiChannel.CUSTOM_MESSAGE);
String payload = nimPushService.buildPayload(request.getPushContent(), peer);
history.setMessageBody(payload);
history.getOrCreateRecordExt().setPayload(payload);
history.getOrCreateRecordExt().setSound(payload);
} else {
BizAssertions.assertNotNull(request.getBizType(), "业务类型不能为空");
history.setMessageBody(JSON.toJSONString(messageBody));

View File

@ -1,5 +1,6 @@
package cn.axzo.im.service.impl;
import cn.axzo.im.center.api.vo.ApiChannel;
import cn.axzo.im.center.api.vo.req.ExcludePushPayload;
import cn.axzo.im.center.api.vo.req.SendMessageParam;
import cn.axzo.im.center.common.enums.AccountTypeEnum;
@ -12,6 +13,8 @@ import cn.axzo.im.entity.AccountRegister;
import cn.axzo.im.entity.MessageHistory;
import cn.axzo.im.entity.MessageTask;
import cn.axzo.im.enums.MessageHistoryStatus;
import cn.axzo.im.push.NimPushService;
import cn.axzo.im.push.PushPeer;
import cn.axzo.im.service.AccountRegisterService;
import cn.axzo.im.service.AccountRegisterService.AccountRegisterDTO;
import cn.axzo.im.service.AccountService;
@ -67,6 +70,8 @@ public class MessageTaskServiceImpl extends ServiceImpl<MessageTaskMapper, Messa
private OrganizationalTeamOuRelationApi organizationalTeamOuRelationApi;
@Autowired
private UpdatableMessageManager updatableMessageManager;
@Autowired
private NimPushService nimPushService;
private static final Integer DEFAULT_PAGE_SIZE = 500;
@ -261,9 +266,16 @@ public class MessageTaskServiceImpl extends ServiceImpl<MessageTaskMapper, Messa
return personIdMatches && appTypeMatches;
});
messageHistory.getOrCreateRecordExt().setPayloadExcluded(excludePayload);
if (!excludePayload)
messageHistory.getOrCreateRecordExt().setPayload(
bizData == null ? null : bizData.getPayload());
if (bizData != null && !excludePayload) {
PushPeer peer = new PushPeer();
peer.setOuId(receivePerson.getOuId());
peer.setWorkspaceId(receivePerson.getWorkspaceId());
peer.setSenderImAccount(messageHistory.getFromAccount());
peer.setAppType(AppTypeEnum.isValidAppType(messageHistory.getAppType()));
peer.setApiChannel(ApiChannel.COMMON_MESSAGE);
String payload = nimPushService.buildPayload(bizData.getPushContent(), peer);
messageHistory.getOrCreateRecordExt().setPayload(payload);
}
messageHistory.setMessageBody(resolveBody(receivePerson, messageTask,
messageHistory));
return messageHistory;

View File

@ -49,13 +49,6 @@ public class BizAssertions {
AssertUtil.notEmpty(actual, MessageFormatter.arrayFormat(message, args).getMessage());
}
/**
* 断言集合为空
*/
public static void assertEmpty(Collection<?> actual, String message, Object... args) {
AssertUtil.isEmpty(actual, MessageFormatter.arrayFormat(message, args).getMessage());
}
/**
* 断言值为真
*/
@ -88,18 +81,26 @@ public class BizAssertions {
}
}
public static void assertNotBlank(String content, String message, Object... args) {
if (StringUtils.isBlank(content)) {
throw new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
}
}
public static void assertBlank(String content, String message, Object... args) {
if (StringUtils.isNotBlank(content)) {
throw new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
}
}
public static <T> T assertResponse(CommonResponse<T> response) {
return assertResponse(response, "error resp={}", JSON.toJSONString(response));
}
public static <T> T assertResponse(CommonResponse<T> response, String message, Object... args) {
if (response.getCode() != HttpStatus.HTTP_OK) {
String finalMsg = MessageFormatter.arrayFormat(message, args).getMessage();
if (StringUtils.isNotBlank(response.getMsg())) {
finalMsg += ": " + response.getMsg();
}
ServiceException e = new ServiceException(finalMsg);
log.warn("remote call response with error. response={}", JSON.toJSONString(response), e);
if (response == null || response.getCode() != HttpStatus.HTTP_OK) {
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
log.warn("remote call response with error", e);
throw e;
}
return response.getData();
@ -111,12 +112,8 @@ public class BizAssertions {
public static <T> T assertResponse(ApiResult<T> response, String message, Object... args) {
if (!response.isSuccess()) {
String finalMsg = MessageFormatter.arrayFormat(message, args).getMessage();
if (StringUtils.isNotBlank(response.getMsg())) {
finalMsg += ": " + response.getMsg();
}
ServiceException e = new ServiceException(finalMsg);
log.warn("remote call response with error. response={}", JSON.toJSONString(response), e);
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
log.warn("remote call response with error", e);
throw e;
}
return response.getData();
@ -128,12 +125,8 @@ public class BizAssertions {
public static <T> List<T> assertResponse(ApiListResult<T> response, String message, Object... args) {
if (!response.isSuccess()) {
String finalMsg = MessageFormatter.arrayFormat(message, args).getMessage();
if (StringUtils.isNotBlank(response.getMsg())) {
finalMsg += ": " + response.getMsg();
}
ServiceException e = new ServiceException(finalMsg);
log.warn("remote call response with error. response={}", JSON.toJSONString(response), e);
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
log.warn("remote call response with error", e);
throw e;
}
return response.getData();