nodejs实战案例(Express框架+mongoDB)之3:路由,摸版引擎基础知识

这篇博客对app.js讲解非常清晰

下面是引用:

——————————————————————————–

工程结构

我们回头看看生成的工程目录里面有什么,打开 D:\blog,里面如图所示:

app.js:启动文件。
package.json:存储着工程的信息及所需的依赖模块,当在 dependencies 中添加依赖时,运行npm install,会检查当前目录下的 package.json,并自动安装所有指定的依赖模块。
node_modules:存放 package.json 中安装的模块,当你在 package.json 添加依赖的模块并安装后,默认存放在这个文件夹下
public:存放 image、css、js 等文件
routes:存放路由文件
views:存放模版文件

打开 app.js,让我们看看里面究竟有什么东西:

/**
 * Module dependencies.
 */

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}

app.get('/', routes.index);
app.get('/users', user.list);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

在 node.js 中模块分为核心模块和文件模块两种,核心模块是通过 require(‘xxxx’) 导入的,文件模块是以 require(‘/xxxx’) 或 require(‘./xxxx’)、require(‘../xxxx’) 形式导入的;核心模块是用c/c++编译的二进制模块,而文件模块是后缀为.js、.json、.node 的文件,在 node.js 中一个文件/文件夹也可以称之为一个模块。更多关于模块及模块加载顺序的信息请查阅官网:http://nodejs.org/api/all.html#all_modules
这里导入了 express、http、path 核心模块,routes 文件夹下的 index.js 和 user.js 文件模块。

因为 express 框架是依赖 connect 框架(Node的一个中间件框架)创建而成的,可查阅 connect 文档:http://www.senchalabs.org/connect/和 express 官方文档:http://expressjs.com/api.html了解更多内容。
app.set(name, value):设置 name 的值为 value
app.set(‘port’, process.env.PORT || 3000):设置端口为 process.env.PORT 或 3000
app.set(‘views’, __dirname + ‘/views’):设置 views 文件夹为视图文件的目录,存放模板文件,__dirname 为全局变量,存储着当前正在执行脚本所在的目录名。
app.set(‘view engine’, ‘ejs’):设置视图模版引擎为 ejs

app.use([path], function):使用中间件 function,可选参数path默认为”/”
app.use(express.favicon()):connect 内建的中间件,使用默认的 favicon 图标,如果想使用自己的图标,需改为app.use(express.favicon(__dirname + ‘/public/images/favicon.ico’)); 这里我们把自定义的 favicon.ico 放到了 public/images 文件夹下。
app.use(express.logger(‘dev’)):connect 内建的中间件,在开发环境下使用,在终端显示简单的不同颜色的日志,比如在启动 app.js 后访问 localhost:3000,终端会输出:

Express server listening on port 3000
GET / 200 21ms - 206b
GET /stylesheets/style.css 304 4ms

数字200显示为绿色,304显示为蓝色。假如你去掉这一行代码,不管你怎么刷新网页,终端都只有一行 Express server listening on port 3000。
app.use(express.bodyParser()):connect 内建的中间件,用来解析请求体,支持 application/json, application/x-www-form-urlencoded, 和 multipart/form-data。
app.use(express.methodOverride()):connect 内建的中间件,可以协助处理 POST 请求,伪装 PUT、DELETE 和其他 HTTP 方法。
app.use(app.router):设置应用的路由(可选),详细请参考:http://stackoverflow.com/questions/12695591/node-js-express-js-how-does-app-router-work
app.use(express.static(path.join(__dirname, ‘public’))):connect 内建的中间件,设置根目录下的 public 文件夹为静态文件服务器,存放 image、css、js 文件于此。
if (‘development’ == app.get(‘env’)) {app.use(express.errorHandler());}:开发环境下的错误处理,输出错误信息。

app.get(‘/’, routes.index):路由控制器,如果用户访问” / “路径,则由 routes.index 来控制,routes/index.js 内容如下:

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

通过 exports.index 导出 index 函数接口,app.get(‘/’, routes.index) 相当于:

