本文轉自:http://blog.csdn.net/yanghua_kobe/article/details/17199417javascript
https://github.com/yanghua/FixedAssetManager_Serverphp
這是一個資產管理項目,主要的目的就是實現對資產的無紙化管理。經過爲每一個資產生成二維碼,來聯合移動終端完成對資產的審覈等。這個項目既提供了Web端的管理界面也提供移動端(Andorid)的資產審覈、派發等相關功能。 咱們用Node.js構建該項目的Web端以及移動端的Serveice API。css
Express 是一個很是流行的node.js的web框架。基於connect(node中間件框架)。提供了不少便於處理http請求等web開發相關的擴展。 Express簡單的結構圖:html
Express的特性:前端
Bootstrap是Twitter推出的一個用於前端開發的開源工具包。它由Twitter的設計師MarkOtto和JacobThornton合做開發,是一個CSS/HTML框架。Bootstrap是簡潔、直觀、強悍的前端開發框架,讓web開發更迅速、簡單。 同時,不少基於Bootstrap的開源插件也讓Bootstrap社區更加活躍。 最新的Bootstrap3提供了很是強的定製化特性。包括Less,jQuery插件等。 Bootstrap 爲您提供了全部這些基本的模塊- Grid、Typography、Tables、Forms、Buttons和Responsiveness。 此外,還有大量其餘有用的前端組件,好比Dropdowns、Navigation、Modals、Typehead、Pagination、Carousal、Breadcrumb、Tab、Thumbnails、Headers等等。 有了這些,你能夠搭建一個Web 項目,並讓它運行地更快速更輕鬆。 此外,因爲整個框架是基於模塊的,你能夠經過定製你本身的CSS來使得它知足你的特殊需求。 它是基於幾種最佳實踐,咱們認爲這是一個很好的開始學習現代Web 開發的時機,一旦你掌握了HTML 和JavaScript/jQuery 的基本知識,你就能夠在Web 開發中運用這些知識。vue
Ember.js是一個JavaScript的MVC框架,它由Apple前僱員建立的SproutCore2.0更名進化而來。 構建一個Ember應用程序,一般會使用到六個主要部件:應用程序(Application)、模型(Model)、視圖(View)、模板(Template)、路由(Routing)和控制器(Controller)。 這裏咱們server端主要依賴express框架,它提供的這些功能跟express有些是相同的。咱們主要應用了Ember的模板組件,Express對於它提供了很好的集成。咱們只須要進行很簡單的配置便可:java
app.set('view engine', 'html'); app.set('views', path.join(__dirname, 'views')); app.set("view options", {layout : false}); app.register('.html', require('ejs'));
should 是用於node.js的一個表述性、可讀性很強的測試無關的「斷言」庫。它是BDD風格的,用一個單例的不可枚舉的屬性訪問器擴展了Object的prototype,容許你表述對象應該展現的行爲。 should的一個特性是能夠支持鏈式斷言,好比:node
user.should.be.an.instanceOf(Object).and.have.property('name', 'tj'); user.pets.should.be.instanceof(Array).and.have.lengthOf(4);
功能簡介:mysql- node.js平臺mysql驅動,支持事務、鏈接池、集羣、sql注入檢測、多作參數傳遞寫法等特性。 主頁地址:https://github.com/felixge/node-mysqlmysql
功能簡介:eventproxy- node.js 異步回調代理。主要用來解決node中深層次回調嵌套的問題,支持不少異步模式:多類型異步、重複異步、持續型異步。 主頁地址:https://github.com/JacksonTian/eventproxyjquery
功能簡介:javascript的驗證工具集,支持兩種模式:check(校驗)/sanitize(處理),同時提供了可擴展的錯誤處理。 主頁地址:http://github.com/chriso/node-validator
功能簡介:embered.jsjavascript 模板引擎(能夠跟express集成,做爲服務端模板引擎) 主頁地址:https://github.com/visionmedia/ejs
功能簡介:loader- 資源加載工具,能夠區分開發模式、發佈模式;在發佈模式下可進行資源壓縮、合併。以實現減小靜態資源帶寬而且便於實現客戶端緩存 主頁地址:https://github.com/TBEDP/loader
功能簡介:canvas - node.js 經常使用的圖形圖像處理庫,是不少其它庫的基礎依賴庫 主頁地址:https://github.com/learnboost/node-canvas
功能簡介:captchagen-node.js經常使用驗證碼圖片處理庫,依賴上面的canvas庫 主頁地址:http://github.com/wearefractal/captchagen
功能簡介:crypto-js- javascript 經常使用加密庫、hash庫封裝,支持sha-x / md5 / hash等各類加密、hash算法 主頁地址:http://github.com/wearefractal/captchagen
功能簡介:nodemailer- 郵件發送工具,支持SMTP等郵件發送協議 主頁地址:http://github.com/andris9/nodemailer
功能簡介:qrcode- node.js服務端的qrcode生成器。支持多種輸出類型(dataUrl/file/bitArray) 主頁地址:http://github.com/soldair/node-qrcode
功能簡介:qrcode- node.js服務端的qrcode生成器。支持多種輸出類型(dataUrl/file/bitArray) 主頁地址:http://github.com/soldair/node-qrcode
功能簡介:excel- node.js excel解析器,支持xlsx(Excel2007+) 主頁地址:https://github.com/trevordixon/excel
功能簡介:excel-export- node.js excel生成器,支持導出excel 主頁地址:https://github.com/functionscope/Node-Excel-Export
功能簡介:net-ping- node.js 對ping的封裝,用於測試目標主機是否可達 主頁地址:https://bitbucket.org/stephenwvickers/node-net-ping
功能簡介:debug- node.js debug工具,對console.log的封裝,支持多種顏色輸出。 主頁地址:https://github.com/visionmedia/debug
npm是管理node.js模塊依賴的工具,依賴於開源技術的優點就是你有很是多的優秀庫能夠幫助你快速構建一個系統,但就像一把雙刃劍,因爲開源致使版本的升級不可控。這時,一個集中性的模塊依賴管理工具的優點就十分明顯。它負責幫你管理開源項目的版本,你只須要添加對某個開源模塊的依賴便可。
unix/linux下安裝npm:
curl http://npmjs.org/install.sh | sudo sh
如何在項目中使用npm管理你的依賴:
(1)在項目的根目錄下建立一個package.json文件
在dependencies下添加所須要依賴的模塊,示例以下:$ cd projectPath安裝這些module到本地repository:
$ npm install
這時你會發現,項目的根目錄下多了一個node_modules文件夾,那裏面就是從npm遠程庫裏下載的模塊而後「安裝」到你的項目中的。 如今,你就能夠在你的項目中應用你依賴的這些modules了。你能夠經過require關鍵字來使用他們。好比,
require("eventproxy");
node.js的模塊加載基於CommonJS規範。 在Node.js中,將模塊分爲兩大類: (1)原生模塊 原生模塊在Node.js源代碼編譯的時候編譯進了二進制執行文件,加載速度最快。 (2)文件模塊 node.js依賴modulepath(模塊路徑)來加載module,而modulepath的生成規則主要是從當前文件目錄開始查找node_modules文件夾,而後依次進入父目錄查找父目錄下的node_modules目錄直至到根目錄下得node_modules目錄。因此在require的時候,若是帶上module的路徑,則按照該路徑查找,若是沒有就按照上面的node_modules文件夾向上追溯查找,若是都沒有找到,則拋出異常。
項目環境的構建、部署都是自動化的。 咱們假設項目最終會發布在任意版本的Ubuntuserver上。在安裝git的前提下,經過以下命令去clone項目到本地:
git clone git://github.com/yanghua/FixedAssetManager_Server.git項目doc下有四個shell文件:
node.js 處處都是異步調用。經常使用的try/catch同步捕獲異常並處理的方式,在這裏不起做用了。這是由於不少callback已經離開了當時try的上下文,致使沒法獲取異常產生的堆棧信息。基於這個問題,咱們對異常處理的模式按類型進行區分處理:
(1)http請求異常 這種異常Express就能夠進行處理。若是是非法請求,在路由的時候,對未匹配的請求進行統一處理:
app.get("*", others.fourofour);
(2)業務異常
這種異常一般不會影響到程序的運行,咱們以不一樣的異常代碼返回給前端或者終端,來給調用端友好的提示。
(3)應用程序級別的異常或必須處理的錯誤
這種狀況下,應用程序可能沒有辦法處理異常,也有可能由應用程序拋出。對於這種應用程序級別的異常。咱們用兩種方式來catch:
[1]利用Express提供的應用程序的異常處理機制:app.error(function(err, req, res, next) { mailServie.sendMail({ subject : "FixedAssetManager_Server[App Error]", text : err.message + "\n" + err.stack + "\n" + err.toString() }); if (err instanceof PageNotFoundError) { res.render("errors/404"); } else if (err instanceof ServerError) { res.render("errors/500"); } });[2]應用程序已經沒法響應處理了,則利用node.js提供的,對於進程級別的異常處理方式:
process.on("uncaughtException", function (err) { mailServie.sendMail({ subject : "FixedAssetManager_Server[App Error]", text : err.message + "\n" + err.stack + "\n" + err.toString() }); });這兩種應用程序級別的異常,優先級都比較高,所以咱們採用了郵件通知的策略,來輔助開發人員進行快速定位並修復。
web應用中對於資源的定義大體分爲:靜態資源、動態資源兩種。動態資源一般是可變的,須要進行相應處理的,而靜態資源在線上一般都是不會變的。常見的靜態資源有:javascript文件、css文件、圖片文件等。對於這些靜態文件,咱們經過設置過時時間來進行緩存。而對於文本文件,因爲瀏覽器的解析行爲,對他們進行合併或者壓縮都不會產生影響。 這裏須要提到咱們在組件中介紹的Loader。在項目剛被clone下來的時候,須要先執行makebuild來對項目進行初始化。在初始化的過程當中,Loader會對項目的views文件夾中的文件進行掃描。它一般會掃描html界面:查找相似於以下的片斷:
<!-- style --> <%- Loader("/public/stylesheets/login.min.css") .css("/public/libs/bootstrap/css/bootstrap.min.css") .css("/public/stylesheets/login.css") .done(assets) %> <!-- script --> <%- Loader("/public/libs/js/login.min.js") .js("/public/libs/jquery/jquery-1.10.2.min.js") .js('/public/libs/bootstrap/js/bootstrap.min.js') .js("/public/libs/CryptoJS_v3.1.2/rollups/sha256.js") .js("/public/libs/js/login.js") .done(assets) %>去查找.css()以及.js()方法中的這些路徑參數,並對這些文件進行合併或壓縮混淆(這取決於配置),來產生一份assets.json(資產列表)文件。這裏面定義了一些鍵值對,鍵爲上面代碼段中Loader()方法後面跟的參數,值爲具體合併後文件的路徑。這樣,Loader會根據配置來判斷加載類型。若是當前爲開發模式或者爲debug模式,則調用.js()/.css(),基於其中的路徑參數來生成<script/> <link />。若是爲發佈模式,則根據.done()裏的assets鍵值對,結合Loader()的參數,來輸出合併後的文件。以減小前端http請求數量以及總大小。對publich文件夾下的文件,設置靜態文件緩存:
//config for production env app.configure("production", function () { app.use('/public', express.static(staticDir, { maxAge: maxAge })); app.use(express.errorHandler()); app.set('view cache', true); });由於設置了緩存,在從新改動這些靜態文件再發布的時候,若是緩存時間太長,則客戶端的靜態文件可能不會被替換。對於這個問題,Loader經過在文件的後綴追加一個版本號來做爲參數。這樣,當從新生成assets.json的時候每一個文件會產生新的版本號,瀏覽器會請求「新文件」替換掉客戶端老的緩存文件。
Restful以「Resource」爲核心概念,認爲URL是用來表示一種資源。而不該該表示一個動做或者其餘的東西。而動做,好比「CRUD」正好對應http的四個method:get/post/put/delete。本項目中,咱們大部分的URL以Restful風格爲主,但沒有嚴格貫徹執行。
前端咱們採用的是ejs的模板來構建,它很好得實現了html的片斷化、組件化。有一個基礎的模板,別的都只是一塊html片斷。它們在服務端完成組合、解析,生成完整的html流輸出到客戶端。 這樣的開發模式,使得前端代碼的劃分比較清晰,組件化也使得代碼的複用變得更容易。
在項目初始化的過程當中,咱們使用makefile文件來使得一些動做自動化運行。好比咱們以前提到過的構建assets.json來合併文件的動做,就是經過執行makebuild文件來完成的。
目前,Node.js尚未很強大的調試工具。經常使用的輔助診斷方式就是打log。但繁多的日誌輸出,混雜在http log裏實在是不方便判斷。咱們在項目中使用了debug module來進行debug,他支持對log加不一樣顏色的key word而且還支持timestamp。你在一大堆日誌中,一眼就足以區分是從哪一個module或者組件輸出的。咱們在項目中對不一樣的layer應用不一樣的關鍵字:
var debug4Ctrller = require("debug")("controller"); var debug4Proxy = require("debug")("proxy"); var debug4Lib = require("debug")("lib"); var debug4Test = require("debug")("test"); var debug4Other = require("debug")("other");
將其置爲全局:
global.debugCtrller = debug4Ctrller; global.debugProxy = debug4Proxy; global.debugLib = debug4Lib; global.debugTest = debug4Test; global.debugOther = debug4Other;這樣你在controller層的log就能夠以以下方式log:
debugCtrller("XXX %s", "YYY");
npm install -g grunt-cli2:在項目的根目錄下新建一個Gruntfile.js文件,該文件爲grunt的配置、初始化文件
npm install grunt --save-dev
依賴會被自動寫入package.json的devDependencies項中。
關於Gruntfile的編寫規則,詳細請查看, Gruntjs中文文檔。你只須要在項目的根目錄下,建立一個.jsbeautifyrc文件,裏面對縮進,空格等進行定義便可覆蓋默認配置。這很是方便那些已經習慣了本身有一套代碼風格的人使用這些插件。
更難能難得的是,對於一個項目你能夠有多個.jsbeautifyrc文件進行配置。他們的優先級取決於這些配置文件靠近待格式化文件的程度(某種意義上就是這些配置文件在目錄層次的深度)。這很是切換咱們的需求:由於node項目先後端都是js。對於後端咱們採用的是4空格縮進,對於前端JS咱們採用的2空格縮進。那麼咱們只須要在前端JS文件夾下,新建一個新的.jsbeautifyrc配置文件,copy上面的配置,而後將indent_size修改成2便可。自動格式化工具只是一種「效率工具」,不足以造成「強制規定」。這裏咱們輔以代碼檢查工具,來強制要求代碼風格、語法規範。
檢查工具在GruntSection已經列出,在commit代碼以前,必須運行檢查,並確保沒有任何Warnning跟Error。<% layout('layout') -%>來標識一個component會套用某個模板,而在3.x中ejs模板引擎,改成採用middleware的方式使用:(須要安裝一個module:express-partials)
app.use(require('express-partials')());與此同時,3.x專門提供了一個設置引擎的接口:
app.engine('html', require('ejs').renderFile);替代了原先2.x的:
app.register('.html', require('ejs'));二、處理錯誤的方式改變:
2.x處理錯誤有專門的一個API:
app.error(function(err, req, res, next) { //error logic handle };
3.x退而採用middleware的方式來處理:
app.use(function(err, req, res, next) { //error logic handle }
更多express2.x to 3.x的改變,能夠看看官方給出的變動列表。
eventproxy是淘寶前端團隊開發的一個node.js事件處理代理。用於輔助開放人員組織代碼的執行順序,對於不少須要干預執行順序與過程的代碼,避免了node.js深層嵌套的callback模式。
async跟eventproxy出於一樣的目的。但在API的設計模式上有所差別。async的API的風格偏向於「整合」,Eventproxy偏向於「拆分」。model的定義
mongodb裏數據的集合稱之爲collection。而每一個collection都有一個schema與之對應,能夠簡單的理解爲是對其數據的定義(類型與結構)。
對應到mongoose裏,一個schema是一個model,形如: