- 创建编写JavaScript脚本文件
- 打开终端c;定位脚本文件的所属目录
- 输入
node 文件名
执行对应的文件 @H_373_1555@
@H_450_5@注意:文件名不要用node.js
来命名c;也就是说除了node
这个名字随便起c;最好不要使用中文。
文件的读写
@H_450_5@文件读取:
var fs = require('fs');
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log('文件读取失败');
}
else{
console.log(data.toString());
}
})
@H_450_5@文件写入:
var fs = require('fs');
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){
if(err){
console.log('文件写入失败');
}
else{
console.log(data.toString());
}
})
@H_450_5@服务器:
var http = require('http');
var server = http.createServer();
server.on('Request',function(){
console.log('收到客户的请求了')
})
server.listen(3000,function(){
console.log('Runing...')
})
端口号(范围0~65536之间)
@H_450_5@ 注意:可以同时开启多个服务c;但一定要确保不同的服务占用的端口号不一致c;说的通俗易懂点儿c;在一台计算机上一次一个端口号只能开启一个服务。
3. Node中的模块系统
@H_450_5@使用Node编写应用程序主要就是在使用:
- @H_450_5@EcmaScript语言
- @H_450_5@核心模块
- 文件操作的fs
- http服务操作的http
- url路径操作模块
- path路径处理模块
- os操作系统信息
- @H_450_5@第三方模块
- art-template
- 必须通过npm来下载才可以使用
- @H_450_5@自己写的模块
什么是模块化
- 文件作用域(模块是独立的c;在不同的文件使用必须要重新引用)【在Node中没有全局作用域c;它是文件模块作用域】
- 通信规则
CommonJS模块规范
@H_450_5@在Node中的JavaScript还有一个重要的概念c;模块系统。
模块原理
@H_450_5@exports和@H_723_435@module.exports的一个引用:
console.log(exports === module.exports);
exports.foo = 'bar';
module.exports.foo = 'bar';
@H_450_5@当给exports重新赋值后c;exports!= module.exports.
@H_450_5@最终return的是module.exports,无论exports中的成员是什么都没用。
真正去使用的时候:
导出单个成员:exports.xxx = xxx;
导出多个成员:module.exports 或者 modeule.exports = {};
总结
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.jQuery中的each 和 原生JavaScript方法forEach的区别:
提供源头:
原生js是es5提供的(不兼容IE8),
jQuery的each是jQuery第三方库提供的(如果要使用需要用2以下的版本也就是1.版本),它的each方法主要用来遍历jQuery实例对象(伪数组),同时也可以做低版本forEach的替代品,jQuery的实例对象不能使用forEach方法c;如果想要使用必须转为数组([].slice.call(jQuery实例对象))才能使用
2.模块中导出多个成员和导出单个成员
3.301和302的区别:
301永久重定向,浏览器会记住
302临时重定向
4.exports和module.exports的区别:
每个模块中都有一个module对象
module对象中有一个exports对象
我们可以把需要导出的成员都挂载到module.exports接口对象中
也就是`@H_509_1032@module.exports.xxx = xxx`的方式
但是每次写太多了就很麻烦c;所以Node为了简化代码c;就在每一个模块中都提供了一个成员叫`exports`
`exports === module.exports`结果为true,所以完全可以`exports.xxx = xxx`
当一个模块需要导出单个成员的时候必须使用`@H_509_1032@module.exports = xxx`的方式c;=,使用`exports = xxx`不管用,因为每个模块最终return的是module.exports,而exports只是module.exports的一个引用,所以`exports`即使重新赋值,也不会影响`@H_509_1032@module.exports`。
有一种赋值方式比较特殊:`exports = module.exports`这个用来新建立引用关系的。
4. require的加载规则
require的加载规则:
- @H_450_5@优先从缓存加载
- @H_450_5@判断模块标识符
- 核心模块
- 自己写的模块(路径形式的模块)
- 第三方模块(node_modules)
- 第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致)
- npm
- 开发人员可以把写好的框架库发布到npm上
- 使用者通过npm命令来下载
- 使用方式:
var 名称 = require('npm install【下载包】 的包名')
- node_modules/express/package.json main
- 如果package.json或者main不成立c;则查找被选择项:index.js
- 如果以上条件都不满足c;则继续进入上一级目录中的node_modules按照上面的规则依次查找c;直到当前文件所属此盘根目录都找不到最后报错
require('fs');
var template = require('art-template');
模块标识符中的/
和文件操作路径中的/
@H_450_5@文件操作路径:
fs.readFile('./index.txt',function(err,data){
if(err){
return console.log('读取失败');
}
console.log(data.toString());
})
@H_450_5@模块操作路径:
require('./index')('hello')
5. npm
- node package manage(node包管理器)
- 通过npm命令安装jQuery包(npm install --save jquery)c;在安装时加上–save会主动生成说明书文件信息(将安装文件的信息添加到package.json里面)
npm网站
@H_450_5@ npmjs.com 网站 是用来搜索npm包的
npm命令行工具
@H_450_5@npm是一个命令行工具c;只要安装了node就已经安装了npm。
@H_450_5@npm也有版本概念c;可以通过npm --version
来查看npm的版本
@H_450_5@升级npm(自己升级自己):
npm install --global npm
常用命令
- npm init(生成package.json说明书文件)
- npm init -y(可以跳过向导c;快速生成)
- npm install
- 一次性把dependencies选项中的依赖项全部安装
- 简写(npm i)
- npm install 包名
- npm install --save 包名
- 下载并且保存依赖项(package.json文件中的dependencies选项)
- 简写(npm i 包名)
- npm uninstall 包名
- 只删除c;如果有依赖项会依然保存
- 简写(npm un 包名)
- npm uninstall --save 包名
- 删除的同时也会把依赖信息全部删除
- 简写(npm un 包名)
- npm Help
- npm 命令 --Help
- 查看具体命令的使用帮助(npm uninstall --Help)
解决npm被墙问题
@H_450_5@npm存储包文件的服务器在国外c;有时候会被墙c;速度很慢c;所以需要解决这个问题。
@H_450_5@https://developer.aliyun.com/mirror/NPM?from=tnpm淘宝的开发团队把npm在国内做了一个镜像(也就是一个备份)。
@H_450_5@安装淘宝的cnpm:
npm install -g cnpm --registry=https://registry.npm.taobao.org;
npm install --global cnpm
@H_450_5@安装包的时候把以前的npm
替换成cnpm
。
npm install jQuery;
cnpm install jQuery;
@H_450_5@如果不想安装cnpm
又想使用淘宝的服务器来下载:
npm install jquery --registry=https://npm.taobao.org;
@H_450_5@但是每次手动加参数就很麻烦c;所以我们可以把这个选项加入到配置文件中:
npm config set registry https://npm.taobao.org;
npm config list;
@H_450_5@只要经过上面的配置命令c;则以后所有的npm install
都会通过淘宝的服务器来下载
6. package.json
@H_450_5@每一个项目都要有一个package.json
文件(包描述文件c;就像产品的说明书一样)
@H_450_5@这个文件可以通过npm init
自动初始化出来
D:codenode中的模块系统>npm init
This 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中的模块系统) cls
version: (1.0.0)
description: 这是一个测试项目
entry point: (@H_626_629@main.js)
test command:
git repository:
keywords:
author: xiaochen
license: (ISC)
About to write to D:codenode中的模块系统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
@H_450_5@对于目前来讲c;最有用的是dependencies
选项c;可以用来帮助我们保存第三方包的依赖信息。
@H_450_5@如果node_modules
删除了也不用担心c;只需要在控制面板中npm install
就会自动把package.json
中的dependencies
中所有的依赖项全部都下载回来。
- 建议每个项目的根目录下都有一个
package.json
文件 - 建议执行
npm install 包名
的时候都加上--save
选项c;目的是用来保存依赖信息
package.json和package-lock.json
@H_450_5@npm 5以前是不会有package-lock.json
这个文件
@H_450_5@npm5以后才加入这个文件
@H_450_5@当你安装包的时候c;npm都会生成或者更新package-lock.json
这个文件
- npm5以后的版本安装都不要加
--save
参数c;它会自动保存依赖信息 - 当你安装包的时候c;会自动创建或者更新
package-lock.json
文件 package-lock.json
这个文件会包含node_modules
中所有包的信息(版本c;下载地址。。。)
- 这样的话重新
npm install
的时候速度就可以提升
- 从文件来看c;有一个
lock
称之为锁
- 这个
lock
使用来锁版本的 - 如果项目依赖了
1.1.1
版本 - 如果你重新install其实会下载最细版本c;而不是
1.1.1
package-lock.json
的另外一个作用就是锁定版本号c;防止自动升级
path路径操作模块
@H_450_5@参考文档:https://nodejs.org/docs/latest-v13.x/api/path.html
- path.basename:获取路径的文件名c;默认包含扩展名
- path.dirname:获取路径中的目录部分
- path.extname:获取一个路径中的扩展名部分
- path.parse:把路径转换为对象
- root:根路径
- dir:目录
- base:包含后缀名的文件名
- ext:后缀名
- name:不包含后缀名的文件名
- path.join:拼接路径
- path.isAbsolute:判断一个路径是否为绝对路径[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ERa4PXdZ-1630228376843)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315150610001.png)]
7. Node中的其它成员(__dirname,__fileName)
@H_450_5@在每个模块中c;除了require
,exports
等模块相关的API之外c;还有两个特殊的成员:
- @H_450_5@
__dirname
c;是一个成员c;可以用来动态获取当前文件模块所属目录的绝对路径 - @H_450_5@
__filename
c;可以用来动态获取当前文件的绝对路径(包含文件名) - @H_450_5@
__dirname
和filename
是不受执行node命令所属路径影响的 @H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMSBfDuF-1630228376845)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315151551873.png)]
@H_450_5@在文件操作中c;使用相对路径是不可靠的c;因为node中文件操作的路径被设计为相对于执行node命令所处的路径。
@H_450_5@所以为了解决这个问题c;只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。
@H_450_5@就可以使用__dirname
或者__filename
来帮助我们解决这个问题
@H_450_5@在拼接路径的过程中c;为了避免手动拼接带来的一些低级错误c;推荐使用path.join()
来辅助拼接
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);
});
@H_450_5@补充:模块中的路径标识和这里的路径没关系c;不受影响(就是相对于文件模块)
@H_450_5@注意:
@H_450_5@模块中的路径标识和文件操作中的相对路径标识不一致
@H_450_5@模块中的路径标识就是相对于当前文件模块c;不受node命令所处路径影响
8. Express(快速的)
@H_450_5@作者:Tj
@H_450_5@原生的http在某些方面表现不足以应对我们的开发需求c;所以就需要使用框架来加快我们的开发效率c;框架的目的就是提高效率c;让我们的代码高度统一。
@H_450_5@在Node中有很多web开发框架。主要学习express
- @H_450_5@
http://expressjs.com/
,其中主要封装的是http。 -
var express = require('express');
var app = express();
app.use('/public/',express.static('/public/'));
app.get('/',function(req,res){
res.send('Hello express');
})
app.listen(3000,function(){
console.log('app is runing at port 3000');
})
学习Express
起步
安装:
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDfpgV4Q-1630228376847)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200310123723079.png)]
cnpm install express
Hello world:
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUGcoqri-1630228376850)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200310124850557.png)]
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...');
})
基本路由
@H_450_5@路由:
@H_450_5@get:
app.get('/',function(req,res){
res.send('Hello world');
})
@H_450_5@post:
app.post('/',function(req,res){
res.send('Hello world');
})
Express静态服务API
app.use(express.static('public'));
app.use(express.static('files'));
app.use('/stataic',express.static('public'));
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中c;有很多第三方模板引擎都可以使用c;不是只有
art-template
- 还有ejsc;jade(pug)c;handlebarsc;nunjucks
@H_450_5@安装:
npm install --save art-template
npm install --save express-art-template
//两个一起安装
npm i --save art-template express-art-template
@H_450_5@配置:
app.@R_674_10846@ne('html', require('express-art-template'));
@H_450_5@使用:
app.get('/',function(req,res){
res.render('index.html',{
title:'Hello world'
});
})
@H_450_5@如果希望修改默认的views
视图渲染存储目录c;可以:
app.set('views',目录路径);
在Express中获取表单请求数据
获取get请求数据:
@H_450_5@Express内置了一个apic;可以直接通过req.query
来获取数据
var comment = req.query;
获取post请求数据:
@H_450_5@在Express中没有内置获取表单post请求体的apic;这里我们需要使用一个第三方包body-parser
来获取数据。
@H_450_5@安装:
npm install --save body-parser;
@H_450_5@配置:
@H_450_5@// 配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
@H_450_5@使用:
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
插件操作
@H_450_5@参考文档:https://github.com/expressjs/session
@H_450_5@安装:
npm install express-session
@H_450_5@配置:
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
@H_450_5@使用:
req.session.foo = 'bar';
req.session.foo
req.session.foo = null;
delete req.session.foo
@H_450_5@提示:
@H_450_5@默认Session数据时内存储数据c;服务器一旦重启c;真正的生产环境会把Session进行持久化存储。
利用Express实现ADUS项目
模块化思想
@H_450_5@模块如何划分:
@H_450_5@javascript模块化:
- Node 中的 CommonJS
- 浏览器中的:
- es6中增加了官方支持
起步
路由设计
@H_450_462@请求方法 | 请求路径 | get参数 | post参数 | 备注 | @H_450_462@GET | /students | | | 渲染首页 | @H_450_462@GET | /students/new | | | 渲染添加学生页面 | @H_450_462@POST | /students/new | | name,age,gender,hobbies | 处理添加学生请求 | @H_450_462@GET | /students/edit | id | | 渲染编辑页面 | @H_450_462@POST | /students/edit | | id,name,age,gender,hobbies | 处理编辑请求 | @H_450_462@GET | /students/delete | id | | 处理删除请求 |
提取路由模块
@H_450_5@router.js:
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;
@H_450_5@app.js:
var router = require('./router');
app.use(router);
设计操作数据的API文件模块
@H_450_5@es6中的find和findIndex:
@H_450_5@find接受一个方法作为参数c;方法内部返回一个条件
@H_450_5@find会便利所有的元素c;执行你给定的带有条件返回值的函数
@H_450_5@符合该条件的元素会作为find方法的返回值
@H_450_5@如果遍历结束还没有符合该条件的元素c;则返回undefined[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EVjZMlw-1630228376851)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200313103810731.png)]
var fs = require('fs');
exports.find = function(){
}
exports.save = function(){
}
exports.update = function(){
}
exports.delete = function(){
}
步骤
- @H_450_5@处理模板
- @H_450_5@配置静态开放资源
- @H_450_5@配置模板引擎
- @H_450_5@简单的路由c;/studens渲染静态页出来
- @H_450_5@路由设计
- @H_450_5@提取路由模块
- @H_450_5@由于接下来的一系列业务操作都需要处理文件数据c;所以我们需要封装student.js’
- @H_450_5@先写好student.js文件结构
- @H_450_5@实现具体功能
- 通过路由收到请求
- 接受请求中的参数(getc;post)
- 调用数据操作API处理数据
- 根据操作结果给客户端发送请求
- @H_450_5@业务功能顺序
子模板和模板的继承(模板引擎高级语法)【includec;extendc;block】
@H_450_5@注意:
@H_450_5@模板页:
<!DOCTYPE html>
<html lang="zh">
<head>
<@H_626_629@meta charset="UTF-8">
<@H_626_629@meta name="viewport" content="width=device-width, initial-scale=1.0">
<@H_626_629@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>
@H_450_5@模板的继承:
@H_450_5@ header页面:
<div id="">
<h1>公共的头部</h1>
</div>
@H_450_5@ footer页面:
<div id="">
<h1>公共的底部</h1>
</div>
@H_450_5@模板页的使用:
<!-- 继承(extend:延伸c;扩展)模板也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 }}
@H_450_5@最终的显示效果:
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f5WIFaUD-1630228376852)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200316134759517.png)]
9. MongoDB
关系型数据库(表就是关系c;或者说表与表之间存在关系)。
- 所有的关系型数据库都需要通过
sql
语言来操作 - 所有的关系型数据库在操作之前都需要设计表结构
- 而且数据表还支持约束
- 非关系型数据库非常的灵活
- 有的关系型数据库就是key-value对儿
- 但MongDB是长得最像关系型数据库的非关系型数据库
- 数据库 -》 数据库
- 数据表 -》 集合(数组)
- 表记录 -》文档对象
@H_450_5@一个数据库中可以有多个数据库c;一个数据库中可以有多个集合(数组)c;一个集合中可以有多个文档(表记录)
{
qq:{
user:[
{},{},{}...
]
}
}
- 也就是说你可以任意的往里面存数据c;没有结构性这么一说
安装
- @H_450_5@下载
- 下载地址:https://www.mongodb.com/download-center/community
- @H_450_5@安装
npm i mongoose
- @H_450_5@配置环境变量
- @H_450_5@最后输入@H_723_435@mongod --version测试是否安装成功
启动和关闭数据库
@H_450_5@启动:
mongod
@H_450_5@如果想要修改默认的数据存储目录c;可以:
@H_723_435@mongod --dbpath = 数据存储目录路径
@H_450_5@停止:
在开启服务的控制台c;直接Ctrl+C;
或者直接关闭开启服务的控制台。
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lq9R7bnx-1630228376853)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314101047100.png)]
连接数据库
@H_450_5@连接:
# 该命令默认连接本机的 MongoDB 服务
mongo
@H_450_5@退出:
# 在连接状态输入 exit 退出连接
exit
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eozyzkE8-1630228376855)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314100821112.png)]
show dbs
db
use 数据库名称
show collections
db.表名.find()
在Node中如何操作MongoDB数据库
使用官方的@H_723_435@mongoDB包来操作
@H_450_5@ http://mongodb.github.io/node-mongodb-native/
使用第三方包@H_723_435@mongoose来操作MongoDB数据库
@H_450_5@ 第三方包:@H_723_435@mongoose基于MongoDB官方的@H_723_435@mongodb包再一次做了封装c;名字叫@H_723_435@mongoosec;是WordPress项目团队开发的。
@H_450_5@ https://mongoosejs.com/
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJ2y2y9R-1630228376856)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314105632745.png)]
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T0jnSXF8-1630228376857)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314105717993.png)]
学习指南(步骤)
@H_450_5@官方学习文档:https://mongoosejs.com/docs/index.html
设计scheR_515_11845@e 发布Model (创建表)
var mongoose = require('mongoose');
var scheR_515_11845@a = mongoose.scheR_515_11845@a;
mongoose.connect('mongodb://localhost/test');
var userscheR_515_11845@a = new scheR_515_11845@a({
username: {
type: String,
require: true
},
password: {
type: String,
require: true
},
email: {
type: String
}
});
var User = mongoose.@H_814_756@model('user', userscheR_515_11845@a);
添加数据(增)
var user = new User({
username: 'admin',
password: @R_675_6879@23456',
email: 'xiaochen@qq.com'
});
user.save(function(err, ret) {
if (err) {
console.log('保存失败');
} else {
console.log('保存成功');
console.log(ret);
}
});
删除(删)
@H_450_5@根据条件删除所有:
User.remove({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {
console.log('删除失败');
} else {
console.log('删除成功');
console.log(ret);
}
});
@H_450_5@根据条件删除一个:
@H_723_435@model.findOneAndRemove(conditions,[options],[callBACk]);
@H_450_5@根据id删除一个:
User.findByIdAndRemove(id,[options],[callBACk]);
更新(改)
@H_450_5@更新所有:
User.remove(conditions,doc,[options],[callBACk]);
@H_450_5@根据指定条件更新一个:
User.FindOneAndupdate([conditions],[update],[options],[callBACk]);
@H_450_5@根据id更新一个:
User.findByIdAndupdate('5e6c5264fada77438c45dfcd', {
username: 'junjun'
}, function(err, ret) {
if (err) {
console.log('更新失败');
} else {
console.log('更新成功');
}
});
查询(查)
@H_450_5@查询所有:
User.find(function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
@H_450_5@条件查询所有:
User.find({ username:'xiaoxiao' },function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
@H_450_5@条件查询单个:
User.findOne({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {
console.log('查询失败');
} else {
console.log(ret);
}
});
10. 使用Node操作MySQL数据库
@H_450_5@文档:https://www.npmjs.com/package/mysql
@H_450_5@安装:
npm install --save mysql
var mysql = require('mysql');
var connection = mysql.createConnection({
host : @R_674_3384@host',
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();
异步编程
回调函数
@H_450_5@不成立的情况下:
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));
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x6NLOQ65-1630228376858)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200313085008929.png)]
@H_450_5@使用回调函数解决:
@H_450_5@回调函数:通过一个函数c;获取函数内部的操作。(根据输入得到输出结果)
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);
});
@H_450_5@注意:
@H_450_5@ 凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)
@H_450_5@ 这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)
@H_450_5@ajax:
@H_450_5@基于原生XMLhttprequest封装get方法:
var oReq = new XMLhttprequest();
oReq.onload = function(){
console.log(oReq.responseText);
}
oReq.open("GET", "请求路径",true);
oReq.send();
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
@H_450_5@callBACk Hell(回调地狱):
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XWH7qzin-1630228376859)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314143410972.png)]
@H_450_5@文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)
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);
});
@H_450_5@通过回调嵌套的方式来保证顺序:
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);
});
});
});
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZWbpddG-1630228376860)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314144807008.png)]为了解决以上编码方式带来的问题(回调地狱嵌套)c;所以在EcmaScript6新增了一个API:Promise
。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ctFL5g3S-1630228376861)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314150050839.png)]
- Promise:承诺c;保证
- Promise本身不是异步的c;但往往都是内部封装一个异步任务
@H_450_5@基本语法:
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);
});
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNRvC9GN-1630228376861)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315100611620.png)]
@H_450_5@链式循环:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iI4RLzkz-1630228376862)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200315125559136.png)]
@H_450_5@封装Promise的readFile
:
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);
})
@H_450_5@mongoose所有的API都支持Promise:
User.find()
.then(function(data){
console.log(data)
})
@H_450_5@注册:
User.findOne({username:'admin'},function(user){
if(user){
console.log('用户已存在')
} else {
new User({
username:'aaa',
password:@R_675_6879@23',
email:'fffff'
}).save(function(){
console.log('注册成功');
})
}
})
User.findOne({
username:'admin'
})
.then(function(user){
if(user){
console.log('用户已存在');
}
else{
return new User({
username:'aaa',
password:@R_675_6879@23',
email:'fffff'
}).save();
}
})
.then(funciton(ret){
console.log('注册成功');
})
Generator
@H_450_5@async函数
11. 其他
修改完代码自动重启
@H_450_5@我们在这里可以使用一个第三方命名行工具:nodemon
来帮助我们解决频繁修改代码重启服务器的问题。
@H_450_5@nodemon
是一个基于Node.js开发的一个第三方命令行工具c;我们使用的时候需要独立安装:
#在任意目录执行该命令都可以
#也就是说c;所有需要 --global安装的包都可以在任意目录执行
npm install --global nodemon
npm install -g nodemon
#如果安装不成功的话c;可以使用cnpm安装
cnpm install -g nodemon
@H_450_5@安装完毕之后使用:
node app.js
#使用Nodemon
nodemon app.js
@H_450_5@只要是通过nodemon
启动的服务c;则他会监视你的文件变化c;当文件发生变化的时候c;会自动帮你重启服务器。
封装异步API
@H_450_5@回调函数:获取异步操作的结果
function fn(callBACk){
setTimeout(function(){
var data = 'hello';
callBACk(data);
},1000);
}
fn(function(data){
console.log(data);
})
数组的遍历方法c;都是对函数作为一种参数
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oiG3ap1H-1630228376863)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200314094620191.png)]
EcmaScript 6
@H_450_5@参考文档:https://es6.ruanyifeng.com/
12. 项目案例
目录结构
.
app.js 项目的入口文件
controllers
models 存储使用mongoose设计的数据模型
node_modules 第三方包
package.json 包描述文件
package-lock.json 第三方包版本锁定文件(npm5之后才有)
public 公共静态资源
routes
views 存储视图目录
模板页
路由设计
@H_450_462@路由 | 方法 | get参数 | post参数 | 是否需要登录 | 备注 | @H_450_462@/ | get | | | | 渲染首页 | @H_450_462@/register(登录) | get | | | | 渲染注册页面 | @H_450_462@/register | post | | email,nickname,password | | 处理注册请求 | @H_450_462@/login | get | | | | 渲染登陆界面 | @H_450_462@/login | post | | email,password | | 处理登录请求 | @H_450_462@/loginout | get | | | | 处理退出请求 | @H_450_462@ | | | | | |
模型设计
功能实现
步骤
- 创建目录结构
- 整合静态也-模板页
- 设计用户登陆c;退出c;注册的路由
- 用户注册
- 先处理客户端页面的内容(表单控件的namec;收集表单数据c;发起请求)
- 服务端
- 获取从客户端收到的数据
- 操作数据库
- 如果有错c;发送500告诉客户端服务器错了‘
- 其他的根据业务发送不同的响应数据
- 登录
- 退出
13. Express中间件
中间件的概念
@H_450_5@参考文档:http://expressjs.com/en/guide/using-middleware.html
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JsOS7jNs-1630228376864)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200316202757617.png)]
@H_450_5@中间件:把很复杂的事情分割成单个c;然后依次有条理的执行。就是一个中间处理环节c;有输入c;有输出。
@H_450_5@说的通俗易懂点儿c;中间件就是一个(从请求到响应调用的方法)方法。
@H_450_5@把数据从请求到响应分步骤来处理c;每一个步骤都是一个中间处理环节。
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...');
});
@H_450_5@同一个请求对象所经过的中间件都是同一个请求对象和响应对象。
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.');
});
@H_450_5@[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Reh90kg0-1630228376875)(C:UsersAApPDAtaroaR_515_11845@ingTyporatypora-user-imagesimage-20200317110520098.png)]
中间件的分类:
应用程序级别的中间件
@H_450_5@万能匹配(不关心任何请求路径和请求方法的中间件):
app.use(function(req,res,next){
console.log('Time',Date.now());
next();
});
@H_450_5@关心请求路径和请求方法的中间件:
app.use('/a',function(req,res,next){
console.log('Time',Date.now());
next();
});
路由级别的中间件
@H_450_5@严格匹配请求路径和请求方法的中间件
@H_450_5@get:
app.get('/',function(req,res){
res.send('get');
});
@H_450_5@post:
app.post('/a',function(req,res){
res.send('post');
});
@H_450_5@put:
app.put('/user',function(req,res){
res.send('put');
});
@H_450_5@delete:
app.delete('/delete',function(req,res){
res.send('delete');
});
总
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.');
});
错误处理中间件
app.use(function(err,req,res,next){
console.error(err,stack);
res.status(500).send('Something broke');
});
@H_450_5@配置使用404中间件:
app.use(function(req,res){
res.render('404.html');
});
@H_450_5@配置全局错误处理中间件:
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
});
});
内置中间件
- express.static(提供静态文件)
- http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express
第三方中间件
@H_450_5@参考文档:http://expressjs.com/en/resources/middleware.html
- body-parser
- compression
- cookie-parser
@H_401_11@mogran- response-time
- server-static
- session