express框架初识

1. 安装使用express框架:

express是nodejs中一个比较流行的web开发框架,可以快速搭载一个web应用

1.1 使用npm全局安装express命令行工具,可以让我们初始化一个express项目:

npm install -g express-generator

1.2 创建一个安装express项目的文件夹,我这里为nodejs:

使用命令提示符进入这个nodejs文件夹:

image

1.3 使用命令初始化一个名为jun的项目:(这里的-e代表使用ejs模板引擎)

$ express -e jun

下图说明初始化成功,图中红框中还提示接下来的步骤:

image

1.4 然后进入这个文件夹,安装依赖模块

cd jun && npm install

1.5 调试与运行:

SET DEBUG=jun:* & npm start

成功运行express基本骨架:

image


2. express框架结构:

image

app.js:启动文件,或者说入口文件

package.json:存储着工程的信息及模块依赖,当在 dependencies 中添加依赖的模块时,运行 npm install ,npm 会检查当前目录下的 package.json,并自动安装所有指定的模块。(如果我们想要安装一个package.json中不存在的模块,我们不需要在package.json中添加模块信息,然后重新运行npm install,只需要在安装某一个模块的时候,添加--save参数就可以了,添加--save参数的作用是当你安装某一个模块的时候,会把该模块依赖信息自动添加到package.json中,例如安装一个mongoose模块,运行npm install mongoose --save)

node_modules:存放 package.json 中安装的模块,当你在 package.json 添加依赖的模块并安装后,存放在这个文件夹下

public:存放 image、css、js 等文件

routes:存放路由文件

views:存放模版文件

bin:存放可执行文件,从packet.josn中可以知道

image

2.1 app.js代码:

导入express模块


var express = require('express');

导入path模块,使用该模块方法,设置相对路径,可以参考菜鸟教程的path模块解释

var path = require('path');

该模块用于设置网页的logo,就是网页标题左边的图标:

image

var favicon = require('serve-favicon');

导入morgan日志中间件,用于把访问信息等输出到控制台或者文件中,详细使用参考 大神文章

var logger = require('morgan');

导入cookie-parser中间件,用于设置浏览器的cookie,详细参考 大神文章

var cookieParser = require('cookie-parser');

body-parser中间件,对post请求进行格式化

var bodyParser = require('body-parser');

导入路由文件

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

实例化一个express,名为app

var app = express();

设置views文件夹下的模板文件的路径为根路径,即是可以直接使用views下面的文件,而不需要指定具体的相对路径或者绝对路径:

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

使用ejs模板引擎

app.set('view engine', 'ejs');

设置网页logo为/public/favicon.ico的图标文件

app.use(favicon(__dirname + '/public/favicon.ico'));

使用dev格式输出日志(express默认使用dev格式): 而Morgan预定义了5中输出格式:

combined
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"



common
:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]



dev
:method :url :status :response-time ms - :res[content-length]



short
:remote-addr :remote-user :method :url HTTP/:http-version :status :res[content-length] - :response-time ms



tiny
:method :url :status :res[content-length] - :response-time ms


例如我们npm start,运行一下我们的项目,然后我们访问一下http://localhost:3000/,控制台输出:

image

app.use(logger('dev'));

返回一个只解析json的中间件,可以支持任何unicode编码的消息体,同时也支持gzip和deflate编码。最后保存的数据都放在req.body对象上

app.use(bodyParser.json());

extended为false表示使用querystring来解析数据,这是URL-encoded解析器

app.use(bodyParser.urlencoded({ extended: false }));

使用cookieParser中间件

app.use(cookieParser());

这里设置public文件夹为静态文件夹,参考 文章

app.use(express.static(path.join(__dirname, 'public')));

使用路由:

app.use('/', routes);
app.use('/users', users);

3. 使用路由express.Router():

routes文件夹是存放各种路由文件的地方: 当我们接收到对应的url路由,就会执行对应的路由函数

看routes中的index.js

var express = require('express');

实例化一个router
var router = express.Router();

当访问到(根/)路径时(即访问'http://localhost:3000/'时),渲染views文件夹下的index.ejs,(因为前面已经对views文件夹下的模板文件进行了路径设置,所以只需要直接render指定的模板文件名就可以了):
router.get('/', function(req, res, next) {
   res.render('index', { title: 'Express' });
});


module.exports = router;

再看app.js下的对routes下的路由文件处理:

导入routes下的index函数
var index = require('./routes/index');

实例化一个app对象
var app = express();

这个use方法,当访问根路径('http://localhost:3000')的时候,执行index路由
app.use('/', index);


这里的app.use()方法的第一个参数与index.js里面的rouer.get()方法的第一个参数的路径是相对的,下面我们改一下代码

//app.js
app.use('/a',index);

//routes/index.js
router.get('/b',function(){})

这样,浏览器访问路径就变成http://localhost:3000/a/b了:

image

4. 渲染ejs模板:

什么是模板呢,作用是什么,为什么要使用模板引擎呢?其实很简单,模板引擎就是用来渲染数据的,一个模板实际上就是一个静态的html页面,通过ejs等模板语法,把nodejs后台取到的数据渲染出来,当我们访问一个路由时,nodejs通过res.render方法执行模板引擎,渲染页面,然后把渲染出来的带有数据的html页面发送到前台,就成了拥有动态数据的html页面了。

routes/index.js下:

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

res.render()方法是返回一个渲染后的模板文件,这里为index。 第一个参数是views下的一个模板引擎,第二个参数是需要传递给模板引擎的json数据。

下面我们改一下index.js和index.ejs文件,传递复杂一点的数据: index.js

var data=
[
	{
		name:'xiaojun',
		age:'22',
		color:['red','green','blue']
	},
	{
		name:'xiao',
		age:'22',
		color:['black','white','gray']
	}
];

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

index.ejs:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
  
  	<ul>
		<% data.forEach(function(childData){ %>  
		     	<li><%=childData.name%></li>
		     	<li><%=childData.age%></li>
		     	<li>
		     		<ul>
		     			<% childData.color.forEach(function(color){ %>  
							<li><%=color%></li>
		     			<% })%>
		     		</ul>
		     	</li>
		<% })%>  
	</ul>
  </body>
</html>

npm start 运行:

image

5. 中间件:app.js中多次提到中间件,那么中间件是什么呢,它的作用又是什么呢?而按照我的理解,中间件就是在运行router的get()或者post()方法之前先运行的函数,使用use()方法实现中间件。

下面举个例子,自定义一个中间件: index.js:

color本来是black;
var color='black';

这是一个没有挂载路径的中间件,所以每个请求都会执行该中间件,必须要有next参数,并且必须执行next(),next的作用是跳转到下一个相同路由的中间件,如果忽略了next参数,当项目运行到这个中间件的时候,会无法跳出这个中间件,从而无法运行之后的代码。

router.use(function (req, res, next) {
  
  把color变成white
  color='white';
  next();
});

router.get('/', function(req, res, next) {

   res.render('index', {showColor:color});
   
});

npm start 运行:

image