页面树结构
转至元数据结尾
转至元数据起始

1 消息订阅控件简介

利用DWF的服务器端脚本可以在后端(服务器)运行自己的程序,此时DWF的前端和后端之间没有任何方式进行联系,消息订阅控件可以帮助前后端脚本之间建立起实时联系,从而有助于帮助用户通过脚本对后端发生的情况作出相应的处理,使用消息订阅控件的场合包括:

  • 服务器端脚本运行时间很长,例如:持续10秒以上,需要通过诸如进度条的方式展示效果。
  • 希望通过持续访问后端的数据库,例如:时序数据库IoTDB发送特定结果给前端实现动态变化。
  • 希望在特定类型对象新增、删除或修改的时候在前端得到通知并利用脚本实现动态刷新,例如:当用户使用手机提交一个订单以后,自动在大屏上得到信息并刷新。

下面是订阅控件的一个例子:

图-订阅控件示例

在表单编辑工具里,消息订阅控件位于多对象控件分类中,拖入以后会在建模工具的画布区显示一个占位符,在应用端消息订阅控件不会显示任何效果,仅负责向服务器端发送和从服务器端接受消息的任务。

图-消息订阅控件的使用

虽然DWF中的大部分控件均具有动态响应开关,会在对象发生变化的时候自动更新其展示方式,但是消息订阅控件和控件自身动态响应开关的作用存在下面的两项不同:

第一、消息订阅控件允许在对象增删改的时候得到通知进行更加个性化的前端刷新操作

第二、对于超出增删改以外的自定义的后端逻辑,使用消息订阅控件可以允许用户在后端脚本中建立个性化的通讯,从而实现个性化的前端动态响应。

下面,介绍消息订阅控件的基本概念和用法。

2 基本概念

2.1 消息订阅模式

当消息订阅控件被拖入表单中以后,有两种针对服务器端发生事件的订阅模式:

  • 类事件订阅模式:针对目标类的内置系统事件,包括:对象的创建、删除和修改的事件。
    • 当选择类事件订阅时,触发类型的下拉框将会显示出可订阅的后端事件
  • 脚本事件订阅模式:针对用户自行实现的服务器端脚本配套的事件,包含结束事件和进度事件。
    • 当用户选择脚本事件订阅模式的时候,需要指定产生事件的后处理操作名。
    • 如果用户选择脚本事件订阅开放式,表明双向通讯的内容是自行约定的,此时需要设定触发后端的操作类型
  • 自动启动:订阅通道的建立默认在打开表单时会自动完成,但是用户可以将“自动启动”开关关闭。

图-消息订阅的类型设置界面

2.2 订阅控件的启动停止

默认情况下,订阅控件所在表单启动的时候会自动启动消息订阅,如果选择手动启动消息订阅,前端脚本可以使用如下的函数开始或停止订阅:

var addin = this.getAddinById("控件ID");

  • addin.start(obj):
    • 类事件订阅模式:开始监听类对象在后端的各类变化,包括:增删改对象中的一种。
    • 脚本事件订阅模式:调用这个函数将会启动后端脚本开始监听,启动的时候可以传入一个对象作为辅助参数,该参数可以在使用后端脚本的订阅控件的中,通过var obj = this.customData得到辅助参数;[请问是否还有其他方法?比如,如果订阅控件使用前端脚本则如何获取该参数。]
  • addin.stop():
    • 类事件订阅模式:停止监听类对象在后端的各类变化,包括:增删改对象中的一种。
    • 脚本事件订阅模式:向后端程序发出停止消息,后端程序收到消息以后自行采取措施停止执行。
  • addin.pause():
    • 类事件订阅模式:暂停监听类对象在后端的各类变化,包括:增删改对象中的一种。
    • 脚本事件订阅模式:向后端程序发出停止消息,后端程序收到消息以后自行采取措施暂停执行。
  • addin.resume():
    • 类事件订阅模式:恢复监听类对象在后端的各类变化,包括:增删改对象中的一种。
    • 向后端程序发出停止消息,后端程序收到消息以后自行采取措施恢复执行。

2.3 基于消息订阅的双向通讯

在开启订阅的双向通讯通道之后,消息订阅控件不仅能帮助前端感知后端的变化,脚本的开发者也可以利用订阅控件在前后端发送或者接受消息,从而实现快速通讯。

前端消息发送和接收

在前端脚本中,可以使用this.getAddinById()获得订阅插件的引用,之后使用sendMsg(obj)可以向正在运行的后端发送消息。

前端发送消息代码示例:

var addin = this.getAddinById("控件代号");
var obj = { };
addin.sendMsg(obj);

后端在执行的脚本里通过this.websocket.socketId判断连接是否有效,利用this.websocket.getMsg()得到最近一次发送的消息。

后端接受消息代码示例:

if (this.websocket.socketId){
	var msg = this.webSocket.getMsg();
	this.logger.info(msg.toString());
}

后端消息发送和接收

同样的道理,后端向前端发送消息的过程可以利用this.websocket.sendMsg(obj)实现,向前端的消息发送,此时会触发订阅控件的阶段消息到达事件。

