数据预警第三方渠道添加示例参考AlarmPushChannel.zip
项目相关文件说明
整体说明
预警推送有两种,一种是常规消息推送,一种是含动态接收人的消息推送。由于动态接收人的相关逻辑比较复杂,为了方便后续有项目只需要常规推送,准备了两个demo,分是常规推送渠道demo和包含动态接收人的渠道demo
前端二开运行
详见 仪表盘 前端二开开发文档说明 自助仪表盘开发快速入门
- cd进webpack目录
- 执行npm install smartbi-ext-env
- npm run dev (开发调试) npm run build (打包命令)
这个项目运行直接使用 npm run dev 即可, 已将 node_modules 一起打包
整体结构
前端文件
前端文件在 src\webpack\src\plugins\modifyExtenders\alarm-push 目录下
- src\webpack\src\plugins\modifyExtenders\alarm-push\index.js
前端整体入口文件,供X二开扫描引用 - src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmPushExtender.js
渠道扩展点插入定义入口,包含常规渠道DEMO
, 和 动态接收人DYNAMIC_DEMO
两个渠道
import SmartBIExt from 'smartbi-ext'
import SxAlarmPushChannel from './AlarmPushChannel.vue'
import SxAlarmDynamicPushChannel from './AlarmDynamicPushChannel.vue'
let {
AlarmModule: {
AlarmEventEnum: {
ALARM_PUSH_ON_INIT
},
BaseAlarmExtender
},
Lang
} = SmartBIExt
class AlarmPushExtender extends BaseAlarmExtender {
constructor() {
super()
}
install () {
// 预警推送界面初始化接口
this.on(ALARM_PUSH_ON_INIT, iAlarmPush => {
const channel = {
id: 'DEMO', // id 即是渠道的类型
icon: 'sx-icon-push-textmessage icon-16', // 图标
label: Lang.$t('pushChannel.pushDemo'), // 标签
tooltip: Lang.$t('pushChannel.pushDemo'), // 提示
comp: SxAlarmPushChannel, // 面板实现Vue,具体的预警面板内容
getDefaultData () { // 添加新的渠道时,初始化的默认数据结构
return {
config: {
receiverType: 'USER',
receivers: [],
custom: ''
}
}
},
getDefaultTitle () { // 默认标题
return Lang.$t('pushChannel.pushDemo')
}
}
iAlarmPush.insertChannel(-1, channel) // 插入渠道,-1 标识插入到末尾
})
}
}
-
src\webpack\src\plugins\lang.js
前端多语言文件 -
src\webpack\src\assets\alarmpush.css
前端CSS样式文件 -
SmartbiX封装好的相关控件
const {
SxAlarmRecipientInput,
SxAlarmDynamicRecipient,
SettingPanel: {
SxInputTextWidget,
SxSelectWidget
}
} = SmartUI
a. SxAlarmRecipientInput 预警接收用户控件,封装了打开用户弹窗,选择用户的逻辑
b. SxAlarmDynamicRecipient 预警动态接收人控件,封装了动态接收人的控件实现
c. SxInputTextWidget 符合礼显哥UI规范的输入框控件
d. SxSelectWidget 符合礼显哥UI规范的下拉选择框控件
后端文件
后端文件在 src\java\smartbi\demo 目录下
- src\java\smartbi\demo\AlarmPushDemoModule.java
后端逻辑注册主文件,注册 渠道订阅器、预警渠道实现代理
// 某些服务器异常情况下,可能会重复注册subscriber,导致接到的消息发送两遍,复现原因场景未知
// 先取消注册,再重新注册
// 通过重写subscriber的equals方法使subscriber移除注册成功
CommonMessageService.getInstance().unsubscribe(demoType, subscriber);
CommonMessageService.getInstance().subscribe(demoType, subscriber);
AlarmModule.getInstance().addAlarmChannelDelegate("DEMO", new AlarmDemoDelegate());
AlarmModule.getInstance().addAlarmChannelDelegate("DYNAMIC_DEMO", new AlarmDemoDynamicDelegate());
AlarmModule.getInstance().registerAlarmChannelClz("DYNAMIC_DEMO", AlarmDemoChannel.class);
- src\java\smartbi\demo\errorcode\DemoErrorCode.java
错误码定义文件,用来规范渠道的异常信息,对应多语言文件为 src\web\META-INF\classes\smartbi\demo\errorcode\DemoErrorCode_en.properties、src\web\META-INF\extension_lang_zh_CN.properties、src\web\META-INF\extension_lang_zh_TW.properties
渠道推送
渠道subscriber
由消息推送模块 CommonMessageService 统一管理接收从预警渠道发出的消息,每个渠道的subscriber自己接收处理
相关文件在 src\java\smartbi\demo\channel\config 目录下
- src\java\smartbi\demo\channel\subscriber\AlarmPushDemoSubscriber.java 自定义渠道推送的主文件,主要方法为 onMessage。接收的参数应为自己渠道接收的指类型,如IDemoConfig等。该文件在执行时,自己对相关参数进行类型转换,来处理后续逻辑
public class AlarmPushDemoSubscriber implements ISubscriber {
@Override
public void onMessage(IMessageBody messageBody, IChannelConfig channelConfig, IPublisher publisher) {
if (channelConfig == null) {
return;
}
// 类型强转
IDemoConfig demoConfig = (IDemoConfig) channelConfig;
try {
send(messageBody, demoConfig);
} catch (Exception e) {
LogManager.getLogger(AlarmPushDemoSubscriber.class).error(e.getMessage(), e);
futureException(channelConfig, e);
}
}
}
-
src\java\smartbi\demo\channel\config\DemoConfig.java AlarmPushDemoSubscriber 接收的主要参数,含有渠道推送需要的相关定义,主要由于该类没有实现ICompletableConfig接口,只能能接收处理预警推送消息,无法将处理后的消息结果进行回调处理,返回给预警
-
src\java\smartbi\demo\channel\config\DemoCompletableConfig.java
AlarmPushDemoSubscriber 接收的主要参数,含有渠道推送需要的相关定义有实现ICompletableConfig接口,可以通过config.getFuture().complete(DemoResult)将相关推动消息结果进行回调处理,返回给预警 -
src\java\smartbi\demo\channel\config\DemoReceiverType.java
渠道可能会接收多种推送方式,不同的推送方式,处理不同,使用枚举类区别规范化 -
src\java\smartbi\demo\channel\config\DemoMessageBodyExtend.java
IMessageBody messageBody 的相关接口提供了基本的推送消息内容。但是不同的渠道对信息的需求不同,这些信息统一xiezaile messageBody exntended中,DemoMessageBodyExtend为和exntended数据结构对应的实体bean -
src\java\smartbi\demo\channel\config\DemoResult.java
通过IDemoCompletableConfig接口回调给预警的结果,预警接到结果后,对结果中的信息进行解析,将详细信息和错误信息写入预警日志 -
src\java\smartbi\demo\channel\config\DemoResultType.java
渠道推送处理的结果类型,方便预警根据结果类型进行归类处理相信信息和错误信息 -
将AlarmPushDemoSubscriber 注册给渠道
在 AlarmPushDemoModule中将AlarmPushDemoSubscriber注册给系统,以便能够由系统统一管理渠道的推送消息接收
// 某些服务器异常情况下,可能会重复注册subscriber,导致接到的消息发送两遍,复现原因场景未知
// 先取消注册,再重新注册
// 通过重写subscriber的equals方法使subscriber移除注册成功
CommonMessageService.getInstance().unsubscribe(demoType, subscriber);
CommonMessageService.getInstance().subscribe(demoType, subscriber);
常规渠道推送
前端实现文件
- src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmPushChannel.vue 定义常规渠道推送的文件,通过实现主要接口,将结果从预警读取和写入预警
export default {
name: 'SxAlarmPushChannel',
components: { SxAlarmRecipientInput, SxInputTextWidget },
props: {
channel: {
type: Object, // 渠道定义
},
},
data () {
return {
config: {
// 接收人相关的配置项
receiverType: 'USER',
receivers: [],
custom: ''
},
...
}
},
...
created () {
this.intConfig()
},
methods: {
intConfig () {
// 解析传入的channel,初始化
let config = this.channel ? this.channel.config : {}
this.config = {
receiverType: config.receiverType,
receivers: config.receivers || [],
custom: config.custom
}
},
...
// 校验方法,校验当前页面的输入是否合法,由预警系统整体调用
validate () {
return new Promise((resolve, reject) => {
this.$refs.form.validate((valid) => resolve(valid))
})
},
// 将被父组件 AlarmPushChannel.vue 调用
getContent () {
// 返回定义主体内容
return {
// config 属性,返回时需要写在自己定义的属性名下
// 返回的结构和在AlarmPushExtender getDefaultData方法的对象结构整体一致
// AlarmPushChannel.vue 会将属性定义复制到 channel 定义中
config: {
// 接收人相关的配置项
receiverType: this.config.receiverType,
receivers: this.config.receiverType === 'USER' ? this.config.receivers : [],
custom: this.config.receiverType === 'CUSTOM' ? this.config.custom : ''
}
}
},
async sync () {
// 预警定义变更时,做一些同步动作,主要动态接收人时需要
}
}
}
后端实现文件
后端预警渠道实现文件在 src\java\smartbi\demo\alarm 目录先
渠道定义相关文件
将JavaBean和前端渠道定义channel 的结构一一对应,方便delegate中的逻辑处理
-
src\java\smartbi\demo\alarm\AlarmDemoChannel.java
渠道定义文件,其结构和预警渠道定义一致 -
src\java\smartbi\demo\alarm\AlarmDemoChannelConfig.java
渠道Config文件,其结构和前端config界面文件一致
渠道delegate文件
对接预警渠道处理逻辑的文件,通过实现相关接口逻辑,使得预警系统那边能够根据相关信息进行消息推送
- src\java\smartbi\demo\alarm\delegate\AlarmDemoDelegate.java
/**
* 常规的渠道推送delegate
*/
public class AlarmDemoDelegate implements IAlarmChannelDelegate {
@Override
public IAlarmConvertor getContentConvertor() {
// html 转其他内容的转换器,以预警系统做整体上的转换
// 可以自己在channel的 subsriber中自己做转换,以更好的切合实际
return null;
}
// 返回渠道接受的config
// 系统接收到config后,组装拼接成CommonMessageService需要消息体等,由预警统一进行消息推送处理
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel) {
// 转成对应的实体bean,方便后续读取
// channel.toJSON() 为将渠道转成JSON,主要针对没有将渠道对应的JavaBean如AlarmDemoChannel注册给预警系统的情况,如果注册后,可以直接进行类型转换
AlarmDemoChannel demoChannel = JSONUtil.toBean(channel.toJSON(), AlarmDemoChannel.class);
DemoCompletableConfig config = new DemoCompletableConfig();
...
return config;
}
// 对推送后的结构进行包装成IAlarmChannelResult接口对象,供预警统一执行判读推送结果和记录日志
@Override
public IAlarmChannelResult getAlarmSendResult(AlarmBO alarmBO, IAlarmChannelConfig config) {
IChannelConfig channelConfig = config.getChannelConfig();
// AlarmChannelResult 为产品定义的 IAlarmChannelResult
// 渠道有需要也可以自己实现
// 具体处理逻辑见 AlarmDemoDelegate
AlarmChannelResult result = new AlarmChannelResult();
...
return result;
}
...
}
- 在 AlarmPushDemoModule 中 注册Delegate
// 第一个参数 "DEMO" 和在AlarmPushExtender中的渠道ID 一致
AlarmModule.getInstance().addAlarmChannelDelegate("DEMO", new AlarmDemoDelegate());
含动态接收人逻辑的渠道推送
前端实现文件
- src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmDynamicPushChannel.vue
export default {
name: 'SxAlarmDynamicPushChannel',
components: { SxAlarmRecipientInput, SxInputTextWidget, SxSelectWidget, SxAlarmDynamicRecipient },
props: {
channel: {
type: Object,
},
alarmBusiness: Object
},
data () {
return {
config: {
// 接收人相关的配置项
receiverType: 'USER',
receivers: [],
custom: '',
dynamic: {
id: '',
type: null
}
},
...
},
computed: {
...
fields () {
return (this.alarmBusiness.getDataProvider().getFields() || []).map(({ uniqueId: value, label }) => ({ value, label }))
}
},
watch: {
},
created () {
this.intConfig()
},
methods: {
intConfig () {
// 解析输入的channel,初始化
let config = this.channel ? this.channel.config : {}
let dynamic = config.dynamic || { id: '', type: null }
this.config = {
receiverType: config.receiverType,
receivers: config.receivers || [],
custom: config.custom,
dynamic: {
id: dynamic.id,
type: dynamic.type
}
}
},
...
validate () {
return new Promise((resolve, reject) => {
this.$refs.form.validate((valid) => resolve(valid))
})
},
// 将被父组件 AlarmPushChannel.vue 调用
getContent () {
// 返回定义主体内容
return {
// config 属性,返回时需要写在自己定义的属性名下
// AlarmPushChannel.vue 会将属性定义复制到 channel 定义中
config: {
// 接收人相关的配置项
receiverType: this.config.receiverType,
receivers: this.config.receiverType === 'USER' ? this.config.receivers : [],
custom: this.config.receiverType === 'CUSTOM' ? this.config.custom : '',
dynamic: this.config.receiverType === 'DYNAMIC' ? this.config.dynamic : {},
}
}
},
...
// 将被父组件 AlarmPushChannel.vue 调用
async sync () {
// 前面数据范围字段变更后,可能动态接收人选择的字段已经不存在了
// 这个时候需要清空动态接收人的字段定义
if (this.checkFieldId()) {
return
}
this.$set(this.config.dynamic, 'id', null)
},
checkFieldId () {
let id = this.config.dynamic.id
return this.fields.some(f => f.value === id)
}
}
后端实现文件
对接预警渠道处理逻辑的文件,通过实现相关接口逻辑,使得预警系统那边能够根据相关信息进行消息推送
- src\java\smartbi\demo\alarm\delegate\AlarmDemoDynamicDelegate.java
/**
*
* 包含动态接收人处理逻辑的delegate
*/
public class AlarmDemoDynamicDelegate implements IAlarmChannelDelegate, IAlarmChannelDynamicDelegate { // 一般即实现常规渠道推送接口,也实现动态接收人渠道推送接口
@Override
public IAlarmConvertor getContentConvertor() {
// html 转其他内容的转换器,以预警系统做整体上的转换
// 可以自己在channel的 subsriber中自己做转换,以更好的切合实际
return null;
}
// 返回渠道接受的config
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel) {
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
DemoCompletableConfig config = new DemoCompletableConfig();
config.setType(ChannelType.valueOf(demoChannel.getType().name()));
config.setCustom(demoChannel.getConfig().getCustom());
config.setHtml(true);
config.setReceiverType(demoChannel.getConfig().getReceiverType());
config.setRecipients(demoChannel.getConfig().getReceivers().stream().map(reciver ->
new AlarmChannelRecipient(RecipientType.valueOf(reciver.getTargettype()), reciver.getTargetid(), reciver.getAlias()))
.collect(Collectors.toList()));
return config;
}
@Override
public IAlarmChannelResult getAlarmSendResult(AlarmBO alarmBO, IAlarmChannelConfig config) {
return new AlarmDemoResultGenerator().generate(config);
}
// ------------- 下面是动态接收人的处理逻辑 ----------------------
/**
* 是否是动态接收人的方式
* 是动态接收人时,由预警系统管理相关逻辑走动态接收人的逻辑
*/
@Override
public boolean isDynamic(AlarmBO alarmBO, IAlarmChannel channel) {
// AlarmDemoChannel 注册给了预警系统,有预警系统统一转成对应的JavaBean,和前端属性一一对应,可以直接进行类型转义
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
return DemoReceiverType.DYNAMIC == demoChannel.getConfig().getReceiverType();
}
@Override
public IAlarmDynamicRecipient getDynamicRecipient(AlarmBO alarmBO, IAlarmChannel channel) {
// 返回动态接收人对象
return ((AlarmDemoChannel) channel).getConfig().getDynamic();
}
// 动态接收人接口生成config
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel, List<IRecipient> recipients) {
// 对于动态接收人,实际走的时User类型的渠道退丝攻
// 只是接收人是由预警系统根据执行结果生成的
// 转成对应的实体bean,方便后续读取
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
DemoCompletableConfig config = new DemoCompletableConfig();
config.setType(ChannelType.valueOf("DEMO"));
config.setCustom(demoChannel.getConfig().getCustom());
config.setHtml(true);
// 动态接收人实际走的用户逻辑
config.setReceiverType(DemoReceiverType.USER);
// 将接收人设置为本次的接收人
config.setRecipients(recipients);
return config;
}
@Override
public IAlarmChannelResult getAlarmDynamicSendResult(AlarmBO alarmBO, IAlarmChannel channel,
List<IAlarmChannelDynamicConfig> dynamicConfigs) {
// dynamicConfigs 是动态接收人结果config列表
// 一次推送动态接收人,由于动态接收人会触发多次推送,需要将多次推送的结果合并处理后,才是这次渠道的推送结果
return new AlarmDemoResultGenerator().generateDynamicResult(channel, dynamicConfigs);
}
-
src\java\smartbi\demo\alarm\delegate\AlarmDemoResultGenerator.java
预警渠道结果生成器,将渠道的返回信息进行解析整理,返回给预警系统 -
在 AlarmPushDemoModule 中 注册Delegate
// 第一个参数 "DYNAMIC_DEMO" 和在AlarmPushExtender中的渠道ID 一致
AlarmModule.getInstance().addAlarmChannelDelegate("DYNAMIC_DEMO", new AlarmDemoDynamicDelegate());
// 将渠道数据结构对应的JavaBean注册给预警,以便后续delegate处理时,不需要每次都使用JSONUtil转成JavaBean。
// 如果想要在delegate直接操作ObjectNode,也可以不用注册
// 操作ObjectNode的工具类 smarbix.util.JSONUtil.java
AlarmModule.getInstance().registerAlarmChannelClz("DYNAMIC_DEMO", AlarmDemoChannel.class);
预警推送有两种,一种是常规消息推送,一种是含动态接收人的消息推送。由于动态接收人的相关逻辑比较复杂,为了方便后续有项目只需要常规推送,准备了两个demo,分是常规推送渠道demo和包含动态接收人的渠道demo
前端二开运行
详见 仪表盘 前端二开开发文档说明 自助仪表盘开发快速入门
- cd进webpack目录
- 执行npm install smartbi-ext-env
- npm run dev (开发调试) npm run build (打包命令)
这个项目运行直接使用 npm run dev 即可, 已将 node_modules 一起打包
整体结构
前端文件
前端文件在 src\webpack\src\plugins\modifyExtenders\alarm-push 目录下
- src\webpack\src\plugins\modifyExtenders\alarm-push\index.js
前端整体入口文件,供X二开扫描引用 - src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmPushExtender.js
渠道扩展点插入定义入口,包含常规渠道DEMO
, 和 动态接收人DYNAMIC_DEMO
两个渠道
import SmartBIExt from 'smartbi-ext'
import SxAlarmPushChannel from './AlarmPushChannel.vue'
import SxAlarmDynamicPushChannel from './AlarmDynamicPushChannel.vue'
let {
AlarmModule: {
AlarmEventEnum: {
ALARM_PUSH_ON_INIT
},
BaseAlarmExtender
},
Lang
} = SmartBIExt
class AlarmPushExtender extends BaseAlarmExtender {
constructor() {
super()
}
install () {
// 预警推送界面初始化接口
this.on(ALARM_PUSH_ON_INIT, iAlarmPush => {
const channel = {
id: 'DEMO', // id 即是渠道的类型
icon: 'sx-icon-push-textmessage icon-16', // 图标
label: Lang.$t('pushChannel.pushDemo'), // 标签
tooltip: Lang.$t('pushChannel.pushDemo'), // 提示
comp: SxAlarmPushChannel, // 面板实现Vue,具体的预警面板内容
getDefaultData () { // 添加新的渠道时,初始化的默认数据结构
return {
config: {
receiverType: 'USER',
receivers: [],
custom: ''
}
}
},
getDefaultTitle () { // 默认标题
return Lang.$t('pushChannel.pushDemo')
}
}
iAlarmPush.insertChannel(-1, channel) // 插入渠道,-1 标识插入到末尾
})
}
}
-
src\webpack\src\plugins\lang.js
前端多语言文件 -
src\webpack\src\assets\alarmpush.css
前端CSS样式文件 -
SmartbiX封装好的相关控件
const {
SxAlarmRecipientInput,
SxAlarmDynamicRecipient,
SettingPanel: {
SxInputTextWidget,
SxSelectWidget
}
} = SmartUI
a. SxAlarmRecipientInput 预警接收用户控件,封装了打开用户弹窗,选择用户的逻辑
b. SxAlarmDynamicRecipient 预警动态接收人控件,封装了动态接收人的控件实现
c. SxInputTextWidget 符合礼显哥UI规范的输入框控件
d. SxSelectWidget 符合礼显哥UI规范的下拉选择框控件
后端文件
后端文件在 src\java\smartbi\demo 目录下
- src\java\smartbi\demo\AlarmPushDemoModule.java
后端逻辑注册主文件,注册 渠道订阅器、预警渠道实现代理
// 某些服务器异常情况下,可能会重复注册subscriber,导致接到的消息发送两遍,复现原因场景未知
// 先取消注册,再重新注册
// 通过重写subscriber的equals方法使subscriber移除注册成功
CommonMessageService.getInstance().unsubscribe(demoType, subscriber);
CommonMessageService.getInstance().subscribe(demoType, subscriber);
AlarmModule.getInstance().addAlarmChannelDelegate("DEMO", new AlarmDemoDelegate());
AlarmModule.getInstance().addAlarmChannelDelegate("DYNAMIC_DEMO", new AlarmDemoDynamicDelegate());
AlarmModule.getInstance().registerAlarmChannelClz("DYNAMIC_DEMO", AlarmDemoChannel.class);
- src\java\smartbi\demo\errorcode\DemoErrorCode.java
错误码定义文件,用来规范渠道的异常信息,对应多语言文件为 src\web\META-INF\classes\smartbi\demo\errorcode\DemoErrorCode_en.properties、src\web\META-INF\extension_lang_zh_CN.properties、src\web\META-INF\extension_lang_zh_TW.properties
渠道推送
渠道subscriber
由消息推送模块 CommonMessageService 统一管理接收从预警渠道发出的消息,每个渠道的subscriber自己接收处理
相关文件在 src\java\smartbi\demo\channel\config 目录下
- src\java\smartbi\demo\channel\subscriber\AlarmPushDemoSubscriber.java 自定义渠道推送的主文件,主要方法为 onMessage。接收的参数应为自己渠道接收的指类型,如IDemoConfig等。该文件在执行时,自己对相关参数进行类型转换,来处理后续逻辑
public class AlarmPushDemoSubscriber implements ISubscriber {
@Override
public void onMessage(IMessageBody messageBody, IChannelConfig channelConfig, IPublisher publisher) {
if (channelConfig == null) {
return;
}
// 类型强转
IDemoConfig demoConfig = (IDemoConfig) channelConfig;
try {
send(messageBody, demoConfig);
} catch (Exception e) {
LogManager.getLogger(AlarmPushDemoSubscriber.class).error(e.getMessage(), e);
futureException(channelConfig, e);
}
}
}
-
src\java\smartbi\demo\channel\config\DemoConfig.java AlarmPushDemoSubscriber 接收的主要参数,含有渠道推送需要的相关定义,主要由于该类没有实现ICompletableConfig接口,只能能接收处理预警推送消息,无法将处理后的消息结果进行回调处理,返回给预警
-
src\java\smartbi\demo\channel\config\DemoCompletableConfig.java
AlarmPushDemoSubscriber 接收的主要参数,含有渠道推送需要的相关定义有实现ICompletableConfig接口,可以通过config.getFuture().complete(DemoResult)将相关推动消息结果进行回调处理,返回给预警 -
src\java\smartbi\demo\channel\config\DemoReceiverType.java
渠道可能会接收多种推送方式,不同的推送方式,处理不同,使用枚举类区别规范化 -
src\java\smartbi\demo\channel\config\DemoMessageBodyExtend.java
IMessageBody messageBody 的相关接口提供了基本的推送消息内容。但是不同的渠道对信息的需求不同,这些信息统一xiezaile messageBody exntended中,DemoMessageBodyExtend为和exntended数据结构对应的实体bean -
src\java\smartbi\demo\channel\config\DemoResult.java
通过IDemoCompletableConfig接口回调给预警的结果,预警接到结果后,对结果中的信息进行解析,将详细信息和错误信息写入预警日志 -
src\java\smartbi\demo\channel\config\DemoResultType.java
渠道推送处理的结果类型,方便预警根据结果类型进行归类处理相信信息和错误信息 -
将AlarmPushDemoSubscriber 注册给渠道
在 AlarmPushDemoModule中将AlarmPushDemoSubscriber注册给系统,以便能够由系统统一管理渠道的推送消息接收
// 某些服务器异常情况下,可能会重复注册subscriber,导致接到的消息发送两遍,复现原因场景未知
// 先取消注册,再重新注册
// 通过重写subscriber的equals方法使subscriber移除注册成功
CommonMessageService.getInstance().unsubscribe(demoType, subscriber);
CommonMessageService.getInstance().subscribe(demoType, subscriber);
常规渠道推送
前端实现文件
- src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmPushChannel.vue 定义常规渠道推送的文件,通过实现主要接口,将结果从预警读取和写入预警
export default {
name: 'SxAlarmPushChannel',
components: { SxAlarmRecipientInput, SxInputTextWidget },
props: {
channel: {
type: Object, // 渠道定义
},
},
data () {
return {
config: {
// 接收人相关的配置项
receiverType: 'USER',
receivers: [],
custom: ''
},
...
}
},
...
created () {
this.intConfig()
},
methods: {
intConfig () {
// 解析传入的channel,初始化
let config = this.channel ? this.channel.config : {}
this.config = {
receiverType: config.receiverType,
receivers: config.receivers || [],
custom: config.custom
}
},
...
// 校验方法,校验当前页面的输入是否合法,由预警系统整体调用
validate () {
return new Promise((resolve, reject) => {
this.$refs.form.validate((valid) => resolve(valid))
})
},
// 将被父组件 AlarmPushChannel.vue 调用
getContent () {
// 返回定义主体内容
return {
// config 属性,返回时需要写在自己定义的属性名下
// 返回的结构和在AlarmPushExtender getDefaultData方法的对象结构整体一致
// AlarmPushChannel.vue 会将属性定义复制到 channel 定义中
config: {
// 接收人相关的配置项
receiverType: this.config.receiverType,
receivers: this.config.receiverType === 'USER' ? this.config.receivers : [],
custom: this.config.receiverType === 'CUSTOM' ? this.config.custom : ''
}
}
},
async sync () {
// 预警定义变更时,做一些同步动作,主要动态接收人时需要
}
}
}
后端实现文件
后端预警渠道实现文件在 src\java\smartbi\demo\alarm 目录先
渠道定义相关文件
将JavaBean和前端渠道定义channel 的结构一一对应,方便delegate中的逻辑处理
-
src\java\smartbi\demo\alarm\AlarmDemoChannel.java
渠道定义文件,其结构和预警渠道定义一致 -
src\java\smartbi\demo\alarm\AlarmDemoChannelConfig.java
渠道Config文件,其结构和前端config界面文件一致
渠道delegate文件
对接预警渠道处理逻辑的文件,通过实现相关接口逻辑,使得预警系统那边能够根据相关信息进行消息推送
- src\java\smartbi\demo\alarm\delegate\AlarmDemoDelegate.java
/**
* 常规的渠道推送delegate
*/
public class AlarmDemoDelegate implements IAlarmChannelDelegate {
@Override
public IAlarmConvertor getContentConvertor() {
// html 转其他内容的转换器,以预警系统做整体上的转换
// 可以自己在channel的 subsriber中自己做转换,以更好的切合实际
return null;
}
// 返回渠道接受的config
// 系统接收到config后,组装拼接成CommonMessageService需要消息体等,由预警统一进行消息推送处理
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel) {
// 转成对应的实体bean,方便后续读取
// channel.toJSON() 为将渠道转成JSON,主要针对没有将渠道对应的JavaBean如AlarmDemoChannel注册给预警系统的情况,如果注册后,可以直接进行类型转换
AlarmDemoChannel demoChannel = JSONUtil.toBean(channel.toJSON(), AlarmDemoChannel.class);
DemoCompletableConfig config = new DemoCompletableConfig();
...
return config;
}
// 对推送后的结构进行包装成IAlarmChannelResult接口对象,供预警统一执行判读推送结果和记录日志
@Override
public IAlarmChannelResult getAlarmSendResult(AlarmBO alarmBO, IAlarmChannelConfig config) {
IChannelConfig channelConfig = config.getChannelConfig();
// AlarmChannelResult 为产品定义的 IAlarmChannelResult
// 渠道有需要也可以自己实现
// 具体处理逻辑见 AlarmDemoDelegate
AlarmChannelResult result = new AlarmChannelResult();
...
return result;
}
...
}
- 在 AlarmPushDemoModule 中 注册Delegate
// 第一个参数 "DEMO" 和在AlarmPushExtender中的渠道ID 一致
AlarmModule.getInstance().addAlarmChannelDelegate("DEMO", new AlarmDemoDelegate());
含动态接收人逻辑的渠道推送
前端实现文件
- src\webpack\src\plugins\modifyExtenders\alarm-push\AlarmDynamicPushChannel.vue
export default {
name: 'SxAlarmDynamicPushChannel',
components: { SxAlarmRecipientInput, SxInputTextWidget, SxSelectWidget, SxAlarmDynamicRecipient },
props: {
channel: {
type: Object,
},
alarmBusiness: Object
},
data () {
return {
config: {
// 接收人相关的配置项
receiverType: 'USER',
receivers: [],
custom: '',
dynamic: {
id: '',
type: null
}
},
...
},
computed: {
...
fields () {
return (this.alarmBusiness.getDataProvider().getFields() || []).map(({ uniqueId: value, label }) => ({ value, label }))
}
},
watch: {
},
created () {
this.intConfig()
},
methods: {
intConfig () {
// 解析输入的channel,初始化
let config = this.channel ? this.channel.config : {}
let dynamic = config.dynamic || { id: '', type: null }
this.config = {
receiverType: config.receiverType,
receivers: config.receivers || [],
custom: config.custom,
dynamic: {
id: dynamic.id,
type: dynamic.type
}
}
},
...
validate () {
return new Promise((resolve, reject) => {
this.$refs.form.validate((valid) => resolve(valid))
})
},
// 将被父组件 AlarmPushChannel.vue 调用
getContent () {
// 返回定义主体内容
return {
// config 属性,返回时需要写在自己定义的属性名下
// AlarmPushChannel.vue 会将属性定义复制到 channel 定义中
config: {
// 接收人相关的配置项
receiverType: this.config.receiverType,
receivers: this.config.receiverType === 'USER' ? this.config.receivers : [],
custom: this.config.receiverType === 'CUSTOM' ? this.config.custom : '',
dynamic: this.config.receiverType === 'DYNAMIC' ? this.config.dynamic : {},
}
}
},
...
// 将被父组件 AlarmPushChannel.vue 调用
async sync () {
// 前面数据范围字段变更后,可能动态接收人选择的字段已经不存在了
// 这个时候需要清空动态接收人的字段定义
if (this.checkFieldId()) {
return
}
this.$set(this.config.dynamic, 'id', null)
},
checkFieldId () {
let id = this.config.dynamic.id
return this.fields.some(f => f.value === id)
}
}
后端实现文件
对接预警渠道处理逻辑的文件,通过实现相关接口逻辑,使得预警系统那边能够根据相关信息进行消息推送
- src\java\smartbi\demo\alarm\delegate\AlarmDemoDynamicDelegate.java
/**
*
* 包含动态接收人处理逻辑的delegate
*/
public class AlarmDemoDynamicDelegate implements IAlarmChannelDelegate, IAlarmChannelDynamicDelegate { // 一般即实现常规渠道推送接口,也实现动态接收人渠道推送接口
@Override
public IAlarmConvertor getContentConvertor() {
// html 转其他内容的转换器,以预警系统做整体上的转换
// 可以自己在channel的 subsriber中自己做转换,以更好的切合实际
return null;
}
// 返回渠道接受的config
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel) {
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
DemoCompletableConfig config = new DemoCompletableConfig();
config.setType(ChannelType.valueOf(demoChannel.getType().name()));
config.setCustom(demoChannel.getConfig().getCustom());
config.setHtml(true);
config.setReceiverType(demoChannel.getConfig().getReceiverType());
config.setRecipients(demoChannel.getConfig().getReceivers().stream().map(reciver ->
new AlarmChannelRecipient(RecipientType.valueOf(reciver.getTargettype()), reciver.getTargetid(), reciver.getAlias()))
.collect(Collectors.toList()));
return config;
}
@Override
public IAlarmChannelResult getAlarmSendResult(AlarmBO alarmBO, IAlarmChannelConfig config) {
return new AlarmDemoResultGenerator().generate(config);
}
// ------------- 下面是动态接收人的处理逻辑 ----------------------
/**
* 是否是动态接收人的方式
* 是动态接收人时,由预警系统管理相关逻辑走动态接收人的逻辑
*/
@Override
public boolean isDynamic(AlarmBO alarmBO, IAlarmChannel channel) {
// AlarmDemoChannel 注册给了预警系统,有预警系统统一转成对应的JavaBean,和前端属性一一对应,可以直接进行类型转义
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
return DemoReceiverType.DYNAMIC == demoChannel.getConfig().getReceiverType();
}
@Override
public IAlarmDynamicRecipient getDynamicRecipient(AlarmBO alarmBO, IAlarmChannel channel) {
// 返回动态接收人对象
return ((AlarmDemoChannel) channel).getConfig().getDynamic();
}
// 动态接收人接口生成config
@Override
public IChannelConfig getChannelConfig(AlarmBO alarmBO, IAlarmChannel channel, List<IRecipient> recipients) {
// 对于动态接收人,实际走的时User类型的渠道退丝攻
// 只是接收人是由预警系统根据执行结果生成的
// 转成对应的实体bean,方便后续读取
AlarmDemoChannel demoChannel = (AlarmDemoChannel) channel;
DemoCompletableConfig config = new DemoCompletableConfig();
config.setType(ChannelType.valueOf("DEMO"));
config.setCustom(demoChannel.getConfig().getCustom());
config.setHtml(true);
// 动态接收人实际走的用户逻辑
config.setReceiverType(DemoReceiverType.USER);
// 将接收人设置为本次的接收人
config.setRecipients(recipients);
return config;
}
@Override
public IAlarmChannelResult getAlarmDynamicSendResult(AlarmBO alarmBO, IAlarmChannel channel,
List<IAlarmChannelDynamicConfig> dynamicConfigs) {
// dynamicConfigs 是动态接收人结果config列表
// 一次推送动态接收人,由于动态接收人会触发多次推送,需要将多次推送的结果合并处理后,才是这次渠道的推送结果
return new AlarmDemoResultGenerator().generateDynamicResult(channel, dynamicConfigs);
}
-
src\java\smartbi\demo\alarm\delegate\AlarmDemoResultGenerator.java
预警渠道结果生成器,将渠道的返回信息进行解析整理,返回给预警系统 -
在 AlarmPushDemoModule 中 注册Delegate
// 第一个参数 "DYNAMIC_DEMO" 和在AlarmPushExtender中的渠道ID 一致
AlarmModule.getInstance().addAlarmChannelDelegate("DYNAMIC_DEMO", new AlarmDemoDynamicDelegate());
// 将渠道数据结构对应的JavaBean注册给预警,以便后续delegate处理时,不需要每次都使用JSONUtil转成JavaBean。
// 如果想要在delegate直接操作ObjectNode,也可以不用注册
// 操作ObjectNode的工具类 smarbix.util.JSONUtil.java
AlarmModule.getInstance().registerAlarmChannelClz("DYNAMIC_DEMO", AlarmDemoChannel.class);