基础概要
node.js就是一个运行环境,类似与浏览器的引擎,为js代码提供api使其能操控浏览器和操作系统。不同的是,node.js是为js代码提供操控操作系统(服务器)的api,而浏览器的引擎是为js代码提供操作浏览器的api。
文件操作
想要对文件进行操作,首先就要引入node.js提供的文件系统模块:const fs = require('fs');
然后再调用api进行操作。
读取文件(readFile):
写入文件(writeFile): 注意这是直接覆盖原先内容
写入文件-追加操作(appendFile):
模块化开发
模块化开发分为两种规范,一种是ESM(ECMAScript Module)标准规范,一种是CommonJs规范。
ESM
默认导入:
若控制台报modules类型错误,则需要再package.json中添加"type": "module"配置项,因为有些node版本默认还是使用commonJs规范
具名导入:
CommonJs
因目前node.js都支持ESM规范,所以只需了解commonJs即可
每个文件都有一个模块对象module与之对应:
我们可以通过直接给这个对象赋值的方式导出数据,如:
npm包管理器
npm是Node.js的默认包管理器
命令
控制台输入npm就会得到以下信息:
npm init
使用这个命令后控制台会指引你对这个项目进行初始化:
输入ok后会为你创建一个名为package.json的文件,你可以在这里配置你的项目:
你可以在这修改你需要执行的命令,之后你若是输入npm run dev,就会执行‘node b.js’这个命令
自定义脚手架
脚手架基本能力
1、全局命令执行能力(在任何一个地方都能输入命令使用这个脚手架)
2、命令行交互能力(创建脚手架时与用户交互一些信息,如项目名称以及一些配置)
3、代码初始化下载能力(能够从远程仓库(如 GitHub、GitLab 或私有仓库)下载模板或项目骨架,并根据用户配置生成对应的项目结构和文件)
自定义创建命令
在package.json中添加"bin"字段并指定正确路径:
注意,你的cli.js下必须要有这个shebang命令,让操作系统能够通过寻找环境变量中的node来运行你的cli.js代码:
然后使用npm link,它会将你的整个文件复制到你node安装文件下的node_modules中
在使用npm link时你可能会报权限错误,你需要给予用户对此文件夹的所有权限:
之后你就可以在任意命令行使用了:
使用commander处理help选项
1、先输入npm install commander安装相关依赖
2、在入口文件中编写一下代码:
此时输入--help后就会显示:
处理自定义指令
使用program的command方法创建一个自定义指令:
封装模块
将program.option以及program.command分别封装到lib/core下
命令行交互
1、引入inquirer依赖(npm i inquirer)
2、在action中使用:
3、输出结果如下:
通过用户选择的框架进行远程下载
1、引入下载git的依赖download-git-repo(npm i download-git-repo)
2、 新建download.js专门编写下载逻辑:
在action中调用:
其中framworkUrl也是在config里配置了
3、下载等待提示交互:
(1)下载ora依赖,npm i ora
(2)在download.js中使用ora().star():
spinner为无限循环,在没有调用spinner.succeed或fail的情况下会一直执行
4、命令行的样式输出
下载chalk依赖后直接使用:
Node开发web服务器(原生)
1、引入http,const http = require('http')
2、创建实例并监听request:
3、服务器响应不同数据类型
(1)纯文本数据:
(2)html数据:
(3)引入静态页面:
服务器返回静态页面时如果引用了其他文件浏览器会再次发送该文件的请求,所以要再次判断并且返回引用的文件数据
4、http不同方法的请求处理
(1)处理get方法:
使用node库中的url解析返回结果的数据,第二个参数true表示是否把请求参数提取出来
(2)处理post方法:
这里使用字符串拼接了流数据并且使用querystring库的parse方法转换流数据
5、模块化封装
新建router.js用于专门判断请求方式和路由路径:
新建controller.js用于处理业务逻辑:
最后在request.js中调用即可:
express框架
搭建
使用npm i express下载相关依赖
使用
1、处理get请求(获取用户信息)
注意:要想使用async await必须现将fs变成promise对象。res.status(500)是
2、处理post请求(添加用户信息)
注意:
(1)请求体的格式如果是json格式,则要添加app.use(express.json()),不然浏览器无法识别。同样如果是x-www-form-urlencoded格式则要添加app.use(express.urlencoded())
(2)db是封装的方法:
(3)总体代码:
3、处理put请求(修改用户信息):
其中_.isEqual是使用了loadash依赖的方法进行深度比较对象
// 修改用户
app.put('/user/:id', async (req, res) => {
const userId = Number(req.params.id)
const users = await db.getDb()
const index = users.findIndex(item => item.id === userId)
const body = req.body
body.id = userId
if (index !== -1) {
if (!_.isEqual(users[index], body)) {
users[index] = body
try {
const err = await db.serveDb(users)
if (!err) {
res.status(200).json({
msg: '修改成功'
})
}
} catch (error) {
res.status(500).json({ error })
}
} else {
res.json({
msg: '未做任何修改'
})
}
} else {
res.status(403).json({
msg: '未找到该用户'
})
}
})
MongoDB数据库
下载
通过这个网址下载mongodb
Download MongoDB Community Server | MongoDB
连接
使用navicat连接即可:
概念
MongoDB是非关系型数据库(NoSQL)的基本类型,它跟关系型数据库的关系如下:
增删改查
插入数据(Create)
1、插入单个文档
db.collection_name.insertOne({name: "张三", age: 25, hobbies: ["阅读", "游泳"]});
2、插入多个文档
db.collection_name.insertMany([
{name: "李四", age: 30, hobbies: ["篮球", "音乐"]},
{name: "王五", age: 28, hobbies: ["绘画", "旅行"]}
]);
查询数据(Read)
1、查询所有文档
db.collection_name.find({});
2、根据条件查询
db.collection_name.find({age: {$gt: 25}}); // 查找年龄大于25的所有记录
3、返回特定字段
db.collection_name.find({}, {name: 1, age: 1}); // 只返回name和age字段
注意:
- 如果你用了
1
来指定字段,那没写的字段默认就是不显示(等于 0)。 - 如果你用了
0
来排除字段,那没写的字段默认都显示。 - 不能混用
1
和0
,除非是_id
。
更新数据(Update)
1、更新单个文档
db.collection_name.updateOne(
{name: "张三"},
{$set: {age: 26}}
);
2、更新多个文档
db.collection_name.updateMany(
{age: {$lt: 30}},
{$inc: {age: 1}} // 将年龄小于30的所有记录的年龄增加1
);
删除数据(Delete)
1、删除单个文档
db.collection_name.deleteOne({name: "张三"});
2、删除多个文档
db.collection_name.deleteMany({age: {$gt: 25}}); // 删除年龄大于25的所有记录
使用node.js连接到数据库
import { MongoClient } from "mongodb";
const client = new MongoClient('mongodb://127.0.0.1:27017') //创建数据库实例对象
const main = async () => {
await client.connect() //连接数据库
const db = client.db('express_demo') //获取指定数据库
const user = db.collection('user') //获取指定集合
const data = user.find() //查找该集合所有数据
console.log(await data.toArray()); //以数组的形式输出(如果只输出data将会是find()的方法实例)
}
main().finally(() => client.close()) //关闭连接
express中间件
内置中间件
1、express.json()
功能:解析传入请求体中的JSON数据。
使用示例:
app.use(express.json());
2、express.urlencoded([options])
功能:解析传入请求体中的URL编码数据,常用于表单提交。
使用示例:
app.use(express.urlencoded({ extended: true }));
3、express.static(root, [options])
功能:提供静态文件服务,如HTML、CSS、图片等。
使用示例:
app.use(express.static('public'));
4、express.Router()
功能:创建模块化、可挂载的路由处理器。
使用示例:
const router = express.Router();
router.get('/', (req, res) => {
res.send('Home page');
});
app.use('/', router);
mongoose
Mongoose 是一个用于 MongoDB 的 Node.js 对象模型工具,它提供了对数据建模、查询、验证和中间件等功能的支持。
使用Mongoose完成注册功能
1、在项目中建立model文件夹,专门用于创建模型以及操控mongodb数据库。然后创建Index.js引入mongoose并连接数据库
import mongoose from "mongoose";
import userSchema from "./user.js";
const main = async () => {
await mongoose.connect('mongodb://localhost:27017/express_demo')
}
main().then((res) =>{
console.log('mongodb已连接');
}).catch((err) => {
console.log(err);
console.log('mongodb连接失败');
})
const User = mongoose.model('User', userSchema)
export default User
其中 userSchema 是在同级目录下创建的,为的是区分不同集合的模型。mongoose.model方法中,当你首次通过该模型保存(.save()
)或者查询(如 .find()
、.findOne()
等)数据时,如果对应的集合不存在,Mongoose 和 MongoDB 会自动创建这个集合。
2、以下是user.js中的内容:
import mongoose from "mongoose";
const userSchema = new mongoose.Schema({
username: {
type: String,
require: true
},
password: {
type: String,
require: true
},
age: {
type: Number,
require: true
},
email: {
type: String,
require: true
},
phone: {
type: String,
require: true
},
avatar: {
type: String,
default: null
},
creatTime: {
type: Date,
default: Date.now()
},
updateTime: {
type: Date,
default: Date.now()
}
})
export default userSchema
3、创建一个controller文件夹并在下面创建usercontroller.js文件来调用:
register: (req, res) => {
const body = req.body
const user = new User(body)
user.save().then(() => {
res.send(`注册成功`)
}).catch(() => {
res.send('注册失败')
})
}
4、使用中间件express-validator验证数据格式
1、下载express-validator依赖
2、 创建middleware文件夹,用于专门存放有关中间件的配置文件。在该文件夹下创建一个validator/userValidator.js文件并引入express-validator中的body方法,定义需要验证的格式:
import { body } from 'express-validator'
import validator from './errorBack.js'
import User from '../../model/index.js'
export default {
register: validator([
body('username')
.notEmpty() //非空判断
.withMessage('用户名不能为空').bail() //提示信息,bail()是当用户名为空是就不会执行后面的校验了
.isLength({ min: 3 })
.withMessage('用户名至少需要3个字符')
.custom(async val => {
const isExit = await User.findOne({ username: val }) //查找是否有同名用户
if (isExit) {
return Promise.reject('用户名已存在')
}
}),
// password: 必须存在,字符串,至少6字符
body('password')
.notEmpty()
.withMessage('密码不能为空')
.isLength({ min: 6 })
.withMessage('密码至少需要6个字符'),
// age: 必须存在,数字,范围1~120
body('age')
.notEmpty()
.withMessage('年龄不能为空')
.isInt({ gt: 0, lt: 120 })
.withMessage('请输入有效的年龄'),
// email: 必须存在,且为合法邮箱
body('email')
.notEmpty()
.withMessage('邮箱不能为空')
.isEmail()
.withMessage('请输入合法的邮箱地址')
.custom(async val => {
const isExit = await User.findOne({ email: val }) //查找是否有同名邮箱
if (isExit) {
return Promise.reject('邮箱已存在')
}
}),
// phone: 必须存在,字符串,符合手机号格式(示例)
body('phone')
.notEmpty()
.withMessage('电话号码不能为空')
.isMobilePhone('zh-CN')
.withMessage('请输入中国大陆的手机号')
.custom(async val => {
const isExit = await User.findOne({ phone: val }) //查找存在该手机号
if (isExit) {
return Promise.reject('手机号已存在')
}
}),
// avatar: 可选,必须是 URL 或 null
body('avatar')
.optional()
.isURL()
.withMessage('头像地址必须是一个合法的 URL')
])
}
3、再在validator文件夹下创建一个errBack.js文件,用于收集错误信息。此文件是在刚刚的userValidator中使用的
import { validationResult } from 'express-validator'
export default validator => {
return async (req, res, next) => {
await Promise.all(validator.map(validate => validate.run(req))) //并发执行所有验证规则
const errors = validationResult(req) //返回所有验证规则的错误信息
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() })
}
next() //放行
}
}
4、最后要在router.post中调用:
router
.get('/', userController.getUser)
.post('/register',
userValidator.register,
userController.register)