后端发送消毒的代码示例:

if (this.websocket.socketId) {
	var msg = {};
	this.websocket.sendMsg(msg);
}

前端接受消息的代码示例:

var addin = this.getAddinById("控件ID");
var msg = addin.getMsg();
console.log(msg);

2.4 消息订阅内的事件感知

开始订阅以后,如何在前端得到后端事件发生的消息并进行处理呢?在消息订阅控件自身控件事件有两种内置的前端事件一个是结束消息到达事件,一个是阶段消息到达事件。

在事件的代码中获取消息的方法是通过

var addin = this.getAddinById("控件ID");

  • addin.getMsg():获得最近一次从服务器发到前端的消息。

在类事件订阅模式中:

  • 每当后端的订阅事件发生的时候,就会触发控件对应的结束消息到达事件,在事件的脚本中获得消息,如下面的代码所示:
var addin = this.getAddinById("控件ID");
var msg = addin.getMsg();
console.log(msg);

在脚本事件订阅模式中:

  • 服务器脚本可以在后端脚本中根据自己的需要多次发送阶段消息,以此来触发阶段消息到达事件,只需通过this.webSocket.sendMsg(obj)调动实现前端事件的触发。
  • 当服务器脚本结束后,DWF会自动触发结束消息到达事件。

同样的,在脚本中也可以利用getMsg()得到最近的消息。

3 举例:使用消息订阅实现动态仪表盘

在了解了消息订阅控件的用法以后,接下来介绍一个案例,用自定义控件创建一个仪表盘,并且从服务器端收集数据控制前端刷新仪表盘的读数,效果如下所示:

图-利用消息订阅实现实时刷新

实现上述效果的定制方法是:

  • 利用1个自定义控件实现仪表读数的更新,自定义控件依照,Echarts案例写入:https://echarts.apache.org/examples/zh/editor.html?c=gauge-car
  • 利用1个消息订阅控件实现后端读数的启动和停止,将其设置为:“脚本事件”,关闭自动启动。
  • 再设置2个按钮插件用于调用启动和停止。

被定制表单如下所示:

图-被定制的表单

定制好表单以后,实现动态刷新的基本原理是:

第一步:设置启动按钮和结束按钮,调用消息订阅控件启动后端脚本,或者发送停止信息给消息订阅控件通知后端停止采集数据。可以新建两个动作为implement的操作填入以下代码:

启动订阅控件

var addin = this.getAddinById("WatchMessage1"); // WatchMessage1是消息订阅控件的代号
addin.start();

停止订阅控件

var addin = this.getAddinById("WatchMessage1"); // WatchMessage1是消息订阅控件的代号
addin.stop();


第二步:设置消息订阅控件的后端脚本操作,只要没有收到停止消息,就每隔1.5秒收集速度,油位,水位,转速信息发往前端,在本次案例中上述信息以随机数形式产生,在真实情况下上述信息可以从IoTDB等时间序列数据库中查询。

var Thread = Java.type("java.lang.Thread");

while (this.websocket.socketId) {
    var msg = this.websocket.getMsg();
    if (msg){
        var objMsg = {
                "speed":(Math.random()*100).toFixed(2) - 0,
                "rpm":(Math.random()*7).toFixed(2) - 0,
                "oil":(Math.random()*2).toFixed(2) - 0,
                "water":(Math.random()*2).toFixed(2) - 0
            }
        this.websocket.sendMsg(objMsg); // 向前端发送消息
        if (msg.data.contains("stop")) {
            this.res = "停止读数"
            break;
        }
    }
    Thread.sleep(1500);
}
this.logger.info("运行结束");

第三步:前端自定义控件按照2秒的周期刷新,每次刷新的时候从消息订阅控件中读取最新后端消息,然后设置刷新自身,下面是简略的代码:

option = {
	...
}
let that = this;
setInterval(function (){
    let addin = that.getAddinById("WatchMessage1");
    let myChart = that.getAddinById("EChart1"); 
    if (addin){
        var msg = addin.getMsg();
        if (msg){
            option.series[0].data[0].value = msg.data.speed;//speed
            option.series[1].data[0].value = msg.data.rpm;//rpm
            option.series[2].data[0].value = msg.data.oil;//oil
            option.series[3].data[0].value = msg.data.water;//water
            myChart.chart.setOption(option, true);
        }
    }
},2000);

最后,启动的效果如下所示:

4 小结

本章主要介绍了订阅控件的使用方法,消息订阅控件可以在后端脚本和前端界面之间建立起一个通道,使得前端能及时了解后端的运行状态,订阅控件提供了下面的支持:

  1. 提供类事件订阅和自定义脚本订阅两种模式,其中自定义脚本订阅允许用户实现个性化后端服务并且和前端进行通讯。
  2. 提供启动,通知,暂停,重启的函数,调用以后会主动将后端脚本启动并且建立通讯通道。
  3. 为前后端消息发送提供了基础的接口。
  4. 控件本身自带消息到达和脚本终止事件,帮助前端脚本针对消息采取相应的动作。

最后,结合自定义可视化事件,实现了一个仪表盘的案例。


  • 无标签