主頁 > 軟體設計 > 利用nodemcu和mqtt協議讓嵌入式設備接入互聯網(三.實作資料互動)

利用nodemcu和mqtt協議讓嵌入式設備接入互聯網(三.實作資料互動)

2021-08-22 07:08:15 軟體設計

文章目錄

  • 前言
  • KOA2框架
    • koa2初步使用
      • koa示例代碼解釋
    • koa-static中間件
  • Aedes
    • mqtt協議
    • 用aedes創建broker并測驗
    • MQTT server over WebSocket
      • http協議和websocket
      • mqtt over websocket
    • 后端
    • 前端腳本
    • 測驗

前言

我們已經搭建好了開發環境,并且已經設計好了UI界面,現在就要正式撰寫后端軟體,來進行資料互動,先來介紹這些第三方依賴包,

KOA2框架

基于nodejs的web框架有很多,討論最多的就是express和koa2,express生態最好,用的最多,而koa2是express的原班人馬打造,相當于express的升級版,我個人的原則是:學就學最新的,除非學不會,所以我選用koa2框架,
推薦B站這個教程,koa教程,說實話因為之前沒接觸過web相關的知識,理解這些路由和中間件等概念,還是讓我頭痛了一陣,就算現在我也不能保證我理解的完全正確,但基本能實作我現在想要的功能,歡迎指正批評,而且想學好KOA和nodejs還是要花費很多功夫的,我目前這樣的淺嘗輒止的程度還是不夠的,有機會繼續深入研究,
在這篇文章中不系統總結(還沒學到位),只解釋我用到的一些東西,

koa2初步使用

我們現在專案目錄中新建一個index.js檔案,然后鍵入以下代碼

//引入Koa
const koa=require('koa');
const app=new koa();
//配置中間件
app.use( async (ctx)=>{
 ctx.body='hello koa2'
})
//監聽埠
app.listen(3000);
//本地終端列印log
console.log('[demo] start-quick is starting at port 3000')

然后在瀏覽器中訪問localhost:3000或者127.0.0.1:3000(一個意思),可以看到,字串’hello koa2’就出現在網頁中了,

在這里插入圖片描述PS :

  • javascript的字串可以用單引號也可以用雙引號,
  • javascript每條陳述句可以不加分號,只敲回車,也能正常運行,但最好加,因為不是不需要分好,而是JS剖析器會在執行期間自動幫你插入分號,

koa示例代碼解釋

引入模塊用require,require是CommonJS規范引入模塊的方法,而對于最新的ES6規范,引入模塊的方法是import,關于這兩種規范引入模塊方法的錯雜和歷史以后我有機會再整理,我們只跟著npm官網,包的使用教程來使用,npm官網koa,官網怎么用,我們怎么用,參考模塊后,再用new關鍵字,對模塊進行實體化,
在這里插入圖片描述

//配置中間件
app.use( async (ctx)=>{
 ctx.body='hello koa2'
})

這里的中間件的概念,官方沒給定義,koa中文網給的解釋是

中間件就是匹配路由之前或者匹配路由完成做的一系列的操作,我們就可以把它叫做中間件

我的理解是,中間件就是一個插件,也可以理解為一個函式,當用戶請求時,要經過中間件的處理,生成回應時也要經過中間件的處理,處理順序符合洋蔥模型詳細解釋,

在這里插入圖片描述

和=>這種匿名函式的寫法,都請移步到B站的視頻學習koa教程,
最后使用app.listen方法,對3000埠進行監聽,這個函式必須呼叫,否則瀏覽器訪問網址時,發出的GET、POST請求都無法回應,那么我的網址也是無法訪問的,

//監聽埠
app.listen(3000);

要注意nodejs的編程,不同于C或其他的一些語言順序性、程序性比較強,nodejs更偏向于事件驅動,函式呼叫也都是異步的,如果想同步,順序的執行某些回呼函式,就得用asyncawait的組合,

koa-static中間件

