mongodb
# MongoDB
# 基本命令
show dbs //查看数据库列表(数据库中的所有数据库)
db //查看当前连接的数据库
use 数据库名称 //切换到指定的数据库,(如果没有会新建)
show collections //查看当前目录下的所有集合(数据表)
db.集合名.find() //查看表中的详细信息
# 在Node中如何操作MongoDB数据库
# 使用官方的MongoDB
包来操作
http://mongodb.github.io/node-mongodb-native/
# 使用第三方包mongoose
来操作(推荐使用)
https://mongoosejs.com/ //官网
第一步安装mongoose:(在哪里使用安装在哪里)
npm i mongoose --save
第二步连接数据库 (此案例数据库名为demo)
//连接数据库
//引入mongoose
let mongoose = require('mongoose')
mongoose.set('useCreateIndex',true) //使用一个新的索引创建器
//1.连接数据库
mongoose.connect('mongodb://localhost:27017/demo',{
useNewUrlParser: true, //使用一个新的URL解析器,用于解决一些安全性问题。
useUnifiedTopology: true //使用一个统一的新的拓扑结构
})
//2.绑定数据库连接的监听
mongoose.connection.on('open',function (err) {
if(err){
console.log('数据库连接失败',err)
}else {
console.log('数据库连接成功')
//3.操作数据库
//3.1. ------ 引入模式对象
let Schema = mongoose.Schema
//3.2.-------- 创建约束对象
let studentsRule = new Schema({
stu_id: {
type: String, //限制学号必须为:字符串
required: true,
unique: true
},
name: {
type: String, //限制姓名必须为:字符串
required: true, //限制姓名为必填项
},
age: {
type: Number, //限制年龄必须为:字符串
required: true, //限制年龄为必填项
},
sex: {
type: String, //限制性别必须为:字符串
required: true, //限制性别为必填项
},
hobby: [String], //限制爱好只能为数组,数组中的每一项必须为字符串
info: Schema.Types.Mixed, //接收所有类型
date: {
type: Date,
default: Date.now()
},
enable_flag: {
type: String,
default: 'Y'
}
})
//3.3.------- 创建模型对象('students'是自己创建的集合)
let stuModel = mongoose.model('students',studentsRule) //用于生成某个集合所对应的模型对象
//4进行CURD操作
}
})
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
55
56
第三步:进行CURD操作(对应第二步里面的4)
-Create
模型对象.create(文档对象,回调函数)
模型对象.create(文档对象)
stuModel.create({
stu_id:'004',
name:'强',
age:'42',
sex:'男',
hobby:['女','打代码','打篮球'], //限制爱好只能为数组,数组中的每一项必须为字符串
info:'一个风一样的男子', //接收所有类型
},function(err,data){
if (!err) console.log(data)
else console.log(err)
})
2
3
4
5
6
7
8
9
10
11
-Read
模型对象.find(查询条件[,投影])不管有没有数据,都返回一个数组
模型对象.findOne(查询条件[,投影])找到了返回一个对象,没找到返回null
find方法:
1.返回的是一个数组,就算是一条数据,也包裹一个数组
2.若查询结果为空,则返回一个空数组。
findOne方法:
1.若有结果,返回的是一个对象
2.若没有结果,返回一个null
stuModel.find({name:'小明'},function (err,data) {
if (!err) console.log(data)
else console.log(err)
})
stuModel.findOne({name:'班长',age:42},function (err,data) {
if (!err) console.log(data)
else console.log(err)
})
2
3
4
5
6
7
8
-Update
模型对象.updateOne(查询条件,要更新的内容[,配置对象])
模型对象.updateMany(查询条件,要更新的内容[,配置对象])
备注:存在update方法,但是即将废弃,查询条件匹配到多个时,依然只修改一个,强烈建议用updateOne或updateMany
stuModel.updateOne({name:'静静'},{age:16},function (err,data) {
if (!err) console.log(data)
else console.log(err)
})
2
3
4
-Delete
模型对象.deleteOne(查询条件)
模型对象.deleteMany(查询条件)
备注:没有delete方法,会报错!
stuModel.deleteMany({age:16},function (err,data) {
if (!err) console.log(data)
else console.log(err)
})
2
3
4
备注: 以上所有方法,如果没有指定回调函数,则返回值是一个Promise对象
# 使用Node操作MySQL数据库
文档:https://www.npmjs.com/package/mysql
安装:
npm install --save mysql
// 引入mysql包
var mysql = require('mysql');
// 创建连接
var connection = mysql.createConnection({
host : 'localhost', //本机
user : 'me', //账号root
password : 'secret', //密码12345
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();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 异步编程
# 回调函数
不成立的情况下:
function add(x,y){
console.log(1);
setTimeout(function(){
console.log(2);
var ret = x + y;
return ret;
},1000);
console.log(3);
//到这里执行就结束了,不会i等到前面的定时器,所以直接返回了默认值 undefined
}
console.log(add(2,2));
// 结果是 1 3 undefined 4
2
3
4
5
6
7
8
9
10
11
12
13
使用回调函数解决:
回调函数:通过一个函数,获取函数内部的操作。(根据输入得到输出结果)
var ret;
function add(x,y,callback){
// callback就是回调函数
// var x = 10;
// var y = 20;
// var callback = function(ret){console.log(ret);}
console.log(1);
setTimeout(function(){
var ret = x + y;
callback(ret);
},1000);
console.log(3);
}
add(10,20,function(ret){
console.log(ret);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
注意:
凡是需要得到一个函数内部异步操作的结果(setTimeout,readFile,writeFile,ajax,readdir)
这种情况必须通过 回调函数 (异步API都会伴随着一个回调函数)
ajax:
基于原生XMLHttpRequest封装get方法:
var oReq = new XMLHttpRequest();
// 当请求加载成功要调用指定的函数
oReq.onload = function(){
console.log(oReq.responseText);
}
oReq.open("GET", "请求路径",true);
oReq.send();
2
3
4
5
6
7
function get(url,callback){
var oReq = new XMLHttpRequest();
// 当请求加载成功要调用指定的函数
oReq.onload = function(){
//console.log(oReq.responseText);
callback(oReq.responseText);
}
oReq.open("GET", url,true);
oReq.send();
}
get('data.json',function(data){
console.log(data);
});
2
3
4
5
6
7
8
9
10
11
12
13
# Promise
callback hell(回调地狱):
文件的读取无法判断执行顺序(文件的执行顺序是依据文件的大小来决定的)(异步api无法保证文件的执行顺序)
var fs = require('fs');
fs.readFile('./data/a.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
fs.readFile('./data/b.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
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){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/b.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/a.text','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
});
});
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
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在EcmaScript6新增了一个API:Promise
。
- Promise:承诺,保证
- Promise本身不是异步的,但往往都是内部封装一个异步任务
基本语法:
// 在EcmaScript 6中新增了一个API Promise
// Promise 是一个构造函数
var fs = require('fs');
// 1 创建Promise容器 resolve:解决 reject:失败
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./a.text', 'utf8', function(err, data) {
if (err) {
// console.log(err);
// 把容器的Pending状态变为rejected
reject(err);
} else {
// console.log(data);
// 把容器的Pending状态变为resolve
resolve(data);
}
});
});
// 当p1成功了,然后就(then)做指定的操作
// then方法接收的function就是容器中的resolve函数
p1
.then(function(data) {
console.log(data);
}, function(err) {
console.log('读取文件失败了', err);
});
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
!
链式循环:
封装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);
})
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
mongoose所有的API都支持Promise:
// 查询所有
User.find()
.then(function(data){
console.log(data)
})
2
3
4
5
注册:
User.findOne({username:'admin'},function(user){
if(user){
console.log('用户已存在')
} else {
new User({
username:'aaa',
password:'123',
email:'fffff'
}).save(function(){
console.log('注册成功');
})
}
})
2
3
4
5
6
7
8
9
10
11
12
13
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('注册成功');
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 其他
# 修改完代码自动重启
我们在这里可以使用一个第三方命名行工具:nodemon
来帮助我们解决频繁修改代码重启服务器的问题。
npm install -g nodemon //安装nodemon
安装完毕之后使用:
nodemon app.js
# 封装异步API
回调函数:获取异步操作的结果
function fn(callback){
// var callback = funtion(data){ console.log(data); }
setTimeout(function(){
var data = 'hello';
callback(data);
},1000);
}
// 如果需要获取一个函数中异步操作的结果,则必须通过回调函数的方式来获取
fn(function(data){
console.log(data);
})
2
3
4
5
6
7
8
9
10
11
# 数组的遍历方法,都是对函数作为一种参数
# EcmaScript 6
参考文档:https://es6.ruanyifeng.com/
# 项目案例
# 目录结构
.
app.js 项目的入口文件
controllers
models 存储使用mongoose设计的数据模型
node_modules 第三方包
package.json 包描述文件
package-lock.json 第三方包版本锁定文件(npm5之后才有)
public 公共静态资源
routes
views 存储视图目录
2
3
4
5
6
7
8
9
10
# 模板页
- 子模板
- 模板继承
# 路由设计
路由 | 方法 | get参数 | post参数 | 是否需要登录 | 备注 |
---|---|---|---|---|---|
/ | get | 渲染首页 | |||
/register(登录) | get | 渲染注册页面 | |||
/register | post | email,nickname,password | 处理注册请求 | ||
/login | get | 渲染登陆界面 | |||
/login | post | email,password | 处理登录请求 | ||
/loginout | get | 处理退出请求 | |||
# 模型设计
# 功能实现
# 步骤
- 创建目录结构
- 整合静态也-模板页
- include
- block
- extend
- 设计用户登陆,退出,注册的路由
- 用户注册
- 先处理客户端页面的内容(表单控件的name,收集表单数据,发起请求)
- 服务端
- 获取从客户端收到的数据
- 操作数据库
- 如果有错,发送500告诉客户端服务器错了‘
- 其他的根据业务发送不同的响应数据
- 登录
- 退出
# Express中间件
# 中间件的概念
参考文档:http://expressjs.com/en/guide/using-middleware.html
中间件:把很复杂的事情分割成单个,然后依次有条理的执行。就是一个中间处理环节,有输入,有输出。
说的通俗易懂点儿,中间件就是一个(从请求到响应调用的方法)方法。
把数据从请求到响应分步骤来处理,每一个步骤都是一个中间处理环节。
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(){
// 解析请求地址中的get参数
// var obj = url.parse(req.url,true);
// req.query = obj.query;
query(req,res); //中间件
// 解析请求地址中的post参数
req.body = {
foo:'bar'
}
});
if(req.url === 'xxx'){
// 处理请求
...
}
server.listen(3000,function(){
console.log('3000 runing...');
});
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.get('/abc',function(req,res,next){
// 同一个请求的req和res是一样的,
// 可以前面存储下面调用
console.log('/abc');
// req.foo = 'bar';
req.body = {
name:'xiaoxiao',
age:18
}
next();
});
app.get('/abc',function(req,res,next){
// console.log(req.foo);
console.log(req.body);
console.log('/abc');
});
app.listen(3000, function() {
console.log('app is running at port 3000.');
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 中间件的分类:
# 应用程序级别的中间件
万能匹配(不关心任何请求路径和请求方法的中间件):
app.use(function(req,res,next){
console.log('Time',Date.now());
next();
});
2
3
4
关心请求路径和请求方法的中间件:
app.use('/a',function(req,res,next){
console.log('Time',Date.now());
next();
});
2
3
4
# 路由级别的中间件
严格匹配请求路径和请求方法的中间件
get:
app.get('/',function(req,res){
res.send('get');
});
2
3
post:
app.post('/a',function(req,res){
res.send('post');
});
2
3
put:
app.put('/user',function(req,res){
res.send('put');
});
2
3
delete:
app.delete('/delete',function(req,res){
res.send('delete');
});
2
3
# 总
var express = require('express');
var app = express();
// 中间件:处理请求,本质就是个函数
// 在express中,对中间件有几种分类
// 1 不关心任何请求路径和请求方法的中间件
// 也就是说任何请求都会进入这个中间件
// 中间件本身是一个方法,该方法接收三个参数
// Request 请求对象
// Response 响应对象
// next 下一个中间件
// // 全局匹配中间件
// app.use(function(req, res, next) {
// console.log('1');
// // 当一个请求进入中间件后
// // 如果需要请求另外一个方法则需要使用next()方法
// next();
// // next是一个方法,用来调用下一个中间件
// // 注意:next()方法调用下一个方法的时候,也会匹配(不是调用紧挨着的哪一个)
// });
// app.use(function(req, res, next) {
// console.log('2');
// });
// // 2 关心请求路径的中间件
// // 以/xxx开头的中间件
// app.use('/a',function(req, res, next) {
// console.log(req.url);
// });
// 3 严格匹配请求方法和请求路径的中间件
app.get('/',function(){
console.log('/');
});
app.post('/a',function(){
console.log('/a');
});
app.listen(3000, function() {
console.log('app is running at port 3000.');
});
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
# 错误处理中间件
app.use(function(err,req,res,next){
console.error(err,stack);
res.status(500).send('Something broke');
});
2
3
4
配置使用404中间件:
app.use(function(req,res){
res.render('404.html');
});
2
3
配置全局错误处理中间件:
app.get('/a', function(req, res, next) {
fs.readFile('.a/bc', funtion() {
if (err) {
// 当调用next()传参后,则直接进入到全局错误处理中间件方法中
// 当发生全局错误的时候,我们可以调用next传递错误对象
// 然后被全局错误处理中间件匹配到并进行处理
next(err);
}
})
});
//全局错误处理中间件
app.use(function(err,req,res,next){
res.status(500).json({
err_code:500,
message:err.message
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 内置中间件
- express.static(提供静态文件)
- http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express
# 第三方中间件
参考文档:http://expressjs.com/en/resources/middleware.html
body-parser
compression
cookie-parser
mogran
response-time
server-static
session
#