Node.js + React Native毕设:农业物联网监测系统的开发手记

毕设大概是大学四年里最坑爹之一的事情了,毕竟一旦选题不好,就很容易浪费一年的时间做一个并没有什么卵用,又不能学到什么东西的鸡肋项目。所幸,鄙人所在的硬件专业,指导老师并不懂软件,他只是想要一个农业物联网的监测系统,能提供给我的就是一个Oracle 11d数据库,带着一个物联网系统运行一年所保存的传感器数据…That’s all。然后,因为他不懂软件,所以他显然以结果为导向,只要我交出一个移动客户端和一个服务端,并不会关心我在其中用了多少坑爹的新技术。

那还说什么?上!我以强烈的恶搞精神,决定采用业界最新最坑爹最有可能烂尾的技术,组成一个 Geek 大杂烩,幻想未来那个接手我工作的师兄的一脸懵逼,我露出了邪恶的笑容,一切只为了满足自己的上新欲。

全部代码在 GPL 许可证下开源:
服务端代码:https://github.com/CauT/the-wall
客户端代码:https://github.com/CauT/NightWatch

由于数据库是学校实验室所有,所以不能放出数据以供运行,万分抱歉~。理论上应该有一份文档,但事实上太懒,不知道什么时候会填坑~。

总体架构

OK,上图说明技术框架。
总体结构

该物联网监测系统整体上可分为三层:数据库层,服务器层和客户端层。

数据库和代码层

数据库层除了原有的Oracle 11d数据库以外,还额外增加了一个Redis数据库。之所以增加第二个数据库,原因为:
1. Node.js 的 Oracle 官方依赖 node-oracledb 没有ORM,也就是说,所有的对数据库的操作,都是直接执行SQL语句,简单粗暴,我担心自己孱弱的数据库功底(本行是 Android 开发)会引发锁表问题,所以通过限制只读来避开这个问题。
2. 由于该系统服务于农业企业的内部管理人员,因此其账号数量和总体数据量必然有限,因此使用 redis 这种内存型数据库,可以不必考虑非关系型数据库在容量占用上的劣势。读取速度反而较传统的 SQL 数据库有一定的优势。
3. 使用非关系型数据库比关系型数据库好玩多了(雾
4. 之所以写了右边的Git部分,是因为原本打算利用docker技术搞一个持续集成和部署的程序,实现提交代码=>自动测试=>更新服务器部署更新=>客户端自动更新 这样一整套持续交付的流程,然而最后并没有时间写。

服务器层

服务器层,采用 Node.js 的 Express 框架作为客户端的 API 后台。因为 Node.js 的单线程异步并发结构使之可以轻松实现较高的 QPS,所以非常适合 API 后端这一特点。其框架设计和主要功能如下图所示:
服务端结构

像网关层:鉴权模块这么装逼的说法,本质也就是app.use(jwt({secret: config.jwt_secret}).unless({path: ['/signin']}));一行而已。因为是直接从毕业论文里拿下来的图,毕业论文都这尿性你们懂的,所以一些故弄玄虚敬请谅解。

客户端层

客户端层绝大部分是 React Native 代码,但是监控数据的图表生成这一块功能(如下图),由于 React Native 目前没有开源的成熟实现;试图通过 Native 代码来画图表,需要实现一个 Native 和 React Native 互相嵌套的架构,又面临一些可能的困难;故而最终选择了内嵌一个 html 页面,前端代码采用百度的 Echarts 框架来绘制图表。最终的结构就是大部分 React Native + 少部分 Html5 的客户端结构。

另外就是采用了 Redux 来统一应用的事件分发和 UI 数据管理了。可以说,React Native 若能留名青史,Redux 必定是不可或缺的一大原因。这一点我们后文再述。

细节详述

服务端层

服务端接口表:
服务端接口表

服务端程序的编写过程中,往往涉及到了大量的异步操作,如数据库读取,网络请求,JSON解析等等。而这些异步操作,又往往会因为具体的业务场景的要求,而需要保持一定的执行顺序。此外,还需要保证代码的可读性,显然此时一味嵌套回调函数,只会使我们陷入代码几乎不可读的回调地狱(Callback Hell)中。最后,由于JavaScript单线程的执行环境的特性,我们还需要避免指定不必要的执行顺序,以免降低了程序的运行性能。因此,我在项目中使用Promise模式来处理多异步的逻辑过程。如下代码所示: