npm install jquery
@import('文件路径')
script
标签来加载@import ()
一样来引用加载JavaScript脚本文件node --version
node
命令直接敲回车require
加载。node文件名
执行对应文件node.js
来命名!// 1.使用require方法加载fs核心模块
var fs = require('fs');
/* 2.读取文件
第一个参数是要读取的文件路径
第二个参数就是一个回调函数
成功
data 数据
error null
失败
data null
error 错误对象
*/
fs.readFile('data/readfile.txt',function(error,data){
// console.log(data);
console.log(data.toString());
/*
文件中存取的其实都是二进制数据
这里为什么看到的不是0和1呢?原因是二进制转为了16进制
但是无论是二进制还是16进制,人类都不认识
所以可以通过toString方法转为我们能认识的字符
*/
});
//1.加载http核心模块
var http = require('http');
//2.使用http.createServer()方法创建一个web服务器
// 返回一个Server实例
var server = http.createServer();
//3.服务器要干嘛
// 提供服务:对数据的服务
// 发送请求
// 接受请求
// 处理请求
// 发送响应
//3.绑定端口号,启动服务器
server.listen(3000,function(){
console.log('服务器启动成功,通过http://127.0.0.1:3000/ 进行访问');
});
// 4.注册request请求事件
// 当客户端请求过来,就会自动触发request请求事件,然后执行第二个参数(回调函数)
server.on('request',function(){
console.log('接收到客户端请求');
});
var http = require('http');
var server = http.createServer();
server.listen(3000,function(){
console.log('服务器启动成功,通过http://127.0.0.1:3000/ 进行访问');
});
/*
request请求事件处理函数,需要接受两个参数
Request请求对象
请求对象可以用来获取客户端的一些请求信息,例如请求路径
Response响应对象
响应对象可以用来给客户端发送响应消息
*/
server.on('request',function(request,response){
console.log('接收到客户端请求,请求路径是:'+ request.url);
/*response对象有一个方法:write可以用来给客户端发送响应数据
write可以使用多次,但是最后一定要使用 “end” 来结束响应,否则客户端会一直等待*/
/*response.write('hello ');
response.write('this is node.js');
response.end();*/
//上面write的方式比较麻烦,可以直接end的同时发送数据
response.end('hello this is node.js');
});
Node为JavaScript提供了很多服务器级别的API,这些API绝大多数都被包装到了一个具名的核心模块中。例如:
fs
核心模块fs
核心模块中readFile
API的第二个参数是可选的,传入utf8可以把读取到的文件直接按照utf8编码转成我们能认识的字符(默认是二进制),除了这种方法,也可以通过data.toString()
方法。fs.readFile('./db.json','utf8',function(err,data){
if(err){
return res.status(500).send('Server error...')
}
console.log(data)
})
http
模块path
路径操作模块os
操作系统信息模块//用来获取机器信息的
var os = require('os');
//用来操作路径的
var path = require('path');
//获取当前机器的CPU信息
console.log(os.cpus());
//memory 内存
console.log(os.totalmem());
//获取一个路径中的扩展名部分
//extname extension name
console.log(path.extname('D:/a/c/d/c/hellow.txt'));
参考文档:https://nodejs.org/dist/latest-v11.x/docs/api/path.html
path.basename
path.dirname
path.extname
path.parse
path.join
path.isAbsolute
在每个模块中,除了require
、exports
等模块相关API之外,还有两个特殊成员:
__dirname
动态获取 可以用来获取当前文件模块所属目录的绝对路径__filename
动态获取 可以用来获取当前文件的绝对路径__dirname
和__filename
是不受执行node命令所属路径影响的__dirname
或者__filename
来解决这个问题。path.join()
来辅助拼接。补充:模块中的路径标识和这里的路径没关系,不受影响(就是相对于文件模块)
fs
,http
./
(不然会当做核心模块)。exports
require
加载规则如果想要了解更多底层细节,可以自行参考:《深入浅出Node.js》中的模块系统章节。
var 自定义变量名 = require('模块')
exports
导出的接口对象require('fs')
require('http')
require('包名')
的方式来进行加载就可以使用node_modules/art-template
node_modules/art-template/package.json文件
node_modules/art-template/package.json文件中的main属性
main属性中就记录了art-template的入口模块
然后加载使用这个第三方包
实际上最终加载的还是文件
Can not find module xxx
。路径形式的模块:
./
当前目录,不可省略
../
上一级目录,不可省略
/
几乎不用,macOS和linux的磁盘根目录
d:/a/foo.js/
几乎不用
exports
exports
接口对象中就可以了exports.a = 123;
exports.b = 'hello';
exports.c = function(){
console.log('ccc');
}
exports.d = {
foo : 'bar'
}
module.exports = function(x,y){
return x + y;
}
下面这个方法同样可以导出多个成员,但是需要重新建立与require
的引用关系
module.exports = { }
var module = {
exports: {
foo : 'bar'
}
}
module.exports.foo = 'bar';
谁来require我,谁就得到module.exports
默认在代码的最后有一句:
return module.exports
我们发现,每次导出接口成员的时候都通过module.exports.xxx = xxx的方式很麻烦。所以,Node为了简化我们的操作,专门提供了一个变量exports
等于module.exports,所以在return之前还有一句exports = module.exports
exports
是module.exports
的一个引用
console.log(exports === module.exports) // => true
exports.foo = 'bar' // 等价于 module.exports.foo = 'bar'
module.exports.xxx = xxx
的方式module.exports.xxx = xxx
的方式很麻烦。exports
exports === module.exports
的结果为true
module.exports.xxx = xxx
的方式完全可以替换为exports.xxx = xxx
module.exports = xxx
的方式return
的是module.exports
exports
只是module.exports
的一个引用exports
重新赋值,也不会影响module.exports
exports = module.exports
这个用来重新建立引用关系的在Node中的JavaScript还有一个重要的概念:模块系统。
http
服务的80response.setHeader('Content-Type','text/plain; charset=utf-8')
var http = require('http');
var server = http.createServer();;
server.on('request',function(request,response){
//设置请求头信息,告诉浏览器用utf-8去解析响应内容
response.setHeader('Content-type','text/plain;charset=utf-8');
response.end('hello,世界');
});
server.listen(3000,function(){
console.log('Server is runing...');
});
text/plain
:普通文本text/html
:HTML格式的字符串模板引擎最早就是诞生于服务器领域,后来才发展到了前端
npm install art-template
art-template
require
方法加载就可以了:require('art-template')
install
的名字是什么,则你require中的就是什么https://www.npmjs.com/
只要安装了node就会自动安装npm
npm也有版本这个概念
可以通过在命令行中输入:
npm --version
升级npm
npm install --global npm
npm常用命令参考链接
npm init
npm init -y
可以跳过向导,快速生成npm install
dependencies
选项中的依赖全部安装npm install 包名
npm i
简写npm install --save 包名
package.json
文件中的dependencies
选项)npm uninstall 包名
npm uninstall --save 包名
npm un -S 包名
npm help
npm 命令 --help
npm uninstall --help
npm存储包文件的服务器在国外,有时候会被墙,速度很慢,我们需要解决这个问题
// --global 表示安装到全局,而非当前目录
npm insatll --global cnpm
接下来安装包的时候把npm
替换成cnpm
例子:
//还是通过国外npm服务器,速度比较慢
npm insatll jquery
//使用cnpm会通过淘宝的服务器来下载jquery
cnpm
又想使用淘宝的服务器来下载npm install jquery --registry=https://registry.npm.taobao.org
但是每次手动添加参数很麻烦,所以可以把这个选项添加到配置文件中:
npm config set registry https://registry.npm.taobao.org
npm config list 可以查看配置信息
通过上述命令的配置,以后下载所有的包都会通过淘宝镜像来下载。
我们建议每一个项目都要有一个package.json
文件(包描述文件,就像产品说明书一样)
这个文件可以通过npm init
的方式来自动初始化出来
对于前端开发者来说,最有用的是那个dependencies
选项,可以用来帮我们保存第三方包的依赖信息。
npm install 包名
的时候都加上--save
这个选项,目的是为了保存依赖信息。node_modules
删除了也不用担心,我们只需要:npm install
就会自动把package,json
中的dependencies
中所有的依赖项都下载下来npm5 以前是不会有package-lock.json
这个文件的
npm5 之后才加入这个文件
当你安装包的时候,npm都会生成或者更新package-lock.json
文件
Express官方网站
原生的http在某些方面表现不足以应对我们的开发需求,所以我们就需要使用框架来加快我们的开发效率,框架的目的就是提高效率,让我们的代码高度统一。
npm install --save express
const express = require('express')
const app = express()
app.get('/',(req,res) => res.send('hello world')
app.listen(3000,() => console.log('express app listening on port 3000!'))
路由
//当你以GET方法请求/的时候,执行对应的处理函数
app.get('/',function(req,res) {
res.send('Hello World!');
});
post:
//当你以POST方法请求/的时候,执行对应的处理函数
app.post('/',function(req,res) {
res.send('Hello World!');
});
// /public资源
app.use(express.static('public'));
// /files资源
app.use(express.static('files'));
// /public/xxx
app.use('/public'express.static('public'))
// /static/xxx
app.use('/static',express.static('public'));
app.use('/static',express.static(path.join(__dirname,'public')));
art-template
模板引擎github仓库
官方网站
npm install --save art-template
npm install --save express-art-template
var express = require('express');
var app = express();
// 第一个参数用来配置视图的后缀名,这里是art,则你存储在veiws目录中的模板文件必须是xxx.art,我们可以把art改为html
app.engine('art',require('express-art-template'));
app.set('view options',{
debug:process.env.NODE_ENV!== 'production'
});
配置使用art-template模板引擎
第一个参数表示:当渲染以,.art
结尾的文件的时候,使用art-template模板引擎
express-art-template
是专门用来在Express
中把art-template
整合到Express
中
虽然外面不需要加载art-template
但是也必须安装
原因就在于express-art-template
依赖了art-template
Express
为Response
响应对象提供了一个方法:render
render
方法默认不可以使用,但是如果配置了模板引擎就可以使用了
res.render('html模板名',{模板数据})
第一个参数不能写路径,默认回去项目中的views目录
查找该模板文件
也就是说Express
有一个约定:开发人员把所有的视图文件都放到views目录
中
另外:如果想要修改默认的views目录,则可以使用下面的方法
app.set('views',目录路径)
app.get('/',function(req,res) {
res.render('index.art',{
user:{
name:'aui',
tags:[ 'art','template','nodejs' ]
}
});
});
Express内置了一个API,可以直接通过req.query
来获取
req.query
在Express中没有内置获取表单POST请求体的API,所以我们需要借助第三方包:body-parser
。
npm install --save body-parser
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/x-www-form-urlencoded
/*配置body-parser
只要加入了这个配置,则在req请求对象上会多出来一个属性:body
也就是说可以直接通过req.body来获取表单POST请求体数据*/
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
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-session
插件参考文档:https://github.com/expressjs/session
npm i express-session
//在Express这个框架中,默认不支持Session和Cookie
//但是我们可以使用第三方中间件:express-session来解决
//该插件会为req请求对象添加一个成员:req.session默认是一个对象
app.use(session({
secret: 'keyboard cat', //配置加密字符串,他会在原有加密基础之上和这个字符串拼起来去加密,增加安全性,防止客户端恶意伪造!
resave: false,
saveUninitialized: true//无论你是否使用session,都会默认分配一把钥匙。
}))
// 添加Session数据
req.session.foo = 'bar'
// 获取Session数据
req.session.foo
提示:默认Session数据时内存存储的,服务器一旦重启就会丢失,真正的生产环境会把Session进行持久化存储。
路由因为比较多,一般都单独放在一个模块中
var express = require('express');
//创建路由容器
var router = express.Router();
//把路由都挂载到router路由容器上
router.get('/',function(req,res){}
//把router导出
module.exports = router
接下来在入口模块中
var express = require('express');
var router = require('./router');//路由文件
var app = express();
//把路由容器挂载到app服务中
app.use(router);
我们划分模块的目的就是为了增强项目的可维护性,提升开发效率。
https://expressjs.com/en/guide/using-middleware.html
中间件的本质就是一个请求处理方法,我们把用户从请求到响应的整个过程分发到多个中间件去处理,这样做的目的是提高代码的灵活性,动态可扩展的。
万能匹配(不关心任何请求路径和请求方法):
app.use(function(req,res,next){
console.log('Time:',Date.now())
next()
})
仅以/xxx/
开头的:
app.use('/a',function(req,res,next){
console.log('Time:',Date.now())
next()
})
get:
app.get('/',function(req,res){
res.send('Hello World!')
})
post:
app.post('/',function(req,res){
res.send('Get a POST request')
})
put:
app.put('/user',function(req,res){
res.send('Get a PUT request at /user')
})
delete:
app.delete('/user',function(req,res){
res.send('Get a DELETE request at /user')
})
app.use(function(err,req,res,next){
console.error(err.stack)
res.status(500).send('Something broke!')
})
https://expressjs.com/en/resources/middleware.html
github项目地址
请求方法 | 请求路径 | get参数 | post参数 | 备注 |
---|---|---|---|---|
GET | /students | 渲染首页 | ||
GET | /students/new | 渲染添加学生页面 | ||
POST | /students/new | name,age,gender,hobbies | 处理添加学生请求 | |
GET | /students/edit | id | 渲染编辑页面 | |
POST | /students/edit | id,name,age,gender,hobbies | 处理编辑请求 | |
GET | /students/delete | id | 处理删除请求 |
router.js
/*
router.js路由模块
职责:
处理路由
根据不同的请求方法+请求路径设置具体的请求处理函数
模块职责要单一
划分模块的目的是为了增强代码的可维护性
提高开发效率
*/
var express = require('express')
//1. 创建一个路由容器
var router = express.Router()
//2. 把路由都挂在到router路由容器中
router.get('/students',function(req,res){
})
router.get('/students/new',function(req,res){
})
router.post('/students/new',function(req,res){
})
router.get('/students/edit',function(req,res){
})
router.post('/students/edit',function(req,res){
})
router.get('/students/delete',function(req,res){
})
//3. 把router导出
module.exports = router
/students
渲染静态页student.js
student.js
文件结构
req.query
req.body
菜鸟教程|MongoDB参考文档
表就是关系,或者说表与表之间存在关系
sql
语言来操作key-value
键值对{
qq:{
users:[
{name:'张三1',age:15},
{name:'张三2',age:15},
{name:'张三3',age:15},
{name:'张三4',age:15},
],
products:[],
...
}
wechat:{}
...
}
MongoDB官网
C:\Program Files\MongoDB\Server\4.0\bin
mongod --version
出现以下结果就是安装成功。启动:
# mongodb默认使用执行mongod命令所处盘符根目录下的/data/db作为自己的数据存储目录
# 所以在第一次执行该命令之前手动新建/data/db目录
mongod
如果想要修改默认的数据存储目录,可以:
mongod --dbpath=数据存储目录路径
停止:
在开启服务的控制台,直接Ctrl+c即可停止
或者直接关闭控制台
连接:
# 该命令默认连接本机的MongoDB服务
mongo
退出:
# 在连接状态输入exit退出连接
exit
show dbs
use 数据库名称
db
show collections
db.students.insertOne({"name":"Jack"})
# 查询所有students的数据
db.students.find()
mongodb
包来操作MongoDB官方驱动包
第三方包:mongoose
基于MongoDB官方的mongodb
包再一次做了封装
mongoose官网
mongoose官方指南
mongoose官方API文档
npm i mongoose
hello world
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true});
const Cat = mongoose.model('Cat', { name: String });
const kitty = new Cat({ name: 'Zildjian' });
kitty.save().then(() => console.log('meow'));
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//1. 连接数据库,指定连接的数据库不需要存在,当你插入第一条数据之后就会自动被创建出来
mongoose.connect('mongodb://localhost/demo1');
/*
2. 设计文档结构(表结构)
字段名称就是表结构中的属性名称
约束的目的就是为了保证数据的完整性,不要有脏数据
*/
var userSchema = new Schema({
username: {
type:String,
required: true//必须有
},
password: {
type: String,
required: true
},
email: {
type: String
}
});
/*
3. 将文档结构发布为模型
mongoose.model方法就是将一个架构发布为model
第一个参数:传入一个大写名词单数字符串用来表示你的数据库名称
mongoose会自动将大写名词的字符串生成小写复数的集合名称
例如这里的User最终会变为users集合名称
第二个参数:Schema
返回值: 模型构造函数
*/
var User = mongoose.model('User',userSchema);
/*
4. 当我们有了模型构造函数之后,就可以使用这个构造函数对users集合中的数据为所欲为了(增删改查)
*/
var admin = new User({
username: 'admin',
password: '123456',
email: '[email protected]'
});
admin.save(function(err,ret){
if(err){
console.log('err')
} else{
console.log('ok')
console.log(ret)
}
});
// 查询
User.find(/*{name: 'admin'},查找所有符合条件的,不加就是查询所有*/function(err,ret){
if(err){
console.log('err')
} else {
console.log(ret)
}
})
// 按条件查询单个数据
User.findOne({
username: 'admin', password: '123456'
},function(err,ret){
if(err){
console.log('err')
} else {
console.log(ret)
}
})
User.remove({
username: 'admin'
},function(err,ret){
if(err){
console.log('err')
} else {
console.log('ok')
}
});
// 根据条件更新所有:
Model.update(conditiions,doc,[options],[callback]);
// 根据指定条件更新一个:
Model.findOneAndUpdate([conditions],[update],[options],[callback]);
// 根据id更新一个
User.findByIdAndUpdate('50dfd4535500df00554gf',{
password: '123'
},function(err,ret){
if(err){
console.log('err')
} else {
console.log('ok')
}
})
我们这里可以使用一个第三方工具:nodemon
来帮我们解决频繁修改代码重启服务器的问题。
nodemon
是一个基于Node.js开发的一个第三方命令行工具,我们使用的时候需要独立安装:
npm install --global nodemon
安装完毕之后,使用:
不用再使用node xx.js命令
使用nodemon
nodemon xxx.js
只要是通过nodemon
启动的服务,它会监视你的文件变化,当文件发生变化,会自动重启服务器。
文件操作路径:
/*
在文件操作的相对路径中
./data/a.txt 相对于当前目录
data/a.txt 相对于当前目录
/data/a.txt 绝对路径,当前文件模块所处磁盘根目录
c:/xx/xxx... 绝对路径
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log(err)
return console.log('读取失败')
}
console.log(data.toString)())
})
*/
模块操作路径:
//这里如果忽略了,则也是磁盘根目录
require('/data/foo.js')
//相对路径
require('.data/foo.js')
//模块加载的路径中的相对路径不能省略 ./
注:Node不适合从来没有接触过服务端的人学习
如果想要真正的学好服务端,还是老牌的java、PHP这些平台
node不是特别适合入门服务端,但不代表node不强大
node很厉害,具有经验的人可以玩的非常牛
不适合新手的原因就是在于偏底层、而且太灵活
java、PHP好入门的原因就在于:这些平台屏蔽了一些底层