NodeJs就是一个可以让JavaScript脱离浏览器还能执行的平台,并且这个平台对JavaScript功能进行了增强。 具有特定功能的文件就是一个模块(把特定的功能写在一个js文件里面,这个文件就是一个模块) 导出模块 exports.属性名 = 函数名; 引入模块 let 变量名 = require('./相对路径');
-
模块内的变量都是局部变量 模块内的函数 都是局部函数 所有的模块(.js文件), 都被一个函数包裹起来 function (exports, require, module, __filename, __dirname) { // 实际上我们写的代码,都被包裹在这个函数里
}
-
require函数:主要用来引入模块,引入模块有三种方式 a) 引入自定义模块(自己写) var 变量名 = require('./相对路径')
b) 引入系统模块,不需要下载和安装 var 变量名 = require('模块名')
c)引入第三方模块 下载第三方模块 npm install 模块名 // 缩写 npm i 模块名 备注: 所有通过npm下载的第三方模块, 都被放入一个 node_modules文件夹里。 引入模块 var 变量名 = require('模块名')
-
exports导出(只是指向导出对象的一个引用,真正的导出对象是 module.exports) exports.属性名 = 函数名; exports.属性名 = 变量名;
补充: 变量不写 var关键字 就是全局变量(不需要导出,只要引入这个模块就能使用) global,全局对象,(相当于window,nodejs没有window对象)
-
exports 和 module.exports的区别: exports只是一个指向 module.exports 的一个地址(指针),真正的导出对象是 module.exports;
-
node_modules文件夹: 所有的node第三方模块(需要下载),都自动存入 node_modules文件夹里面 补充: 引入模块,可以不写后缀;
-
一个文件目录(文件夹)就是一个包,文件夹里面的模块,可以使用包管理 需要一个包管理文件 pakage.json
-
包管理工具的使用:(***** ) 一个文件目录 就是一个包
a) 生成一个包描述文件 pakage.json 从这个目录进入cmd,运行 : npm init
b) 下载 模块 npm install 模块名 // 缩写 npm i 模块名
c) 引入模块 var 变量名 = require('模块名')
本地安装和全局安装: 本地安装,装在当前目录下 npm i 模块名 全局安装: 装在 c盘 C:\Users\Administrator\AppData\Roaming\npm 目录下 npm i 模块名 -g
8 npm常用命令 1) 安装包,并且添加到依赖列表 npm i 模块名 --save ( cnpm i 模块名 --save )
2) 全局安装包
npm i 模块名 -g
3) 删除包
npm remove 模块名 // npm remove 模块名 -g (删除安装在全局的包)
4) 更新包(更新到最新版本)
npm update 模块名
5) 查看可用版本
npm view 模块名 versions
6) 安装指定版本的包(模块, 并且添加到依赖列表
npm i 模块名@版本号 --save
补充: npm i 或者 cnpm i
可以依次安装完pakage.json依赖列表(dependencies)里面的所有 模块
同步和异步: a) 同步阻塞代码 b) 异步不阻塞代码
Promise(承诺),es6新增的一个对象,主要用来控制异步操作 (*****)
a) Promise有三个状态:
a) 进行中 pendding
b) 已完成 resolved
c) 已失败 rejected
Promise的状态: 只会从 进行中(pendding) 变成 已完成(resolved)
或者从 进行中(pendding) 变成 已失败(rejected)
b) 基本使用方法
// 创建promise实例
var promise = new Promise((resolve, reject) => {
// 这里写你的逻辑代码
if (true) {
resolve(data)
} else {
reject(err)
}
});
promise.then((data) => { 这里获取的是成功的数据 }, (err) => { 失败信息 })
###fs模块 这个一个主要对文件进行操作的模块 封装了很多关于文件操作的api(方法和属性) 1)使用fs模块步骤: 引入模块 var fs = require('fs'); 2) fs模块 读取文件 a) 异步读取 fs.readFile('要读取的文件名', func9tion (err, data) { if (err) { throw err } else { console.log('文件读取成功:', data) } })
b) 同步读取:
var data = readFileSync('要读取的文件名')
console.log(data); // 同步读取的结果
3) 文件信息
// 异步获取文件信息
fs.stat('文件的路径和名字', function (err, stats) {
// 这里面 的 stats 包含了文件的所有信息
})
// 同步获取文件信息
var stats = fs.statSync(path)
4) fs写文件
// 异步写文件
fs.writeFile('要写入的文件的路径', '写入的内容', function (err) {
if (err) {
console.log('写入文件失败')
}
console.log('写入文件成功')
})
// 同步写
fs.writeFileSync()
5) fs删除文件
// 异步删除
fs.unlink('要删除的文件的路径和名字', function (err) {
if (err) {
throw err;
} else {
console.log('删除成功')
}
})
// 同步删除
fs.unlinkSync(path)
6) 获取目录(文件夹)里面的文件和文件夹
fs.readdir('文件目录', function (err, files) {
// 读取出来的结果 是一个数组(files是数组)
})
// 同步读取
fs.readdirSync('目录')
7) 创建文件夹
fs.mkdir('要创建的文件夹', function (err) {
if (err) {
throw err;
} else {
console.log('文件夹创建成功')
}
})
8)删除文件夹
fs.rmdir('要删除的文件夹的路径', function (err) {
if (err) {
throw err;
} else {
console.log('文件夹删除成功')
}
})
-
流读取 readFile(readFileSync)读取文件的时候,都会把一个文件完成的放入Buffer缓存区, 电脑需要准备同样大小的内存空间,可能造成内存溢出。 所以需要,流读取
1) 创建读取流 var 变量 = fs.createReadStream('文件路径')
// 事件类型 变量.on('data',callback) // 读取过程中触发 变量.on('end',callback) // 读取结束触发 变量.on('error',callback) // 错误触发2) 创建写入流 var 变量 = fs.createWriteStream('文件路径')
// 写入数据 变量.write('要被写入的数据') // 写入结束 变量.end(); // 监听写入完成的事件 finish 变量.on('finish', callback) // 监听出错事件 变量.on('error', callback)-
管道流方式 a) 创建读取流 var readStream = fs.createReadStream('读取的文件目录')
b) 创建写入流 var writeStream = fs.createWriteStream('写入的文件的目录')
c) 使用管道流 readStream.pipe(writeStream)
4) 链式流 需要引入压缩处理模块 var zip = require("zlib");
a) 创建读取流 var readStream = fs.createReadStream('读取的文件目录') b) 创建写入流 var writeStream = fs.createWriteStream('写入的文件的目录') c) 使用链式流 readStream.pipe(zip.createGzip()).pipe(writeStream); -
url 全球统一资源定位符,是可以在互联网上访问到资源的唯一地址
https: 协议 常见的有http https
www: 主机名
itsource.cn 域名
upload/class/20180806/ 文件路径
80 端口号(默认是80 可以不写 其他的都要写)
http状态码
2xx
200 请求成功
3XX
304 未修改(缓存)
301 请求的 URL 已移走
4XX
404 找不到
403 服务器拒绝请求(没有权限)
5XX
500 内部服务器错误
备注:
在响应头设置状态码
res.writeHead(状态码, {"Content-Type":"text/html; charset=utf-8"})
http模块
搭建服务器 前后端数据传递 (请求数据 响应请求)
http模块get方法:
http.get('请求的地址url', (res) => {
// res 就是请求获取的数据对象
// 监听data事件
res.on('data', (data) => {
// 这里可以获取data(buffer类型)
})
// 监听数据请求结束事件
res.on('end', () => {
console.log('获取数据完毕')
})
}).on('error', (err) => {
console.log(err);
})
请求的两种方式的区别(get/post)
1) get
a) 请求的数据了比较少
b) 参数暴露在url上,不安全
c) 请求的参数 放在 url?参数1=值1&参数2=值2
e) get方式传参由于参数在url上,浏览器url长度有限制
2) post
a) 请求的数据库比较多
b) 相对安全
c) 请求的参数放入请求体 不会暴露出来
Express 是一个基于 Node.js 平台的开发框架
项目快速生成工具 express-generator,全局安装express-generator
npm i express-generator -g
新建一个文件夹, 就可以在这个文件夹里面使用 express命令创建项目
express 项目的名字 -e // -e 是使用nodejs的ejs模板,例子: express app -e
安装所有依赖npm i
启动项目
A) 自带方式:
npm run start
npm start
备注: 这两个方式回去运行 bin目录下的www文件,默认启动端口是3000
B) 推荐方式:
a) 找到 app.js 在导出之前(module.exports = app; 之前) 监听端口
app.listen(80, () => {
console.log('服务器启动成功...')
})
b) 运行app.js
node app
项目目录详解:
pakage.json 包描述文件 里面可以看到依赖的模块有哪些?
app.js 是主模块 里面可以启动服务器 定义路由的对应关系 (其他的配置)
views 里面放的是nodejs的后端模板文件 =》 ejs模板文件
routes 里面放的是 路由文件
public 里面放的是 静态文件(html/css/js/iamges前端文件)
说明: 如果有一个页面 index.html 前端会先请求到这个页面 否则就找路由index.js
node_modules 放的是安装的node的第三方模块
bin 放的是默认启动的文件
路由详解:
所有项目根目录路由 交给index路由处理
所有项目users路由 交给users路由处理
如果要新建路由:
1)在router里面创建一个 路由名.js 文件
2)在app.js里面 改造两个地方
a) 引入自己写的路由
var 变量名 = require('./routes/路由名');
例如: var vipRouter = require('./routes/vip');
b) 设置处理url和路由的对应关系
app.use('/url', 变量名)
例如: app.use('/vip', vipRouter);
说明: 一个请求 一个响应
前端: 在浏览器输入 localhost:666 相当于请求首页根目录
后端: 在路由index.js里面:
router.get('/', (req, res) => {
// 响应前端发送的请求,返回数据给前端
res.send('响应给前端的数据')
})
前端: 在浏览器输入localhost:666/news.html 相当于请求更目录下的 /news.htm文件
后端: 在路由index.js里面:
router.get('/news.html', (req, res) => {
// 响应前端发送的请求,返回数据给前端
res.send('响应给前端的数据')
})
响应对象res(response),主要用来响应前端发送的请求,把响应数据发送给前端
备注: 如果不响应,前端请求会一直挂起(打圈圈);
1) res.send() (*****)
a) res.send(json数据对象)
b)res.send(字符串)
c) res.send(html)
说明: res.send() 在一个逻辑里面只能用一次
不能发送数字 会被当成状态码
2) res.json() 响应json数据给前端
res.josn(JSON对象)
3) res.jsonp 用于响应前端的跨域访问
res.jsonp(json对象)
4) res.render(参数1, 参数2) (*****)
作用: 数据和模板合并渲染 生成html 发送(响应)给前端
参数1: 使用的ejs模板文件的名字
参数2: json数据 必须是 key:value 这种形式
请求对象req(request),主要用来接收前端(浏览器)发送的数据。
a) 如果请求是get方式 (*****)
req.query.参数名
b)如果请求是post方式(*****)
req.body.参数名
c) 获取ip
req.ip
###mongodb 配置环境变量(让mongo命令可以在任何目录使用) a) 复制目录C:\Program Files\MongoDB\Server\4.0\bin地址 b) 计算机右键 =》 属性 =》 高级系统设置 =》 环境变量 =》 系统变量path => 加个英文分号 粘贴: C:\Program Files\MongoDB\Server\4.0\bin 备注: 如果是window10 直接新建一个 粘贴进去
MongoDB的基本使用:
1) 常用命令:
a) 显示当前数据库列表(当前有哪些数据库, 只有数据库里面有数据才能显示)
show dbs
b) 显示当前你在哪个数据库里面
db
c) 创建数据库(如果这个数据已经存在 那么就直接使用, 如果不存在,就会创建)
use 数据库的名字
e) 显示数据库中的集合
show collections
6. 数据库的增删改查(CRUD)操作(*****)
<-------------------------- 增加数据 ------------------------->
语法:
1) db.集合名.insert({json结构的数据}) // 集合名是自己取的 如果存在
直接往里插入数据 如果不存在, 会自动创建集合
示例: db.student.insert({"name":"小张", "age":18})
2) db.集合名.save({json结构的数据})
示例:db.h50528.save({"name":"小李", "age":28})
区别: insert() 插入数据 如果有相同的(id一样的数据)会报错 插入失败
save() 插入数据 如果有相同的(id一样的数据)会覆盖 插入成功
<-------------------------- 查询数据 ------------------------->
语法:
db.集合名.find() // 查询集合中的所有数据
db.集合名.findOne() // 查询集合中的第一条数据
db.集合名.find().pretty() // 查询集合中的所有数据 查询的结果要格式化
<-------------------------- 删除数据 ------------------------->
1. 删除文档
db.集合名.remove({}) 删除集合下所有数据
db.集合名.remove({"name": "张三"}) 删除集合下name=”张三”的数据,按条件删除
2. 删除集合
db.集合名.drop() 或 db.runCommand({"drop":"集合名"}) 删除集合
3. 删除数据库(先确定当前在哪个数据库里面)
db.runCommand({"dropDatabase": 1}) 删除当前数据库,注意 此处的1没加双引号
<-------------------------- 修改数据 ------------------------->
语法:db.web.update({"name":"a1"}, {"age":10}) // 第一个括号是查找的条件
第二个括号是修改后的新内容
示例:db.stu.update({"name":"张三"}, {"age": "5"})
补充: db.stu.update({"name":"王五"}, {$set: {"age":28}})
7. 高级条件查询
语法1:db.collection.find({ "key" : value }) 查找key=value的数据.
例1:查找女歌星。
思路:查找sex=”女”的歌星。
示例: db.list.find({"sex":"女"})
语法2: db.collection.find({ "key" : { $gt: value } }) key > value
例2:查找年龄大于53的歌星。
示例: db.list.find({"age": { $gt: 53 }})
语法3:db.collection.find({ "key" : { $lt: value } }) key < value
例3:查询年龄小于35岁的歌星。
示例: db.list.find({"age": { $lt: 35 }})
语法4:db.collection.find({ "key" : { $gte: value } }) key >= value
例4:查询成绩大于等于95的歌星。
示例: db.list.find({"score": { $gte: 95 }})
语法5:db.collection.find({ "key" : { $lte: value } }) key <= value
例5:查询年龄在小于等于32岁的歌星。
示例: db.list.find({"age": { $lte: 32 }})
语法6:db.collection.find({ "key" : { $gt: value1 , $lt: value2 } }) value1 < key <value2
例6:查找年龄在30-40岁之间的歌星。
示例: db.list.find({"age": { $gt: 30 , $lt: 40 }})
语法7:db.collection.find({ "key" : { $ne: value } }) key <> value
例7:查询外国歌手。
示例: db.list.find({"country": { $ne: "中国" }})
语法8:db.collection.find({ "key" : { $mod : [ 10 , 1 ] } }) 取模运算,
条件相当于key % 10 == 1 即key除以10余数为1的
例8:查询成绩为5 、15、 25、。。。。95的歌星。
示例: db.list.find({"score" : { $mod : [10, 5] }})
语法9:db.collection.find({ "key" : { $in: [ 1, 2, 3 ] } }) 属于,
条件相当于key等于[ 1, 2, 3 ]中任何一个.
例9:查询序号(num)为3或者6或者9的歌星。
示例: db.list.find({ "num" : { $in: ["3", "6", "9"] } })
语法10:db.collection.find({ "key" : { $nin: [ 1, 2, 3 ] } }) 不属于,
条件相当于key的值不属于[ 1, 2, 3 ]中任何一个。
例10:查询国籍不为美国和韩国的歌手。
示例: db.list.find({"country" : { $nin: ["美国", "韩国"] }})
语法11:db.collection.find({ "key" : { $size: 1 } })
$size 数量、尺寸,条件相当于key对应的值的数量是1(值必须是数组)
例11:查询有3个代表作品的歌手
示例: db.list.find({"works" : { $size: 3 }})
语法12:db.collection.find({ "key" : { $exists : true|false } })
例12-1:查询包含name字段的数据。
示例: db.list.find({"name" : { $exists : true }})
语法13:db.collection.find({ $or : [{a : 1}, {b : 2} ] })
例13:某个娱乐公司15个人,资料都在数据库里面,某个活动必须要刘德华参加,
另外需要团队的全部女歌手配合演出,领导安排你帮忙打印歌手的资料。
示例: db.list.find({$or : [{"name":"刘德华"}, {"sex":"女"}]})
语法14: 如果值是对象
db.list.insert({"name":"test", "score":{"yy":80, "sx":79, "wy":95}})
查询语文成绩为80的同学
示例: db.list.find({"score.yy": 80})
8. 其他高级条件语法(***)
1) 排序:
db.collection.find().sort({ "key1" : -1 ,"key2" : 1 }) 这里的1代表升序,-1代表降序
例1:对所有歌星安年龄排序。
示例: db.list.find().sort({"age": 1})
2)limit(n) 限制输出多少条
实现输出5条
示例:db.list.find().limit(5)
3) skip(n) 跳过多少条再输出
跳过5条再输出
示例: db.list.find().skip(5)
4) 综合使用:
跳过5条 输出5条
db.list.find().skip(5).limit(5)
分页数据输出思路
假如103 条数据 每页显示10条 一共分 11页
var pagesize = 10;
var n = (currentpage - 1)*pagesize;
db.list.find().skip(n).limit(pagesize)
###mongoose
1. 它是nodejs的一个第三方模块,主要是用来操作MongoDB数据库的。
2. mongoose入门步骤:
1) 新建一个项目目录(文件夹),初始化项目目录,安装mongoose
npm init // 生成一个pakage.json
cnpm i mongoose --save // 安装mongoose 并且添加到依赖列表里面去
2) 新建一个.js文件, 引入mongoose
var mongoose = require('mongoose');
3) 使用mongoose连接数据库
连个前提条件:
a) 确保你的mongodb正在运行(已经安装为window服务 已经在提供服务)
b) 确保你的mongoose模块已经安装
/*
mongoose.connect(参数1, 参数2)
参数1:mongodb://127.0.0.1:27017/web
mongodb:// 协议
127.0.0.1 本地地址 相当于 localhost
27017 mongodb的默认端口好
web 想要连接的数据库的名字(自己取,如果有 直接连接 没有 会创建一个)
参数2:就是一个回调函数
*/
mongoose.connect('mongodb://127.0.0.1:27017/web', (err) => {
if (err) {
throw err;
} else {
console.log('连接数据库成功')
}
})
3. 以上步骤完成以后,想要操作数据库,还得完成以下三步:
1) 定义骨架(需要操作数据库的哪些字段 都需要先定义骨架)
var userSchema = new mongoose.Schema({
name: String,
age: Number
})
备注: 骨架本身不具备操作数据库的能力
2) 发布模型
var userModel = mongoose.model('userModel', userSchema, 'user')
model(参数1, 参数2, 参数3)
参数1: 基本不用 模型名
参数2: 发布这个模型 需要使用的骨架
参数2: 连接这个数据库 索要操作的里面的集合名(集合最好先创建好 如果不创建 会自动创建)
备注:
模型主要用来 查询 数据
3) 创建实体
var intance = new userModel();
备注: 实体具备新增数据的能力 主要用来 新增 删除 修改
实体: 什么地方使用 就在什么地方创建
1. 使用mongoose新增数据
1)完成以上几步
2)把需要新增的数据 挂在实体上面
3)实体执行保存操作(save()方法),在save()里面传入回调
如果有错 抛出错误
否则 打印新增数据成功
2. 使用mongoose删除数据
1)以上准备步骤
2)删除数据 得根据id删除 所有 需要一个id
var id = '5b6f9968c83affe9e1a9eeeb';
3) 根据id 查询出这条数据
userModel.findById(id, (err, data) => {
console.log(data); // 这里能够把 data查询出来
if (data) {
data.remove((err) => {
if (err) {
throw err;
} else {
console.log('删除成功 gg')
}
})
}
})
3. 使用mongoose修改数据
首先根据id查询出数据数据,然后把新数据保存即可
router.post("/doedit.html",(req,res)=>{
let id=req.query.id;
console.log(id);
listModel.findById(id,(err,doc)=>{
doc.title=req.body.title;
doc.author=req.body.author;
doc.time=new Date().toLocaleString();
doc.from=req.body.from;
doc.content=req.body.content;
doc.hits=1;
doc.save();
})
res.redirect("/list.html");
});
4. 使用mongoose查询数据
router.get("/view.html", (req, res) => {
id = req.query.id;
//console.log(id);
listModel.findById(id, (err, data) => {
if (err) {
throw err;
}
if (data) {
res.render("view.ejs", {
newsdetail: data
});
}
})
});
以上案例是根据id查询到数据,docs表示查询的结果,可用于渲染到ejs模板
如果不加条件,表示查询全部,结果是一个数组
listModel.find({},(err,doc)=>{
console.log(doc);
})