为什么要学习Node.js
企业需求
具有服务端开发经验更改
front-end
back-end
全栈开发工程师
基本的网站开发能力
多人社区
Node.js是什么
Node.js是JavaScript 运行时
通俗易懂的讲,Node.js是JavaScript的运行平台
Node.js既不是语言,也不是框架,它是一个平台
浏览器中的JavaScript
EcmaScript
基本语法
if
var
function
Object
Array
Bom
Dom
Node.js中的JavaScript
没有Bom,Dom
EcmaScript
在Node中这个JavaScript执行环境为JavaScript提供了一些服务器级别的API
例如文件的读写
网络服务的构建
网络通信
http服务器
构建与Chrome的V8引擎之上
代码只是具有特定格式的字符串
引擎可以认识它,帮你解析和执行
Google Chrome的V8引擎是目前公认的解析执行JavaScript代码最快的
Node.js的作者把Google Chrome中的V8引擎移植出来,开发了一个独立的JavaScript运行时环境
Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.
envent-driven 事件驱动
non-blocking I/O mode 非阻塞I/O模型(异步)
ightweight and efficent. 轻量和高效
Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
npm 是世界上最大的开源生态系统
绝大多数JavaScript相关的包都存放在npm上,这样做的目的是为了让开发人员更方便的去下载使用
npm install jquery
Node能做什么
web服务器后台
命令行工具
npm(node)
git(c语言)
hexo(node)
…
对于前端工程师来讲,接触最多的是它的命令行工具
自己写的很少,主要是用别人第三方的
webpack
gulp
npm
起步 安装Node环境
解析执行JavaScript
创建编写JavaScript脚本文件
打开终端,定位脚本文件的所属目录
输入node 文件名
执行对应的文件
注意:文件名不要用node.js
来命名,也就是说除了node
这个名字随便起,最好不要使用中文。
文件的读写 文件读取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var fs = require ('fs' ); fs.readFile ('./data/a.txt' ,function (err,data ){ if (err){ console .log ('文件读取失败' ); } else { console .log (data.toString ()); } })
文件写入:
1 2 3 4 5 6 7 8 9 10 11 12 var fs = require ('fs' ); fs.writeFile ('./data/a.txt' ,'我是文件写入的信息' ,function (err,data ){ if (err){ console .log ('文件写入失败' ); } else { console .log (data.toString ()); } })
http 服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var http = require ('http' );var server = http.createServer (); server.on ('request' ,function ( ){ console .log ('收到客户的请求了' ) }) server.listen (3000 ,function ( ){ console .log ('runing...' ) })
Node中的模块系统 使用Node编写应用程序主要就是在使用:
EcmaScript语言
核心模块
文件操作的fs
http服务操作的http
url路径操作模块
path路径处理模块
os操作系统信息
第三方模块
art-template
必须通过npm来下载才可以使用
自己写的模块
什么是模块化
文件作用域(模块是独立的,在不同的文件使用必须要重新引用)【在node中没有全局作用域,它是文件模块作用域】
通信规则
CommonJS模块规范 在Node中的JavaScript还有一个重要的概念,模块系统。
模块作用域
使用require方法来加载模块
使用exports接口对象来导出模板中的成员
加载require
语法:
1 var 自定义变量名 = require('模块' )
作用:
执行被加载模块中的代码
得到被加载模块中的exports
导出接口对象
导出exports
模块原理 exports和module.exports
的一个引用:
1 2 3 4 5 6 console .log (exports === module .exports ); exports .foo = 'bar' ;module .exports .foo = 'bar' ;
当给exports重新赋值后,exports!= module.exports.
最终return的是module.exports,无论exports中的成员是什么都没用。
1 2 3 真正去使用的时候: 导出单个成员:exports .xxx = xxx; 导出多个成员:module .exports 或者 modeule.exports = {};
总结 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 var http = require ('http' );var fs = require ('fs' );var template = require ('art-template' );var server = http.createServer ();var wwwDir = 'D:/app/www' ; server.on ('request' , function (req, res ) { var url = req.url ; fs.readFile ('./template-apche.html' , function (err, data ) { if (err) { return res.end ('404 Not Found' ); } fs.readdir (wwwDir, function (err, files ) { if (err) { return res.end ('Can not find www Dir.' ) } var htmlStr = template.render (data.toString (), { title : 'D:/app/www/ 的索引' , files :files }); res.end (htmlStr); }) }) }); server.listen (3000 , function ( ) { console .log ('running....' ); })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1. jQuery中的each 和 原生JavaScript 方法forEach的区别: 提供源头: 原生js是es5提供的(不兼容IE8 ), jQuery的each是jQuery第三方库提供的(如果要使用需要用2 以下的版本也就是1. 版本),它的each方法主要用来遍历jQuery实例对象(伪数组),同时也可以做低版本forEach的替代品,jQuery的实例对象不能使用forEach方法,如果想要使用必须转为数组([].slice .call (jQuery实例对象))才能使用2. 模块中导出多个成员和导出单个成员3.301 和302 的区别: 301 永久重定向,浏览器会记住 302 临时重定向4. exports 和module .exports 的区别: 每个模块中都有一个module 对象 module 对象中有一个exports 对象 我们可以把需要导出的成员都挂载到module .exports 接口对象中 也就是`module.exports.xxx = xxx` 的方式 但是每次写太多了就很麻烦,所以Node 为了简化代码,就在每一个模块中都提供了一个成员叫`exports` `exports === module.exports` 结果为true ,所以完全可以`exports.xxx = xxx` 当一个模块需要导出单个成员的时候必须使用`module.exports = xxx` 的方式,=,使用`exports = xxx` 不管用,因为每个模块最终return 的是module .exports ,而exports 只是module .exports 的一个引用,所以`exports` 即使重新赋值,也不会影响`module.exports` 。 有一种赋值方式比较特殊:`exports = module.exports` 这个用来新建立引用关系的。
require的加载规则
require的加载规则:
优先从缓存加载
判断模块标识符
核心模块
自己写的模块(路径形式的模块)
第三方模块(node_modules)
第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致)
npm
开发人员可以把写好的框架库发布到npm上
使用者通过npm命令来下载
使用方式:var 名称 = require('npm install【下载包】 的包名')
node_modules/express/package.json main
如果package.json或者main不成立,则查找被选择项:index.js
如果以上条件都不满足,则继续进入上一级目录中的node_modules按照上面的规则依次查找,直到当前文件所属此盘根目录都找不到最后报错
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 require ('fs' ); var template = require ('art-template' );
模块标识符中的/
和文件操作路径中的/
文件操作路径:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 fs.readFile ('./index.txt' ,function (err,data ){ if (err){ return console .log ('读取失败' ); } console .log (data.toString ()); })
模块操作路径:
1 2 3 require ('./index' )('hello' )
npm
node package manage(node包管理器)
通过npm命令安装jQuery包(npm install –save jquery),在安装时加上–save会主动生成说明书文件信息(将安装文件的信息添加到package.json里面)
npm网站
npmjs.com 网站 是用来搜索npm包的
npm命令行工具 npm是一个命令行工具,只要安装了node就已经安装了npm。
npm也有版本概念,可以通过npm --version
来查看npm的版本
升级npm(自己升级自己):
1 npm install --global npm
常用命令
npm init(生成package.json说明书文件)
npm install
一次性把dependencies选项中的依赖项全部安装
简写(npm i)
npm install 包名
npm install –save 包名
下载并且保存依赖项(package.json文件中的dependencies选项)
简写(npm i 包名)
npm uninstall 包名
只删除,如果有依赖项会依然保存
简写(npm un 包名)
npm uninstall –save 包名
删除的同时也会把依赖信息全部删除
简写(npm un 包名)
npm help
npm 命令 –help
查看具体命令的使用帮助(npm uninstall –help)
解决npm被墙问题 npm存储包文件的服务器在国外,有时候会被墙,速度很慢,所以需要解决这个问题。
https://developer.aliyun.com/mirror/NPM?from=tnpm淘宝的开发团队把npm在国内做了一个镜像(也就是一个备份)。
安装淘宝的cnpm:
1 npm install -g cnpm --registry=https :
1 2 3 4 # 在任意目录执行都可以 # --global表示安装到全局,而非当前目录 # --global不能省略,否则不管用 npm install --global cnpm
安装包的时候把以前的npm
替换成cnpm
。
1 2 3 4 5 # 走国外的npm服务器下载jQuery包,速度比较慢 npm install jQuery;# 使用cnpm就会通过淘宝的服务器来下载jQuery cnpm install jQuery;
如果不想安装cnpm
又想使用淘宝的服务器来下载:
1 npm install jquery --registry=https://npm.taobao.org;
但是每次手动加参数就很麻烦,所以我们可以把这个选项加入到配置文件中:
1 2 3 4 npm config set registry https://npm.taobao.org;# 查看npm配置信息 npm config list;
只要经过上面的配置命令,则以后所有的npm install
都会通过淘宝的服务器来下载
package.json 每一个项目都要有一个package.json
文件(包描述文件,就像产品的说明书一样)
这个文件可以通过npm init
自动初始化出来
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 D :\code\node中的模块系统>npm initThis utility will walk you through creating a package.json file.It only covers the most common items, and tries to guess sensible defaults.See `npm help json` for definitive documentation on these fields and exactly what they do .Use `npm install <pkg>` afterwards to install a package and save it as a dependency in the package.json file.Press ^C at any time to quit. package name : (node中的模块系统)Sorry , name can only contain URL -friendly characters. package name : (node中的模块系统) clsversion : (1.0 .0 )description : 这是一个测试项目 entry point : (main.js ) test command : git repository :keywords :author : xiaochenlicense : (ISC )About to write to D :\code\node中的模块系统\package.json : { "name" : "cls" , "version" : "1.0.0" , "description" : "这是一个测试项目" , "main" : "main.js" , "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" }, "author" : "xiaochen" , "license" : "ISC" }Is this OK ? (yes) yes
对于目前来讲,最有用的是dependencies
选项,可以用来帮助我们保存第三方包的依赖信息。
如果node_modules
删除了也不用担心,只需要在控制面板中npm install
就会自动把package.json
中的dependencies
中所有的依赖项全部都下载回来。
建议每个项目的根目录下都有一个package.json
文件
建议执行npm install 包名
的时候都加上--save
选项,目的是用来保存依赖信息
package.json和package-lock.json npm 5以前是不会有package-lock.json
这个文件
npm5以后才加入这个文件
当你安装包的时候,npm都会生成或者更新package-lock.json
这个文件
npm5以后的版本安装都不要加--save
参数,它会自动保存依赖信息
当你安装包的时候,会自动创建或者更新package-lock.json
文件
package-lock.json
这个文件会包含node_modules
中所有包的信息(版本,下载地址。。。)
这样的话重新npm install
的时候速度就可以提升
从文件来看,有一个lock
称之为锁
这个lock
使用来锁版本的
如果项目依赖了1.1.1
版本
如果你重新install其实会下载最细版本,而不是1.1.1
package-lock.json
的另外一个作用就是锁定版本号,防止自动升级
path路径操作模块
参考文档:https://nodejs.org/docs/latest-v13.x/api/path.html
path.basename:获取路径的文件名,默认包含扩展名
path.dirname:获取路径中的目录部分
path.extname:获取一个路径中的扩展名部分
path.parse:把路径转换为对象
root:根路径
dir:目录
base:包含后缀名的文件名
ext:后缀名
name:不包含后缀名的文件名
path.join:拼接路径
path.isAbsolute:判断一个路径是否为绝对路径
Node中的其它成员(__dirname,__filename) 在每个模块中,除了require
,exports
等模块相关的API之外,还有两个特殊的成员:
__dirname
,是一个成员,可以用来动态 获取当前文件模块所属目录的绝对路径
__filename
,可以用来动态 获取当前文件的绝对路径(包含文件名)
__dirname
和filename
是不受执行node命令所属路径影响的
在文件操作中,使用相对路径是不可靠的,因为node中文件操作的路径被设计为相对于执行node命令所处的路径。
所以为了解决这个问题,只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。
就可以使用__dirname
或者__filename
来帮助我们解决这个问题
在拼接路径的过程中,为了避免手动拼接带来的一些低级错误,推荐使用path.join()
来辅助拼接
1 2 3 4 5 6 7 8 9 10 11 var fs = require ('fs' );var path = require ('path' ); fs.readFile (path.join (__dirname + '/a.txt' ),'utf8' ,function (err,data ){ if (err){ throw err } console .log (data); });
补充:模块中的路径标识和这里的路径没关系,不受影响(就是相对于文件模块)
注意:
模块中的路径标识和文件操作中的相对路径标识不一致
模块中的路径标识就是相对于当前文件模块,不受node命令所处路径影响
Express(快速的) 作者:Tj
原生的http在某些方面表现不足以应对我们的开发需求,所以就需要使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码高度统一。
在node中有很多web开发框架。主要学习express
http://expressjs.com/
,其中主要封装的是http。
// 1 安装
// 2 引包
var express = require('express');
// 3 创建服务器应用程序
// 也就是原来的http.createServer();
var app = express();
// 公开指定目录
// 只要通过这样做了,就可以通过/public/xx的方式来访问public目录中的所有资源
// 在Express中开放资源就是一个API的事
app.use('/public/',express.static('/public/'));
//模板引擎在Express中开放模板也是一个API的事
// 当服务器收到get请求 / 的时候,执行回调处理函数
app.get('/',function(req,res){
res.send('hello express');
})
// 相当于server.listen
app.listen(3000,function(){
console.log('app is runing at port 3000');
})
1 2 3 4 5 6 7 8 9 10 ### 学习Express #### 起步 ##### 安装:![image-20200310123723079 ](C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200310123723079. png) ```javascript cnpm install express
hello world: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var express = require ('express' );var app = express (); app.get ('/' ,function (req,res ){ res.send ('hello world' ); }) app.listen (3000 ,function ( ){ console .log ('express app is runing...' ); })
基本路由 路由:
get:
1 2 3 4 app.get ('/' ,function (req,res ){ res.send ('hello world' ); })
post:
1 2 3 4 app.post ('/' ,function (req,res ){ res.send ('hello world' ); })
Express静态服务API 1 2 3 4 5 6 app.use (express.static ('public' )); app.use (express.static ('files' )); app.use ('/stataic' ,express.static ('public' ));
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 var express = require ('express' );var app = express (); app.use ('/public/' ,express.static ('./public/' )); app.get ('/' ,function (req,res ){ res.end ('hello world' ); }); app.listen (3000 ,function ( ){ console .log ('express app is runing...' ); });
在Express中配置使用art-templete
模板引擎
art-template官方文档
在node中,有很多第三方模板引擎都可以使用,不是只有art-template
还有ejs,jade(pug),handlebars,nunjucks
安装:
1 2 3 4 5 npm install --save art-template npm install --save express-art-template //两个一起安装 npm i --save art-template express-art-template
配置:
1 app.engine ('html' , require ('express-art-template' ));
使用:
1 2 3 4 5 6 app.get ('/' ,function (req,res ){ res.render ('index.html' ,{ title :'hello world' }); })
如果希望修改默认的views
视图渲染存储目录,可以:
在Express中获取表单请求数据 获取get请求数据: Express内置了一个api,可以直接通过req.query
来获取数据
1 2 3 var comment = req.query ;
获取post请求数据: 在Express中没有内置获取表单post请求体的api,这里我们需要使用一个第三方包body-parser
来获取数据。
安装:
1 npm install --save body-parser;
配置:
// 配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var express = require ('express' )var bodyParser = require ('body-parser' )var app = express () app.use (bodyParser.urlencoded ({ extended : false })) app.use (bodyParser.json ())
使用:
1 2 3 4 5 6 app.use (function (req, res ) { res.setHeader ('Content-Type' , 'text/plain' ) res.write ('you posted:\n' ) res.end (JSON .stringify (req.body , null , 2 )) })
在Express中配置使用express-session
插件操作
参考文档:https://github.com/expressjs/session
安装:
1 npm install express-session
配置:
1 2 3 4 5 6 7 8 9 10 11 app.use (session ({ secret : 'keyboard cat' , resave : false , saveUninitialized : true , cookie : { secure : true } }))
使用:
1 2 3 4 5 6 7 8 9 10 11 12 req.session .foo = 'bar' ; req.session .foo req.session .foo = null ;delete req.session .foo
提示:
默认Session数据时内存储数据,服务器一旦重启,真正的生产环境会把Session进行持久化存储。
利用Express实现ADUS项目 模块化思想 模块如何划分:
javascript模块化:
Node 中的 CommonJS
浏览器中的:
AMD require.js
CMD sea.js
es6中增加了官方支持
起步
路由设计
请求方法
请求路径
get参数
post参数
备注
GET
/students
渲染首页
GET
/students/new
渲染添加学生页面
POST
/students/new
name,age,gender,hobbies
处理添加学生请求
GET
/students/edit
id
渲染编辑页面
POST
/students/edit
id,name,age,gender,hobbies
处理编辑请求
GET
/students/delete
id
处理删除请求
提取路由模块 router.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 var fs = require ('fs' );var express = require ('express' );var router = express.Router (); router.get ('/students' , function (req, res ) { fs.readFile ('./db.json' , 'utf8' , function (err, data ) { if (err) { return res.status (500 ).send ('Server error.' ) } var students = JSON .parse (data).students ; res.render ('index.html' , { students :students }) }) }); router.get ('/students/new' ,function (req,res ){ res.render ('new.html' ) }); router.get ('/students/edit' ,function (req,res ){ }); router.post ('/students/edit' ,function (req,res ){ }); router.get ('/students/delete' ,function (req,res ){ });module .exports = router;
app.js:
1 2 3 4 5 6 var router = require ('./router' ); app.use (router);
设计操作数据的API文件模块 es6中的find和findIndex:
find接受一个方法作为参数,方法内部返回一个条件
find会便利所有的元素,执行你给定的带有条件返回值的函数
符合该条件的元素会作为find方法的返回值
如果遍历结束还没有符合该条件的元素,则返回undefined
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 fs = require ('fs' ); exports .find = function ( ){ } exports .save = function ( ){ }exports .update = function ( ){ } exports .delete = function ( ){ }
步骤
子模板和模板的继承(模板引擎高级语法)【include,extend,block】 注意:
模板页:
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 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>模板页</title> <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/> {{ block 'head' }}{{ /block }} </head> <body> <!-- 通过include导入公共部分 --> {{include './header.html'}} <!-- 留一个位置 让别的内容去填充 --> {{ block 'content' }} <h1>默认内容</h1> {{ /block }} <!-- 通过include导入公共部分 --> {{include './footer.html'}} <!-- 公共样式 --> <script src="/node_modules/jquery/dist/jquery.js" ></script> <script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script> {{ block 'script' }}{{ /block }} </body> </html>
模板的继承:
header页面:
1 2 3 <div id="" > <h1 > 公共的头部</h1 > </div>
footer页面:
1 2 3 <div id="" > <h1 > 公共的底部</h1 > </div>
模板页的使用:
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 <!-- 继承(extend :延伸,扩展)模板也layout.html --> <!-- 把layout.html 页面的内容都拿进来作为index.html 页面的内容 --> {{extend './layout.html' }} <!-- 向模板页面填充新的数据 --> <!-- 填充后就会替换掉layout页面content中的数据 --> <!-- style样式方面的内容 --> {{ block 'head' }} <style type="text/css" > body{ background-color : skyblue; } </style> {{ /block }} {{ block 'content' }} <div id="" > <h1 > Index页面的内容</h1 > </div> {{ /block }} <!-- js部分的内容 --> {{ block 'script' }} <script type="text/javascript" > </script> {{ /block }}
最终的显示效果:
MongoDB 关系型和非关系型数据库 关系型数据库(表就是关系,或者说表与表之间存在关系)。
所有的关系型数据库都需要通过sql
语言来操作
所有的关系型数据库在操作之前都需要设计表结构
而且数据表还支持约束
非关系型数据库
非关系型数据库非常的灵活
有的关系型数据库就是key-value对儿
但MongDB是长得最像关系型数据库的非关系型数据库
数据库 -》 数据库
数据表 -》 集合(数组)
表记录 -》文档对象
一个数据库中可以有多个数据库,一个数据库中可以有多个集合(数组),一个集合中可以有多个文档(表记录)
1 2 3 4 5 6 7 { qq :{ user :[ {},{},{}... ] } }
也就是说你可以任意的往里面存数据,没有结构性这么一说
安装
启动和关闭数据库 启动:
1 2 3 # mongodb 默认使用执行mongod 命令所处盼复根目录下的/data/db作为自己的数据存储目录 # 所以在第一次执行该命令之前先自己手动新建一个 /data/db mongod
如果想要修改默认的数据存储目录,可以:
1 mongod --dbpath = 数据存储目录路径
停止:
1 2 在开启服务的控制台,直接Ctrl +C; 或者直接关闭开启服务的控制台。
连接数据库 连接:
1 2 # 该命令默认连接本机的 MongoDB 服务 mongo
退出:
1 2 # 在连接状态输入 exit 退出连接 exit
基本命令
show dbs
db
use 数据库名称
show collections
db.表名.find()
在Node中如何操作MongoDB数据库 使用官方的MongoDB
包来操作
http://mongodb.github.io/node-mongodb-native/
使用第三方包mongoose
来操作MongoDB数据库 第三方包:mongoose
基于MongoDB官方的mongodb
包再一次做了封装,名字叫mongoose
,是WordPress项目团队开发的。
https://mongoosejs.com/
学习指南(步骤) 官方学习文档:https://mongoosejs.com/docs/index.html
设计Scheme 发布Model (创建表) 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 mongoose = require ('mongoose' );var Schema = mongoose.Schema ; mongoose.connect ('mongodb://localhost/test' );var userSchema = new Schema ({ username : { type : String , require : true }, password : { type : String , require : true }, email : { type : String } });var User = mongoose.model ('User' , userSchema);
添加数据(增) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var user = new User ({ username : 'admin' , password : '123456' , email : 'xiaochen@qq.com' }); user.save (function (err, ret ) { if (err) { console .log ('保存失败' ); } else { console .log ('保存成功' ); console .log (ret); } });
删除(删) 根据条件删除所有:
1 2 3 4 5 6 7 8 9 10 User .remove ({ username : 'xiaoxiao' }, function (err, ret ) { if (err) { console .log ('删除失败' ); } else { console .log ('删除成功' ); console .log (ret); } });
根据条件删除一个:
1 Model .findOneAndRemove (conditions,[options],[callback]);
根据id删除一个:
1 User .findByIdAndRemove (id,[options],[callback]);
更新(改) 更新所有:
1 User .remove (conditions,doc,[options],[callback]);
根据指定条件更新一个:
1 User .FindOneAndUpdate ([conditions],[update],[options],[callback]);
根据id更新一个:
1 2 3 4 5 6 7 8 9 10 User .findByIdAndUpdate ('5e6c5264fada77438c45dfcd' , { username : 'junjun' }, function (err, ret ) { if (err) { console .log ('更新失败' ); } else { console .log ('更新成功' ); } });
查询(查) 查询所有:
1 2 3 4 5 6 7 8 User .find (function (err,ret ){ if (err){ console .log ('查询失败' ); }else { console .log (ret); } });
条件查询所有:
1 2 3 4 5 6 7 8 User .find ({ username :'xiaoxiao' },function (err,ret ){ if (err){ console .log ('查询失败' ); }else { console .log (ret); } });
条件查询单个:
1 2 3 4 5 6 7 8 9 10 11 User .findOne ({ username : 'xiaoxiao' }, function (err, ret ) { if (err) { console .log ('查询失败' ); } else { console .log (ret); } });
使用Node操作MySQL数据库 文档:https://www.npmjs.com/package/mysql
安装:
1 npm install --save mysql
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var mysql = require ('mysql' );var connection = mysql.createConnection ({ host : 'localhost' , user : 'me' , password : 'secret' , database : 'my_db' }); connection.connect (); connection.query ('SELECT * FROM `users` ' , function (error, results, fields ) { if (error) throw error; console .log ('The solution is: ' ,results); }); connection.end ();
异步编程 回调函数 不成立的情况下:
1 2 3 4 5 6 7 8 9 10 11 12 13 function add (x,y ){ console .log (1 ); setTimeout (function ( ){ console .log (2 ); var ret = x + y; return ret; },1000 ); console .log (3 ); }console .log (add (2 ,2 ));
使用回调函数解决:
回调函数:通过一个函数,获取函数内部的操作。(根据输入得到输出结果)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var ret;function add (x,y,callback ){ console .log (1 ); setTimeout (function ( ){ var ret = x + y; callback (ret); },1000 ); console .log (3 ); }add (10 ,20 ,function (ret ){ console .log (ret); });
注意:
凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)
这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)
ajax:
基于原生XMLHttpRequest封装get方法:
1 2 3 4 5 6 7 var oReq = new XMLHttpRequest (); oReq.onload = function ( ){ console .log (oReq.responseText ); } oReq.open ("GET" , "请求路径" ,true ); oReq.send ();
1 2 3 4 5 6 7 8 9 10 11 12 13 function get (url,callback ){ var oReq = new XMLHttpRequest (); oReq.onload = function ( ){ callback (oReq.responseText ); } oReq.open ("GET" , url,true ); oReq.send (); }get ('data.json' ,function (data ){ console .log (data); });
Promise callback hell(回调地狱):
文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)
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 var fs = require ('fs' ); fs.readFile ('./data/a.text' ,'utf8' ,function (err,data ){ if (err){ return console .log ('读取失败' ); throw err; } console .log (data); }); fs.readFile ('./data/b.text' ,'utf8' ,function (err,data ){ if (err){ return console .log ('读取失败' ); throw err; } console .log (data); });
通过回调嵌套的方式来保证顺序:
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 fs = require ('fs' ); fs.readFile ('./data/a.text' ,'utf8' ,function (err,data ){ if (err){ return console .log ('读取失败' ); throw err; } console .log (data); fs.readFile ('./data/b.text' ,'utf8' ,function (err,data ){ if (err){ return console .log ('读取失败' ); throw err; } console .log (data); fs.readFile ('./data/a.text' ,'utf8' ,function (err,data ){ if (err){ return console .log ('读取失败' ); throw err; } console .log (data); }); }); });
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在EcmaScript6新增了一个API:Promise
。
Promise:承诺,保证
Promise本身不是异步的,但往往都是内部封装一个异步任务
基本语法:
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 var fs = require ('fs' );var p1 = new Promise (function (resolve, reject ) { fs.readFile ('./a.text' , 'utf8' , function (err, data ) { if (err) { reject (err); } else { resolve (1234 ); } }); }); p1 .then (function (data ) { console .log (data); }, function (err ) { console .log ('读取文件失败了' , err); });
链式循环:
封装Promise的readFile
:
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 var fs = require ('fs' );function pReadFile (filePath ) { return new Promise (function (resolve, reject ) { fs.readFile (filePath, 'utf8' , function (err, data ) { if (err) { reject (err); } else { resolve (data); } }); }); }pReadFile ('./a.txt' ) .then (function (data ) { console .log (data); return pReadFile ('./b.txt' ); }) .then (function (data ) { console .log (data); return pReadFile ('./a.txt' ); }) .then (function (data ) { console .log (data); })
mongoose所有的API都支持Promise:
1 2 3 4 5 User .find () .then (function (data ){ console .log (data) })
注册:
1 2 3 4 5 6 7 8 9 10 11 12 13 User .findOne ({username :'admin' },function (user ){ if (user){ console .log ('用户已存在' ) } else { new User ({ username :'aaa' , password :'123' , email :'fffff' }).save (function ( ){ console .log ('注册成功' ); }) } })
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 User .findOne ({ username :'admin' }) .then (function (user ){ if (user){ console .log ('用户已存在' ); } else { return new User ({ username :'aaa' , password :'123' , email :'fffff' }).save (); } }) .then (funciton (ret ){ console .log ('注册成功' ); })
Generator async函数
其他 修改完代码自动重启 我们在这里可以使用一个第三方命名行工具:nodemon
来帮助我们解决频繁修改代码重启服务器的问题。
nodemon
是一个基于Node.js开发的一个第三方命令行工具,我们使用的时候需要独立安装:
1 2 3 4 5 6 7 #在任意目录执行该命令都可以 #也就是说,所有需要 --global 安装的包都可以在任意目录执行 npm install --global nodemon npm install -g nodemon #如果安装不成功的话,可以使用cnpm安装 cnpm install -g nodemon
安装完毕之后使用:
1 2 3 4 node app.js #使用nodemon nodemon app.js
只要是通过nodemon
启动的服务,则他会监视你的文件变化,当文件发生变化的时候,会自动帮你重启服务器。
封装异步API 回调函数:获取异步操作的结果
1 2 3 4 5 6 7 8 9 10 11 function fn (callback ){ setTimeout (function ( ){ var data = 'hello' ; callback (data); },1000 ); }fn (function (data ){ console .log (data); })
数组的遍历方法,都是对函数作为一种参数
EcmaScript 6
参考文档:https://es6.ruanyifeng.com/
项目案例 目录结构 1 2 3 4 5 6 7 8 9 10 . app.js 项目的入口文件 controllers models 存储使用mongoose设计的数据模型 node_modules 第三方包 package.json 包描述文件 package-lock.json 第三方包版本锁定文件(npm5之后才有) public 公共静态资源 routes views 存储视图目录
模板页
路由设计
路由
方法
get参数
post参数
是否需要登录
备注
/
get
渲染首页
/register(登录)
get
渲染注册页面
/register
post
email,nickname,password
处理注册请求
/login
get
渲染登陆界面
/login
post
email,password
处理登录请求
/loginout
get
处理退出请求
模型设计 功能实现 步骤
创建目录结构
整合静态也-模板页
设计用户登陆,退出,注册的路由
用户注册
先处理客户端页面的内容(表单控件的name,收集表单数据,发起请求)
服务端
获取从客户端收到的数据
操作数据库
如果有错,发送500告诉客户端服务器错了‘
其他的根据业务发送不同的响应数据
登录
退出
Express中间件 中间件的概念
参考文档:http://expressjs.com/en/guide/using-middleware.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 27 var http = require ('http' );var url = require ('url' );var cookie = require ('./expressPtoject/cookie' );var query = require ('./expressPtoject/query' );var postBody = require ('./expressPtoject/post-body' );var server = http.createServer (function ( ){ query (req,res); req.body = { foo :'bar' } });if (req.url === 'xxx' ){ ... } server.listen (3000 ,function ( ){ console .log ('3000 runing...' ); });
同一个请求对象所经过的中间件都是同一个请求对象和响应对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var express = require ('express' );var app = express (); app.get ('/abc' ,function (req,res,next ){ console .log ('/abc' ); req.body = { name :'xiaoxiao' , age :18 } next (); }); app.get ('/abc' ,function (req,res,next ){ console .log (req.body ); console .log ('/abc' ); }); app.listen (3000 , function ( ) { console .log ('app is running at port 3000.' ); });
中间件的分类: 应用程序级别的中间件 万能匹配(不关心任何请求路径和请求方法的中间件):
1 2 3 4 app.use (function (req,res,next ){ console .log ('Time' ,Date .now ()); next (); });
关心请求路径和请求方法的中间件:
1 2 3 4 app.use ('/a' ,function (req,res,next ){ console .log ('Time' ,Date .now ()); next (); });
路由级别的中间件 严格匹配请求路径和请求方法的中间件
get:
1 2 3 app.get ('/' ,function (req,res ){ res.send ('get' ); });
post:
1 2 3 app.post ('/a' ,function (req,res ){ res.send ('post' ); });
put:
1 2 3 app.put ('/user' ,function (req,res ){ res.send ('put' ); });
delete:
1 2 3 app.delete ('/delete' ,function (req,res ){ res.send ('delete' ); });
总 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 var express = require ('express' );var app = express (); app.get ('/' ,function ( ){ console .log ('/' ); }); app.post ('/a' ,function ( ){ console .log ('/a' ); }); app.listen (3000 , function ( ) { console .log ('app is running at port 3000.' ); });
错误处理中间件 1 2 3 4 app.use (function (err,req,res,next ){ console .error (err,stack); res.status (500 ).send ('Something broke' ); });
配置使用404中间件:
1 2 3 app.use (function (req,res ){ res.render ('404.html' ); });
配置全局错误处理中间件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app.get ('/a' , function (req, res, next ) { fs.readFile ('.a/bc' , funtion ( ) { if (err) { next (err); } }) }); app.use (function (err,req,res,next ){ res.status (500 ).json ({ err_code :500 , message :err.message }); });
内置中间件
第三方中间件
参考文档:http://expressjs.com/en/resources/middleware.html
body-parser
compression
cookie-parser
mogran
response-time
server-static
session