二十二、MongoDB数据库
5、一般不在命令行中直接使用命令
- 在node.js中使用mongodb数据库
- 官方原生 node-mongodb-native;
- MongoDB官方也自带的封装的包:
mongodb
用于操作数据库,比较原始; - 第三方模块库:
mongoose
:连接数据库,创建文档(约束)信息,根据文档信息创建集合(类似表),创建文档(类似表记录),保存文档。
//安装
npm i mongoose
//引入第三方模块
const mongoose = require('mongoose');
//连接test数据库
mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true});
//创建集合,并对内部属性值做约束;(类似关系数据库中表)
const Cat = mongoose.model('Cat', { name: String });//这种方式创建的集合名为:‘cats’
---
//创建文档结构
const Schema = mongoose.Schema
const userSchema = new Schema({ title:String})//专门用于设计文档约束信息
//将文档结构发布到模型
const User = mongoose.model('User',userSchema)//创建集合:users
---
/增:new+save;创建实例文档(类似表记录)
const kitty = new User({ name: 'Zildjian' });
//添加到集合中,成功后回调(类似保存)
//kitty.save().then(() => console.log('meow'));
kitty.save(function(err,ret){
if(err){console.log('保存失败')}
else{console.log(ret)}
})
---
/查:[集合名].find([参数1],参数2)、[集合名].findOne([参数1],参数2)、findById('',function(){})
User.find({name:'条件'},function(err,ret){});//以数组形式返回集合所有/指定文档数据,
第一个参数是筛选条件,不写就是返回所有;
User.findOne({[条件]},function(err,ret){});//以对象形式返回单条数据,
第一个参数是条件,不写就是第一次数据;
---
/删:[集合名].remove(参数1,参数2)
User.remove({[条件]},function(err,ret){});//成功返回删除了几个等信息;
---
/改:[集合名].findByIdAndUpdate('2e13qw...',{password:'123'},function(err,ret){})
参数1:_id号;
参数2:要改的内容
参数3:成功与否的回调函数
- 用可视化工具
6、存储集合中数据时,默认会添加一个_id
属性,值是字符串;通过使用这个属性当做唯一值id来操作数据,展示的时候使用索引
来当用户考到的id。
二十三、ES6之Promise异步编程
1、背景
回调地狱:需要在异步操作中再进行异步操作,从而使异步操作保持一定顺序;
throw err
:阻止代码执行,把错误信息打印到控制台;相当于return console.log(err)
2、new Promise([异步操作])
;本身不是异步,因为是构造函数,会立即执行,内部往往用异步操作;
二十四、nodejs+express+mongodb实现博客
1、配置基本文件:
- 初始化项目管理:
npm init
- 初始化git环境:
git init
,创建README.md文件
- 创建
.gitignore文件
- 初始化文件目录
2、安装模块:
- 核心模块:
path
- 第三方模块:
express、mongoose
app.use('/public/',express.static(path.join(__dirname,'./public/')))
公开资源目录;- 文件操作路径中,设计的相对路径就是相对于执行node命令时所在的文件目录,而不是相对所处文件本身;
app.js:fs.readFile('./aa.txt','utf8',function(){})
,这里./
是相对于执行node命令所在的目录;而不是app.js
,因为通常读文件嵌套少,C:\nodejs\06\code> node app.js
时在app.js所处文件夹下,而app.js与所读文件都在同一目录下,所以看不出; - 但是在app.js中执行了同级文件夹
\code\foo\index.js
里的index.js,正好这个js要读取自身目录\code\foo\b.txt
中的b.txt文件,那么此时index.js中文件相对路径应该是./foo/b.txt
- 这样就不太直观,而且项目中不能直接用绝对路径写死,项目移动时就变了;
- 所以就有了
Node自带的__dirname、__filename
动态将文件相对路径转为绝对路径,并且还能进行自定义拼接字符串,不受命令在哪执行影响。 _dirname
:动态获取当前js文件所处的文件夹绝对路径C:/nodejs/06/code
;_filename
:动态获取当前js文件的绝对路径C:/nodejs/06/code/app.js
/
:代码中写路径时用斜杠表示,因为反斜杠有转义含义;\
:命令行中使用反斜杠;express.static(path.join(__dirname,'./public/'))
:就是做了进一步保险,其中'./public/'只是按相对路径习惯,path.join方法会正确拼接,如果不用这个方法转换,就必须按这个相对路径写,让系统按相对路径操作;
- 文件操作路径中,设计的相对路径就是相对于执行node命令时所在的文件目录,而不是相对所处文件本身;
3、安装模板引擎,配置模板页
art-template、express-art-template
- 配置:
app.engine('html',require('express-art-template'))
app.set('views',path.join(__dirname,'./views/'))
- 使用模板继承:
- 模板页留‘坑’:
<body>
{{include './header.html'}}
{{block 'content坑名'}}{{/block}}
{{include './footer.html'}}
</body>
- 子页面继承,填坑:
{{extend './index.html'}}
{{block 'content坑名'}}<div>任意内容<div>{{/block}}
4、路由设计
5、设计用户数据模型
- 注册页面需要的数据、
- 一些跟用户相关不需要在注册时填写的数据
- 确定文档结构
mongoose.Schema
6、注册请求逻辑
- 用户输入信息,符合文档结构约束则可以发送注册请求;
- 采用异步ajax发送;
$('#formId').on('submit',function(e){
e.preventDefault()
var formData = $(this).serialize()//表单要提交的数据序列化为字符串
$.ajax({
url:'',
type:'post',
data:formData,
dataType:'json',
success:function(data){}
})
})
- 后端接收请求数据
req.body
; - 判断用户、邮箱是否存在;
- 存储数据:
var body = req.body
就是对象形式,可以直接让集合使用;new User(body).save()
- 使用第三方模块
md5
,给密码(重复多次也可以)加密存储; req.body.password = md(md(req.body.password))
- 根据ajax要求
dataType:json
返回json格式数据:res.status(200).json({对象})
;如{ err_code:0,msg:'注册成功' }
;
7、注册表单的同步提交与异步提交
- 表单默认
method='post' action='/register'
提交时同步提交; - 使用
jquery
监听提交按钮的事件,event.preventDefault() 方法阻止元素发生默认的行为,
并且阻止原生的同步提交,从而实现异步提交; - 问题:早期没有ajax,表单同步提交页面会刷新,所以浏览器会将响应的数据渲染到当前页面,从而使得原来的页面被覆盖,用户体验不好,每次还要返回上一步的注册页面;
- 服务端处理:后来为了让注册页面存在,也能有提示信息,服务器端采用重新渲染新页面的方式;
return res.render('register.html',{err_msg:'邮箱已存在',form:body})
,然后修改模板页,当有数据时就会渲染出来;(这也是同步提交,浏览器会刷新,服务器端渲染,所以返回的新页面要用数据填充上,服务器压力大但更安全,大公司用) - 前端处理:ajax,异步提交,页面不会刷新,只需要返回响应数据,所以可以使用js操作dom、bom使用数据;
- 异步请求的不足:如果异步请求是重定向请求,那么该请求对于服务器来说无效,因为浏览器页面又不刷新;如果需要重定向就在客户端
ajax
中操作window.location.href='/'
; - 所以,同步请求一般用于页面需要刷新或重定向页面改变;异步请求用于在当前页面处理数据;
8、session保存登陆状态
- express框架中使用第三方模块express-session 记录状态,通过req.session来存储使用数据;
- 默认session是存储在内存中,当服务器重启数据就会消失,在真正生产环境中会被会话对象做持久化处理,比如使用插件存储到mongodb数据库中。
9、概述注册-登陆-退出的前后端交互
二十五、Node.JS的中间件
- 中间件:就是请求与响应之间的一步步的步骤,提高代码灵活性,动态可扩展,本质就是函数;
- 同一个请求所经过的中间件都是同一个请求对象和响应对象;
- 一次请求只按顺序执行一个中间件,在这个中间件中执行
next()
来按执行下一个符合条件中间件; - express中间件类别
- 应用程序级别中间件:其他级别最终也会返回这种形式,并调用
next()
app.use(function(req,res,next){ next() })
app.[method]('/',function(req,res,next){next()})
- 路由级别:
router.use()
router.METHOD()
- 错误处理中间件:写在代码后面,前面中间件都不匹配时执行;
app.use(function(err,req,res,next){})
- 常于
next(err)
连用,当其他中间件中执行next(err)
会直接找这个中间件并传入错误对象执行;
- 内置中间件:
express.static\express.json\express.urlencoded
app.use('/public/',express.static(path.join(__dirname,'./public/')))
- 第三方中间件:
body-parser
app.use(bodyParser.json())
- 应用程序级别中间件:其他级别最终也会返回这种形式,并调用