1 使用 nodemon 工具来自动重启web服务器
1.1 nodemon的作用:能够实时监听当前项目中,文件的变化;只要监听到了文件的变化,则 nodemon 工具,会自动重新启动 web 服务器,从而使最新的代码生效;免去了程序员手动重启服务器的困扰;
1.2 如何安装:运行 npm i nodemon -g 全局安装即可;
1.3 如何使用:
nodemon .\01-express中使用art-template.js
2 Node 中开发web项目的框架 - express
定义(什么是Express):一个快速的网站开发框架,封装了原生的http模块,用起来更方便;API更人性化
2.1 express 框架的特点
- 基于Node.js平台之上,进一步封装了 http 模块,从而提供了更好用,更友好的 API
- 使用Express创建网站,比使用原生的http模块更加方便;
- Express 并没有覆盖 原生 http 模块中的方法,而是基于 原生方法之上,做了更友好的封装,让用户体验更好
2.2 express 框架的安装和基本使用
- 安装:
npm i express -S
- 创建基本的 express 服务器:
// 导入 expree第三方模块
const express = require('express')
// 创建服务器的实例
const app = express()
// 监听客户端请求
app.get('/',(req,res) => {
// res.end('你好!') //end()为http模块的方法,express也可以用 乱码问题
res.send("你好!") //express方法 没有乱码问题
})
// 启动服务器
app.listen(3000,() => {
console.log('server running at http://127.0.0.1:3000')
})
2.3 express 中的快捷方法
- res.send()
app.get('/',(req,res) => {
res.send('Ok') //普通字符串
res.send({name:'cc',age:16}) //对象 {"name":"cc","age":16} json格式
res.send(['吃饭','睡觉','打豆豆']) //数组 ["吃饭","睡觉","打豆豆"]
res.send(new Buffer('123')) //二进制 下载效果 不常用
})
- res.sendFile()
- 注意:res.sendFile() 可以向浏览器发送 静态页面;
app.get('/',(req,res) => {
// 一个参数:这个参数必须是绝对路径
// res.sendFile(path.join(__dirname,'./public/index.html'))
// 两个参数: 第一个实参可传相对路径 第二个必须是绝对路径
res.sendFile('./public/index.html',{root:__dirname})
})
app.get('/movie',(req,res) => {
res.sendFile('./public/movie.html',{root:__dirname})
})
app.get('/about',(req,res) => {
res.sendFile('./public/about.html',{root:__dirname})
})
2.4 使用 express.static() 快速托管静态资源
app.use(express.static('./public'))
// app.use()专门用来注册中间件
// express.static()把指定的目录托管为静态资源目录,这样指定目录下的所有文件都可以直接被浏览器访问,是express的内置中间件;
app.use('/page',express.static('./public'))
// /page:指定要挂载的虚拟路径
2.5 为 express 框架配置模板引擎渲染动态页面
- 安装 ejs 模板引擎
npm i ejs -S
- 注意,模板页面的 后缀名,可以省略不写!
// 使用 app.set('view engine',引擎模板的名称)
app.set('view engine','ejs')
//设置模板页面的默认存放路径 app.set('views','模板页面的具体存放路径')
app.set('views','./ejs_pages') //默认存放路径
app.get('/',(req,res) => {
//若想调用res.render,必须先配置引擎模板
res.render('index.ejs',{name:'cc',age:16,hobby:['吃饭','睡觉','打豆豆']})
})
2.6 在 express 中配置 art-template
cnpm i art-template express-art-template -S
const artTemplate = require('express-art-template')
// 注意: 安装两个包 art-template express-art-template 安装多个包用空格隔开
// 1.使用app.engine方法自定义模板引擎(模板引擎的名字,artTemplate)
// 这个位置配置的模板引擎的名字将会是模板文件的后缀名称
app.engine('html',artTemplate)
// 2 使用app.set('view engine','指定模板引擎名称')来配置项目中用到的模板引擎
app.set('view engine','html')
// 3 配置模板页面的存放路径 配置模板引擎的根目录
app.set('views','./art-pages')
app.get('/',(req,res) => {
res.render('index.html',{name:'cc',age:16,hobby:['吃饭','睡觉','打豆豆']})
})
2.7 使用 express 框架中提供的路由来分发请求
-
什么是路由:路由就是对应关系;
-
什么叫做后端路由:前端请求的URL地址,都要对应一个后端的处理函数,那么 这种URL地址到 处理函数之间的对应关系,就叫做后端路由;
-
定义路由模块
// 1. 封装单独的 router.js 路由模块文件
const express = require('express')
// 创建路由对象
const router = express.Router()
router.get('/', (req, res)=>{})
router.get('/movie', (req, res)=>{})
router.get('/about', (req, res)=>{})
// 导出路由对象
module.exports = router
- 使用路由模块
// 导入自己的路由模块
const router = require('./router.js')
// 使用 app.use() 来注册路由
app.use(router)
2.8 Express 框架里 中间件的概念
- 什么是中间件
定义:中间件就是一个处理函数;只不过这个函数比较特殊,包含了三个参数,分别是 req,res,next
注意:中间件方法中的三个参数:
- req:请求对象;
- res:响应对象;
- next:next()可以被调用,表示调用下一个中间件方法;
- Express 框架中对中间件的5种分类
- 应用级别的中间件: 挂载到 app 上的中间件 app.get(‘URL地址’, (req, res, next)=> {});
- 路由级别的中间件: 挂载到 router 对象上的中间件 router.get(‘url地址’, (req, res, next)=>{})
- 错误级别的中间件: 回调函数中,有四个参数 app.use((err, req, res, next)=>{})
- 唯一内置的中间件: express.static()
- 第三方中间件: 非express框架提供的,需要程序员手动安装才能使用的中间件;body-parser 解析post 表单数据
const querystring = require('querystring');
// 定义应用级别的中间件
app.use((req,res,next) => {
let dataStr = ''
// 只要客户端向服务器提交了表单,都会触发req的data事件
// 在data事件中,可以获取客户端每次提交过来的不完整的数据
req.on('data',chunk => {
dataStr += chunk
})
// 只要req出发了end事件,就表示表单数据提交完毕
req.on('end',() => {
// console.log(dataStr) //username=cc&userage=12
//想要把 username=ls&password=123 字符串,
//解析为 { username: 'ls', password: 123 }
// querystring.parse() 方法将 URL 查询字符串 dataStr 解析为键值对的集合。
const obj = querystring.parse(dataStr)
req.body = obj
// 注意:在中间件中,最后一定要合理调用next(),否则服务器无法结束这次响应
next()
})
})
// get请求
app.get('/',(req,res) => {
res.sendFile('./11-中间件index.html',{root:__dirname})
})
// post请求
app.post('/postdata',(req,res) => {
res.send(req.body) //{"username":"cc","userage":"123"}
})
2.9 Express 中进行数据库操作
- 配置 MySql 数据库环境
npm i mysq
- mysql 第三方模块的介绍和基本配置
// 1.导入mysql模块
const mysql = require('mysql')
// 2.创建mysql的连接对象
const conn = mysql.createConnection({
host:'localhost',
user:'root',
password:'root',
database:'express-mysql'
})
- 使用 mysql 第三方模块实现 CRUD
- 查询
// 查询conn.query('sql语句',回调函数)
const sql ='SELECT * FROM `user` '
conn.query(sql,(err,result) => {
if(err) return console.log('获取数据失败'+err.message)
console.log(result)
//[ RowDataPacket { id: 1, name: 'cc', age: 16, gender: 'girl' } ]
})
- 新增
const user = {name:'zz',age:22,gender:'boy'}
const sql = "INSERT INTO `user` SET ?"
conn.query(sql,user,(err,result) => {
if(err) return console.log('插入数据失败'+err.message)
console.log(result)
// OkPacket {
// fieldCount: 0,
// affectedRows: 1,
// insertId: 6,
// serverStatus: 2,
// warningCount: 0,
// message: '',
// protocol41: true,
// changedRows: 0
// }
})
- 修改
const user ={id:6,name:'zz',age:18}
const sql = 'UPDATE `user` SET ? WHERE id = ?'
//若sql语句中包含多个?占位符,第二个实参必须传递一个数组,并一一对应
conn.query(sql,[user,user.id],(err,result) => {
if(err) return console.log("修改数据失败")
console.log(result)
// OkPacket {
// fieldCount: 0,
// affectedRows: 1,
// insertId: 0,
// serverStatus: 2,
// warningCount: 0,
// message: '(Rows matched: 1 Changed: 1 Warnings: 0',
// protocol41: true,
// changedRows: 1
// }
})
- 删除
const sql = 'DELETE FROM `user` WHERE id=?'
conn.query(sql, 1, (err, result) => {
if (err) return console.log('删除失败!' + err.message)
console.log(result)
// OkPacket {
// fieldCount: 0,
// affectedRows: 1,
// insertId: 0,
// serverStatus: 2,
// warningCount: 0,
// message: '',
// protocol41: true,
// changedRows: 0
// }
})
模块加载机制
- 优先从缓存中加载
- 当一个模块初次被 require 的时候,会执行模块中的代码,当第二次加载相同模块的时候,会优先从缓存中查找,看有没有这样的一个模块!
- 好处:提高模块的加载速度;不需要每次都重新执行并加载模块!
- 核心模块的加载机制
- 先查找缓存;
- 如果缓存中没有,再去加载核心模块;
- 用户模块的加载机制
- 先查找缓存;
- 如果缓存中没有则尝试加载用户模块;
- 如果在加载用户模块时候省略了后缀名,则:
首先,严格按照指定的名称去查找
其次,尝试加载后缀名是 .js 的文件
如果没有.js的文件,则尝试加载 .json 结尾的文件
如果没有 .json 的文件,则尝试加载 .node 结尾的文件
查找规则:index -> index.js -> index.json -> index.node
- 第三方模块的加载机制【了解】
- 先在项目根目录中查找node_modules文件夹
- 在node_modules文件夹下,查找模块相关的文件夹
- 在对应的文件夹下,查找package.json的文件
- 查找package.json文件中的main属性(指定了模块的入口文件)
- 如果找到了main属性,同时,main属性指定的文件路径存在,那么尝试加载指定的文件模块
- 加入没有main属性,或者main属性对应的文件不存在,或者没有package.json,那么会依次尝试加载index.js,index.json,index.node;
- 如果没有index相关的文件,或者没有指定模块对应文件夹,或者,当前项目根目录中没有node_modules文件夹,则向上一层目录中查找node_modules,查找规则同上!
- 最后,如果在项目所在磁盘的盘符根目录中,还找不到对应模块,则报错:cannot find module ***