打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
从零开发TinyWebDB原型系统(2)

在上一篇文章中,我们得出了一个重要结论,TinyWebDB本质上就是一个典型的Web服务系统。那么在这篇文章中,我们就来着手实现这样一个系统。

一、工具

市面上可用于开发Web服务系统的语言和工具有很多,比如Java、Python、Node.js等,但大多都面向专业开发领域,对于非专业开发人员而言,需要跨越一定的学习门槛。为此,我们特意选择由IBM Emerging Technology团队开发的Node-RED,作为我们构建TinyWebDB原型的主要工具,实际这是一个面向物联网应用的开源可视化编程和运行环境。

选择Node-RED的最主要原因是,首先,它在功能、形式和概念上与App Inventor有许多共通之处,比如组件化开发模式、浏览器开发环境以及图形化、拖拽式编程方式等。对具有一定App Inventor开发经验的人来说,应该很容易上手。再者,Node-RED对运行和部署环境的适应性较强,除传统的Windows、MacOS和Linux等桌面系统外,还可以部署到AWS、Azure等云平台上。更值得关注的是,它还能在树莓派、安卓手机这类所谓的边缘设备上运行,为开发和学习带来了极大的便利。最后,凭借技术上的开源和开放,Node-RED已经形成了丰富的组件和代码库生态资源,几乎涵盖了与物联网和互联网应用相关的各个领域,这对于提高开发和应用的整体效率具有十分重要的意义。

二、概念

结构化的软件应用开发在某种程度上有点像搭积木或盖房子,一般都先要有一些最基本的建筑块,然后把它们按一定的方式,进行堆砌、连接与组合,最终构建成为一个预想的完整系统。在我们熟悉的App Inventor中,组件是最基本的构筑单元,主要负责应用与外界环境之间的连接和信息交换(当然也可以包括一些非接口类的通用信息处理和业务功能组件),而组件功能的调用以及组件之间的协作则主要通过(预设的事件处理)过程来实现。从整体看,应用是由功能构成的主体,功能在逻辑上映射为过程,而过程的作用就是将功能分解为由各个组件承担的具体任务,并以指令的方式指派或下达给它们。

在概念上,Node-RED与App Inventor有许多对应和相通之处。就一个具体的应用而言,Node-RED所关注的基本要素实际只有三个,即节点(Node)、消息(Msg)和流程(Flow)。如果排除变量、过程等自定义因素,那么节点其实就相当于App Inventor中的组件,消息相当于功能调用和属性存取指令,而流程则相当于(预设的事件处理)过程。为了方便理解,我们想通过一个简单的Hello World应用,来具体说明一下二者的联系和差别。

在App Inventor里,这是一段非常典型的事件处理逻辑,其重点是与功能相关的详细指令序列及具体执行步骤。其中,(按钮点击事件处理)过程是管控指令执行的主体,(按钮、标签和对话框等)组件对象虽然是指令的具体执行者,但对其功能和特性的使用都要由过程来统一指挥和调度。换句话说,组件只是过程用来实现功能的道具,它的所有行为都受到过程的直接控制。反过来,过程对组件功能也具有相当程度的依赖性和绑定性,个别组件的微小变化和改动都有可能引起整个过程的调整。

现在,让我们来转换一下视角,把整个功能实现的重心由指令转向指令的执行者。也就是说,把原来处于从属地位的组件提升为具有自主执行能力的独立个体对象,而原来承载功能逻辑的主体过程则降格为与组件对等的个体功能模块。于是,整个功能实现的方式就由原来自上而下的分层控制模式转换为自底向上的对等协作模式,原来刚性的指令执行序列也转变为由组件节点相互协作构成的消息流程图。

实际这就是Node-RED构建应用和实现功能的基本方式,但其中重要的区别在于,节点之间的协作并不是指令式的,而是声明式的。也就是说,各个节点并不关心所连接节点的具体类型、功能和特性,它的任务仅仅是接收消息、处理消息和发送消息,不负责对所发消息的用法做具体要求和详细规定。因此,Node-RED节点不必对外暴露其具体的功能和特性。节点之间发送的消息只是纯粹的数据,不必承载明确的指令和意图。节点之间只是依从数据交换和处理的需要相互连接,不必因某种逻辑关系而强制绑定。通常我们把这种编程方式叫做基于流程或数据流的编程模式

三、环境

