Nodejs之MEAN棧開發(一)---- 路由與控制器

由於工做須要,最近再次學習了node,上一次學習node是2014年,純粹是我的興趣,學了入門以後沒有運用,加上趕別的項目又不了了之。此次正好撿起來。廢話很少說,這裏的MEAN指的是MongodbExpressAngularNode。 經過整個項目逐步整合在一塊兒。MEAN棧最大的特點不是運用了哪些框架或第三方,而是先後端都是一種語言,即JavaScript。早些年我也是對node抱着疑態度,以爲這個頁面上操做dom的腳本語言,能扛得起後端那麼多模塊嗎?但懷疑不防多瞭解一下,才決定寫這個系列的文章。css

Mongodb作數據存儲,Express是基於node的後端框架,Angular是前端框架,Node是後端運行環境。安裝過程和node的特性就不講了,網上一大把。開發環境是VS2013.安裝了NTVS。node安裝完後,有時候須要設置下環境變量。在cmd目錄下輸入 node -v 若是顯示版本號,則說明安裝正確了。html

起始工程前端

在VS中新建項目,選擇JavaScript-->Node.js,選擇Express4的應用。java

  

  爲了不一直Ctrl+C,安裝nodemon,文件更新,它會自動重啓,-g表示安裝成全局。node

npm install nodemon -g

修改routes文件夾下的index.js中的title爲ReadingClub。而後用cmd切到工程目錄,輸入nodemon啓動工程。 git

 在瀏覽器裏面訪問lochost:3000 ,成功打開:angularjs

 先看routes文件夾下面的index.js ,這就是一個簡單的路由,處理的路徑爲「/」,請求方式get,req表明的是request,res表明的response。github

 

render方法有兩個參數,「index」,表明的是要渲染的視圖模板名稱,這裏默認的視圖引擎是jade,然後面{title:'ReadingClub'}就是傳遞到視圖的數據模型。這裏和Asp.net MVC 的return View() 有些類似,而這裏的function就至關 Asp.net MVC中Controller的一個Action。View()默認是對應當前Action名稱的視圖。而render必須指定。mongodb

res 也能夠直接發回一個響應express

res.send('respond with a resource');

創建Controllers

 不像Asp.net MVC有默認的路由規則,Express的路由須要一個個配置,不妨把Controller提出來。但在此以前,咱們先修改一下目錄。以下,創建app_server文件夾。裏面分controllers、views和routes。能夠把原來的views和routes直接移進去。

在controllers文件夾中新建一個home.js,加入三個方法:index、books和about。

module.exports.index = function(req, res) {
    res.render('index', { title: 'Index' });
};

module.exports.books = function(req, res) {
    res.render('books', { title: 'Books', });
};

module.exports.about = function (req, res) {
    res.render('about', { title: 'About' });
};

路由

一樣,在view文件夾中把index.jade複製兩遍,修改成books.jade和about.jade. 而後咱們修改routes下的index.js,運用Express框架自帶的Router。

var express = require('express');
var router = express.Router();
var homeController = require('../controllers/home');

router.get('/', homeController.index); router.get('/about', homeController.about); router.get('/books', homeController.books);

module.exports = router;

這時候仍是沒法運行的,由於咱們改變了目錄結構尚未在app.js中從新設定。首先設置路由:

var routes = require('./app_server/routes/index');
app.use('/', routes);

修改視圖引擎的起始位置

//app.set('views', path.join(__dirname, 'views'));
app.set('views', path.join(__dirname, 'app_server', 'views'));

__dirname表明的是根目錄。而後再瀏覽器訪問/books或者/about 。

 這樣就分離了controller,請求經過路由抵達控制器,控制器將模型數據填充到對應的視圖的模板.這就是咱們熟悉的MVC模式。咱們再看router.METHOD方法定義。

router.METHOD(path, [callback, ...] callback)

這裏的METHOD指get,post,put和delete等。由於咱們能夠定義:

router.get('/book/:bookId', homeController.detail);
router.put('/book/:bookId', homeController.updateBook);
router.delete('/book/:bookId', homeController.deleteBook);

雖然路徑都是同樣,可是表明的是不一樣的用意,徹底restful,:bookId表示是參數。

一樣支持正則匹配,會匹配相似於這樣的‘GET /commits/71dbb9c’

router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){
  var from = req.params[0];
  var to = req.params[1] || 'HEAD';
  res.send('commit range ' + from + '..' + to);
});

若是每一個請求都須要作某種處理,能夠用all方法:

router.all('*', requireAuthentication, loadUser);

這等價於:

router.all('*', requireAuthentication)
router.all('*', loadUser);

Asp.net MVC的路由每個都須要設置名稱,且不能重複出現,且匹配到以後就再也不匹配,Express沒有這個限制,匹配到以後只要沒返回響應就會向下繼續傳遞。相對而言,Express的Router更靈活一些。

更多細節請參考官方API:http://www.expressjs.com.cn/4x/api.html#router

接下來咱們回顧下整個app.js。

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./app_server/routes/index');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'app_server', 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function (err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


module.exports = app;
View Code

1.模塊定義:

首先看到不少的require的語法。

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./app_server/routes/index');

require表示應用一個模塊,npm上已經有超過25萬個包。這些能直接引用的模塊,是已經安裝在node_modules文件中。若是是本身定義的模塊,好比routes 就要用相對路徑。在node中模塊分如下幾類:

  • 核心模塊,如http,fs,path等
  • .或..開始的相對路徑文件模塊
  • 以/開始的絕對路徑文件模塊
  • 非路徑形式的文件模塊,如自定義的模塊。

核心模塊會優先加載,以相對或絕對路徑加載的模塊,require都會轉爲真實路徑,將編譯執行後的結果放到緩存中,這樣二次加載就會更快。require能加載.js,.node.json的文件,其他擴展名都會被當.js文件載入。模塊與文件是一一對應的,一個文件夾的模塊就稱做包,包一般是一些模塊的集合。require是用來獲取模塊,而exports對象就是用來定義模塊。

module.exports.hello = function() {
console.log('Hello.');
};

至關因而定義接口,給外部調用。而上面的路由就是把一整個對象封裝到模塊中。

module.exports = router;

在app.js中直接獲取到整個路由對象:

var routes = require('./app_server/routes/index');

看到module.exports直接賦值router有點奇怪,會想不會覆蓋掉其餘的模塊嗎,但事實上在編譯的過程當中,node會對獲取的JavaScript文件內容進行包裝,等因而每一個文件之間都進行了做用域的隔離。

2.app.set

app.js中用set方法設置了路由起始路徑和視圖引擎。 

app.set('views', path.join(__dirname, 'app_server', 'views'));//這裏咱們修改了路徑在app_server文件夾下
app.set('view engine', 'jade');//默認的視圖引擎是jade

還能夠設置路由是否忽略大小寫,默認是不忽略。

app.set('case sensitive routing',true)

還能夠設置環境變量是開發環境仍是生產環境,更多的設置能夠參考官方文檔:http://www.expressjs.com.cn/4x/api.html#app.settings.table

3.app.use

use方法是用來註冊一系列中間件,監聽端口上的請求,中間件利用了尾觸發機制,每一箇中間件傳遞請求對象,響應對象和尾觸發函數,經過隊列造成一個處理流。

 最簡單的中間件形式:

app.use(function (req, res, next) {
  console.log('Time: %d', Date.now());
  next();
})

看下各個中間件的做用:

app.use(logger('dev')); //日誌,在開發環境下用彩色輸出響應狀態,會顯示請求方式,響應時間和大小。
app.use(bodyParser.json());//解析json請求。
app.use(bodyParser.urlencoded({ extended: false }));//解析form請求(含有key-value鍵值對),false表示value的類型是string或array,爲true表示任意類型。
app.use(cookieParser());//解析cookie
app.use(require('stylus').middleware(path.join(__dirname, 'public')));//使用stylus作css預編譯,並指定路徑。
app.use(express.static(path.join(__dirname, 'public')));//靜態文件路徑

4.error

咱們看到在設置了路由以後,若是請求還沒返回則認爲頁面沒有找到,這個時候app拋出一個error。並繼續往下傳遞

app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

而接下來,對錯誤進行了處理

// 開發環境錯誤處理
// 會打印出錯誤堆棧
if (app.get('env') === 'development') {
    app.use(function (err, req, res, next) {
        res.status(err.status || 500);//若是不是404就認爲是內部錯誤
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// 生產環境錯誤處理
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

檢測到異常的時候,就渲染error模板。 接下來看下error模板,簡單介紹下jade語法:

extends layout  //至關於Asp.net MVC 設置Layout

block content //至關於 Asp.net MVC RenderBody
  h1= message  //顯示message
  h2= error.status  //顯示錯誤狀態
  pre #{error.stack} //錯誤堆棧

這樣就能處理404和500錯誤頁面。

小結:至此,整個默認工程已經介紹完,這一節經過Express框架創建一個基本的MVC工程,瞭解基本的請求和響應,node的基本模塊和中間件;並初步設置了路由,創建起專門的controller;解讀了app.js中的相關代碼;下一節關注模型和視圖。時至今日,node的開發環境已經很完善,從09年到如今這個技術已經走過了7年了,已經有不少書籍資料,國內的cnode社區很活躍。若是把技術比喻成股票的話,java,C#,PHP這些無疑是大盤白馬股,學這樣的技術風險小,不愁找不到工做。而node這樣的就像創業板股票,你也許認爲這有很大的泡沫,認爲新的公司不過是炒概念,但他就是在快速增加着。

 源碼:http://files.cnblogs.com/files/stoneniqiu/Reading.rar

參考文章:

http://www.tuicool.com/articles/emeuie 

http://www.2cto.com/kf/201207/142885.html

http://www.tuicool.com/articles/emeuie

https://github.com/expressjs/body-parser

書籍:《深刻淺出nodejs》《Getting MEAN with Mongo, Express, Angular, and Node

相關文章
相關標籤/搜索