1. 消息集成
1.1. 概述
实现协同平台和业务系统的消息互通:
发送消息
发送系统消息,外部系统可以调用接口向协同用户发送消息。通过消息的链接可单点登录到业务系统进行处理。
消息通道扩展
即PC消息、M1/M3消息推送等这都属于其中一种通道,根据实际需要可以扩展其他通道,监听系统消息,发送到邮件、IM或业务系统。
短信接口
通过短信插件,可以通过短信发送系统通知消息。
1.2. 消息组件(第三方系统发送消息到平台)
第三方系统可以通过消息通道接收协同平台的消息,也可以使用下面两种方式向协同用户发送消息:
远程:调用web service,使用消息服务发送消息
本地:开发插件,使用消息组件接口发送。
平台开发手册.消息集成.消息组件(第三方系统发送消息到平台).
1.2.1. 应用范围
系统内用户发起、处理某些业务时,需要告知或提醒另外一些用户的时候需要用到系统消息组件
系统在线呼叫,需要用到系统消息组件
1.2.2. 开发规范
下面主要介绍本地的消息接口
注入消息接口 userMessageManager
例如:
<bean class="com.seeyon.apps.collaboration.manager.impl.ColManagerImpl">
<property name="userMessageManager" ref="userMessageManager" />
</bean>
private UserMessageManager userMessageManager;
public UserMessageManager getUserMessageManager(){
return this.userMessageManager;
}
public void setUserMessageManager(UserMessageManager userMessageManager){
this.userMessageManager = userMessageManager;
}
private void sendMessage(){
userMessageManager.sendSystemMessage(msgContent, ApplicationCategoryEnum.taskManage, userId.longValue(), msgReceivers, new Object[] {1});
}
接口说明:
几种接口形式:
/**
* 发送系统消息,发送给单个接收者
* @param content 消息体
* @param messageCategroy 消息所属应用分类 在com.seeyon.ctp.common.constants.ApplicationCategoryEnum中定义
* @param senderId 发送者ID
* @param receiver 接收者
* @param messageFilterArgs 消息转移的参数,与对应的UserMessageFilter对应
* @see com.seeyon.ctp.common.constants.ApplicationCategoryEnum
* @throws MessageException
*/
void sendSystemMessage(MessageContent content,
ApplicationCategoryEnum messageCategroy, long senderId,
MessageReceiver receiver, Object... messageFilterArgs) throws MessageException;
/**
* 发送系统消息,发送给多个接收者
* @param content 消息体
* @param messageCategroy
* 消息所属应用分类
* 在com.seeyon.ctp.common.constants.ApplicationCategoryEnum中定义
* @param senderId 发送者ID
* @param receivers 接收者
* @param messageFilterArgs 消息转移的参数,与对应的UserMessageFilter对应
* @see com.seeyon.ctp.common.constants.ApplicationCategoryEnum
* @throws MessageException
*/
void sendSystemMessage(MessageContent content,
ApplicationCategoryEnum messageCategroy, long senderId,
Collection receivers, Object... messageFilterArgs) throws
MessageException;
/**
* 发送系统消息,使用指定的时间发送给多个接收者
* @param content 消息体
* @param messageCategroy
* 消息所属应用分类
* 在com.seeyon.ctp.common.constants.ApplicationCategoryEnum中定义
* 如果是插件,需要在插件定义文件中配置applicationCategory属性
* @param senderId 发送者ID
* @param creationDate 发送时间
* @param receivers 接收者
* @param messageFilterArgs 消息转移的参数,与对应的UserMessageFilter对应
* @see com.seeyon.ctp.common.constants.ApplicationCategoryEnum
* @throws MessageException
*/
void sendSystemMessage(MessageContent content, int messageCategroy,
long senderId, Date creationDate,
Collection receivers, Object... messageFilterArgs)
throws MessageException;
接口使用注意事项:
- 如果MessageContent相同,接收者为多人的情况下,禁止通过for-each 方式调用sendSystemMessage方法发送消息 ;而应该使用多接收者的接口。
- 如果MessageContent的Subject是动态的,比如:处理协同的状态,通过消息定义来解决。
接口参数说明:
MessageContent 构造消息体
MessageContent 消息体,主要封装国际化key以及参数。国际化内容放在各插件的中的国际化文件中,不需要在消息组件中的国际化文件中增加。
几种构造方法说明:
方式一: new MessageContent(String key, Object... param)
方式二:MessageContent.get(String key, Object... param)
方式三:new MessageContent() .add(String key, Object... params)……
例如:
MessageContent messageContent = new MessageContent()
.add("col.send", subject, sender.getName())
.add("col.agent")
.setBody(bodyContent, bodyType, bodyCreateDate);
设置正文,主要用于email的正文:MessageContent.setBody(String bodyContent, String bodyType, Date bodyCreateDate)
设置重要程度:1普通,2重要,3非常重 要:MessageContent.setImportantLevel(Integer)
MessageReceiver 消息接收者
MessageReceiver 消息接收者,主要封装关联主体对象id、接收人Id、链接类型及链接参数
几种构造方法说明:
- 每个接收者的链接地址都不一样,通过for-each单个构造 MessageReceiver MessageReceiver.get(Long referenceId, long receiverId, String linkType, String... linkParam)
- 一个接收者,但没有连接 MessageReceiver MessageReceiver.get(Long referenceId, long receiverId)
- 多个接收者,一样的链接 List get(Long referenceId, List receiverIds, String linkType, String... linkParam)
- 多个接收者,都没有链接 List get(Long referenceId, List receiverIds)
1.3. 消息通道(第三方系统接收平台消息)
当第三方系统(sms,email,rtx,gke)需要接收协同平台消息时,可以使用消息展现通道。
只需实现一个消息接口, 系统就可以把外部的应用集成进来,在集成端可以接收系统 的所有消息,如在线消息,协同,会议,计划等,在系统启动前和用户个人设置中均可以配置。
1.3.1. 接口说明
接口名称:interface MessagePipeline
必须实现的方法如下:
方法定义 | 返回值 | 备注 |
---|---|---|
getName() | String | 消息展现通道的系统标示,注意不要重复,有数字字母 下划线构成,如:pc,sms,email,rtx,gke getShowName() string 消息展现通道的显示名称 isAvailability() boolean 该通道是否可用,可以控制是否需要消息展现 |
isAllowSetting(User currentUser) | String | 是否允许用户在“个人设置-消息提示设置”中进行配 置; 如:短信提示,需要后台管理员授权,并且设置了个人 的手机号码,人员是当前登录者,允许配置返回 null, 否则返回提示信息(注意国际化) |
getAllowSettingCategory() | List |
得到哪些应用类别可以配置(参考 ApplicationCategoryEnum), 如果采用系统默认, 请直接返回 null 如果不允许配置请参考 isAllowSetting(User currentUser) |
invoke(Message[] messages) | void | 在此方法中处理消息,把消息集成到外系统 getSortId() int 排序号,从 0 开始 |
isDefaultSend() | boolean | 默认是否发送,如果为 false,则个人需要在“个人设 置-消息提示设置”中进行配置 |
isShowSetting() | boolean | 如果 isDefaultSend 设置为false,则个人需要设置为true |
注册到系统
<bean id="rtxMessagePipeline" class="com.seeyon.v3x.plugin.rtx.message.RTXMessagePipeline"/>
系统启动时显示:
[main] INFO MessagePipelineManagerImpl:68 - 加载消息展现通道:[pc, email, rtx]
则代表pc、email和rtx三个消息通道实现加载成功。
代码示例
以 RTX 消息展现为例:
public class RTXMessagePipeline implements MessagePipeline {
// 处理消息
public void invoke(Message[] messages) {
for (Message message: messages) {
try {
String remoteURL = message.getRemoteURL();
String userName = message.getReceiverMember().getLoginName();
RTXNotifyValueBean value = new RTXNotifyValueBean();
String content = message.getContent();
value.title = message.getSenderMember().getName();
// ...
rtxSendNotifyManager.sendNotify(value);
} catch (Throwable e) {
log.error("", e);
}
}
}
// 该通道是否可用
public boolean isAvailability() {
return SystemEnvironment.hasPlugin("rtx");
}
// 消息展现通道的系统标示
public String getName() {
return "rtx";
}
// 默认是否发送
public boolean isDefaultSend() {
return false;
}
// 排序号
public int getSortId() {
return 6;
}
}
1.4. 短信接口
二次开发时客户可能指定具体短信网关,这样我们需要支持此短信网关来发短信,可以只采用普通方式发短信息, 实现 平台普通短信接口即可,短信插件被启用时加载到系统。 例如:UFMOBILE,短信王 如果客户想使用消息回调,打开链接,必须开启移动应用插件,就是实现 wappush 接口的,必须开启移动应用插 件,并且短信网关必须支持 wap 方式,只实现 wap 短信接口不能支持普通短信方式.
例如:中国移动 CMPP3,金迪,分众 短信接口使用情况如下:
短信插件启用:
1 实现了“普通短信接口”,则系统启动时加载.
2 只实现了“支持 wap 方式接口”,并且移动应用插件未启用,则系统启动时不加载.
3 实现了“普通短信接口”,并且也实现了“支持 wap 方式接口”,并且移动应用插件未启用,则支持普通短信 插件功能,不支持 wap 方式。
1.4.1. 接口说明
接口名称: interface AdapterMobileMessageManger
普通短信接口 interface AdapterMobileWapPushManager 支持 wap 方式接口,wappush url 不能为空,即消息回调地址不能为空,如果同时实现了普通短信接口,则实现普通短信功能。
1.4.2. 支持wap
/**
* 检测Wappush适配器是否可用
*/
public boolean isAvailability();
/**
* 短信网关的名称
*/
public String getName();
/**
* 发送Wappush消息
* @param messageId
* 消息的唯一标示
* @param srcPhone
* 短信的发送方手机号码
* @param destPhone
* 短信的接收方手机号码
* @param content
* 短信内容
* @param wappushURL
* wap push的url,如果为null,说明不发送wappush,采用普通短信
* @return true 发送成功
*/
public boolean sendMessage(int messageId, String srcPhone, String destPhone, String content,
String wappushURL);
/**
* 发送Wappush消息
* @param messageId
* 消息的唯一标示
* @param srcPhone
* 短信的发送方手机号码
* @param destPhone
* 短信的接收方手机号码
* @param content
* 短信内容
* @param wappushURL
* wap push的url,如果为null,说明不发送wappush,如果同时实现了AdapterMobileMessageManger 采用普通短信
* @return true 发送成功
*/
public boolean sendMessage(int messageId, String srcPhone, Collection destPhone,
String content, String wappushURL);
/**
* 是否支持群发
*
* @return true 支持
*/
public boolean isSupportQueueSend();
1.4.3. 普通方式
/**
* 检测短信适配器是否可用
* @return
*/
public boolean isAvailability();
/**
* 短信网关名称
* @return
*/
public String getName();
/**
* 发送短消息
*
* @param messageId
* 消息的唯一标示
* @param srcPhone
* 短信的发送方手机号码
* @param destPhone
* 短信的接收方手机号码
* @param content
* 短信内容
* @return true 发送成功
*/
public boolean sendMessage(int messageId, String srcPhone, String destPhone,
String content);
/**
* 发送短消息
*
* @param messageId
* 消息的唯一标示
* @param srcPhone
* 短信的发送方手机号码
* @param destPhone
* 短信的接收方手机号码
* @param content
* 短信内容
* @return true 发送成功
*/
public boolean sendMessage(int messageId, String srcPhone, Collection
destPhone,
String content);
/**
* 是否支持群发
* @return true 支持
*/
public boolean isSupportQueueSend();
/**
* 是否支持收短信
* @return
*/
public boolean isSupportRecive();
/**
* 从手机端返回到协同平台系统*
* @return
*/
public List recive();
1.4.4. 注册到系统
插 件 配 置 文 件 sms.xml , 在 这 个 文 件 中 找 到 smsAdapterManager.xml,spring Bean 在这里配置
<bean id="adapterMobileMessageManagerShortMessageKing"
class="com.seeyon.v3x.mobile.adapter.king.AdapterMobileMessageManagerShortMessageKingImpl"/>
短信网关需要的配置参数统一在 sms.properties 里配置 如:
#M 短信王 的用户名
mobile.kingname =
#M 短信王 的密码
mobile.kingpassword =
系统启动日志:
MobileMessageManagerImpl:852 - 启动手机短信收发线程[短信王短信, ?]
代表短信接口启动成功
1.4.5. 代码示例
以短信王为例:
public class AdapterMobileMessageManagerShortMessageKingImpl implements
AdapterMobileMessageManger {
//标识名称
public String getName() {
return "短信王短信";
}
//单个短信发送
public boolean sendMessage(int messageId, String srcPhone,
String destPhone, String content) {
//短信的内容不超过 60个字,小灵通号不超过 40个字。
Sender sender = new Sender(kingName, kingPassword);
String result = sender.massSend(destPhone, content, "", "");
String success = getParameters(result).get("success");
if (Strings.isBlank(success)) {
return false;
}
String[] str = success.split(",");
boolean successSend = false;
for (int i = 0; i < str.length; i++) {
if (str[i].equals(destPhone)) {
successSend = true;
}
}
return successSend;
}
//接收短信
public List < MobileReciver > recive() {
Sender sender = new Sender(kingName, kingPassword);
String str = sender.readSms();
String string = null;
String srcphonenum = null;
String srcPhone = null;
String content = null;
if (str.indexOf("&msg=") != str.indexOf("&dst=")) {
string = str.substring(str.indexOf("&msg"), str.indexOf("&dst"));
content = string.substring(string.indexOf("=") + 1);
}
if (str.indexOf("&src=") != str.indexOf("&msg=")) {
srcphonenum = str.substring(str.indexOf("&src="), str.indexOf("&msg="));
if (srcphonenum != null) {
srcPhone = srcphonenum.substring(srcphonenum.indexOf("=") + 1);
}
}
List < MobileReciver > list = new ArrayList < MobileReciver > ();
if (content != null && srcPhone != null) {
MobileReciver reciver = new MobileReciver();
reciver.setContent(content);
reciver.setSrcPhone(srcPhone);
list.add(reciver);
}
return list;
}
}