app.get('/', function(req, res){
  res.render('index', { title: 'Express' });
};)

res.render(‘index’, { title: ‘Express’ }):调用 ejs 模板引擎解析 views/index.ejs(我们之前通过 app.set(‘views’, __dirname + ‘/views’)设置了模版文件默认存储在 views 下),并传入一个对象作为参数,这个对象只有一个属性 title: ‘Express’,即用字符串 Express 替换 views/index.ejs 中所有 title 变量,后面我们将会了解更多关于模板引的内容。

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

这段代码的意思是创建服务器并监听3000端口,成功后在命令行中显示 Express server listening on port 3000,然后我们就可以通过在浏览器输入 localhost:3000 来访问了。

这一小节我们学习了如何创建一个工程并启动它,了解了工程的大体结构,下一节我们将学习 Express 的基本使用及路由控制。

——————————————————————————–

路由控制原理:

同样,内容引用如下:

——————————————————————————–

工作原理

上面提到过 app.js 中 app.get(‘/’, routes.index) 可以用以下代码取代:

app.get('/', function(req, res){
  res.render('index', { title: 'Express' });
};)

这段代码的意思是当访问主页时,调用 ejs 模板引擎,传入 title 变量的值为字符串 Express,来渲染 index.ejs 模版文件,生成静态页面并显示在浏览器里。

我们来作一些修改,以上代码实现了路由的功能,我们当然可以不要 routes/index.js 文件,把实现路由功能的代码都放在 app.js 里,但随着时间的推移 app.js 会变得难以维护,这也违背了代码模块化的思想,所以我们把实现路由功能的代码都放在 routes/index.js 里。官方给出的写法是在 app.js 中实现了简单的路由分配,然后再去 index.js 中找到对应的路由函数,最终实现路由功能。我们不妨把路由控制器和实现路由功能的函数都放到 index.js 里,app.js 中只有一个总的路由接口。
打开 app.js,删除 , user = require(‘./routes/user’) (我们这里用不到 routes/user.js,同时删除这个文件)和

app.get('/', routes.index);
app.get('/users', user.list);

在 app.js 最后添加:

routes(app);

修改 index.js 如下:

module.exports = function(app){
  app.get('/',function(req,res){
    res.render('index', { title: 'Express' });
  });
};

现在,再运行你的 app,你会发现主页毫无二致。这两种写法的区别就好比:
你的朋友结婚了,你收到请帖要赴宴。到了酒店门口被总管给拦住了。官方的写法是总管看了看请帖然后给你指了朋友团的地方,然后你过去坐下。咱的写法是总管看了看请帖简单确认了下你是被邀请的人,然后你进去自己找到朋友团的地方坐下。

路由规则

express 封装了多种 http 请求方式,但我们这里主要只使用 get 和 post 两种。
get 和 post 的第一个参数都为请求的路径,第二个参数为处理请求的回调函数,它有两个参数分别是 req 和 res,表示请求信息和响应信息 。路径请求及对应的获取路径有以下几种形式:

req.query

// GET /search?q=tobi+ferret  
req.query.q  
// => "tobi ferret"  

// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse  
req.query.order  
// => "desc"  

req.query.shoe.color  
// => "blue"  

req.query.shoe.type  
// => "converse"

req.body

// POST user[name]=tobi&user[email]=tobi@learnboost.com  
req.body.user.name  
// => "tobi"  

req.body.user.email  
// => "tobi@learnboost.com"  

// POST { "name": "tobi" }  
req.body.name  
// => "tobi"

req.params

// GET /user/tj  
req.params.name  
// => "tj"  

// GET /file/javascripts/jquery.js  
req.params[0]  
// => "javascripts/jquery.js"  

**req.param(name)**

// ?name=tobi  
req.param('name')  
// => "tobi"  

// POST name=tobi  
req.param('name')  
// => "tobi"  

// /user/tobi for /user/:name   
req.param('name')  
// => "tobi"