Node-RED的安装方法和过程都非常简单,概括说就只有两步:第一,下载(https://nodejs.org/en/download/ )并安装Node.js;第二,利用Node.js中的npm,安装Node-RED

安装完成后,只要在命令行窗口中输入执行node-red,就可以启动整个Node-RED系统。这时,如果将浏览器指向运行Node-RED的主机地址和端口(默认为1880),即可进入其开发环境界面。

打开后的开发环境一般包括六个主体功能单元,分别为:1) 节点面板,用于显示所有开发可用的节点类型;2) 流程面板,用于为开发者提供连接节点、创建和编辑流程等功能;3) 信息面板,用于显示节点的详细规格信息;4) 调试面板,用于显示流程运行过程中产生的调试信息;5) 编辑面板,用于设置节点的属性行为,主要包括消息内容的修改、转换和处理等;6) 部署按钮系统菜单,用于流程的部署运行以及整个开发环境的配置管理。

Node-RED应用开发的一般过程是,首先将所需的节点从节点面板中拖入流程面板,然后根据需要分别双击各个节点,并在弹出的编辑面板中设置其属性和行为。设置完成后,按数据流向和业务逻辑要求,以拖拽方式将流程面板中的相关节点组合连接起来,形成业务和数据流程。最后点击部署按钮,将设计好的流程部署到Node-RED服务器上运行。简单说就是,添加节点设置节点连接节点部署运行四步(具体顺序可根据情况进行适当调整),更详细的步骤和说明请大家自行参考Node-RED官网(https://nodered.org )或17coding的Node-RED子站(https://nodered.17coding.net )。

四、实现

让我们重新回到TinyWebDB的开发和实现上来。在上一篇关于TinyWebDB客户端的分析中,我们提到,其每项功能都涉及到了发送服务请求接收返回结果这两个过程,从数据流向看,一个为数据输出,另一个则为数据输入。因此,我们在后台服务的设计上,也需要有相应的节点与之对接。比如,对应于前端的发送服务请求,后端应该有个侦听服务请求节点;对应于前端的接受返回结果,后端应该有个发送返回结果节点。这就像两个人之间对话交流,一个人用嘴倾诉时,需要另一个人用耳朵聆听,反之亦然。

1) 初步设计

根据上面的分析,我们应首先针对storeavalue和getvalue这两项功能,向Node-RED的流程面板中分别拖入两组输入、输出节点。由于我们采用的是标准的HTTP通信协议,所以在类型上,应该选择和使用节点面板中的http in(HTTP输入)和http response(HTTP输出)节点,分别对应于数据通信中的请求(Request)和应答(Response)功能。

值得注意的是,请求和应答之间必须具有一定的绑定性和关联性,即我们常说的所问即所答,如此才能保证通信的成功。因此,我们要先将同组的输入、输出节点用消息线连接起来,这样就可以确保二者所针对的通信对象具有一致性,避免通信过程中出现偏差。

另外,为了在开发过程中测试和调试的方便,我们还要再加入两个debug(调试)节点,分别连接到两个功能组的http in节点上,这样就能使接收到的外部消息被同时传送并显示到调试面板上,以验证接收功能的正确性。

在进行正式的开发、设置之前,有必要先对流程中各节点进行统一命名,突出其作用和功能,以方便开发过程中的管理、跟踪和调试。

之后,我们才按照TinyWebDB通信协议的约定,对http in节点中与通信相关的属性进行设置,主要包括通信方法和侦听地址这两项。对照上一篇文章中的相关说明,应分别进行如下设置。

设置完成后,点击右上角的部署按钮,将设置好的节点和流程部署到Node-RED系统中运行。这样,我们所设计的流程就初步具备接收前端数据的能力了。

2) 验证成果

为验证设计成果,我们还是先利用App Inventor编写一段简单的测试代码。其中,出于简化功能的需要,我们在测试数据部分,特意采用了硬编码的方式。

执行这段代码后,我们就能在Node-RED调试面板中看到以下数据内容。

恰好与前端应用所提交的数据能够对应起来,这说明我们所设计的服务已经能成功接收前端所发送的数据了。只不过在数据形式上,它使用了JavaScript对象类型的表示形式,除了所使用的符号有些差异外,实际它基本可以等同于App Inventor中的键值对列表。

3) 纠正错误

我们再来看一下前端App Inventor一侧的测试结果。

通过对结果做简单分析,不难看出,TinyWebDB组件对于保存数据功能的返回结果是不进行内容验证的,只要有结果就算调用成功,所以弹出了正确提示。而查询数据功能则相反,由于我们没有按约定返回列表字串形式的结果(即JavaScript形式的[VALUE, tag值, value值]),所以出现了解析错误。