koa-static是一個用來加載靜態資源的中間件,我們第一章寫的index.html檔案想要它通過訪問網址,加載到網頁上,就需要用koa-static這個中間件,首先我們去看npm官網的例子

const serve = require('koa-static');
const Koa = require('koa');
const app = new Koa();
 
// $ GET /package.json
app.use(serve('.'));
 
// $ GET /hello.txt
app.use(serve('test/fixtures'));
 
// or use absolute paths
app.use(serve(__dirname + '/test/fixtures'));
 
app.listen(3000);
 
console.log('listening on port 3000');

上面的官方例子代表了koa-static中間件訪問靜態資源的三種情況,第一種訪問當前目錄,在當前目錄找index.html這個檔案,然后顯示到網頁中去,第二種訪問相對路徑,test/fixtures檔案夾下找index.html這個檔案,第三種絕對路徑,__dirname是nodejs全域物件,代表的是當前目錄,

Aedes

Aedes是一個Stream-based MQTT broker,基于流的MQTT代理,所謂broker(代理),可以理解為服務器,所有的mqtt節點的話題發布和訂閱都要經過broker,關于MQTT代理,還有一個包是mosca,也能起到相同的作用,mosca和Aedes是同一個人開發的,github網址moscajs,只不過mosca已經不維護了,Aedes是mosca的升級版本,

mqtt協議

MQTT(Message Queuing Telemetry Transport,訊息佇列遙測傳輸協議),是一種基于發布/訂閱(publish/subscribe)模式的"輕量級"通訊協議,該協議構建于TCP/IP協議上,由IBM在1999年發布,MQTT最大優點在于,可以以極少的代碼和有限的帶寬,為連接遠程設備提供實時可靠的訊息服務,作為一種低開銷、低帶寬占用的即時通訊協議,使其在物聯網、小型設備、移動應用等方面有較廣泛的應用,

mqtt的協議的作業方式就如下圖,broker類似于一個平臺,任何機器都可以在平臺上發布話題(Publish),任何機器也可以訂閱想要看到的話題(Subscribe),這要就能使得每個支持mqtt協議的設備網路互聯,實作所謂的萬物互聯,這里有一個Qos(服務質量等級)的概念,有Qos0、Qos1、Qos2三個等級,

質量等級解釋
Qos0發送者只發一次
Qos1發送者至少發送一次,確保broker收到
Qos2發送者至少發送一次,確保broker收到,且只收到一次

這里的Qos2只是理想,并沒有broker支持,

在這里插入圖片描述

用aedes創建broker并測驗

參考github的aedes官方庫的示例鏈接,我們直接在index.js敲以下代碼,然后在終端啟動,命令
node .\index.js

const aedes = require('aedes')()
const server = require('net').createServer(aedes.handle)
const port = 1883

server.listen(port, function () {
  console.log('server started and listening on port ', port)
})

這里我們已經啟動了一個broker,我們再利用工具來測驗一下,windows10電腦端,在應用商店下載MQTTBox這個應用,點擊creat mqtt client后,填入我們的Ip地址和埠號,協議選擇mqtt/tcp,
在這里插入圖片描述
保存設定后,來到下面這個頁面,左邊發布個mytopic話題,填入資料,右邊我們訂閱自己發布的話題,點擊發布,就可以收到資訊了,
在這里插入圖片描述
當然,我們也可以用其他客戶端進行訂閱,在手機應用商店搜索mqtt,我用的是EasyMQTT這個APP,填入broker的ip和埠號,手機同樣能收到MQTTBox發布的mytopic話題的資訊,
在這里插入圖片描述

MQTT server over WebSocket

我們已經搭建出了mqtt的broker,現在就要考慮怎么將mqtt的話題里的payload傳遞到web端,

http協議和websocket