不难看出:
req.query 处理 get 请求
req.params 处理 /:xxx 形式的 get 请求
req.body 处理 post 请求
req.param(name) 可以处理 get 和 post 请求,但查找优先级由高到低为 req.params→req.body→req.query
路径规则还支持正则表达式,更多请查阅:http://expressjs.com/api.html

——————————————————————————–

安装要求,删除app.js中

, user = require(‘./routes/user’)

和routes中的user.js文件

继续删除app.js中的

app.get(‘/’, routes.index);

app.get(‘/users’, user.list);

在app.js文件最后一行添加routes(app)

修改routes/index.js文件如下:

module.exports = function(app){

app.get(‘/’,function(req,res){

res.render(‘index’, { title: ‘Express’ });

});

};

 

对于ejs模板引擎:

同样引用:

——————————————————————————————-

什么是模板引擎

模板引擎(Template Engine)是一个将页面模板和要显示的数据结合起来生成 HTML 页面的工具。
如果说上面讲到的 express 中的路由控制方法相当于 MVC 中的控制器的话,那模板引擎就相当于 MVC 中的视图。

模板引擎的功能是将页面模板和要显示的数据结合起来生成 HTML 页面。它既可以运 行在服务器端又可以运行在客户端,大多数时候它都在服务器端直接被解析为 HTML,解析 完成后再传输给客户端,因此客户端甚至无法判断页面是否是模板引擎生成的。有时候模板 引擎也可以运行在客户端,即浏览器中,典型的代表就是 XSLT,它以 XML 为输入,在客 户端生成 HTML 页面。但是由于浏览器兼容性问题,XSLT 并不是很流行。目前的主流还是 由服务器运行模板引擎。

在 MVC 架构中,模板引擎包含在服务器端。控制器得到用户请求后,从模型获取数据, 调用模板引擎。模板引擎以数据和页面模板为输入,生成 HTML 页面,然后返回给控制器, 由控制器交回客户端。

——《Node.js开发指南》

什么是 ejs ?

ejs 是模板引擎的一种,也是我们这个教程中使用的模板引擎,因为它十分简单,而且与 Express 集成良好。

使用模板引擎

前面我们通过以下两行代码设置了模板引擎和页面模板的存储位置:

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

在 routes/index.js 中通过调用 res.render 渲染模版,并将其产生的页面直接返回给客户端。它接受两个参数,第一个是模板的名称,即 views 目录下的模板文件名,扩展名 .ejs 可选;第二个参数是传递给模板的数据,用于模板翻译。
index.ejs 内容如下:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

当我们 res.render(‘index’, { title: ‘Express’ }); 时,模板引擎会把 <%= title %> 替换成 Express,然后把替换后的页面现实给用户。

渲染后生成的页面代码为:

<!DOCTYPE html>
<html>
  <head>
    <title>Express</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>Express</h1>
    <p>Welcome to Express</p>
  </body>
</html>

注意:我们设置了静态文静目录为 public(app.use(express.static(path.join(__dirname, ‘public’)))),所以上面代码中的href=’/stylesheets/style.css’ 就相当于 href=’public/stylesheets/style.css’ 。

ejs 的标签系统非常简单,它只有以下3种标签。

<% code %>:JavaScript 代码。  
<%= code %>:显示替换过 HTML 特殊字符的内容。  
<%- code %>:显示原始 HTML 内容。

注意: <%= code %> 和 <%- code %> 的区别,当变量 code 为字符串时,两者没有区别;当 code 为比如<h1>hello</h1>时,<%= code %> 会原样输出 <h1>hello</h1>,而 <%- code %> 则会输出H1大的 hello。

EJS 的官方示例:

The Data

{ title:    'Cleaning Supplies',
  supplies: ['mop', 'broom', 'duster'] }

The Template

<ul>
<% for(var i=0; i<supplies.length; i++) {%>
   <li><%= supplies[i] %></li>
<% } %>
</ul>

The Result

  • mop
  • broom
  • duster

我们可以用上述三种方式实现页面模板系统能实现的任何内容。

未经允许不得转载:前端撸码笔记 » nodejs实战案例(Express框架+mongoDB)之3:路由,摸版引擎基础知识

上一篇:

下一篇: