本節(jié)主要是結(jié)合實(shí)例代碼,詳細(xì)說明使用Node.js和Express創(chuàng)建服務(wù)端的方法。
服務(wù)端的主要功能
- 連接數(shù)據(jù)庫,并能和數(shù)據(jù)庫交互;
- 為數(shù)據(jù)庫創(chuàng)建兩個(gè)集合,分別用來存儲傳感器數(shù)據(jù)和LED燈的狀態(tài);
- 接收來自傳感器上傳來的數(shù)據(jù)(以溫度傳感器為例),并保存到數(shù)據(jù)庫中;
- 從數(shù)據(jù)庫中獲取傳感器的數(shù)據(jù),形成JSON格式的數(shù)據(jù),供客戶端調(diào)用;
- 修改LED燈的狀態(tài),實(shí)現(xiàn)開關(guān)燈。
服務(wù)端的創(chuàng)建步驟
1.在整個(gè)項(xiàng)目的文件夾iot中新建一個(gè)文件夾server,專門用來存放服務(wù)端的所有文件。
mkdir server
2.在server文件夾中,新建一個(gè)文件package.json,主要是列出一些必要的依賴。
文件內(nèi)容參考如下:
{
"name": "iot",
"version": "0.1.0",
"description": "A sample Node.js app using Express 4",
"engines": {
"node": "5.9.1"
},
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"devDependencies": {
"mongoose": "^4.6.2",
"body-parser": "^1.15.2",
"cors": "^2.8.0",
"express": "^4.14.0",
"method-override": "^2.3.6",
"morgan": "^1.7.0",
"silly-datetime": "^0.1.2"
}
}
然后,執(zhí)行下面的命令安裝這些依賴。
npm install (如果安裝有cnpm,用cnpm install)
有關(guān)依賴的作用說明:
- Mongoose: 幫助我們和MongoDB進(jìn)行交互
- Express:用來創(chuàng)建API路由
- Body Parser:幫助我們獲取來自POST請求的信息
- Method Override:提供了對DELETE和PUT的支持
- Morgan:輸出一些有用的調(diào)試信息
- Cors:處理CORS (跨域資源共享,Cross Origin Resource Sharing)問題
- silly-datetime:用來獲取當(dāng)前時(shí)間
3.創(chuàng)建服務(wù)端核心文件server.js,文件內(nèi)容參考如下:
//Set up(設(shè)置)
var express=require('express');
var app=express();
var mongoose=require('mongoose');
var morgan=require('morgan');
var bodyParser=require('body-parser');
var methodOverride=require('method-override');
var cors=require('cors');
var sd=require('silly-datetime');
//Configuration(配置)
mongoose.connect('mongodb://localhost/iot');
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({'extended':'true'}));
app.use(bodyParser.json());
app.use(bodyParser.json({type:'application/vnd.api+json'}));
app.use(methodOverride());
app.use(cors());
app.use(function(req,res,next){
res.header("Access-Control-Allow-Origin","*");
res.header("Access-Control-Allow-Headers","Origin,X-Requested-Width,Content-Type,Accept");
next();
});
//Models(模型)
var sensorSchema=new mongoose.Schema({
temperature:Number,
date:String,
time:String
});
var ledSchema=new mongoose.Schema({
status:{type:Boolean,default:false}
});
var sensorModel=mongoose.model('sensor',sensorSchema);
var ledModel=mongoose.model('led',ledSchema);
//Routes(路由)
app.get('/sensor',function(req,res){//從數(shù)據(jù)庫中獲取傳感器數(shù)據(jù)
sensorModel.find(function(err,data){
if (err)
res.send(err);
res.json(data);
});
});
app.post('/sensor',function(req,res){//獲得新的傳感器數(shù)據(jù),存入數(shù)據(jù)庫中
var cdate=sd.format(new Date(),'YYYY-MM-DD');
var ctime=sd.format(new Date(),'HH:mm');
sensorModel.create({
temperature:req.body.temperature,
date:cdate,
time:ctime
},function(err,state){
if (err)
res.send(err);
sensorModel.find(function(err,data){
if (err){
res.send(err);
}
res.json(data);
});
});
});
app.get('/led',function(req,res){//從數(shù)據(jù)庫中獲取led燈的狀態(tài)
ledModel.find(function(err,data){
if (err)
res.send(err);
res.json(data);
});
});
app.put('/led',function(req,res){//更新Led燈的狀態(tài)
ledModel.update({},{$set:{status:req.body.status}},{upsert:true},function(err,result){
if(err){
res.send(err);
}else{
ledModel.find(function(err,data){
if (err){
res.send(err);
}
res.json(data);
});
}
});
});
//Listen(監(jiān)聽)
app.listen(3000);
然后,執(zhí)行下面的命令運(yùn)行服務(wù)端:
node server.js
代碼要點(diǎn)分析:
- server.js文件包括5個(gè)部分,分別是設(shè)置、配置、模型、路由和監(jiān)聽;
- 在設(shè)置部分,引入了所需要的模塊,如express、mongoose等;
- 在配置部分,用mongoose連接到數(shù)據(jù)庫iot;
- 在模型部分,用mongoose建立了兩個(gè)集合,即sensors和leds,分別用來存儲傳感器數(shù)據(jù)和Led燈的狀態(tài);
- 在路由部分,創(chuàng)建了三個(gè)API路由,分別用到了express的get、post和put方法,并相應(yīng)用到了mongoose的find、create和update方法,分別實(shí)現(xiàn)了從數(shù)據(jù)庫中獲取傳感器數(shù)據(jù)、將獲得的傳感器數(shù)據(jù)存入數(shù)據(jù)庫以及更新Led燈的狀態(tài)。
- 在ledModel.update()方法中,upsert:true選項(xiàng)的意思是如果找到了匹配數(shù)據(jù)即更新,如果沒有找到,即插入一條數(shù)據(jù)。
4.對服務(wù)端進(jìn)行必要的測試:
首先,運(yùn)行服務(wù)端。
運(yùn)行服務(wù)端
然后,打開mongo命令行窗口,使用iot數(shù)據(jù)庫,執(zhí)行查詢命令,查看文檔內(nèi)容為空。
mongo窗口
用curl命令進(jìn)行路由的測試。
執(zhí)行curl命令
在mongo窗口中,再次執(zhí)行查詢命令,可以看到剛才用curl命令插入或更新的文檔內(nèi)容。
再次執(zhí)行查詢
至此,服務(wù)端搭建完畢,接下來,我們就可以在客戶端通過圖形的方式實(shí)時(shí)地、直觀地將傳感器數(shù)據(jù)顯示出來,并且可以實(shí)時(shí)改變Led的狀態(tài)。