国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Node.js + React Native 畢設:農業物聯網監測系統的開發手記

renweihub / 784人閱讀

摘要:所幸,鄙人所在的硬件專業,指導老師并不懂軟件,他只是想要一個農業物聯網的監測系統,能提供給我的就是一個數據庫,帶著一個物聯網系統運行一年所保存的傳感器數據。該物聯網監測系統整體上可分為三層數據庫層,服務器層和客戶端層。的執行是同步的。

畢設大概是大學四年里最坑爹之一的事情了,畢竟一旦選題不好,就很容易浪費一年的時間做一個并沒有什么卵用,又不能學到什么東西的雞肋項目。所幸,鄙人所在的硬件專業,指導老師并不懂軟件,他只是想要一個農業物聯網的監測系統,能提供給我的就是一個Oracle 11d數據庫,帶著一個物聯網系統運行一年所保存的傳感器數據...That"s all。然后,因為他不懂軟件,所以他顯然以結果為導向,只要我交出一個移動客戶端和一個服務端,并不會關心我在其中用了多少坑爹的新技術。

那還說什么?上!我以強烈的惡搞精神,決定采用業界最新最坑爹最有可能爛尾的技術,組成一個 Geek 大雜燴,幻想未來那個接手我工作的師兄的一臉懵逼,我露出了邪惡的笑容,一切只為了滿足自己的上新欲。

全部代碼在 GPL 許可證下開源:

服務端代碼:https://github.com/CauT/the-wall

客戶端代碼:https://github.com/CauT/Night...

由于數據庫是學校實驗室所有,所以不能放出數據以供運行,萬分抱歉~。理論上應該有一份文檔,但事實上太懶,不知道什么時候會填坑~。

總體架構

OK,上圖說明技術框架。


?
該物聯網監測系統整體上可分為三層:數據庫層,服務器層和客戶端層。

數據庫和代碼層

數據庫層除了原有的Oracle 11d數據庫以外,還額外增加了一個Redis數據庫。之所以增加第二個數據庫,原因為:

Node.js 的 Oracle 官方依賴 node-oracledb 沒有ORM,也就是說,所有的對數據庫的操作,都是直接執行SQL語句,簡單粗暴,我擔心自己孱弱的數據庫功底(本行是 Android 開發)會引發鎖表問題,所以通過限制只讀來避開這個問題。

由于該系統服務于農業企業的內部管理人員,因此其賬號數量和總體數據量必然有限,因此使用 redis 這種內存型數據庫,可以不必考慮非關系型數據庫在容量占用上的劣勢。讀取速度反而較傳統的 SQL 數據庫有一定的優勢。