另外,如果与调试面板中出现的信息进行对比,还可以发现,输入、输出数据的有效成分是被封装在消息对象的payload(载荷)属性之中,其作用有点类似于电子邮件中的正文。而像请求对象、应答对象等与网络通信相关的其他内容,则放置在payload之外其他属性中,就像电子邮件中的发送者和接收者等。为了证明这一点,我们可以将debug节点的输出属性修改为“完整消息对象”,然后再来看一下调试面板中出现的结果。

实际在完整的Node-RED消息对象结构中,_msgid和payload是两个必备的主要成分,前者像身份证编号一样,是消息的唯一性标识,而后者则承载了消息的主体内容,其他则是在此基础上根据功能需要进行的扩展,比如上图中的req和res属性。流程中的各个节点之所以能够相互连接成为一个整体,其重要的原因在于它们之间所传送的消息具有一致性,即_msgid必须保持相同,而我们通常所说的消息处理和转换其实是指对同一消息payload部分的处理和转换。

如果要解决前端出现的错误提示问题,我们必须在现有的流程中增加适当的处理节点,将发往http response节点消息的payload内容修改为符合TinyWebDB通信协议要求的形式。这里,我们选择节点面板中的template(模板)节点来完成这一使命。

各节点属性的具体设置如下图所示。暂时我们将返回结果也设为硬编码形式,以方便验证解决问题的效果。

重新测试后的结果如下图所示。

应该说,从输出消息的角度看,基本解决了上面的问题。但是如果看一下调试面板中的信息,不难发现,由于采用了硬编码的方式,所以这样的测试结果,实际和前端的输入没有任何关系,我们需要进一步改进我们的设计,增加相应的处理节点。

4) 改进设计

首先,我们需要将前端发送的请求数据信息以某种方式保存起来,使两个功能流程及其中相关处理节点之间能够实现数据分享。我们知道常规的数据存储方式包括变量存储、文件存储和数据库存储等,由于我们的设计目标是最简系统,所以暂时选择最简单的变量存储方式,以后需要时再根据情况逐渐扩展到其他存储方式。

在Node-Red中,系统性的环境变量包括节点(context)、流程(flow)和全局(global)等三种类型,分别对应于同一节点内、同一流程标签内以及整个开发环境等三类不同范围的作用域。由于我们目前的设计对象是基于同一系统的不同功能,所以采用流程变量会更适合一些。

系统预设的流程变量名为flow,因此,我们可以将所需的存储对象设为flow.tinywebdb,如果有些读者对JavaScript对象类型不太熟悉的话,不妨把它想像成我们在App Inventor中所创建的键值对类型变量。

具体做法是,在节点面板中选取change(修改)节点,将其加入storeavalue流程,并通过属性设置功能,对该存储对象进行命名和赋值,也就是将http in节点接收到的前端数据保存到该对象中。

同时,在getvalue流程中增加switch(切换)节点,将http in节点接收消息中的payload属性值与存储对象的对应值进行比较,根据比较结果将流程切换到不同的返回结果处理分支上。

最后,再统一修改两个流程中所有生成返回结果的template节点,将相关变量以模板方式嵌入到其输出消息的payload属性值中。其中的{{{...}}}符号表示,要在输出时用其中所包围变量的当前值替换这部分占位内容,比如如果a的值为1,那么{{{a}}}的输出结果就为1。

至此,我们就完成了最简TinyWebDB系统的全部设计工作,最后形成的完整数据和业务流程如下图所示。

五、测试

首先,我们来设定一组中文测试数据。

通过执行测试代码,将其保存到TinyWenDB中。

然后,设置查询条件。

再次执行测试代码,向TinyWebDB提交查询请求,并获取相关数据,以验证保存效果。

接着,我们再改变一下查询条件。

看看TinyWebDB是否能正常返回空记录。

经简单测试验证,所设计的系统基本实现了预期的目标。尽管从系统功能上看还十分简陋,技术细节上考虑得也不是很周全,而且所能保存的数据也非常有限,且无法实现持久化存储,但俗话说的好,万丈高楼平地起,一切复杂的应用和扩展其实都是在这类看似简单的原型基础之上逐步搭建起来的。我们将在后续的文章中,以此为基础,陆续向大家介绍一些与应用和功能扩展方面有关的内容和实例。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
构建简单的地震监控系统
Node-RED:工业自动化中的创新利器
Node
MIT App Inventor—一看就会的可视化的APP编程工具
[开源]一个 Vue 开发的 BPMN 2.0 流程设计器,内置三种流程引擎支持
一步一步跟着做,人人都可以开发安卓APP
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服