web網頁常用的通訊協議是HTTP和websocket,像我們前面使用koa中間件發送"hello koa2"字串,雖然這里面經過了koa2的封裝,我們看不到http協議的請求和回應,但這實際上就是一個基于http協議的通訊,
例如這個例子,我們用瀏覽器訪問3000埠,發現我們的請求時GET,response是"hello koa2",

在這里插入圖片描述
response是"hello koa2"

在這里插入圖片描述
ps: 這里的favicon.ico,是去請求小圖示,小圖示就是瀏覽器每個標簽上左側的小圖示,

在這里插入圖片描述
包括后面koa-static中間件,也是封裝了http協議,去請求一個靜態的頁面,HTTP協議是一個單向協議,客戶端放松請求(GET/POST),服務器發送回應,當連接的速度要求不高和只請求一次的場景下,使用HTTP協議, 當需要服務器主動向客戶端推送訊息,并且連接速度需要比較快,資料需要經常更新的場景下,我們使用的就應該是websocket協議了,

mqtt over websocket

對于我們這個場景,每個nodemcu都是一個mqtt客戶端,web網頁也應該是一個mqtt客戶端,nodejs既是mqtt的broker(代理),也是web網頁的服務器,用nodejs 的好處就凸顯出來了,我們可以將mqtt的broker和web服務器,寫在同一個nodejs腳本里,首先我們看官方例程,
在這里插入圖片描述
例程中的ws.createServer({server:httpServer},aedes.handle),我在其git倉庫中沒有找到回應的解釋,但通過試驗,其功能應該是將mqtt協議的資訊流傳給websocket的資訊流,
ps:var=require('模塊')()等價于先參考模塊,再實體化,但并不是所有的模塊都支持這種寫法,應該與封裝匯出的方式相關,

//下面兩行等效于 
aedes=require('aedes')();
// const Aedes = require('aedes');
// var aedes=new Aedes();

后端

koa、koa-static、aedes、websocket-stream這三個依賴包都講了下,可以開始寫我們的nodejs程式了,
這里我們用到3個埠,1883埠用于mqtt broker,8888用于http模塊創建的websocket,5000埠用于koa2創建的http服務器,其實應該可以直接用koa2框架里的工具來創建websocket的,但是我這里暫時是修改的官方例子,沒有去探究怎么用koa2來實作websocket通訊,
其實這里面有兩個http服務器,一個是8888埠,只用于websoket的,一個是5000埠,用于koa2加載靜態資源的,有時間,會去把他們簡化一些,

const Koa = require('koa');
const static = require('koa-static');
//const path = require('path');
//--------------------------------------------//
//下面兩行等效于 
aedes=require('aedes')();
// const Aedes = require('aedes');
// var aedes=new Aedes();
//--------------------------------------------//
//-----------------------MQTT broker creat----------------------- 

const broker = require('net').createServer(aedes.handle);
const httpServer = require('http').createServer();
const ws = require('websocket-stream');
const port = 1883;
const wsPort = 8888;

broker.listen(port, function () {
  console.log('broker listening on port', port)
});

ws.createServer({
  server: httpServer
}, aedes.handle);

httpServer.listen(wsPort, function () {
  console.log('websocket server listening on port', wsPort)
});

//身份驗證
aedes.authenticate = function (client, username, password, callback) {
    callback(null, (username === 'user' && password.toString() === '123456'));
};

// 客戶端連接
aedes.on('client', function (client) {
    console.log('Client Connected: \x1b[33m' + (client ? client.id : client) + '\x1b[0m', 'to broker', aedes.id);
});
// 客戶端斷開
aedes.on('clientDisconnect', function (client) {
    console.log('Client Disconnected: \x1b[31m' + (client ? client.id : client) + '\x1b[0m', 'to broker', aedes.id);
});

//-----------------------MQTT broker creat----------------------- 

var app = new Koa();
//const staticPath = './static';
//app.use(static(path.join(__dirname, staticPath)));
app.use(static('./static'));

app.listen(5000, () => { console.log('server start on port 5000'); });