使用非關系型數據庫比關系型數據庫好玩多了(霧

之所以寫了右邊的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模式來處理多異步的邏輯過程。如下代碼所示:

function renderGraph(req, res, filtereds) {
  var x = [];    
  var ys = [];
  var titles = [];

  filtereds[0].forEach(function(row) {
    x.push(getLocalTime(row.RECTIME));
  });

  filtereds.forEach(function(filtered){
    if (filtered[0] == undefined)
      // even if at least one of multi query was succeed
      // fast-fail is essential for secure
      throw new Error("數據庫返回結果為空");
    var y = [];
    filtered.forEach(function(row) {
      y.push(row.ANALOGYVALUE);
    });
    ys.push(y);
    titles.push(filtered[0].DEVICENAME + ": " + filtered[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,
  });
}

function resFilter(resolve, reject, connection, resultSet, numRows, filtered) {
  resultSet.getRows(
    numRows,
    function (err, rows)
    {
      if (err) {
        console.log(err.message);
        reject(err);
      } else if (rows.length == 0) {
        resolve(filtered);
        process.nextTick(function() {
          oracle.releaseConnection(connection);
        });
      } else if (rows.length > 0) {
        filtered.push(rows[0]);
        resFilter(resolve, reject, connection, resultSet, numRows, filtered);
      }
    }
  );
}

function createQuerySingleDeviceDataPromise(req, res, device_id, start_time, end_time) {
  return oracle.getConnection()
  .then(function(connection) {
    return oracle.execute(
      "SELECT
        DEVICE.DEVICEID,
        DEVICECODE,
        DEVICENAME,
        UNIT,
        ANALOGYVALUE,
        DEVICEHISTROY.RECTIME
      FROM
        DEVICE INNER JOIN DEVICEHISTROY
      ON
        DEVICE.DEVICEID = DEVICEHISTROY.DEVICEID
      WHERE
        DEVICE.DEVICEID = :device_id
        AND DEVICEHISTROY.RECTIME
        BETWEEN :start_time AND :end_time
      ORDER
        BY RECTIME",
      [
        device_id,
        start_time,
        end_time
      ],
      {
        outFormat: oracle.OBJECT,
        resultSet: true
      },
      connection
    )
    .then(function(results) {
      var filtered = [];
      var filterGap = Math.floor(
        (end_time - start_time) / (120 * 100)
      );
      return new Promise(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);
      });
    });
  });
}

function secureCheck(req, res) {
  let qry = req.query;

  if (
    qry.device_ids == undefined
    || qry.start_time == undefined
    || qry.end_time == undefined
  ) {
    throw new Error("device_ids或start_time或end_time參數為undefined");
  }

  if (req.query.end_time < req.query.start_time) {
    throw new Error("終止時間小于起始時間");
  }
};

router.get("/", function(req, res, next) {
  try {
    var device_ids;
    var queryPromises = [];

    secureCheck(req, res);

    device_ids = req.query.device_ids.toString().split(";");

    for(let i=0; i

這是生成指定N個傳感器在一段時間內的折線圖的邏輯。顯然,剖析業務可知,我們需要在數據庫中查詢N次傳感器,獲得N個值對象數組,然后才能去用N組數據渲染出圖表的HTML頁面。 可以看到,外部核心的Promise控制的流程只集中于下面的幾行之中:Promise.all(queryPromises()).then(renderGraph()).catch()。即,只有獲取完N個傳感器的數值之后,才會去渲染圖表的HTML頁面,但是這N個傳感器的獲取過程卻又是并發進行的,由Promise.all()來實現的,合理地利用了有限的機器性能資源。

然而,推入queryPromises數組中的每個Promise對象,又構成了自己的一條Promise邏輯鏈,只有這些子Promise邏輯鏈被處理完了,才可以說整個all()函數都被執行完了。子Promise邏輯鏈大致地可以總結為以下形式:

function() {    
    return new Promise().then().catch();
}

其中的難點在于:

合理地切分整套業務邏輯到不同的then()函數中,且一個then()中只能有一個異步過程。

函數體內的異步過程所產生的新的Promise邏輯鏈必須被通過return的方式掛載到父函數的Promise邏輯鏈中,否則即可能形成一個有先有后的控制流程。

catch()函數必須要做好捕捉和輸出錯誤的處理,否則代碼編寫過程中的錯誤即不可能被發現,異步編程的整個過程也就無從繼續下去了。

值得一提的是Promise模式的引入。Node.js 自身不帶有Promise,可以引入標準的ECMAScript的Promise實現,然而其功能較為簡陋,對于各種API的實現過于匱乏,因此最后選擇了bluebird庫來引入Promise模式的語言支持。

由此我們可以看到,沒有無緣無故的高性能。Node.js 的高并發的優良表現,是用異步編程的高復雜度換來的。當然,你也可以選擇不要編程復雜度,即不采用 Promise,Asnyc 等等異步編程模式,任由代碼淪入回調地獄之中,那么這時候的代價就是維護復雜度了。其中取舍,見仁見智。

客戶端層

客戶端主要功能如下表所示:

?

接下來簡單介紹下幾個主要頁面。可以發現 iOS 明顯比 Android 要來的漂亮,因為只對 iOS 做了視覺上的細調,直接遷移到 Android 上,就會由于屏幕顯示的色差問題,顯得非常粗糙。所以,對于跨平臺的 React Native App 來說,做兩套色值配置文件,以供兩個平臺使用,還是很有必要的。

?

上圖即是土壤墑情底欄的當前數據頁面,分別在Android和iOS上的顯示效果,默認展示所有當前的傳感器的數值,可以通過選擇傳感器種類或監測站編號進行篩選,兩個條件可以分別設置,選定后再點擊查找,即向服務器發起請求,得到數據后刷新頁面。由于React Native 的組件化設計,刷新將只刷新下側的DashBoard部分,且,若有上次已經渲染過的MonitorView,則會復用他們,不再重復渲染,從而實現了降低CPU占用的性能優化。MonitorView,即每一個傳感器的展示小方塊,自上至下依次展示了傳感器種類,傳感器編號,當前的傳感器數值以及該傳感器顯示數值的單位。MonitorView和Dashboard均被抽象為一個一般化,可復用的組件,使之能夠被利用在氣象信息、病蟲害監測之中,提升了開發效率,降低了代碼的重復率。

?

上圖是土壤墑情界面的歷史數據界面,分別在Android和iOS上的展示效果,默認不會顯示數據,直到輸入了傳感器種類和監測站編號,選擇了年月日時間后,再點擊查找,才會得到結果并顯示出來。該界面并非如同當前數據界面一樣,Android和iOS代碼完全共用。原因在于選擇月日和選擇時間的控件,Android和iOS系統有各自的控件,它們也被封裝為React Native中不同的控件,因此,兩條綠色的選擇時間的按鈕,被封裝為HistoricalDateSelectPad,分別放在componentIOS和componentAndroid文件夾中。界面下側的數據監測板,即代碼中的Dashboard,是復用當前數據中的Dashboard。

?

上圖是土壤墑情界面的圖表生成界面,分別在Android和iOS上的展示效果。時間選擇界面,查找按鈕,選擇框,均可復用前兩個界面的代碼,因此無需多提。值得說的是,生成的折線圖,事實上是通過內嵌的WebView來顯示一個網頁的。圖表網頁的生成,則依靠的百度Echarts 第三方庫,然后服務端提供了一個預先寫好的前端模板,Express框架填入需要的數據,最后下發到移動客戶端上,渲染生成圖表。圖表支持了多曲線的刪減,手指選取查看具體數據點,放大縮小等功能。

?

上圖則是實際項目應用中的Redux相關文件的結構。stores中存放全局數據store相關的實現。

actions中則存放根據模塊切割開的各類action生成函數集合。在 Redux 中,改變 State 只能通過 action。并且,每一個 action 都必須是 Javascript Plain Object。事實上,創建 action 對象很少用這種每次直接聲明對象的方式,更多地是通過一個創建函數。這個函數被稱為Action Creator。

reducers中存放許多reducer的實現,其中RootReducer是根文件,它負責把其他reducer拼接為一整個reducer,而reducer就是根據 action 的語義來完成 State 變更的函數。Reducer 的執行是同步的。在給定 initState 以及一系列的 actions,無論在什么時間,重復執行多少次 Reducer,都應該得到相同的 newState。

性能測試 服務端

測試工具:OS X Activity Monitor(http_load)

?

客戶端
iOS

測試工具:Xcode 7.3

?

Android

測試工具:Android Studio 1.2.0

?

代碼量相關

?

簡單總結

React Native 盡管在開發上具有這樣那樣的坑,但是因其天生的跨平臺,和優于 Html5的移動性能表現,使得他在寫一些不太復雜的 App 的時候,開發速度非常快,自帶兩倍 buff。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80619.html

相關文章

  • 幾種典型智慧農業聯網解決方案

    摘要:本文分享幾種典型具有實際應用過的智慧農業物聯網解決方案,供大家參考。智慧農業物聯網解決方案由三部分組成智慧農業物聯網平臺智慧農業物聯網網關無線節點。 智慧農業是現代農業發展的必然趨勢,也是科學技術發展的必然結果。本文分享幾種典型具有實際應用過的智慧農業物聯網解決方案,供大家參考。 結合多年與...

    animabear 評論0 收藏0
  • 河北信息服務業“十三五”規劃重點推云計算

    摘要:建立面向中小企業的信息化服務云計算平臺,為中小企業提供生產管理財務管理營銷管理人力資源管理等云計算服務。  《河北省信息服務業十三五發展規劃》明確,十三五期間,河北省將重點推進云計算服務能力促進工程、云計算創新能力提升工程、云計算服務應用示范工程、電子政務集約化建設工程、數據資源開發共享工程、云計算產業鏈發展培育工程、云計算基礎設施建設工程、云計算安全保障建設工程等八大工程,統籌規劃建設云上...

    gnehc 評論0 收藏0
  • 最流行編程語言 JavaScript 能做什么?

    摘要:首先很遺憾的一點是,雖然是最好的語言,但是它不是最流行的語言。屬于配置比較高的硬件,而低配的呢三星設計了引擎,它能夠運行在小于內存上,且全部代碼能夠存儲在不足的只讀存儲上。你覺得還能做什么 首先很遺憾的一點是,PHP雖然是最好的語言,但是它不是最流行的語言。showImg(https://segmentfault.com/img/bVvqTs);同時對不起的還有剛剛在4月TIOBE編程...

    褰辯話 評論0 收藏0
  • 最流行編程語言 JavaScript 能做什么?

    摘要:首先很遺憾的一點是,雖然是最好的語言,但是它不是最流行的語言。屬于配置比較高的硬件,而低配的呢三星設計了引擎,它能夠運行在小于內存上,且全部代碼能夠存儲在不足的只讀存儲上。你覺得還能做什么 首先很遺憾的一點是,PHP雖然是最好的語言,但是它不是最流行的語言。showImg(https://segmentfault.com/img/bVvqTs);同時對不起的還有剛剛在4月TIOBE編程...

    Alan 評論0 收藏0
  • 翻譯 | 擺脫瀏覽器限制JavaScript

    摘要:在考慮宇航員的生命安全時,輕微的打嗝或者服務中斷都會釀成生死事故。也許最大的挑戰來自谷歌主導的簡稱。在最近的開發者峰會,以及今年的會議上,谷歌都為安排了大量討論。由微軟提供,是廣受歡迎的編輯器,到月份已經獲得了超過五百萬用戶。 譯者:安冬 (滬江Web前端開發工程師)本文原創翻譯,轉載請注明作者及出處。原文地址:http://developer.telerik.com/... 技術世界...

    xfee 評論0 收藏0

發表評論

0條評論

renweihub

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<