├── book ├── img │ ├── 1.1.1.png │ ├── 1.1.2.png │ ├── 1.1.3.png │ ├── 1.1.4.png │ ├── 1.1.5.png │ ├── 1.2.1.png │ ├── 1.2.2.png │ ├── 1.2.3.png │ ├── 1.2.4.png │ ├── 1.2.5.png │ ├── 2.2.1.png │ ├── 2.6.1.png │ ├── 3.1.1.png │ ├── 3.1.2.png │ ├── 3.3.1.png │ ├── 3.4.1.png │ ├── 3.4.2.png │ ├── 4.2.1.png │ ├── 4.2.2.png │ ├── 4.5.1.jpg │ ├── 4.5.1.png │ ├── 4.5.2.png │ ├── 4.5.3.png │ ├── 4.5.4.png │ ├── 4.5.5.png │ ├── 4.5.6.png │ ├── 4.5.7.png │ ├── 4.5.8.png │ ├── 4.5.9.png │ ├── 4.7.1.png │ ├── 4.8.1.png │ ├── 4.8.2.png │ ├── 4.8.3.png │ ├── 4.14.1.png │ ├── 4.14.2.png │ ├── 4.14.3.png │ ├── 4.15.1.png │ ├── 4.15.2.png │ ├── 4.15.3.png │ ├── 4.5.10.png │ ├── 4.5.11.png │ ├── 4.5.12.png │ └── 4.5.13.png ├── 4.1 开发环境.md ├── 4.5 页面设计.md ├── 2.5 package.json.md ├── 2.3 Promise.md ├── 2.4 环境变量.md ├── 4.2 准备工作.md ├── 3.1 初始化一个 Express 项目.md ├── 4.3 配置文件.md ├── 1.2 MongoDB 的安装与使用.md ├── 2.2 exports 和 module.exports.md ├── 2.1 require.md ├── 1.1 Node.js 的安装与使用.md ├── 4.6 连接数据库.md ├── 2.6 npm 使用注意事项.md ├── 3.2 路由.md ├── 4.11 日志.md ├── 3.4 Express 浅析.md ├── 3.3 模板引擎.md ├── 4.8 登出与登录.md ├── 4.13 部署.md ├── 4.12 测试.md ├── 4.4 功能设计.md ├── 4.7 注册.md └── 4.9 添加商品.md ├── public └── images │ ├── xmsz-1.jpg │ ├── xmsz-3.jpg │ ├── xmsz-4.jpg │ └── xmsz-5.jpg ├── views ├── error.ejs ├── addcommodity.html ├── home.html ├── login.html ├── register.html └── cart.html ├── coverage ├── lcov-report │ ├── sort-arrow-sprite.png │ ├── prettify.css │ ├── mysession │ │ ├── routes │ │ │ ├── index.js.html │ │ │ ├── logout.js.html │ │ │ ├── login.js.html │ │ │ ├── index.html │ │ │ ├── home.js.html │ │ │ └── register.js.html │ │ ├── config │ │ │ ├── default.js.html │ │ │ ├── multerUtil.js.html │ │ │ └── index.html │ │ ├── index.html │ │ ├── middlewares │ │ │ ├── testController.js.html │ │ │ ├── index.html │ │ │ └── check.js.html │ │ └── common │ │ │ ├── dbHelper.js.html │ │ │ ├── models.js.html │ │ │ └── index.html │ ├── sorter.js │ ├── base.css │ └── index.html └── lcov.info ├── routes ├── index.js ├── logout.js ├── login.js ├── home.js ├── register.js └── cart.js ├── config ├── default.js └── multerUtil.js ├── common ├── dbHelper.js └── models.js ├── middlewares ├── testController.js └── check.js ├── package.json ├── app.js └── test └── register.js /book/img/1.1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.1.1.png -------------------------------------------------------------------------------- /book/img/1.1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.1.2.png -------------------------------------------------------------------------------- /book/img/1.1.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.1.3.png -------------------------------------------------------------------------------- /book/img/1.1.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.1.4.png -------------------------------------------------------------------------------- /book/img/1.1.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.1.5.png -------------------------------------------------------------------------------- /book/img/1.2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.2.1.png -------------------------------------------------------------------------------- /book/img/1.2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.2.2.png -------------------------------------------------------------------------------- /book/img/1.2.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.2.3.png -------------------------------------------------------------------------------- /book/img/1.2.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.2.4.png -------------------------------------------------------------------------------- /book/img/1.2.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/1.2.5.png -------------------------------------------------------------------------------- /book/img/2.2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/2.2.1.png -------------------------------------------------------------------------------- /book/img/2.6.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/2.6.1.png -------------------------------------------------------------------------------- /book/img/3.1.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/3.1.1.png -------------------------------------------------------------------------------- /book/img/3.1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/3.1.2.png -------------------------------------------------------------------------------- /book/img/3.3.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/3.3.1.png -------------------------------------------------------------------------------- /book/img/3.4.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/3.4.1.png -------------------------------------------------------------------------------- /book/img/3.4.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/3.4.2.png -------------------------------------------------------------------------------- /book/img/4.2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.2.1.png -------------------------------------------------------------------------------- /book/img/4.2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.2.2.png -------------------------------------------------------------------------------- /book/img/4.5.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.1.jpg -------------------------------------------------------------------------------- /book/img/4.5.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.1.png -------------------------------------------------------------------------------- /book/img/4.5.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.2.png -------------------------------------------------------------------------------- /book/img/4.5.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.3.png -------------------------------------------------------------------------------- /book/img/4.5.4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.4.png -------------------------------------------------------------------------------- /book/img/4.5.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.5.png -------------------------------------------------------------------------------- /book/img/4.5.6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.6.png -------------------------------------------------------------------------------- /book/img/4.5.7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.7.png -------------------------------------------------------------------------------- /book/img/4.5.8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.8.png -------------------------------------------------------------------------------- /book/img/4.5.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.9.png -------------------------------------------------------------------------------- /book/img/4.7.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.7.1.png -------------------------------------------------------------------------------- /book/img/4.8.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.8.1.png -------------------------------------------------------------------------------- /book/img/4.8.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.8.2.png -------------------------------------------------------------------------------- /book/img/4.8.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.8.3.png -------------------------------------------------------------------------------- /book/img/4.14.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.14.1.png -------------------------------------------------------------------------------- /book/img/4.14.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.14.2.png -------------------------------------------------------------------------------- /book/img/4.14.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.14.3.png -------------------------------------------------------------------------------- /book/img/4.15.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.15.1.png -------------------------------------------------------------------------------- /book/img/4.15.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.15.2.png -------------------------------------------------------------------------------- /book/img/4.15.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.15.3.png -------------------------------------------------------------------------------- /book/img/4.5.10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.10.png -------------------------------------------------------------------------------- /book/img/4.5.11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.11.png -------------------------------------------------------------------------------- /book/img/4.5.12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.12.png -------------------------------------------------------------------------------- /book/img/4.5.13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/book/img/4.5.13.png -------------------------------------------------------------------------------- /public/images/xmsz-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/public/images/xmsz-1.jpg -------------------------------------------------------------------------------- /public/images/xmsz-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/public/images/xmsz-3.jpg -------------------------------------------------------------------------------- /public/images/xmsz-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/public/images/xmsz-4.jpg -------------------------------------------------------------------------------- /public/images/xmsz-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/public/images/xmsz-5.jpg -------------------------------------------------------------------------------- /views/error.ejs: -------------------------------------------------------------------------------- 1 |
<%= error.stack %>4 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/18820227745/shop-demo-node/HEAD/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function(app){ 2 | require('./login')(app); 3 | require('./home')(app); 4 | require('./logout')(app); 5 | require('./register')(app); 6 | require('./cart')(app); 7 | } -------------------------------------------------------------------------------- /config/default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 3000, 3 | session: { 4 | secret: 'e-commerce', 5 | key: 'e-commerce', 6 | maxAge: 1000 * 60 * 30 7 | }, 8 | mongodb: 'mongodb://localhost:27017/e-commerce' 9 | }; 10 | -------------------------------------------------------------------------------- /routes/logout.js: -------------------------------------------------------------------------------- 1 | module.exports = function ( app ) { 2 | //退出登录 3 | app.get('/logout', function(req, res){ 4 | req.session.user = null; 5 | req.session.error = null; 6 | res.redirect('/home'); 7 | }); 8 | } -------------------------------------------------------------------------------- /book/4.1 开发环境.md: -------------------------------------------------------------------------------- 1 | 从本章开始,正式学习如何使用 Express + MongoDB 搭建一个简单的小电商网站。 2 | 3 | ### Node.js: `6.11.0` 4 | 5 | ### MongoDB: `3.4.2` 6 | 7 | ### Express: `3.4.8` 8 | 9 | 上一节:[3.4 Express 浅析](https://github.com/18820227745/shop-demo-node/blob/master/book/3.4%20Express%20%E6%B5%85%E6%9E%90.md) 10 | 11 | 下一节:[4.2 准备工作](https://github.com/18820227745/shop-demo-node/blob/master/book/4.2%20%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C.md) 12 | -------------------------------------------------------------------------------- /common/dbHelper.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'), 2 | Schema = mongoose.Schema, 3 | models = require('./models'); 4 | 5 | for (var m in models) { 6 | mongoose.model(m, new Schema(models[m])); 7 | } 8 | module.exports = { 9 | getModel: function (type) { 10 | return _getModel(type); 11 | } 12 | }; 13 | 14 | var _getModel = function (type) { 15 | return mongoose.model(type); 16 | }; 17 | 18 | 19 | -------------------------------------------------------------------------------- /middlewares/testController.js: -------------------------------------------------------------------------------- 1 | var muilter = require('../config/multerUtil'); 2 | //multer有single()中的名称必须是表单上传字段的name名称。 3 | var upload = muilter.single('imgSrc'); 4 | exports.dataInput = function (req, res) { 5 | upload(req, res, function (err) { 6 | //添加错误处理 7 | if (err) { 8 | return console.log(err); 9 | } 10 | //文件信息在req.file或者req.files中显示。 11 | console.log(req); 12 | }); 13 | } -------------------------------------------------------------------------------- /middlewares/check.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | checkLogin: function checkLogin(req, res, next) { 3 | if (!req.session.user) { 4 | req.session.error = "请先登录"; 5 | res.redirect("/login"); 6 | } 7 | next(); 8 | }, 9 | 10 | checkNotLogin: function checkNotLogin(req, res, next) { 11 | if (req.session.user) { 12 | req.session.error = "已登录"; 13 | return res.redirect('back');//返回之前的页面 14 | } 15 | next(); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /common/models.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | user:{ 3 | name: {type: String}, 4 | password: {type: String} 5 | }, 6 | commodity: { 7 | name: String, 8 | price: Number, 9 | imgSrc: String 10 | }, 11 | cart: { 12 | uId: {type: String}, 13 | cId: {type: String}, 14 | cName: { type: String}, 15 | cPrice: { type: String}, 16 | cImaSrc: { type: String}, 17 | cQuantity: { type: Number}, 18 | cStatus: { type: Boolean,default: false} 19 | } 20 | } -------------------------------------------------------------------------------- /config/multerUtil.js: -------------------------------------------------------------------------------- 1 | var multer = require('multer'); 2 | var storage = multer.diskStorage({ 3 | //设置上传后文件路径,uploads文件夹会自动创建。 4 | destination: function (req, file, cb) { 5 | cb(null, '../public/images') 6 | }, 7 | //给上传文件重命名,获取添加后缀名 8 | filename: function (req, file, cb) { 9 | var fileFormat = (file.originalname).split("."); 10 | cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]); 11 | } 12 | }); 13 | //添加配置文件到muler对象。 14 | var upload = multer({ 15 | storage: storage 16 | }); 17 | 18 | module.exports = upload; -------------------------------------------------------------------------------- /book/4.5 页面设计.md: -------------------------------------------------------------------------------- 1 | 我们使用 jQuery + Semantic-UI 实现前端页面的设计,最终效果图如下: 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 | 上一节:[4.4 功能设计](https://github.com/18820227745/shop-demo-node/blob/master/book/4.4%20%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1.md) 31 | 32 | 下一节:[4.6 连接数据库](https://github.com/18820227745/shop-demo-node/blob/master/book/4.6%20%E8%BF%9E%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93.md) 33 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e-commerce", 3 | "version": "0.0.2", 4 | "private": true, 5 | "scripts": { 6 | "start": "node app.js", 7 | "test": "node --harmony ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha" 8 | }, 9 | "dependencies": { 10 | "body-parser": "~1.10.0", 11 | "config-lite": "^2.0.0", 12 | "connect-multiparty": "^2.0.0", 13 | "ejs": "~0.8.5", 14 | "express": "~3.4.8", 15 | "express-formidable": "^1.0.0", 16 | "express-session": "~1.9.3", 17 | "express-winston": "^2.4.0", 18 | "mongoose": "~3.8.1", 19 | "multer": "^1.3.0", 20 | "path": "~0.4.9", 21 | "sha1": "^1.1.1", 22 | "winston": "^2.3.1" 23 | }, 24 | "devDependencies": { 25 | "istanbul": "^0.4.5", 26 | "mocha": "^3.4.2", 27 | "supertest": "^3.0.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /routes/login.js: -------------------------------------------------------------------------------- 1 | var sha1 = require('sha1'); 2 | module.exports = function(app){ 3 | //登录页面 4 | app.get('/login',function(req,res){ 5 | res.render('login'); 6 | }); 7 | //登录 8 | app.post('/login',function(req,res){ 9 | var User = global.dbHelper.getModel('user'), 10 | uname = req.body.uname; 11 | //查询数据库 12 | User.findOne({name: uname}, function(error,doc){ 13 | if(error){ 14 | res.send(500); 15 | console.log(error); 16 | }else if(!doc){ 17 | req.session.error = "用户名不存在!"; 18 | res.send(404); 19 | }else{ 20 | if(req.body.upwd !== doc.password ){ 21 | req.session.error = "密码错误!"; 22 | res.send(404); 23 | }else{ 24 | req.session.user = doc; 25 | res.send(200); 26 | } 27 | } 28 | }); 29 | }); 30 | } -------------------------------------------------------------------------------- /book/2.5 package.json.md: -------------------------------------------------------------------------------- 1 | package.json 对于 Node.js 应用来说是一个不可或缺的文件,它存储了该 Node.js 应用的名字、版本、描述、作者、入口文件、脚本、版权等等信息。npm 官网有 package.json 每个字段的详细介绍:[https://docs.npmjs.com/files/package.json](https://docs.npmjs.com/files/package.json)。 2 | 3 | ## 2.5.1 semver 4 | 5 | 语义化版本(semver)即 dependencies、devDependencies 和 peerDependencies 里的如:`"co": "^4.6.0"`。 6 | 7 | semver 格式:`主版本号.次版本号.修订号`。版本号递增规则如下: 8 | 9 | - `主版本号`:做了不兼容的 API 修改 10 | - `次版本号`:做了向下兼容的功能性新增 11 | - `修订号`:做了向下兼容的 bug 修正 12 | 13 | 更多阅读: 14 | 15 | 1. http://semver.org/lang/zh-CN/ 16 | 2. http://taobaofed.org/blog/2016/08/04/instructions-of-semver/ 17 | 18 | 作为 Node.js 的开发者,我们在发布 npm 模块的时候一定要遵守语义化版本的命名规则,即:有 breaking change 发大版本,有新增的功能发小版本,有小的 bug 修复或优化则发修订版本。 19 | 20 | 上一节:[2.4 环境变量](https://github.com/18820227745/shop-demo-node/blob/master/book/2.4%20%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F.md) 21 | 22 | 下一节:[2.6 npm 使用注意事项](https://github.com/18820227745/shop-demo-node/blob/master/book/2.6%20npm%20%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9.md) -------------------------------------------------------------------------------- /book/2.3 Promise.md: -------------------------------------------------------------------------------- 1 | 网上已经有许多关于 Promise 的资料了,这里不在赘述。以下 4 个链接供读者学习: 2 | 3 | 1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (基础) 4 | 2. http://liubin.org/promises-book/ (开源 Promise 迷你书) 5 | 3. http://fex.baidu.com/blog/2015/07/we-have-a-problem-with-promises/ (进阶) 6 | 4. https://promisesaplus.com/ (官方定义规范) 7 | 8 | Promise 用于异步流程控制,生成器与 yield 也能实现流程控制(基于 co),但不在本教程讲解范围内,读者可参考我的另一部教程 [N-club](https://github.com/nswbmw/N-club)。async/await 结合 Promise 也可以实现流程控制,有兴趣请查阅 [《ECMAScript6入门》](http://es6.ruanyifeng.com/#docs/async#async函数)。 9 | 10 | ### 深入 Promise 11 | 12 | - [深入 Promise(一)——Promise 实现详解](https://zhuanlan.zhihu.com/p/25178630) 13 | - [深入 Promise(二)——进击的 Promise](https://zhuanlan.zhihu.com/p/25198178) 14 | - [深入 Promise(三)——命名 Promise](https://zhuanlan.zhihu.com/p/25199781) 15 | 16 | 上一节:[2.2 exports 和 module.exports](https://github.com/nswbmw/N-blog/blob/master/book/2.2%20exports%20%E5%92%8C%20module.exports.md) 17 | 18 | 下一节:[2.4 环境变量](https://github.com/nswbmw/N-blog/blob/master/book/2.4%20%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F.md) 19 | -------------------------------------------------------------------------------- /book/2.4 环境变量.md: -------------------------------------------------------------------------------- 1 | 环境变量不属于 Node.js 的知识范畴,只不过我们在开发 Node.js 应用时经常与环境变量打交道,所以这里简单介绍下。 2 | 3 | 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。在 Mac 和 Linux 的终端直接输入 env,会列出当前的环境变量,如:USER=xxx。简单来讲,环境变量就是传递参数给运行程序的。 4 | 5 | 在 Node.js 中,我们经常这么用: 6 | 7 | ``` 8 | NODE_ENV=test node app 9 | ``` 10 | 11 | 通过以上命令启动程序,指定当前环境变量 `NODE_ENV` 的值为 test,那么在 app.js 中可通过 `process.env` 来获取环境变量: 12 | 13 | ``` 14 | console.log(process.env.NODE_ENV) //test 15 | ``` 16 | 17 | 另一个常见的例子是使用 [debug](https://www.npmjs.com/package/debug) 模块时: 18 | 19 | ``` 20 | DEBUG=* node app 21 | ``` 22 | 23 | Windows 用户需要首先设置环境变量,然后再执行程序: 24 | 25 | ``` 26 | set DEBUG=* 27 | set NODE_ENV=test 28 | node app 29 | ``` 30 | 31 | 或者使用 [cross-env](https://www.npmjs.com/package/cross-env): 32 | 33 | ``` 34 | npm i cross-env -g 35 | ``` 36 | 37 | 使用方式: 38 | 39 | ``` 40 | cross-env NODE_ENV=test node app 41 | ``` 42 | 43 | 上一节:[2.3 Promise](https://github.com/18820227745/shop-demo-node/blob/master/book/2.3%20Promise.md) 44 | 45 | 下一节:[2.5 packge.json](https://github.com/18820227745/shop-demo-node/blob/master/book/2.5%20package.json.md) -------------------------------------------------------------------------------- /book/4.2 准备工作.md: -------------------------------------------------------------------------------- 1 | ## 4.2.1 目录结构 2 | 3 | 我们停止 supervisor 并删除 e-commerce 目录从头来过。重新创建 e-commerce,运行 `npm init`,如下: 4 | 5 |  6 | 7 | 在 myblog 目录下创建以下目录及空文件(package.json 除外): 8 | 9 |  10 | 11 | 对应文件及文件夹的用处: 12 | 13 | 1. `book`: 项目的说明文档 14 | 2. `common`: 数据库模板,操作数据库接口等 15 | 2. `public`: 存放静态文件,如样式、图片等 16 | 3. `routes`: 存放路由文件 17 | 4. `views`: 存放模板文件 18 | 5. `app.js`: 程序主文件 19 | 6. `package.json`: 存储项目名、描述、作者、依赖等等信息 20 | 21 | 22 | > 小提示:不知读者发现了没有,我们遵循了 MVC(模型(model)-视图(view)-控制器(controller/route)) 的开发模式。 23 | 24 | ## 4.2.2 安装依赖模块 25 | 26 | 运行以下命令安装所需模块: 27 | 28 | ``` 29 | npm i express express-session body-parser multer mongoose config-lite ejs sha1 --save 30 | ``` 31 | 32 | 对应模块的用处: 33 | 34 | 1. `express`: web 框架 35 | 2. `express-session`: session 中间件 36 | 3. `body-parser`: 解析客户端请求的body 37 | 4. `multer`: 文件上传中间件 38 | 5. `mongoose`: mongdb数据库 39 | 6. `ejs`: 模板 40 | 7. `config-lite`: 读取配置文件 41 | 8. `sha1`: 加密模块 42 | 43 | 44 | 后面会详细讲解这些模块的用处。 45 | 46 | 上一节:[4.1 开发环境](https://github.com/18820227745/shop-demo-node/blob/master/book/4.1%20%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83.md) 47 | 48 | 下一节:[4.3 配置文件](https://github.com/18820227745/shop-demo-node/blob/master/book/4.3%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6.md) 49 | -------------------------------------------------------------------------------- /book/3.1 初始化一个 Express 项目.md: -------------------------------------------------------------------------------- 1 | 首先,我们新建一个目录 myblog,在该目录下运行 `npm init` 生成一个 package.json,如下所示: 2 | 3 |  4 | 5 | > 注意:括号里的是默认值,如果使用默认值则直接回车即可,否则输入自定义内容后回车。 6 | 7 | 然后安装 express 并写入 package.json: 8 | 9 | ``` 10 | npm i express@4.14.0 --save 11 | ``` 12 | 13 | 新建 index.js,添加如下代码: 14 | 15 | ``` 16 | var express = require('express'); 17 | var app = express(); 18 | 19 | app.get('/', function(req, res) { 20 | res.send('hello, express'); 21 | }); 22 | 23 | app.listen(3000); 24 | ``` 25 | 26 | 以上代码的意思是:生成一个 express 实例 app,挂载了一个根路由控制器,然后监听 3000 端口并启动程序。运行 `node index`,打开浏览器访问 `localhost:3000` 时,页面应显示 hello, express。 27 | 28 | 这是最简单的一个使用 express 的例子,后面会介绍路由及模板的使用。 29 | 30 | ## 3.1.1 supervisor 31 | 32 | 在开发过程中,每次修改代码保存后,我们都需要手动重启程序,才能查看改动的效果。使用 [supervisor](https://www.npmjs.com/package/supervisor) 可以解决这个繁琐的问题,全局安装 supervisor: 33 | 34 | ``` 35 | npm install -g supervisor 36 | ``` 37 | 38 | 运行 `supervisor --harmony index` 启动程序,如下所示: 39 | 40 |  41 | 42 | supervisor 会监听当前目录下 node 和 js 后缀的文件,当这些文件发生改动时,supervisor 会自动重启程序。 43 | 44 | 上一节:[2.6 npm 使用注意事项](https://github.com/18820227745/shop-demo-node/blob/master/book/2.6%20npm%20%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9.md) 45 | 46 | 下一节:[3.2 路由](https://github.com/18820227745/shop-demo-node/blob/master/book/3.2%20%E8%B7%AF%E7%94%B1.md) -------------------------------------------------------------------------------- /routes/home.js: -------------------------------------------------------------------------------- 1 | var testController=require('../middlewares/testController'); 2 | //将检查登录封装成中间件 3 | var multipart = require('connect-multiparty'); 4 | var multipartMiddleware = multipart({ uploadDir: '../public/' }); 5 | var checkLogin = require('../middlewares/check').checkLogin; 6 | module.exports = function (app){ 7 | //home页面为登录时可以直接浏览 8 | app.get('/home',function(req,res){ 9 | var Commodity = global.dbHelper.getModel("commodity"); 10 | var login = { 11 | href:'/login', 12 | message: '登 录' 13 | }; 14 | if (req.session.user) { 15 | login.href='/logout'; 16 | login.message='退 出'; 17 | } 18 | Commodity.find({},function(error,docs){ 19 | res.render('home',{Commoditys:docs,login:login}); 20 | }); 21 | }); 22 | //添加商品页 23 | app.get('/addcommodity',checkLogin,function(req,res){ 24 | //render可以带变量,渲染页面 25 | res.render("addcommodity"); 26 | }); 27 | //添加商品 28 | app.post('/addcommodity',checkLogin,multipartMiddleware, function(req,res){ 29 | var Commodity = global.dbHelper.getModel("commodity"); 30 | Commodity.create({ 31 | name: req.body.name, 32 | price: req.body.price, 33 | price: req.body.price, 34 | imgSrc: req.body.imgSrc 35 | },function(error,doc){ 36 | if(doc){ 37 | res.send(200); 38 | }else{ 39 | res.send(404); 40 | } 41 | }) 42 | }); 43 | } -------------------------------------------------------------------------------- /book/4.3 配置文件.md: -------------------------------------------------------------------------------- 1 | 不管是小项目还是大项目,将配置与代码分离是一个非常好的做法。我们通常将配置写到一个配置文件里,如 config.js 或 config.json ,并放到项目的根目录下。但通常我们都会有许多环境,如本地开发环境、测试环境和线上环境等,不同的环境的配置不同,我们不可能每次部署时都要去修改引用 config.test.js 或者 config.production.js。config-lite 模块正是你需要的。 2 | 3 | ## 4.3.1 config-lite 4 | 5 | [config-lite](https://www.npmjs.com/package/config-lite) 是一个轻量的读取配置文件的模块。config-lite 会根据环境变量(`NODE_ENV`)的不同从当前执行进程目录下的 config 目录加载不同的配置文件。如果不设置 `NODE_ENV`,则读取默认的 default 配置文件,如果设置了 `NODE_ENV`,则会合并指定的配置文件和 default 配置文件作为配置,config-lite 支持 .js、.json、.node、.yml、.yaml 后缀的文件。 6 | 7 | 如果程序以 `NODE_ENV=test node app` 启动,则 config-lite 会依次降级查找 `config/test.js`、`config/test.json`、`config/test.node`、`config/test.yml`、`config/test.yaml` 并合并 default 配置; 如果程序以 `NODE_ENV=production node app` 启动,则 config-lite 会依次降级查找 `config/production.js`、`config/production.json`、`config/production.node`、`config/production.yml`、`config/production.yaml` 并合并 default 配置。 8 | 9 | 在 myblog 下新建 config 目录,在该目录下新建 default.js,添加如下代码: 10 | 11 | **config/default.js** 12 | 13 | ``` 14 | module.exports = { 15 | port: 3000, 16 | session: { 17 | secret: 'e-commerce', 18 | key: 'e-commerce', 19 | maxAge: 1000 * 60 * 30 20 | }, 21 | mongodb: 'mongodb://localhost:27017/e-commerce' 22 | }; 23 | ``` 24 | 25 | 配置释义: 26 | 27 | 1. `port`: 程序启动要监听的端口号 28 | 2. `session`: express-session 的配置信息,后面介绍 29 | 3. `mongodb`: mongodb 的地址,`e-commerce` 为 db 名 30 | 31 | 上一节:[4.2 准备工作](https://github.com/18820227745/shop-demo-node/blob/master/book/4.2%20%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C.md) 32 | 33 | 下一节:[4.4 功能设计](https://github.com/18820227745/shop-demo-node/blob/master/book/4.4%20%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1.md) -------------------------------------------------------------------------------- /book/1.2 MongoDB 的安装与使用.md: -------------------------------------------------------------------------------- 1 | ## 1.2.1 安装与启动 MongoDB 2 | 3 | - Windows 用户向导:https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/ 4 | - Linux 用户向导:https://docs.mongodb.com/manual/administration/install-on-linux/ 5 | - Mac 用户向导:https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/ 6 | 7 | ## 1.2.2 Robomongo 和 Mongochef 8 | 9 | #### Robomongo 10 | 11 | [Robomongo](https://robomongo.org/) 是一个基于 Shell 的跨平台开源 MongoDB 可视化管理工具,支持 Windows、Linux 和 Mac,嵌入了 JavaScript 引擎和 MongoDB mongo,只要你会使用 mongo shell,你就会使用 Robomongo,它还提了供语法高亮、自动补全、差别视图等。 12 | 13 | [Robomongo 下载地址](https://robomongo.org/download) 14 | 15 | 下载并安装成功后点击左上角的 `Create` 创建一个连接,给该连接起个名字如: `localhost`,使用默认地址(localhost)和端口(27017)即可,点击 `Save` 保存。 16 | 17 |  18 | 19 | 20 | 双击 `localhost` 连接到 MongoDB 并进入交互界面,尝试插入一条数据并查询出来,如下所示: 21 | 22 |  23 | 24 | 25 | #### MongoChef 26 | 27 | [MongoChef](http://3t.io/mongochef/) 是另一款强大的 MongoDB 可视化管理工具,支持 Windows、Linux 和 Mac。 28 | 29 | [MongoChef 下载地址](http://3t.io/mongochef/#mongochef-download-compare),我们选择左侧的非商业用途的免费版下载。 30 | 31 |  32 | 33 | 安装成功后跟 Robomongo 一样,也需要创建一个新的连接的配置,成功后双击进入到 MongoChef 主页面,如下所示: 34 | 35 |  36 | 37 | 还可以使用 shell 模式: 38 | 39 |  40 | 41 | > 小提示: MongoChef 相较于 Robomongo 更强大一些,但 Robomongo 比较轻量也能满足大部分的常规需求,所以哪一个适合自己还需读者自行尝试。 42 | 43 | 上一节:[1.1 Node.js 的安装与使用](https://github.com/18820227745/shop-demo-node/blob/master/book/1.1%20Node.js%20%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8.md) 44 | 45 | 下一节:[2.1 require](https://github.com/18820227745/shop-demo-node/blob/master/book/2.1%20require.md) -------------------------------------------------------------------------------- /book/2.2 exports 和 module.exports.md: -------------------------------------------------------------------------------- 1 | require 用来加载代码,而 exports 和 module.exports 则用来导出代码。 2 | 3 | 很多新手可能会迷惑于 exports 和 module.exports 的区别,为了更好的理解 exports 和 module.exports 的关系,我们先来巩固下 js 的基础。示例: 4 | 5 | **test.js** 6 | 7 | ``` 8 | var a = {name: 1}; 9 | var b = a; 10 | 11 | console.log(a); 12 | console.log(b); 13 | 14 | b.name = 2; 15 | console.log(a); 16 | console.log(b); 17 | 18 | var b = {name: 3}; 19 | console.log(a); 20 | console.log(b); 21 | ``` 22 | 23 | 运行 test.js 结果为: 24 | 25 | ``` 26 | { name: 1 } 27 | { name: 1 } 28 | { name: 2 } 29 | { name: 2 } 30 | { name: 2 } 31 | { name: 3 } 32 | ``` 33 | 34 | **解释**:a 是一个对象,b 是对 a 的引用,即 a 和 b 指向同一块内存,所以前两个输出一样。当对 b 作修改时,即 a 和 b 指向同一块内存地址的内容发生了改变,所以 a 也会体现出来,所以第三四个输出一样。当 b 被覆盖时,b 指向了一块新的内存,a 还是指向原来的内存,所以最后两个输出不一样。 35 | 36 | 明白了上述例子后,我们只需知道三点就知道 exports 和 module.exports 的区别了: 37 | 38 | 1. module.exports 初始值为一个空对象 {} 39 | 2. exports 是指向的 module.exports 的引用 40 | 3. require() 返回的是 module.exports 而不是 exports 41 | 42 | Node.js 官方文档的截图证实了我们的观点: 43 | 44 |  45 | 46 | #### exports = module.exports = {...} 47 | 48 | 我们经常看到这样的写法: 49 | 50 | ``` 51 | exports = module.exports = {...} 52 | ``` 53 | 54 | 上面的代码等价于: 55 | 56 | ``` 57 | module.exports = {...} 58 | exports = module.exports 59 | ``` 60 | 61 | 原理很简单:module.exports 指向新的对象时,exports 断开了与 module.exports 的引用,那么通过 exports = module.exports 让 exports 重新指向 module.exports。 62 | 63 | > 小提示:ES6 的 import 和 export 不在本文的讲解范围,有兴趣的读者可以去学习阮一峰老师的[《ECMAScript6入门》](http://es6.ruanyifeng.com/)。 64 | 65 | 上一节:[2.1 require](https://github.com/18820227745/shop-demo-node/blob/master/book/2.1%20require.md) 66 | 67 | 下一节:[2.3 Promise](https://github.com/18820227745/shop-demo-node/blob/master/book/2.3%20Promise.md) -------------------------------------------------------------------------------- /book/2.1 require.md: -------------------------------------------------------------------------------- 1 | require 用来加载一个文件的代码,关于 require 的机制这里不展开讲解,请仔细阅读 [官方文档](https://nodejs.org/api/modules.html)。 2 | 3 | 简单概括以下几点: 4 | 5 | - require 可加载 .js、.json 和 .node 后缀的文件 6 | - require 的过程是同步的,所以这样是错误的: 7 | ``` 8 | setTimeout(() => { 9 | module.exports = { a: 'hello' }; 10 | }, 0); 11 | ``` 12 | require 这个文件得到的是空对象 `{}` 13 | 14 | - require 目录的机制是: 15 | - 如果目录下有 package.json 并指定了 main 字段,则用之 16 | - 如果不存在 package.json,则依次尝试加载目录下的 index.js 和 index.node 17 | - require 过的文件会加载到缓存,所以多次 require 同一个文件(模块)不会重复加载 18 | - 判断是否是程序的入口文件有两种方式: 19 | - require.main === module(推荐) 20 | - module.parent === null 21 | 22 | 23 | #### 循环引用 24 | 25 | 循环引用(或循环依赖)简单点来说就是 a 文件 require 了 b 文件,然后 b 文件又反过来 require 了 a 文件。我们用 a->b 代表 b require 了 a。 26 | 27 | 简单的情况: 28 | 29 | ``` 30 | a->b 31 | b->a 32 | ``` 33 | 34 | 复杂点的情况: 35 | 36 | ``` 37 | a->b 38 | b->c 39 | c->a 40 | ``` 41 | 42 | 循环引用并不会报错,导致的结果是 require 的结果是空对象 `{}`,原因是 b require 了 a,a 又去 require 了 b,此时 b 还没初始化好,所以只能拿到初始值 `{}`。当产生循环引用时一般有两种方法解决: 43 | 44 | 1. 通过分离共用的代码到另一个文件解决,如上面简单的情况,可拆出共用的代码到 c 中,如下: 45 | 46 | ``` 47 | c->a 48 | c->b 49 | ``` 50 | 51 | 2. 不在最外层 require,在用到的地方 require,通常在函数的内部 52 | 53 | 总的来说,循环依赖的陷阱并不大容易出现,但一旦出现了,对于新手来说还真不好定位。它的存在给我们提了个醒,要时刻注意你项目的依赖关系不要过于复杂,哪天你发现一个你明明已经 exports 了的方法报 `undefined is not a function`,我们就该提醒一下自己:哦,也许是它来了。 54 | 55 | 官方示例: [https://nodejs.org/api/modules.html#modules_cycles](https://nodejs.org/api/modules.html#modules_cycles) 56 | 57 | 上一节:[1.2 MongoDB 的安装与使用](https://github.com/18820227745/shop-demo-node/blob/master/book/1.2%20MongoDB%20%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8.md) 58 | 59 | 下一节:[2.2 exports 和 module.exports](https://github.com/18820227745/shop-demo-node/blob/master/book/2.2%20exports%20%E5%92%8C%20module.exports.md) 60 | -------------------------------------------------------------------------------- /routes/register.js: -------------------------------------------------------------------------------- 1 | var sha1 = require('sha1'); 2 | module.exports = function (app) { 3 | app.get('/register', function (req, res) { 4 | res.render("register"); 5 | }); 6 | //解析表单,并写入数据库 7 | app.post("/register", function (req, res) { 8 | var User = global.dbHelper.getModel('user'); 9 | var uname = req.body.username; 10 | // 校验参数 11 | try { 12 | if (!(uname.length >= 1 && uname.length <= 10)) { 13 | throw new Error('名字请限制在 1-10 个字符'); 14 | } 15 | if (req.body.password !== req.body.confirmpwd) { 16 | throw new Error('两次输入密码不一致'); 17 | } 18 | } catch (e) { 19 | // 注册失败 20 | console.log("e.message_----------",e.message); 21 | req.session.error = e.message; 22 | return res.redirect('/register'); 23 | } 24 | User.findOne({ name: uname }, function (error, doc) { 25 | if (error) { 26 | res.send(500); 27 | req.session.error = '网络异常错误!'; 28 | console.log(error); 29 | } else if (doc) { 30 | req.session.error = "用户已存在!"; 31 | res.send(500); 32 | } else { 33 | User.create({ 34 | name: uname, 35 | password: req.body.upwd 36 | }, function (error, doc) { 37 | if (error) { 38 | res.send(500); 39 | console.log(error); 40 | } else { 41 | req.session.error = "用户创建成功!"; 42 | res.redirect("login"); 43 | res.send(200); 44 | } 45 | }); 46 | } 47 | }); 48 | }); 49 | } -------------------------------------------------------------------------------- /book/1.1 Node.js 的安装与使用.md: -------------------------------------------------------------------------------- 1 | ## 1.1.1 安装 Node.js 2 | 3 | 有三种方式安装 Node.js:一是通过安装包安装,二是通过源码编译安装,三是在 Linux 下可以通过 yum|apt-get 安装,在 Mac 下可以通过 [Homebrew](http://brew.sh/) 安装。对于 Windows 和 Mac 用户,推荐使用安装包安装,Linux 用户推荐使用源码编译安装。 4 | 5 | #### Windows 和 Mac 安装: 6 | 7 | **第一步:** 8 | 9 | 打开 [Node.js 官网](https://nodejs.org/en/),可以看到以下两个下载选项: 10 | 11 |  12 | 13 | 左边的是 LTS 版,用过 ubuntu 的同学可能比较熟悉,即长期支持版本,大多数人用这个就可以了。右边是最新版,支持最新的语言特性(比如对 ES6 的支持更全面),想尝试新特性的开发者可以安装这个版本。我们选择左边的 v6.11.1 LTS 点击下载。 14 | 15 | > 小提示:从 [http://node.green](http://node.green) 上可以看到 Node.js 各个版本对 ES6 的支持情况。 16 | 17 | **第二步:** 18 | 19 | 安装 Node.js,这个没什么好说的,一直点击 `继续` 即可。 20 | 21 |  22 | 23 | **第三步:** 24 | 25 | 提示安装成功后,打开终端输入以下命令,可以看到 node 和 npm 都已经安装好了: 26 | 27 |  28 | 29 | #### Linux 安装: 30 | 31 | Linux 用户可通过源码编译安装: 32 | 33 | ``` 34 | curl -O https://nodejs.org/dist/v6.9.1/node-v6.9.1.tar.gz 35 | tar -xzvf node-v6.9.1.tar.gz 36 | cd node-v6.9.1 37 | ./configure 38 | make 39 | make install 40 | ``` 41 | 42 | > 注意: 如果编译过程报错,可能是缺少某些依赖包。因为报错内容不尽相同,请读者自行求助搜索引擎或 [stackoverflow](http://stackoverflow.com/)。 43 | 44 | ## 1.1.2 n 和 nvm 45 | 46 | 通常我们使用稳定的 LTS 版本的 Node.js 即可,但有的情况下我们又想尝试一下新的特性,我们总不能来回安装不同版本的 Node.js 吧,这个时候我们就需要 [n](https://github.com/tj/n) 或者 [nvm](https://github.com/creationix/nvm) 了。n 和 nvm 是两个常用的 Node.js 版本管理工具,关于 n 和 nvm 的使用以及区别,[这篇文章](http://taobaofed.org/blog/2015/11/17/nvm-or-n/) 讲得特别详细,这里不再赘述。 47 | 48 | ## 1.1.3 nrm 49 | 50 | [nrm](https://github.com/Pana/nrm) 是一个管理 npm 源的工具。用过 ruby 和 gem 的同学会比较熟悉,通常我们会把 gem 源切到国内的淘宝镜像,这样在安装和更新一些包的时候比较快。nrm 同理,用来切换官方 npm 源和国内的 npm 源(如: [cnpm](http://cnpmjs.org/)),当然也可以用来切换官方 npm 源和公司私有 npm 源。 51 | 52 | 全局安装 nrm: 53 | 54 | ``` 55 | npm i nrm -g 56 | ``` 57 | 58 | 查看当前 nrm 内置的几个 npm 源的地址: 59 | 60 |  61 | 62 | 切换到 cnpm: 63 | 64 |  65 | 66 | 下一节:[1.2 MongoDB 的安装与使用](https://github.com/18820227745/shop-demo-node/blob/master/book/1.2%20MongoDB%20%E7%9A%84%E5%AE%89%E8%A3%85%E4%B8%8E%E4%BD%BF%E7%94%A8.md) -------------------------------------------------------------------------------- /views/addcommodity.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 | 1× 53 | 1× 54 | 1× 55 | 1× 56 | 1× 57 | 1× 58 | | module.exports = function(app){
59 | require('./login')(app);
60 | require('./home')(app);
61 | require('./logout')(app);
62 | require('./register')(app);
63 | require('./cart')(app);
64 | } |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 | 1× 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | | module.exports = {
65 | port: 3000,
66 | session: {
67 | secret: 'e-commerce',
68 | key: 'e-commerce',
69 | maxAge: 1000 * 60 * 30
70 | },
71 | mongodb: 'mongodb://localhost:27017/e-commerce'
72 | };
73 | |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 | 1× 54 | 55 | 1× 56 | 57 | 58 | 59 | 60 | | module.exports = function ( app ) {
61 | //退出登录
62 | app.get('/logout', function(req, res){
63 | req.session.user = null;
64 | req.session.error = null;
65 | res.redirect('/home');
66 | });
67 | } |
| File | 50 |51 | | Statements | 52 |53 | | Branches | 54 |55 | | Functions | 56 |57 | | Lines | 58 |59 | |
|---|---|---|---|---|---|---|---|---|---|
| app.js | 63 |91.43% | 65 |32/35 | 66 |75% | 67 |3/4 | 68 |33.33% | 69 |1/3 | 70 |91.18% | 71 |31/34 | 72 |
hello, <%= name %>
46 | 47 | 48 | ``` 49 | 50 | 修改 routes/users.js 如下: 51 | 52 | **routes/users.js** 53 | 54 | ``` 55 | var express = require('express'); 56 | var router = express.Router(); 57 | 58 | router.get('/:name', function(req, res) { 59 | res.render('users', { 60 | name: req.params.name 61 | }); 62 | }); 63 | 64 | module.exports = router; 65 | ``` 66 | 67 | 通过调用 `res.render` 函数渲染 ejs 模板,res.render 第一个参数是模板的名字,这里是 users 则会匹配 views/users.ejs,第二个参数是传给模板的数据,这里传入 name,则在 ejs 模板中可使用 name。`res.render` 的作用就是将模板和数据结合生成 html,同时设置响应头中的 `Content-Type: text/html`,告诉浏览器我返回的是 html,不是纯文本,要按 html 展示。现在我们访问 `localhost:3000/users/haha`,如下图所示: 68 | 69 |  70 | 71 | 上面代码可以看到,我们在模板 `<%= name.toUpperCase() %>` 中使用了 JavaScript 的语法 `.toUpperCase()` 将名字转化为大写,那这个 `<%= xxx %>` 是什么东西呢?ejs 有 3 种常用标签: 72 | 73 | 1. `<% code %>`:运行 JavaScript 代码,不输出 74 | 2. `<%= code %>`:显示转义后的 HTML内容 75 | 3. `<%- code %>`:显示原始 HTML 内容 76 | 77 | > 注意:`<%= code %>` 和 `<%- code %>` 都可以是 JavaScript 表达式生成的字符串,当变量 code 为普通字符串时,两者没有区别。当 code 比如为 `hello, <%= name %>
139 | <%- include('footer') %> 140 | ``` 141 | 142 | 我们将原来的 users.ejs 拆成出了 header.ejs 和 footer.ejs,并在 users.ejs 通过 ejs 内置的 include 方法引入,从而实现了跟以前一个模板文件相同的功能。 143 | 144 | > 小提示:拆分模板组件通常有两个好处: 145 | > 146 | > 1. 模板可复用,减少重复代码 147 | > 2. 主模板结构清晰 148 | 149 | > 注意:要用 `<%- include('header') %>` 而不是 `<%= include('header') %>` 150 | 151 | 上一节:[3.2 路由](https://github.com/nswbmw/N-blog/blob/master/book/3.2%20%E8%B7%AF%E7%94%B1.md) 152 | 153 | 下一节:[3.4 Express 浅析](https://github.com/18820227745/shop-demo-node/blob/master/book/3.4%20Express%20%E6%B5%85%E6%9E%90.md) -------------------------------------------------------------------------------- /coverage/lcov-report/mysession/middlewares/testController.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 || 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 | 1× 59 | 60 | 1× 61 | 1× 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | | var muilter = require('../config/multerUtil');
71 | //multer有single()中的名称必须是表单上传字段的name名称。
72 | var upload = muilter.single('imgSrc');
73 | exports.dataInput = function (req, res) {
74 | upload(req, res, function (err) {
75 | //添加错误处理
76 | if (err) {
77 | return console.log(err);
78 | }
79 | //文件信息在req.file或者req.files中显示。
80 | console.log(req);
81 | });
82 | } |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 | 1× 65 | 66 | 67 | 68 | 1× 69 | 3× 70 | 71 | 1× 72 | 73 | 2× 74 | 75 | 76 | 77 | 1× 78 | 2× 79 | 80 | 81 | 82 | | var mongoose = require('mongoose'),
83 | Schema = mongoose.Schema,
84 | models = require('./models');
85 |
86 | for (var m in models) {
87 | mongoose.model(m, new Schema(models[m]));
88 | }
89 | module.exports = {
90 | getModel: function (type) {
91 | return _getModel(type);
92 | }
93 | };
94 |
95 | var _getModel = function (type) {
96 | return mongoose.model(type);
97 | };
98 |
99 |
100 | |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 | 1× 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | | module.exports = {
85 | user:{
86 | name: {type: String},
87 | password: {type: String}
88 | },
89 | commodity: {
90 | name: String,
91 | price: Number,
92 | imgSrc: String
93 | },
94 | cart: {
95 | uId: {type: String},
96 | cId: {type: String},
97 | cName: { type: String},
98 | cPrice: { type: String},
99 | cImaSrc: { type: String},
100 | cQuantity: { type: Number},
101 | cStatus: { type: Boolean,default: false}
102 | }
103 | } |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 | 1× 64 | 1× 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 1× 77 | 78 | 79 | 80 | 1× | var multer = require('multer');
81 | var storage = multer.diskStorage({
82 | //设置上传后文件路径,uploads文件夹会自动创建。
83 | destination: function (req, file, cb) {
84 | cb(null, '../public/images')
85 | },
86 | //给上传文件重命名,获取添加后缀名
87 | filename: function (req, file, cb) {
88 | var fileFormat = (file.originalname).split(".");
89 | cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
90 | }
91 | });
92 | //添加配置文件到muler对象。
93 | var upload = multer({
94 | storage: storage
95 | });
96 |
97 | module.exports = upload; |
| File | 50 |51 | | Statements | 52 |53 | | Branches | 54 |55 | | Functions | 56 |57 | | Lines | 58 |59 | |
|---|---|---|---|---|---|---|---|---|---|
| check.js | 63 |11.11% | 65 |1/9 | 66 |0% | 67 |0/4 | 68 |0% | 69 |0/2 | 70 |11.11% | 71 |1/9 | 72 ||
| testController.js | 76 |42.86% | 78 |3/7 | 79 |0% | 80 |0/2 | 81 |0% | 82 |0/2 | 83 |42.86% | 84 |3/7 | 85 |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 | 1× 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | | module.exports = {
81 | checkLogin: function checkLogin(req, res, next) {
82 | if (!req.session.user) {
83 | req.session.error = "请先登录";
84 | res.redirect("/login");
85 | }
86 | next();
87 | },
88 |
89 | checkNotLogin: function checkNotLogin(req, res, next) {
90 | if (req.session.user) {
91 | req.session.error = "已登录";
92 | return res.redirect('back');//返回之前的页面
93 | }
94 | next();
95 | }
96 | };
97 | |
| File | 50 |51 | | Statements | 52 |53 | | Branches | 54 |55 | | Functions | 56 |57 | | Lines | 58 |59 | |
|---|---|---|---|---|---|---|---|---|---|
| dbHelper.js | 63 |100% | 65 |7/7 | 66 |100% | 67 |0/0 | 68 |100% | 69 |2/2 | 70 |100% | 71 |7/7 | 72 ||
| models.js | 76 |100% | 78 |1/1 | 79 |100% | 80 |0/0 | 81 |100% | 82 |0/0 | 83 |100% | 84 |1/1 | 85 |
| File | 50 |51 | | Statements | 52 |53 | | Branches | 54 |55 | | Functions | 56 |57 | | Lines | 58 |59 | |
|---|---|---|---|---|---|---|---|---|---|
| default.js | 63 |100% | 65 |1/1 | 66 |100% | 67 |0/0 | 68 |100% | 69 |0/0 | 70 |100% | 71 |1/1 | 72 ||
| multerUtil.js | 76 |57.14% | 78 |4/7 | 79 |100% | 80 |0/0 | 81 |0% | 82 |0/2 | 83 |57.14% | 84 |4/7 | 85 |
| 1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 | 1× 76 | 1× 77 | 78 | 1× 79 | 80 | 81 | 82 | 1× 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | | var sha1 = require('sha1');
105 | module.exports = function(app){
106 | //登录页面
107 | app.get('/login',function(req,res){
108 | res.render('login');
109 | });
110 | //登录
111 | app.post('/login',function(req,res){
112 | var User = global.dbHelper.getModel('user'),
113 | uname = req.body.uname;
114 | //查询数据库
115 | User.findOne({name: uname}, function(error,doc){
116 | if(error){
117 | res.send(500);
118 | console.log(error);
119 | }else if(!doc){
120 | req.session.error = "用户名不存在!";
121 | res.send(404);
122 | }else{
123 | if(req.body.upwd !== doc.password ){
124 | req.session.error = "密码错误!";
125 | res.send(404);
126 | }else{
127 | req.session.user = doc;
128 | res.send(200);
129 | }
130 | }
131 | });
132 | });
133 | } |