至此,我們的后端和前端就都搭建好了,可以先脫離nodemcu硬體,用MQTTBox或者手機端的進行資料互動的測驗,

前端腳本

第一章我們我們搭建好了UI,引入了兩個腳本,其中mqtt.min.js是在npm庫unpkg網站上下載的,當然我們也可以用下面注釋的方式來參考它,這個腳本的作用,是讓我們可以在前端的javascript腳本里使用mqtt協議,

	<!-- <script src="https://unpkg.com/mqtt@4.2.8/dist/mqtt.min.js"></script> -->
    <script src="./mqtt.min.js"></script>
    <script src="./webclient.js" charset="utf-8"></script>

參考完mqtt.min.js的腳本后,我們就可以在javascript腳本里使用mqtt腳本的方法了,
注意,腳本第一行的mqtt.connect函式里填寫的url可以是多種形式的,這里推薦ws://協議的形式,當然也可以是mqtt://192.168.3.113:8888,但如果是大家用的也是mqtt@4.2.8版本的,就會報錯,這個錯是官方的錯,見該博客,其實修改成4.0.0版本的mqtt.min.js版本就不會有問題,其實不管什么url,連的其實還是websocket的埠,
在這里插入圖片描述

webclient.js

const client = mqtt.connect('ws://192.168.3.113:8888', {
  username: "user",
  password: '123456'
});
// const client = mqtt.connect('mqtt://192.168.3.113:1883', {
//   username: "user",
//   password: '123456'
// });

client.subscribe("carinfo");
client.subscribe("steerbutton");

client.on("connect", function () {
  console.log("服務器連接成功");
  console.log(client.options.clientId);
  client.subscribe("carinfo", { qos: 1 }); // 訂閱text訊息
});

client.on("message", function (top, message) {
   console.log("當前topic:", top);
   console.log(message.toString());
  let messagestring=message.toString();
  let stringafersplit=messagestring.split(",");
  let throttle=stringafersplit[0];
  let brake=stringafersplit[1];
  let steer=stringafersplit[2];
  let rotationspeed=stringafersplit[3]
  let SOC=stringafersplit[4]
  document.getElementById('throttle').innerHTML = throttle + '%';
  document.getElementById('brake').innerHTML =  brake + '%';
  document.getElementById('steer').innerHTML = steer + "°";
  document.getElementById('rotationspeed').innerHTML = rotationspeed + "rpm";
  document.getElementById('SOC').innerHTML=SOC+'%';
});

// setInterval(() => {
//     steer = steer + 1;
//     document.getElementById('throttle').innerHTML = throttle + '%';
//     document.getElementById('brake').innerHTML = brake + '%';
//     document.getElementById('steer').innerHTML = steer + "°";
// }, 10)

原始碼如上,先連上broker,然后訂閱carinfo這個話題,在message的事件中,我們利用DOM對html中的內容進行賦值DOM教程

測驗

我們先用MQTTBox工具進行測驗,首先在終端開啟服務器,
在這里插入圖片描述
可以看到,三個埠都在正常監聽的狀態,然后我們在瀏覽器中訪問,192.168.3.113:5000這個地址,當然任何連如同一個網路的電腦和手機都可以訪問,網頁如下,
在這里插入圖片描述

再打開MQTTBox,配置如下,
在這里插入圖片描述
此時可以在服務器的終端看到,兩個mqtt客戶端已經連上了broker,
在這里插入圖片描述
這里我們通過MQTTBox,發布carinfo話題,payload隨便填一些資訊,點擊publish.在這里插入圖片描述
網頁端可以看到,我們發送的資訊已經在網頁端更新了,
在這里插入圖片描述
到此為止我們已經完成了后端和前端的代碼,只剩下嵌入式設備的接入了,原始碼鏈接,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/295375.html

標籤:其他

上一篇:實時資料引擎系列(一): 新鮮的資料流

下一篇:nginx為什么不采用多執行緒管理連接及處理邏輯業務

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more