標籤:
時間過得很快,6月和7月忙的不可開交,糟心的事兒也是不少,杭州大連來回飛,也是呵呵。
希望下個階段能沉浸下來,接著學自己想學的。記一下上幾周用了幾天時間寫的課設。因為課設的緣故,所以在短時間裡瞭解下express+mongodb的組合,給APP端搭了個簡易的伺服器,也開了後台網站的web服務。簡單總結一下開發過程中遇到的坑。
一、關於express
瞭解node.js有半年多,第一次用node.js的架構來寫server,瞭解不是很深,簡單看了一下文檔之後就可以上手了,開發入門難度低。
1.運行
express init之後以為是node app.js命令運行項目,結果卻並不是。app.js是項目入口檔案不錯,但是本身也是一個module模組,app.js的代碼裡面並沒有listenserver的操作,express的腳手架命令把項目啟動交給了bin/www檔案,需要通過npm start啟動應用。
通過npm start的應用好像並不能即時重啟[?],所以可以把www檔案轉移至[new]start.js並運行node start.js,就可通過supervisor或者nodemon來自動監控&重啟應用了。
2.中介軟體
express是基於中介軟體的。通過引入中介軟體執行處理函數,例如在處理一個get請求的時候會根據路由情況在app.js裡順序執行函數,app.use(‘/admin‘, admin)就會處理所有localhost/admin下的請求,具體的第二級路由處理就交給了route/admin.js。這個課設裡我只自己定義了一個中介軟體cookie-checker,用於登入識別。在java或者php裡面可以通過filter或者入口模組檢測的方式來檢測cookie、判斷登入,express裡面就剛簡化了,直接定義個cookie-checker中介軟體,放在了app.use(‘/api‘,api)和app.use(‘/admin‘, admin)中間,這樣所有的api請求(app端)無需cookie檢測,而admin下的請求全部需要經過登入檢測操作,整個中介軟體的代碼如下:
exports = module.exports = function(){ return function(req,res,next){ if( req.cookies.gid == undefined || req.cookies.gid == null ){ if( req.path != "/admin/login" ){ res.redirect("/admin/login"); } else{ next(); } } else{ next(); } }}
3.模組引用
express裡面對模組互相引用目測並沒有做什麼處理,當然產生互相引用肯定是我自己代碼的原因。
互相引用具體的位置忘了是哪裡了,但是大概是articleModule.js和favoriteModule.js造成的,在處理mongodb的連表查詢時候的問題。mongodb的連表也是糟心,後來也沒做連表,直接把favorite操作的記錄都add進一張大表裡了。之前兩年一直用的是mysql或者是sqlserver,在實際應用裡nosql的精神還是沒有領會,設計表的時候覺得還挺簡單,實際應用起來就發現跟mysql、sqlserver完全不是一個路數,連表、主鍵、外鍵都沒有。
4.mvc的模式
現在寫個server不基於mvc都不好意思說自己是寫server的。express裡面做的還是不錯的,route、view、modules。
route下是路由檔案,用於處理路由請求,並且根據請求調用對應module的函數。所有的請求都是通過req、res、next來操作,內建函式大多是基於回調的。view下所有的模板檔案,課設裡面使用的是jade,感覺和smarty等範本語言沒什麼功能區別,映射、分布視圖、公用模組、模板繼承、if-else等邏輯判斷,該有的都有,jade的文法倒是變了,寫的不是html標籤,節點名稱、縮排控制層級。modules下自訂的原型模組,例如課設裡面大概有這麼幾個module:ad、article、word、user等,模組內部引入mongoose檔案完成增刪改查操作,增刪改查資料庫的函數都是非同步,所以在檔案下大部分函數也都是基於回調的。
例如API路由下的api/wordItem?id=5x23434fa5sk4dhid7a,擷取的是某條句子的資訊。在api.js裡:
/* 單句(id) api/wordItem?id=5x23434fa5sk4dhid7a */router.get(‘/wordItem‘, function(req, res, next) { var _id = req.query.id; var _user = req.query.uid || -1; word.findById(_id,function(err,data){ if( err ){ data._id = -1; } favorite.check({t_id:data._id,user_id:_user},function(_f){ data.flag = _f; res.send( data ); }); });});
在word.js裡面:
//根據ID擷取word條目var Word = mongodb.mongoose.model("word", wordSchema);var wordModel = function(){};//...wordModel.prototype.findById = function(_id,callback){ var id = _id || 1; Word.findOne({‘_id‘:id}, function(err, obj){ var itemdata = obj || {_id:-1} ; favorite.getCount({t_id:itemdata._id},function(err,count){ itemdata.favorite = count ; callback(err,itemdata); }); });};
路由判斷---調用word原型的findById函數---函數內部執行mongoose封裝的WordModel的findOne操作,查詢結束後執行回調,將err參數和data參數作為形參傳遞給回呼函數。
5.檔案上傳
用的是multer中介軟體,通過json配置直接處理了檔案儲存體位置、上傳回調。
app.use(multer({ dest: ‘public/upload/‘, limits: { fieldNameSize: 100, files: 2, fields: 5 }, onFileUploadComplete: function (file, req, res) { res.flag = true; res.fname = file.name; }, onError: function (error, next) { res.flag = false; res.fname = ""; next(error); }}));
把public檔案夾設定為靜態路由:
app.use(express.static(path.join(__dirname, ‘public‘)));
[node.js]express+mongoose+mongodb的開發筆記