不完全node实践教程-第二发
2016-04-23 16:27
706 查看
今天我们来搭建博客的首页.
req.query 处理get请求, 获取请求参数. 举个例子;
req.params 处理get请求 获取类似于/:name形式的参数.举个例子
req.body 处理post请求, 获取post请求体.举个例子;
req.param() 处理get 和 post请求, 依次从params, body, query查找
我们等会儿试一下就知道怎么用这些api了.在这之前我们还要稍微讲一下ejs的东西.
<% code %> 这种形式的用来写js代码, 控制逻辑
<%= string %> 这种形式用来显示要替换的字符串, 上一发的title就是这种
<%- include -% 这种形式的是用啦包含其他的模板, 方便模板的复用.
举一些例子:
我们有一个模板a.ejs
还有一个b.ejs
那么渲染之后, b.ejs及时这个样子滴
好, 我们终于可以开始干活了!
可以注册
可以登陆
可以登出
好像少了点什么…哦对还要可以
登陆的用户可以发表文章
首页显示最近发的博客(当然这有点无脑, 暂时先这样计划)
/: 首页
/signup: 注册
/login: 登陆
/logout: 登出
/post: 发表文章
我们来看一下现在的app.js
1-6行 分别是引入一些必要的模块.
8-9行 是引入两个路由的模块
11行是实例化一个express对象
14-15行 是设置模板的静态文件防止的目录, 然后设置模板为ejs,也就是说我们可以设置成其他的.
19-23行 分别是加载日志中间件, json解析中间件, 解析urlencoded的中间件, 解析cookie的中间件, 设置静态文件目录
25-26行 设置请求盒路由处理的对应规则
29-33 51-57行分别用一个函数来处理httpcode400和500的问题
60行 导出模块让/bin/www使用
讲道理我们应该把要设置的路由规则添加到app.js里面. 但是想到后面我们可能要添加更多的路由, 这样会显得app.js有点杂乱.所以我们把app.js修改成这样
然后把index.js改成这样
我们再运行app看一下
好, 现在我们就可以在index里面添加路由了.在/routes新建文件login.js, signup.js, logout.js, post.js然后修改index.js
打开终端, 在项目根目录敲下如下命令
安装完成之后.
在根目录创建setting.js 用来保存数据库的配置. 新建model文件夹, 用来盛放模型文件. 并且在model文件夹新建文件database.js. 然后分别写入以下内容.
database.js
setting.js
然后在app.js添加:
这样一来, 只要我们在运行app的时候, 就会自动链接数据库, 而且用dbStates保存数据库链接的状态, 连接一次, 复用多次, 可以说是单例模式的运用.
然后, 然后..我们终于可以开始设计首页, 注册和登陆的前端页面了. 在view里面新建signup.ejs, login.ejs, 如果要加样式的话, 把相应的样式文件写在/public/stylesheets里面.然后注意引入的时候路径是/stylesheets/xxx.css, 因为在app.js已经设置了静态文件的根目录是/public.
代码我这里就不直接给出了.大家可以在这里获取. 如果你觉得我的太丑也可以自己diy…
一切都弄好之后, 再运行app. 没错的话应该是这个样子滴:
接下来我们来添加处理注册盒登陆的代码.在model文件夹新建文件user.js, 添加以下代码:
user分别有两个方法, 一个是保存用户信息的实例. 一个是通过名字获取那个户信息.然后在routes文件夹里面的signup.js 和login.js分别添加以下代码.
第21和22行是用对用户密码进行md5加密. 然后存储进数据库.
最后, 打开header.ejs模板(首页的代码可以从我的github找到.首页由header.ejs和content.ejs,footer.ejs组合而成), 修改内容为
这样一来, 首页显示的按钮及时根据用户是否登陆而不同.
如果以上步骤都没有错, (这几乎是不可能的) 如果出错了, 请用以下步骤解决.
根据提示的错误查找代码看是否有明显的逻辑错误或者语法错误.大部分的错误都是这样引起的.
如果解决不了, 在博客下面留言, 或者在github issue区贴出来.
根据别的同学的回复查找错误.如果继续出错,回到第一步.
假设成功运行app, 打开浏览器应该是这样的
点击注册按钮
然后
点击logout
然后点击login, 用注册过的密码注册
登陆之后
终于, 我们完成了登陆和注册的功能, 由于需要一些初始化的工作, 和这是我第一次写博客, 所以导致这篇有点长…长…长…
如果大家有没看懂的地方, 今天的代码在day02
(今天的逼就装到这里, 谢谢大家.)
关于express
先讲一下我们需要频繁用到的express的api.req.query 处理get请求, 获取请求参数. 举个例子;
// GET localhost:/?name=zhu&&school[university]=hust req.query.name //=> zhu req.query.school.university //=>hust
req.params 处理get请求 获取类似于/:name形式的参数.举个例子
// GET /user/zhu app.get('/user/:name', function(req){ req.params.name // => zhu //do something })
req.body 处理post请求, 获取post请求体.举个例子;
// POST user[name]=zhu req.body.name // => zhu
req.param() 处理get 和 post请求, 依次从params, body, query查找
我们等会儿试一下就知道怎么用这些api了.在这之前我们还要稍微讲一下ejs的东西.
ejs模板
上一发我们已经将模板index.ejs改成了hello world的形式. 我提到过render的过程实际上就是将传过来的参数最相应的’字符串’进行替换. 这些字符串是由三种标签组成的.<% code %> 这种形式的用来写js代码, 控制逻辑
<%= string %> 这种形式用来显示要替换的字符串, 上一发的title就是这种
<%- include -% 这种形式的是用啦包含其他的模板, 方便模板的复用.
举一些例子:
// 从express传过来的数据是 users: ['zhu', 'hai', 'hao'] <ul> <% for (var i = 0; i < users.length; i++){%> <li><%= users[i]%></li> <% } %> </ul> // 替换之后的结果是 <ul> <li>zhu</li> <li>hai</li> <li>hao</li> </ul>
我们有一个模板a.ejs
i am a
还有一个b.ejs
<%- include a %> i am b
那么渲染之后, b.ejs及时这个样子滴
i am a i am b
好, 我们终于可以开始干活了!
开始干活
设计总体架构
我这个水平的同学..看到设计架构就会有一种刁刁哒的感觉.(我也装一逼).说人话就是设计一下这个博客要有哪些功能可以注册
可以登陆
可以登出
好像少了点什么…哦对还要可以
登陆的用户可以发表文章
首页显示最近发的博客(当然这有点无脑, 暂时先这样计划)
设计路由
我们先来设计一下路由/: 首页
/signup: 注册
/login: 登陆
/logout: 登出
/post: 发表文章
我们来看一下现在的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('./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'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); 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;
1-6行 分别是引入一些必要的模块.
8-9行 是引入两个路由的模块
11行是实例化一个express对象
14-15行 是设置模板的静态文件防止的目录, 然后设置模板为ejs,也就是说我们可以设置成其他的.
19-23行 分别是加载日志中间件, json解析中间件, 解析urlencoded的中间件, 解析cookie的中间件, 设置静态文件目录
25-26行 设置请求盒路由处理的对应规则
29-33 51-57行分别用一个函数来处理httpcode400和500的问题
60行 导出模块让/bin/www使用
讲道理我们应该把要设置的路由规则添加到app.js里面. 但是想到后面我们可能要添加更多的路由, 这样会显得app.js有点杂乱.所以我们把app.js修改成这样
var routes = require('./routes/index'); var app = express(); // some thing routes(app);
然后把index.js改成这样
module.exports = function(app) { app.get('/', function(req, res, next) { res.render('index', { title: 'world' }); }); }
我们再运行app看一下
好, 现在我们就可以在index里面添加路由了.在/routes新建文件login.js, signup.js, logout.js, post.js然后修改index.js
var express = require('express'); var router = express.Router(); var login = require('./login'); var signup = require('./signup'); var logout = require('./logout'); var post = require('./post') module.exports = function(app) { app.get('/', function(req, res, next) { res.render('index', { title: 'world' }); }); app.use('/signup', signup); app.use('login', login); app.use('logout', logout); app.use('post', post); }
让app和数据库一起工作
在进行下一步操作之前我们要下两个包.一个是支持mongodb的, 一个是支持回话session的.打开终端, 在项目根目录敲下如下命令
$ sudo npm install mongodb express-session connect-mongo --save
安装完成之后.
在根目录创建setting.js 用来保存数据库的配置. 新建model文件夹, 用来盛放模型文件. 并且在model文件夹新建文件database.js. 然后分别写入以下内容.
database.js
var mongoDb = require('mongodb').MongoClient; var dbState = { db: null }; exports.connect = function(url, callback) { if (dbState.db) return callback(); mongoDb.connect(url, function(err, db) { if(err) return callback(err); dbState.db = db; return callback(); }); }; exports.get = function() { return dbState.db; }; exports.close = function(callback) { if(dbState.db){ dbState.db.close(function(err, result) { if(err) callback(err); dbState.db = null; }); } };
setting.js
module.exports = { cookieSecret: 'share', db: 'share', host: 'host', post: 27017 };
然后在app.js添加:
db.connect(dbUrl, function(err) { if (err) { console.log("can not connect to mongo"); process.exit(0); } console.log("connect to mongo success"); });
这样一来, 只要我们在运行app的时候, 就会自动链接数据库, 而且用dbStates保存数据库链接的状态, 连接一次, 复用多次, 可以说是单例模式的运用.
然后, 然后..我们终于可以开始设计首页, 注册和登陆的前端页面了. 在view里面新建signup.ejs, login.ejs, 如果要加样式的话, 把相应的样式文件写在/public/stylesheets里面.然后注意引入的时候路径是/stylesheets/xxx.css, 因为在app.js已经设置了静态文件的根目录是/public.
代码我这里就不直接给出了.大家可以在这里获取. 如果你觉得我的太丑也可以自己diy…
一切都弄好之后, 再运行app. 没错的话应该是这个样子滴:
处理逻辑
现在上面有四个按钮显然是不合适的, 合理的做法是根据用户是否登陆来选择显示.接下来我们来添加处理注册盒登陆的代码.在model文件夹新建文件user.js, 添加以下代码:
var mongodb = require('./database'); var assert = require('assert'); function User(user) { this.na = user.na; this.password = user.password; this.email= user.email; } module.exports = User; User.prototype.save = function(callback) { var user = { name: this.na, password: this.password, email: this.email }; mongodb.get().collection('users', function(err, collection) { if (err) { mongodb.close(); return callback(err); } assert('string', !typeof(user.name), user.name ); collection.insert(user, function(err, user) { if (err) { return callback(err); } assert.equal('object', typeof(user), "can not insert user"); callback(null, user); }); }); }; User.getByName = function(name, callback) { var doc = { name: name }; mongodb.get().collection('users', function(err, collection) { if(err) { mongodb.close(); return callback(err); } collection.findOne(doc, function(err, user) { if (err) { return callback(err); } callback(null, user); }); }); };
user分别有两个方法, 一个是保存用户信息的实例. 一个是通过名字获取那个户信息.然后在routes文件夹里面的signup.js 和login.js分别添加以下代码.
var crypto = require('crypto'); var User = require('../model/user'); var express = require('express'); var router = express.Router(); /* GET users listing. */ router.get('/', function(req, res, next) { res.render('signup', {title: 'signup'}); }); router.post('/' ,function(req, res, next) { var name = req.body.name, password = req.body.pwd, password_re = req.body.pwd_re; email = req.body.email; if (password != password_re) { req.flash('error', "two passsword is different"); return res.redirect('/signup'); } var md5 = crypto.createHash('md5'), password_hex = md5.update(password).digest('hex'); var newUser = new User ({ na: name, password: password_hex, email: email }); console.dir(newUser); User.getByName(name, function(err, user) { if (err) { req.flash('error', err); return res.redirect('/'); } if (user) { req.flash('error', "user has already exist"); return res.redirect('/login'); } newUser.save(function(err, user) { if (err) { return res.redirect('/'); } req.session.user = user; return res.redirect('/'); }); }); }); module.exports = router;
第21和22行是用对用户密码进行md5加密. 然后存储进数据库.
var crypto = require('crypto'); var User = require('../model/user'); var express = require('express'); var router = express.Router(); /* GET users listing. */ router.get('/', function(req, res, next) { res.render('login', {title: 'login', user: req.session.user}); }); router.post('/', function(req, res, next) { var name = req.body.name; var password = req.body.pwd; var md5 = crypto.createHash('md5'), password_hex = md5.update(password).digest('hex'); var newUser = new User ({ na: name, password: password_hex, email: "" }); User.getByName(name, function(err, user) { if (!user) { res.redirect('/login'); } if (password_hex != user.password) { req.flash("error", "password wrong!"); res.redirect("./login"); } req.session.user = user; res.redirect("/"); }); }); module.exports = router;
最后, 打开header.ejs模板(首页的代码可以从我的github找到.首页由header.ejs和content.ejs,footer.ejs组合而成), 修改内容为
<nav class='header-right'> <ul> <li> <% if(user) { %> <a class='button post' href='/post'>post</a > <% } else { %> <a class='button login' href='/login'>login</a > <% } %> </li> <li> <% if(user) { %> <a class='button logout ' href='/logout'>logout</a > <% } else { %> <a class='button reg ' href='/signup'>signup</a > <% } %> </li> <% if (user) {%> <li class="user"><a class='link' href='/u/<%= user.name%>'><%= user.name %></a ></li> <% } else {%> <li class="home"><a class='link' href='/'>home</a ></li> <% }%> </ul> </nav>
这样一来, 首页显示的按钮及时根据用户是否登陆而不同.
如果以上步骤都没有错, (这几乎是不可能的) 如果出错了, 请用以下步骤解决.
根据提示的错误查找代码看是否有明显的逻辑错误或者语法错误.大部分的错误都是这样引起的.
如果解决不了, 在博客下面留言, 或者在github issue区贴出来.
根据别的同学的回复查找错误.如果继续出错,回到第一步.
假设成功运行app, 打开浏览器应该是这样的
点击注册按钮
然后
点击logout
然后点击login, 用注册过的密码注册
登陆之后
终于, 我们完成了登陆和注册的功能, 由于需要一些初始化的工作, 和这是我第一次写博客, 所以导致这篇有点长…长…长…
如果大家有没看懂的地方, 今天的代码在day02
(今天的逼就装到这里, 谢谢大家.)
相关文章推荐
- 不完全node实践教程-第一发
- 基于 Node.js 实现前后端分离
- 【一天一道LeetCode】#25. Reverse Nodes in k-Group
- 【一天一道LeetCode】#25. Reverse Nodes in k-Group
- nodejs升级
- Node 之 Express 学习笔记 第二篇 Express 4x 骨架详解
- 关于windows下NODE_ENV=test无效的情况解决办法
- JQuery AJAX - NODEJS - Mysql 总结
- 利用nodejs搭建server端
- [译]Node.js 框架比较: Express vs. Koa vs. Hapi
- 24. Swap Nodes in Pairs
- ES6编码规范全部(含node部分)
- 新时代编辑神器:Atom
- 基于 Node.js 实现前后端分离
- 【一天一道LeetCode】#24. Swap Nodes in Pairs
- 【一天一道LeetCode】#24. Swap Nodes in Pairs
- 搭建Hadoop2集群出现Datanode启动不了的问题及解决办法
- Node.js#0基础
- Install Latest Versions NodeJS NPM on ubuntu
- 菜鸟学习nodejs--安装nodejs