当前位置: 首页 > 后端技术 > Node.js

Node.js+ReactNative毕社:农业物联网监控系统开发笔记

时间:2023-04-03 15:10:14 Node.js

毕社大概是大学四年最坑爹的事情之一。毕竟,一旦选题没有选好,很容易浪费一年的时间去做一个没有用,学不到东西的鸡肋项目。还好我是硬件专业的,导师不懂软件,他只是想要一个农业物联网监控系统,他能给我的是一个Oracle11d数据库,一个物联网系统跑了一年,保存Sensor数据。。。仅此而已.然后,因为他不懂软件,他显然是结果导向的。只要交出一个手机客户端和一个服务端,我不在乎我在里面用了多少新技术。还有什么?优越的!带着强烈的恶搞精神,我决定采用业内最新、最坑爹、最有可能烂尾的技术,组成一个极客大杂烩。想着以后接手我工作的大哥,会一脸懵逼的样子。我露出邪恶的笑容,都是为了满足你的求新欲。所有代码在GPL许可下开源:服务器代码:https://github.com/CauT/the-wall客户端代码:https://github.com/CauT/Night...因为数据库是学校实验室全部,所以无法发布数据进行运营,非常抱歉~。理论上应该有文档,但其实懒得知道什么时候填坑~。整体架构还可以,上图是技术框架。?物联网监控系统整体可分为三层:数据库层、服务器层和客户端层。数据库和代码层数据库层除了原有的Oracle11d数据库外,还增加了Redis数据库。之所以添加第二个数据库是因为Node.js的Oracle官方依赖node-oracledb,没有ORM。也就是说,所有对数据库的操作都是直接执行SQL语句,简单粗暴。我担心我的弱点。数据库知识(这行是Android开发)会导致锁表问题,所以可以通过限制只读来避免这个问题。由于系统服务于农业企业内部管理者,因此必须限制账户数量和整体数据量。因此,使用redis等内存数据库不需要考虑非关系型数据库在容量占用方面的劣势。相反,读取速度比传统的SQL数据库有一定的优势。使用非关系型数据库比关系型数据库好玩多了(Wu之所以把Git部分写在右边是因为他本来打算用docker技术搞一个持续集成部署的程序,实现代码提交=>自动测试=>更新服务器部署更新=>客户端自动更新这么一套持续交付的流程,但是最后没时间写server层server层,使用Node.jsExpress框架作为客户端API背景.由于Node.js单线程异步并发结构,很容易实现高QPS,所以非常适合API后端的特点.其框架设计和主要功能如下图所示:网关层:认证模块这么牛逼,本质就是app.use(jwt({secret:config.jwt_secret}).unless({path:['/signin']}));就一行。因为它是毕业论文直接截的图,毕业论文烦你我明白了,还请见谅。Client层?Client层大部分是ReactNative代码,只是监控数据图表生成的功能(如下图),因为ReactNative目前没有开源的成熟实现;尝试通过Native代码绘制图表,需要实现Native和ReactNative的嵌套架构,面临一些可能的困难;因此,我们最终选择嵌入一个html页面,前端代码使用百度的Echarts框架绘制图表。最后的结构是大部分ReactNative+一小部分Html5的客户端结构。此外,Redux用于统一应用的事件分发和UI数据管理。可以说,如果ReactNative能够名垂青史,Redux一定是不可或缺的一大原因。这个我们稍后再说。服务器层服务器接口表详解:?编写服务器程序的过程中,往往会涉及到大量的异步操作,比如数据库读取、网络请求、JSON解析等。而这些异步操作由于特定业务场景的要求,往往需要保持一定的执行顺序。另外,还要保证代码的可读性。显然,此时一味地嵌套回调函数只会让我们陷入代码几乎不可读的回调地狱(CallbackHell)。最后,由于JavaScript单线程执行环境的特点,我们也需要避免指定不必要的执行顺序,以免降低程序的运行性能。因此,我在项目中使用Promise模式来处理多个异步逻辑过程。如下代码所示:functionrenderGraph(req,res,filters){varx=[];变量ys=[];变种标题=[];filters[0].forEach(function(row){x.push(getLocalTime(row.RECTIME));});filters.forEach(function(filtered){if(filtered[0]==undefined)//即使多查询中至少有一个成功//fast-fail对于安全thrownewError('数据库返回结果为空');vary=[];filtered.forEach(function(row){y.push(row.ANALOGYVALUE);});ys.push(y);titles.push(filtered[0].DEVICENAME+':'+过滤[0].DEVICECODE);});res.render('graph',{titles:titles,dataX:x,dataY:ys,height:req.query.height==undefined?200:req.query.height,width:req.query.width==undefined?300:req.query.width,});}functionresFilter(resolve,reject,connection,resultSet,numRows,filtered){resultSet.getRows(numRows,function(err,rows){if(err){console.log(错误消息);拒绝(错误);}elseif(rows.length==0){resolve(filtered);process.nextTick(function(){oracle.releaseConnection(connection);});}elseif(rows.length>0){filtered.push(rows[0]);resFilter(解决,拒绝,连接,resultSet,numRows,过滤);}});}functioncreateQuerySingleDeviceDataPromise(req,res,device_id,start_time,end_time){returnoracle.getConnection().then(function(connection){returnoracle.execute("SELECT\DEVICE.DEVICEID,\DEVICECODE,\DEVICENAME,\UNIT,\ANALOGYVALUE,\DEVICEHISTROY.RECTIME\FROM\DEVICEINNERJOINDEVICEHISTROY\ON\DEVICE.DEVICEID=DEVICEHISTROY.DEVICEID\WHERE\DEVICE.DEVICEID=:device_id\ANDDEVICEHISTROY.RECTIME\BETWEEN:start_timeAND:end_time\ORDER\BYRECTIME",[device_id,start_time,end_time],{outFormat:oracle.OBJECT,resultSet:true},connection).then(函数(结果){varfiltered=[];varfilterGap=Math.floor((end_time-start_time)/(120*100));returnnewPromise(function(resolve,reject){resFilter(resolve,reject,connection,results.resultSet,filterGap,filtered);});}).catch(function(err){res.status(500).json({status:'error',message:err.message});process.nextTick(function(){oracle.releaseConnection(connection);});});});}functionsecureCheck(req,res){让qry=req.query;if(qry.device_ids==undefined||qry.start_time==undefined||qry.end_time==undefined){thrownewError('device_ids或start_time或end_time参数为undefined');}if(req.query.end_time

猜你喜欢