一、简介
1、什么是Node.js
简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
2、Node.js有什么用
如果你是一个前端程序员,你不懂得像PHP、Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择。
Node.js 是运行在服务端的 JavaScript,如果你熟悉Javascript,那么你将会很容易的学会Node.js。
当然,如果你是后端程序员,想部署一些高性能的服务,那么学习Node.js也是一个非常好的选择。
二、安装
1、下载
版本:
LTS:长期支持版本,稳定版,推荐使用
Current:最新版,不稳定
win .msi
mac .pkg
2、安装
3、查看版本
node -v
三、快速入门
1、创建文件夹nodejs
2、控制台程序
创建 01.js
console.log('Hello Node.js')
打开命令行终端:Ctrl + Shift + y
进入到程序所在的目录,输入
node 01.js
浏览器的内核包括两部分核心:
DOM渲染引擎;
js解析器(js引擎)
js运行在浏览器中的内核中的js引擎内部
Node.js是脱离浏览器环境运行的JavaScript程序,基于V8 引擎(Chrome 的 JavaScript的引擎)
3、服务器端应用开发(了解)
创建 02-server-app.js
const http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
response.end('Hello Server');
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
运行服务器程序
node 02-server-app.js
服务器启动成功后,在浏览器中输入:http://localhost:8888/ 查看webserver成功运行,并输出html页面
停止服务:ctrl + c
**
node 中模块查找规则
**
1.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服务器
npm 是世界上最大的开源生态系统
绝大多数JavaScript相关的包都存放在npm上,这样做的目的是为了让开发人员更方便的去下载使用
npm install jquery
2.Node能做什么
web服务器后台
命令行工具
npm(node)
git(c语言)
hexo(node)
...
对于前端工程师来讲,接触最多的是它的命令行工具
自己写的很少,主要是用别人第三方的
webpack
gulp
npm
3.文件的读写
文件读取:
//浏览器中的JavaScript是没有文件操作能力的
//但是Node中的JavaScript具有文件操作能力
//fs是file-system的简写,就是文件系统的意思
//在Node中如果想要进行文件的操作就必须引用fs这个核心模块
//在fs这个和兴模块中,就提供了人所有文件操作相关的API
//例如 fs.readFile就是用来读取文件的
// 1.使用fs核心模块
var fs = require('fs');
// 2.读取文件
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log('文件读取失败');
}
else{
console.log(data.toString());
}
})
文件写入:
// 1.使用fs核心模块
var fs = require('fs');
// 2.将数据写入文件
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){
if(err){
console.log('文件写入失败');
}
else{
console.log(data.toString());
}
})
http
4.服务器:
// 1.加载http核心模块
var http = require('http');
// 2.使用http.createServer()创建一个web服务器
var server = http.createServer();
// 3.服务器要做的事儿
// 提供服务:对数据服务
// 发请求
// 接收请求
// 处理请求
// 反馈(发送响应)
//注册request 请求事件
// 当客户端请求过来,就会自动触发服务器的request请求事件,然后执行第二个参数:回调处理函数
server.on('request',function(){
console.log('收到客户的请求了')
})
// 4.绑定端口号,启动服务
server.listen(3000,function(){
console.log('服务器启动成功,可以通过http:127.0.0.1:3000 来访问)
})
5.Node中的模块系统
使用Node编写应用程序主要就是在使用:
EcmaScript语言
和浏览器一样,在Node中没有Bom和Dom
核心模块
node中提供的API
常用模块:
- 文件操作的fs
- http服务操作的http
- url路径操作模块
- path路径处理模块
- os操作系统信息
第三方模块
art-template
必须通过npm来下载才可以使用
自己写的模块
自己创建的文件
6.什么是模块化
以前javaScript 只能通过script标签来加载,不支持模块化
6.1.文件作用域:
(模块是独立的,在不同的文件使用必须要重新引用)【在node中没有全局作用域,它是文件模块作用域】
所有东西只有在当前文件中有效
6.2.通信规则:
- 加载执行require
- 导出exports
7.CommonJS模块规范
在Node中的JavaScript还有一个重要的概念,模块系统。
模块作用域
使用require方法来加载模块
使用exports接口对象来导出模板中的成员
8.require
查看笔记 es5,es6 模块导出
语法:
var 自定义变量名 = require('模块')
作用:
- 加载文件模块,并执行里面的代码
- 获得,被加载模块,中的exports导出接口对象
- 每个文件模块中都提供了一个exports对象
- exports 默认是一个空对象
9.exports
查看笔记 es5,es6 模块导出
语法:
require
输出
作用:
可以理解为就是给 exports对象 中添加 方法 属性
语法:
exports.hello = '我是可以导出的字符串';
使用的时候:
导出单个成员: 直接导出字符串而非对象
module.exports = 'hello';
导出多个成员:
module.exports 或者
modeule.exports = {
xxx,
xxx2
};
以下情况会覆盖:
module.exports = 'hello';
//后者会覆盖前者
module.exports = function add(x,y) {
return x+y;
}
原理:
1.在 node 中,每个模块都有一个自己的 moudle
2.该moudle 对象中,有一个成员叫 exports
3.也就是说,如果你需要对外导出成员,只需要把导出的成员挂载到 moudle.exports 中
仅限理解用底层并不是这样:
var moudle ={
exports:{
}
}
还有一句
var exports = module.exports
谁来repuire 我,谁就得到 moudle.exports
默认代码最后一句;
return moudle.exports
exports是module.exports的一个引用:
如果给exports 从指定新的地址 exports 将失效
一定要记住最后 return 的是 moudle.exports不是exports
exports.foo = 'bar';
//等价于
module.exports.foo = 'bar'
console.log(exports === module.exports);//true
11.总结
// 引用服务
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.')
}
// 使用模板引擎解析替换data中的模板字符串
// 去xmpTempleteList.html中编写模板语法
var htmlStr = template.render(data.toString(), {
title: 'D:/app/www/ 的索引',
files:files
});
// 发送响应数据
res.end(htmlStr);
})
})
});
server.listen(3000, function () {
console.log('running....');
})
require的加载规则
核心模块
模块名
第三方模块
模块名
用户自己写的
路径
require的加载规则:
优先从缓存加载 (不会重复执行加载,但是可以拿到接口对象,提高模块加载效率)
判断模块标识符
核心模块
自己写的模块(路径形式的模块)
第三方模块(node_modules)
第三方模块的标识就是第三方模块的名称(不可能有第三方模块和核心模块的名字一致)
1.路径形式的标识:
./ 当前目录 不可省略
../ 上一级目录 不可省略
/xxx也就是D:/xxx
带有绝对路径几乎不用(D:/a/foo.js)
首位 **/** 表示的是当前文件模块所属磁盘根目录
require('./a');
2.如果非路径形式的标识:
2.1核心模块
核心模块本质也是文件,核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了
require(‘fs’);
2.2第三方模块
凡是第三方模块都必须通过npm下载(npm i node_modules),使用的时候就可以通过require(‘包名’)来加载才可以使用
第三方包的名字不可能和核心模块的名字是一样的
既不是核心模块,也不是路径形式的模块
require(‘art-template’);
- 先找到当前文所述目录的node_modules
- 然后找node_modules/art-template目录
- node_modules/art-template/package.json
- node_modules/art-template/package.json中的main属性
main属性记录了art-template的入口模块
然后加载使用这个第三方包
实际上最终加载的还是文件 - 如果package.json不存在或者mian指定的入口模块不存在
则node会自动找该目录下的index.js
也就是说index.js是一个备选项,如果main没有指定,则加载index.js文件 - 如果条件都不满足则会进入上一级node_modules目录进行查找
注意:一个项目只有一个node_modules,放在项目根目录中,子目录可以直接调用根目录的文件
var template = require(‘art-template’);
模块标识符中的 / 和 文件操作路径中的 /
文件操作路径:
咱们所使用的所有文件操作的API都是异步的
就像ajax请求一样
读取文件
文件操作中 ./ 相当于当前模块所处磁盘根目录
./index.txt 相对于当前目录
… /index.txt 上级目录
/index.txt 绝对路径,当前文件模块所处根目录
d:express/index.txt 绝对路径
fs.readFile('./index.txt',function(err,data){
if(err){
return console.log('读取失败');
}
console.log(data.toString());
})
模块操作路径:
// 在模块加载中,相对路径中的./不能省略
// 这里省略了.也是磁盘根目录
require('./index')('hello')
Node中的其它成员(__dirname,__filename)
在每个模块中,除了require,exports等模块相关的API之外,还有两个特殊的成员:
1.__dirname,是一个成员,可以用来动态获取当前文件模块所属目录的绝对路径
2.__filename,可以用来动态获取当前文件的绝对路径(包含文件名)
3.__dirname和filename是不受执行node命令所属路径影响的
在文件操作中,使用相对路径是不可靠的,因为node中文件操作的路径被设计为相对于执行node命令所处的路径。
所以为了解决这个问题,只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。
就可以使用 __dirname 或者 __filename 来帮助我们解决这个问题
在拼接路径的过程中,为了避免手动拼接带来的一些低级错误,推荐使用path.join()来辅助拼接
var fs = require('fs');
var path = require('path');
// console.log(__dirname + 'a.txt');
// path.join方法会将文件操作中的相对路径都统一的转为动态的绝对路径
fs.readFile(path.join(__dirname + '/a.txt'),'utf8',function(err,data){
if(err){
throw err
}
console.log(data);
});
二. Express(封装http)
原生的http在某些方面表现不足以应对我们的开发需求,所以就需要使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码高度统一。
在node中有很多web开发框架。主要学习express
安装
步骤 查看
demo
// 0. 安装
//1.引入第三方模块
var express = require('express');
//2.创建服务应用程序
//也就是 原来的http.createServer
var app = express();
// 开放静态资源
// 1.当以/public/开头的时候,去./public/目录中找对应资源 html css js 等
// 访问:http://127.0.0.1:3000/public/main.js
app.use('/public/',express.static('./public/'));
//当服务器收到 get 请求 / 的 时候 ,执行回调处理函数
// 相当于Java 的 controller
app.get('/',function(req,res){
res.send('hello,express')
});
app.get('/about',function(req,res){
res.send('你好,about')
});
//相当于 server.listen
app.listen(3000,function(){
console.log('app is running at port 3000')
});
基本路由
1.请求方法
2.请求路径
3.请求处理函数
get:
//当你以get方法请求/的时候,执行对应的处理函数
app.get('/',function(req,res){
res.send('hello world');
})
post:
//当你以post方法请求/的时候,执行对应的处理函数
app.post('/',function(req,res){
res.send('hello world');
})
Express静态服务API
// app.use不仅仅是用来处理静态资源的,还可以做很多工作(body-parser的配置)
app.use(express.static('public'));
app.use(express.static('files'));
app.use('/stataic',express.static('public'));
静态服务APIdemo
// 引入express
var express = require('express');
// 创建app
var app = express();
// 开放静态资源
1.当以/public/开头的时候,去./public/目录中找对应资源
// 1.当以/public/开头的时候,去./public/目录中找对应资源
// 访问:http://127.0.0.1:3000/public/login.html
app.use('/public/',express.static('./public/'));
2.当省略 第一个参数的时候,可以通过 省略/public 的方
// 2.当省略第一个参数的时候,可以通过 省略/public 的方式来访问
// 访问:http://127.0.0.1:3000/login.html
app.use(express.static('./public/'));
3.访问:http://127.0.0.1:3000/a/login.html
a相当于public的别名
// 3.访问:http://127.0.0.1:3000/a/login.html
// a相当于public的别名
app.use('/a/',express.static('./public/'));
//
app.get('/',function(req,res){
res.end('hello world');
});
app.listen(3000,function(){
console.log('express app is runing...');
});
在Express中配置使用art-template模板引擎
art-template官方文档
在node中,有很多第三方模板引擎都可以使用,不是只有art-template
还有ejs,jade(pug),handlebars,nunjucks
安装:
npm install --save art-template
npm install --save express-art-template
//两个一起安装
npm install --save art-template express-art-template
配置:
app.engine('html', require('express-art-template'));
使用:
直接访问
//http://localhost:3000/
//express默认会去views目录找404.html
app.get('/',function(req,res){
res.render('404.html')
});
模板语法
//http://localhost:3000/index
//express默认会去views目录找index.html
app.get('/index',function(req,res){
// express默认会去views目录找index.html
res.render('index.html',{
//页面通过{{title}} 取值
title:'模板语法'
});
})
如果希望修改默认的views视图渲染存储目录,可以:
// 第一个参数views千万不要写错
app.set('views',目录路径);
demo
// 0. 安装
//1.引入第三方模块
var express = require('express');
//2.创建服务应用程序
//也就是 原来的http.createServer
var app = express();
// 开放静态资源
// 1.当以/public/开头的时候,去./public/目录中找对应资源 html css js 等
// 访问:http://127.0.0.1:3000/public/main.js
app.use('/public/',express.static('./public/'));
//配置使用art-template 模板引擎
//第一个参数,表示,当渲染以.html 结尾的文件的时候,使用ar-template 模板引擎
// express-art-template 是专门用来在 Express 中把 art-template 整合到Express 中
//虽然外面这里不予要记载art-template 但是也必须要安装
//原因在于 express-art-template 依赖了 art-template
app.engine('html', require('express-art-template'));
//当服务器收到 get 请求 / 的 时候 ,执行回调处理函数
// 相当于Java 的 controller
app.get('/',function(req,res){
res.render('404.html',{
//页面通过{{title}} 取值
title:'模板语法'
})
});
app.get('/about',function(req,res){
res.send('你好,about')
});
//相当于 server.listen
app.listen(3000,function(){
console.log('app is running at port 3000')
});
在Express中获取表单请求数据
1.获取get请求数据:
Express内置了一个api,可以直接通过req.query来获取数据
// 通过requery方法获取用户输入的数据
// req.query只能拿到get请求的数据
var comment = req.query;
2.获取post请求数据 body-parser:
在Express中没有内置获取表单post请求体的api,这里我们需要使用一个第三方包body-parser来获取数据。
安装
npm install --save body-parser
配置:
// 配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )
var express = require('express')
// 引包
var bodyParser = require('body-parser')
var app = express()
// 配置body-parser
// 只要加入这个配置,则在req请求对象上会多出来一个属性:body
// 也就是说可以直接通过req.body来获取表单post请求数据
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
使用:
app.post('/about',function(req,res){
//req.body 可以获得post 提交的数据
res.send(req.body)
console.log(req.body)
});
提取路由模块
router.js:
/**
* router.js路由模块
* 职责:
* 处理路由
* 根据不同的请求方法+请求路径设置具体的请求函数
* 模块职责要单一,我们划分模块的目的就是增强代码的可维护性,提升开发效率
*/
var fs = require('fs');
// Express专门提供了一种更好的方式
// 专门用来提供路由的
var express = require('express');
// 1 创建一个路由容器
var router = express.Router();
// 2 把路由都挂载到路由容器中
router.get('/students', function(req, res) {
// res.send('hello world');
// readFile的第二个参数是可选的,传入utf8就是告诉他把读取到的文件直接按照utf8编码,直接转成我们认识的字符
// 除了这样来转换,也可以通过data.toString()来转换
fs.readFile('./db.json', 'utf8', function(err, data) {
if (err) {
return res.status(500).send('Server error.')
}
// 读取到的文件数据是string类型的数据
// console.log(data);
// 从文件中读取到的数据一定是字符串,所以一定要手动转换成对象
var students = JSON.parse(data).students;
res.render('index.html', {
// 读取文件数据
students:students
})
})
});
router.get('/students/new',function(req,res){
res.render('new.html')
});
router.post('/students/edit',function(req,res){
});
// 3 把router导出
module.exports = router;
app.js,入口模块,
var express = require('express')
var app = express()
var router = require('./router');
// router(app);
// 把路由容器挂载到app服务中
// 挂载路由
app.use(router);
MongoDB
关系型和非关系型数据库
关系型数据库(表就是关系,或者说表与表之间存在关系)。
所有的关系型数据库都需要通过sql语言来操作
所有的关系型数据库在操作之前都需要设计表结构
而且数据表还支持约束
唯一的
主键
默认值
非空
非关系型数据库
非关系型数据库非常的灵活
有的关系型数据库就是key-value对儿
但MongDB是长得 最像关系型数据库 的 非关系型数据库
数据库 -》 数据库
数据表 -》 集合(数组)
表记录 -》文档对象
一个数据库中可以有多个数据库,一个数据库中可以有多个集合(数组),一个集合中可以有多个文档(表记录
安装
下载
下载地址:https://www.mongodb.com/download-center/community
安装
npm i mongoose
配置环境变量
最后输入mongod --version测试是否安装成功
启动和关闭数据库
启动:
# mongodb 默认使用执行mongod 命令所处盼复根目录下的/data/db作为自己的数据存储目录
# 所以在第一次执行该命令之前先自己手动新建一个 /data/db
mongod
如果想要修改默认的数据存储目录,可以:
mongod --dbpath = 数据存储目录路径
停止:
在开启服务的控制台,直接Ctrl+C;
或者直接关闭开启服务的控制台。
连接数据库
连接:
# 该命令默认连接本机的 MongoDB 服务
mongo
退出:
# 在连接状态输入 exit 退出连接
exit
基本命令
show dbs
查看数据库列表(数据库中的所有数据库)
db
查看当前连接的数据库
use 数据库名称
切换到指定的数据库,(如果没有会新建)
show collections
查看当前目录下的所有数据表
db.表名.find()
查看表中的详细信息
在Node中如何操作MongoDB数据库
使用官方的MongoDB包来操作
http://mongodb.github.io/node-mongodb-native/
推荐使用第三方包操作MongoDB数据库
使用第三方包mongoose来操作MongoDB数据库
第三方包:mongoose基于MongoDB官方的mongodb包再一次做了封装,名字叫mongoose,是WordPress项目团队开发的。
https://mongoosejs.com/
中文官网
MongoDB demo
const mongoose = require('mongoose');
//创建连接 一个test 数据库,如果没有会创建,
//不是马上创建,在插入第一条数据之后会立即创建
mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true});
//创建模型
//就是在设计数据库
//MongoDB 是动态的,非常灵活 。只需要在代码中,设计你的数据库就可以了
//默认形成一个名称为 小写cats 的集合
//约束一下 name 的类型是string 类型的 ,相当于表结构
const Cat = mongoose.model('Cat', { name: String });
//实例化一个cat,一个对象相当于cats中的一条数据
//此代码可以放在for循环中 存多条数据在cats 中
const kitty = new Cat({ name: 'Zildjian' });
//持久化保存 kitty 实例,保存一个 name:Zildjian 的数据
kitty.save().then(() => console.log('meow'));
使用指南(步骤)
1.设计Scheme 发布Model (创建表)
// 1.引包
// 注意:按照后才能require使用
var mongoose = require('mongoose');
// 拿到schema图表
var Schema = mongoose.Schema;
// 2.连接数据库
// 指定连接数据库后不需要存在,当你插入第一条数据库后会自动创建数据库
mongoose.connect('mongodb://localhost/text');
// 3.设计集合结构(表结构)
// 用户表
var userSchema = new Schema({
username: { //姓名
type: String,
require: true //添加约束,必须有,不能为空
},
password: {
type: String,
require: true
},
email: {
type: String
}
});
// 4.将文档结构发布为模型
// mongoose.model方法就是用来将一个架构发布为 model
// 第一个参数:传入一个大写名词单数字符串用来表示你的数据库的名称
// mongoose 会自动将大写名词的字符串生成 小写复数 的集合名称
// 例如 这里会变成users集合名称
// 第二个参数:架构
// 返回值:模型构造函数
var User = mongoose.model('User', userSchema);
添加数据(增)
// 5.通过模型构造函数对User中的数据进行操作
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);
}
});
查询(查)
查询所有:
// 查询所有
User.find(function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
//查询
User.find().then((ret)=>{
console.log('成功'+ret)
}).catch((err)=>{
console.log('失败'+err)
})
条件查询所有:
// 根据条件查询
User.find({ username:'xiaoxiao' },function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
// 条件 查询 结果集是数组
User.find({
username:'zhangsan'
}).then((ret)=>{
console.log('成功1'+ ret[0].username)
}).catch((err)=>{
console.log('失败'+err)
})
条件查询单个:
// 按照条件查询单个,查询出来的数据是一个对象({})
// 没有条件查询使用findOne方法,查询的是表中的第一条数据
User.findOne({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {
console.log('查询失败');
} else {
console.log(ret);
}
});
// 条件 查询一条数据 结果直接是对象
User.findOne({
username:'zhangsan',
password:'123456651'
}).then((ret)=>{
console.log('成功1'+ ret.username)
}).catch((err)=>{
console.log('失败'+err)
})
删除(删)
根据条件删除所有:
User.remove({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {
console.log('删除失败');
} else {
console.log('删除成功');
console.log(ret);
}
});
根据条件删除一个:
Model.findOneAndRemove(conditions,[options],[callback]);
根据id删除一个:
User.findByIdAndRemove(id,[options],[callback]);
更新(改)
更新所有:
User.remove(conditions,doc,[options],[callback]);
根据指定条件更新一个:
User.FindOneAndUpdate([conditions],[update],[options],[callback]);
根据id更新一个:
// 更新 根据id来修改表数据
User.findByIdAndUpdate('5e6c5264fada77438c45dfcd', {
username: 'junjun'
}, function(err, ret) {
if (err) {
console.log('更新失败');
} else {
console.log('更新成功');
}
});