目录
- 开发环境
- 1、建立工程
- 2、目录结构
- 3、Express配置文件
- 4、Ejs模板
- 5、安装常用库及页面分离
- 6、路由
- 7、session
- 8、页面访问控制及提示
JS是脚本语言,脚本语言都需要一个解析器才能运行。对于写在HTML页面里 的JS,浏览器充当了解析器的角色。而对于需要独立运行的JS,NodeJS就是一个解析器。每一种解析器都是一个运行环境,不但允许JS定义各种数据结 构,进行各种计算,还允许JS使用运行环境提供的内置对象和方法做一些事情。例如运行在浏览器中的JS的用途是操作DOM,浏览器就提供了 document之类的内置对象。而运行在NodeJS中的JS的用途是操作磁盘文件或搭建HTTP服务器,NodeJS就相应提供了fs、http等内 置对象。Express作为NodeJS的Web应用框架,可以帮助我们快速开发Web网站。
开发环境
- NodeJS:v0.10.30
- npm:1.4.21
- OS:Win7旗舰版 32bit
- Express:4.2.0
- MongoDB:2.6.3 12
E:\project> node -v
v0.
10.30
E:\project> npm -v
1.4
.
21
E:\project> express -V
4.2
.
0
1、建立工程
使用express命令建立工程,并支持ejs:
根据提示下载依赖包:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | E:\project> cd .\nodejs-demo E:\project\nodejs-demo> npm install npm WARN deprecated static-favicon@1.0.2: use serve-favicon module static-favicon@1.0.2 node_modules\static-favicon debug@0.7.4 node_modules\debug ejs@0.8.8 node_modules\ejs cookie-parser@1.0.1 node_modules\cookie-parser ├── cookie-signature@1.0.3 └── cookie@0.1.0 morgan@1.0.1 node_modules\morgan └── bytes@0.3.0 body-parser@1.0.2 node_modules\body-parser ├── qs@0.6.6 ├── raw-body@1.1.7 (bytes@1.0.0, string_decoder@0.10.25-1) └── type -is@1.1.0 (mime@1.2.11) express@4.2.0 node_modules\express ├── parseurl@1.0.1 ├── utils-merge@1.0.0 ├── cookie@0.1.2 ├── merge-descriptors@0.0.2 ├── escape-html@1.0.1 ├── range-parser@1.0.0 ├── fresh@0.2.2 ├── cookie-signature@1.0.3 ├── debug@0.8.1 ├── methods@1.0.0 ├── buffer-crc32@0.2.1 ├── serve-static@1.1.0 ├── path-to-regexp@0.1.2 ├── qs@0.6.6 ├── send@0.3.0 (debug@0.8.0, mime@1.2.11) ├── accepts@1.0.1 (negotiator@0.4.7, mime@1.2.11) └── type -is@1.1.0 (mime@1.2.11) E:\project\nodejs-demo> |
工程建立成功,启动服务:
1 | E:\project\nodejs-demo> npm start > nodejs-demo@0.0.1 start E:\project\nodejs-demo > node . /bin/www |
本地3000端口被打开,在浏览器地址栏输入localhost:3000,访问成功。
2、目录结构
- bin——存放命令行程序。
- node_modules——存放所有的项目依赖库。
- public——存放静态文件,包括css、js、img等。
- routes——存放路由文件。
- views——存放页面文件(ejs模板)。
- app.js——程序启动文件。
- package.json——项目依赖配置及开发者信息。
1 2 3 4 5 6 7 8 9 10 11 | E:\project\nodejs-demo> dir 目录: E:\project\nodejs-demo Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 2014 /8/16 21:55 bin d---- 2014 /8/16 22:03 node_modules d---- 2014 /8/16 21:55 public d---- 2014 /8/16 21:55 routes d---- 2014 /8/16 21:55 views -a--- 2014 /8/16 21:55 1375 app.js -a--- 2014 /8/16 21:55 327 package.json |
3、Express配置文件
打开app.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | var express = require( 'express' ); var path = require( 'path' ); var favicon = require( 'static-favicon' ); var logger = require( 'morgan' ); var cookieParser = require( 'cookie-parser' ); var bodyParser = require( 'body-parser' ); var routes = require( './routes/index' ); var users = require( './routes/users' ); var app = express(); // view engine setup app.set( 'views' , path.join(__dirname, 'views' )); app.set( 'view engine' , 'ejs' ); app.use(favicon()); app.use(logger( 'dev' )); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express. static (path.join(__dirname, 'public' ))); app.use( '/' , routes); app.use( '/users' , users); /// 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; |
4、Ejs模板
修改app.js,让ejs模板文件使用扩展名为html的文件:
1 2 3 4 5 | 13 // view engine setup 14 app.set( 'views' , path.join(__dirname, 'views' )); 15 //app.set('view engine', 'ejs'); 16 app.engine( 'html' , require( 'ejs' ).renderFile); 17 app.set( 'view engine' , 'html' ); |
修改完成后,重命名views/index.ejs为views/index.html。重启服务,访问成功。
5、安装常用库及页面分离
添加bootstrap和jQuery:
E:\project\nodejs-demo> npm install bootstrap bootstrap@3.2.0 node_modules\bootstrap E:\project\nodejs-demo> npm install jquery jquery@2.1.1 node_modules\jquery E:\project\nodejs-demo>
接下来,把index.html分成三个部分:
- header.html——页面头部区域。
- index.html——页面内容区域。
- footer.html——页面底部区域。
header.html
1 2 3 4 5 6 7 8 9 | <! DOCTYPE html> < html lang = "en" > < head > < meta charset = "utf-8" > < title ><%= title %></ title > <!-- Bootstrap --> < link href = "/stylesheets/bootstrap.min.css" rel = "stylesheet" media = "screen" > </ head > < body screen_capture_injected = "true" > |
index.html
1 2 3 4 | 1 <% include header.html %> 2 < h1 ><%= title %></ h1 > 3 < p >Welcome to <%= title %></ p > 4 <% include footer.html %> |
footer.html
1 2 3 4 5 6 | <script src= "/javascripts/jquery.min.js" ></script> <script src= "/javascripts/bootstrap.min.js" ></script> </body> </html> |
重启服务,访问成功。
6、路由
登录设计:
访问路径 | 页面 | 描述 |
/ | index.html | 不需要登录,可以直接访问。 |
/home | home.html | 必须用户登录以后,才可以访问。 |
/login | login.html | 登录页面,用户名密码输入正确,自动跳转到home.html。 |
/logout | 无 | 退出登录后,自动跳转到index.html。 |
打开app.js文件,增加路由配置:
1 2 3 4 5 | 26 app.use( '/' , routes); 27 app.use( '/users' , users); 28 app.use( '/login' , routes); 29 app.use( '/logout' , routes); 30 app.use( '/home' , routes); |
打开routes/index.js文件,添加对应方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | var express = require( 'express' ); var router = express.Router(); /* GET home page. */ router.get( '/' , function (req, res) { res.render( 'index' , { title: 'Express' }); }); router.route( '/login' ) .get( function (req, res) { res.render( 'login' , { title: '用户登录' }); }) .post( function (req, res) { var user={ username: 'admin' , password: '123456' } if (req.body.username === user.username && req.body.password === user.password){ res.redirect( '/home' ); } res.redirect( '/login' ); }); router.get( '/logout' , function (req, res) { res.redirect( '/' ); }); router.get( '/home' , function (req, res) { var user={ username: 'admin' , password: '123456' } res.render( 'home' , { title: 'Home' , user: user }); }); module.exports = router; |
创建views/login.html和views/home.html两个文件:
login.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <% include header.html %> < div class = "container" > < form class = "col-sm-offset-4 col-sm-4 form-horizontal" role = "form" method = "post" > < fieldset > < legend >用户登录</ legend > < div class = "form-group" > < label class = "col-sm-3 control-label" for = "username" >用户名</ label > < div class = "col-sm-9" > < input type = "text" class = "form-control" id = "username" name = "username" placeholder = "用户名" required> </ div > </ div > < div class = "form-group" > < label class = "col-sm-3 control-label" for = "password" >密码</ label > < div class = "col-sm-9" > < input type = "password" class = "form-control" id = "password" name = "password" placeholder = "密码" required> </ div > </ div > < div class = "form-group" > < div class = "col-sm-offset-3 col-sm-9" > < button type = "submit" class = "btn btn-primary" >登录</ button > </ div > </ div > </ fieldset > </ form > </ div > <% include footer.html %> |
home.html
1 2 3 4 | 1 <% include header.html %> 2 <h1>Welcome <%= user.username %>, 欢迎登录!!</h1> 3 <a class = "btn" href= "/logout" >退出</a> 4 <% include footer.html %> |
修改index.html,增加登录链接:
1 2 3 4 | 1 <% include header.html %> 2 < h1 >Welcome to <%= title %></ h1 > 3 < p >< a href = "/login" >登录</ a ></ p > 4 <% include footer.html %> |
路由及页面已准备好,重启服务,访问成功。
7、session
安装中间件express-session:
1 2 3 4 5 | E:\project\nodejs-demo> npm install express-session express-session@1.7.5 node_modules\express-session ├── cookie@0.1.2 ├── cookie-signature@1.0.4 ├── on-headers@1.0.0 ├── utils-merge@1.0.0 ├── parseurl@1.3.0 ├── buffer-crc32@0.2.3 ├── depd@0.4.4 ├── debug@1.0.4 (ms@0.6.2) └── uid-safe@1.0.1 (base64-url@1.0.0, mz@1.0.0) E:\project\nodejs-demo> |
安装中间件connect-mongodb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | E:\project\nodejs-demo> npm install connect-mongodb \ > kerberos@0.0.3 install E:\project\nodejs-demo\node_modules\connect-mongodb\nod e_modules\mongodb\node_modules\kerberos > (node-gyp rebuild 2> builderror.log) || ( exit 0) | E:\project\nodejs-demo\node_modules\connect-mongodb\node_modules\mongodb\node_mo dules\kerberos>node "C:\Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\ ..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild | > bson@0.2.11 install E:\project\nodejs-demo\node_modules\connect-mongodb\node_m odules\mongodb\node_modules\bson > (node-gyp rebuild 2> builderror.log) || ( exit 0) E:\project\nodejs-demo\node_modules\connect-mongodb\node_modules\mongodb\node_mo dules\bson>node "C:\Program Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\. .\node_modules\node-gyp\bin\node-gyp.js" rebuild connect-mongodb@1.1.5 node_modules\connect-mongodb ├── connect@1.9.2 (mime@1.2.11, formidable@1.0.15, qs@1.2.2) └── mongodb@1.4.8 (kerberos@0.0.3, readable-stream@1.0.27-1, bson@0.2.11) E:\project\nodejs-demo> |
安装中间件mongodb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | E:\project\nodejs-demo> npm install mongodb - > kerberos@0.0.3 install E:\project\nodejs-demo\node_modules\mongodb\node_module s\kerberos > (node-gyp rebuild 2> builderror.log) || ( exit 0) - E:\project\nodejs-demo\node_modules\mongodb\node_modules\kerberos>node "C:\Progr am Files\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\b in \node-gyp.js" rebuild | > bson@0.2.11 install E:\project\nodejs-demo\node_modules\mongodb\node_modules\b son > (node-gyp rebuild 2> builderror.log) || ( exit 0) E:\project\nodejs-demo\node_modules\mongodb\node_modules\bson>node "C:\Program F iles\nodejs\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bin\n ode-gyp.js" rebuild mongodb@1.4.8 node_modules\mongodb ├── kerberos@0.0.3 ├── readable-stream@1.0.27-1 (isarray@0.0.1, string_decoder@0.10.25-1, inheri ts@2.0.1, core-util-is@1.0.1) └── bson@0.2.11 (nan@1.2.0) E:\project\nodejs-demo> |
添加database/settings.js和database/msession.js这两个文件:
settings.js
1 2 3 4 5 6 7 8 9 | module.exports = { COOKIE_SECRET: 'ywang1724.com' , URL: 'mongodb://127.0.0.1:27017/nodedb' , DB: 'nodedb' , HOST: '127.0.0.1' , PORT: 27017, USERNAME: 'admin' , PASSWORD: '123456' }; |
msession.js
1 2 3 4 5 6 | 1 var Settings = require( './settings' ); 2 var Db = require( 'mongodb' ).Db; 3 var Server = require( 'mongodb' ).Server; 4 var db = new Db(Settings.DB, new Server(Settings.HOST, Settings.PORT, {auto_reconnect: true , native_parser: true }),{safe: false }); 5 6 module.exports = db; |
修改app.js文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var express = require( 'express' ); var path = require( 'path' ); var favicon = require( 'static-favicon' ); var logger = require( 'morgan' ); var cookieParser = require( 'cookie-parser' ); var bodyParser = require( 'body-parser' ); //采用connect-mongodb中间件作为Session存储 var session = require( 'express-session' ); var Settings = require( './database/settings' ); var MongoStore = require( 'connect-mongodb' ); var db = require( './database/msession' ); var routes = require( './routes/index' ); var users = require( './routes/users' ); var app = express(); // view engine setup app.set( 'views' , path.join(__dirname, 'views' )); //app.set('view engine', 'ejs'); app.engine( 'html' , require( 'ejs' ).renderFile); app.set( 'view engine' , 'html' ); app.use(favicon()); app.use(logger( 'dev' )); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); //session配置 app.use(session({ cookie: { maxAge: 600000 }, secret: Settings.COOKIE_SECRET, store: new MongoStore({ username: Settings.USERNAME, password: Settings.PASSWORD, url: Settings.URL, db: db}) })) app.use( function (req, res, next){ res.locals.user = req.session.user; next(); }); app.use(express. static (path.join(__dirname, 'public' ))); ...... |
修改index.js文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | var express = require( 'express' ); var router = express.Router(); /* GET home page. */ router.get( '/' , function (req, res) { res.render( 'index' , { title: 'Express' }); }); router.route( '/login' ) .get( function (req, res) { res.render( 'login' , { title: '用户登录' }); }) .post( function (req, res) { var user = { username: 'admin' , password: '123456' } if (req.body.username === user.username && req.body.password === user.password){ req.session.user = user; res.redirect( '/home' ); } else { res.redirect( '/login' ); } }); router.get( '/logout' , function (req, res) { req.session.user = null ; res.redirect( '/' ); }); router.get( '/home' , function (req, res) { res.render( 'home' , { title: 'Home' }); }); module.exports = router; |
本地安装数据库MongoDB,新建用户nodedb。重启服务,访问成功。
8、页面访问控制及提示
访问控制设计:
访问路径 | 描述 |
/ | 任何人都可以访问,不需要认证。 |
/home | 拦截get请求,调用authentication()进行认证,不通过则自动跳转到登录页面。 |
/login | 任何人都可以访问,不需要认证。 |
/logout | 任何人都可以访问,不需要认证。 |
修改index.js文件:
1 2 3 4 5 6 7 8 9 10 | router.get( '/home' , function (req, res) { authentication(req, res); res.render( 'home' , { title: 'Home' }); }); function authentication(req, res) { if (!req.session.user) { return res.redirect( '/login' ); } } |
重启服务,访问成功。
添加页面提示,修改app.js文件,增加res.locals.message:
1 2 3 4 5 6 7 8 9 10 | app.use( function (req, res, next) { res.locals.user = req.session.user; var err = req.session.error; delete req.session.error; res.locals.message = '' ; if (err) { res.locals.message = '<div class="alert alert-warning">' + err + '</div>' ; } next(); }); |
修改index.js文件,增加req.session.error:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | var express = require( 'express' ); var router = express.Router(); /* GET home page. */ router.get( '/' , function (req, res) { res.render( 'index' , { title: 'Express' }); }); router.route( '/login' ) .get( function (req, res) { if (req.session.user) { res.redirect( '/home' ); } res.render( 'login' , { title: '用户登录' }); }) .post( function (req, res) { var user = { username: 'admin' , password: '123456' } if (req.body.username === user.username && req.body.password === user.password) { req.session.user = user; res.redirect( '/home' ); } else { req.session.error= '用户名或密码不正确' ; res.redirect( '/login' ); } }); router.get( '/logout' , function (req, res) { req.session.user = null ; res.redirect( '/' ); }); router.get( '/home' , function (req, res) { authentication(req, res); res.render( 'home' , { title: 'Home' }); }); function authentication(req, res) { if (!req.session.user) { req.session.error= '请先登录' ; return res.redirect( '/login' ); } } module.exports = router; |
修改login.html,增加<%- message %>:
1 2 3 | 5 <legend>用户登录</legend> 6 <%- message %> 7 <div class = "form-group" > |
重启服务,访问成功。输入错误用户名密码: