nodemon工具 + 搭建expres服务器 + 模板引擎art-template + 中间件 + express中操作数据库(增删改查)

1. 使用 nodemon 工具来自动重启web服务器

  • nodemon的作用:能够实时监听当前项目中,文件的变化;只要监听到了文件的变化,则 nodemon 工具,会自动重新启动 web 服务器,从而使最新的代码生效;免去了程序员手动重启服务器的困扰;
  • 如何安装:运行 npm i nodemon -g 全局安装即可;
  • 如何使用:
    • 之前使用 node 要执行的文件路径 来运行 Node.js 代码;
    • 现在使用 nodemon 要执行的文件路径 来运行 Node.js 代码;
  • 注意:今后在开发Web项目的时候,推荐使用 nodemon 来启动 web 服务器

2. Node 中开发web项目的框架 - express

定义:Express基于Node.js平台、快速、开放、极简的web开发框架。

2.1 express 框架的特点

  • Web应用
Express是一个基于Node.js平台的极简、灵活的web应用开发框架,
它提供了一系列强大的特性,帮助你创建各种Web和移动设备应用
  • API
基于Node.js平台之上,进一步封装了 http 模块,从而提供了更好用,更友好的 API

丰富的HTTP快捷方法和任意排列组合的Connect中间件,让你创建健壮、友好的API变得既快速又简单
  • 性能
Express 并没有覆盖 原生 http 模块中的方法,而是基于 原生方法之上,做了更友好的封装,让用户体验更好

Express不对Node.js已有的特性进行二次抽象,我们只是在它之上扩展了Web应用所需的基本功能

2.2 express 框架的安装和基本使用

  1. 初始化项目:npm init -y
  2. 安装:运行 npm i express -S 即可安装
  3. 创建基本的 express 服务器:
    • 导入 express 第三方模块;
    • 创建服务器的实例:调用 const app = express() 方法;
    • 通过 app.get()app.post() 方法,来监听客户端的 getpost 请求,具体语法:
      • 监听 GET 请求:app.get('请求地址', (req, res) => { 处理函数 })
      • 监听 POST 请求: app.post('请求地址', (req, res) => { 处理函数 })
    • 启动 express 服务器:通过 app.listen(端口, IP地址, 启动成功后的回调函数) 启动服务器;
// 1. 导入express
const express = require('express')

// 2. 调用 express() 创建服务器
const app = express()

/**
 * 3. 调用 app.get() 方法,来监听客户端的请求,并指定要监听的 URL 地址 和 处理函数
 *    URL 地址: '/';表示监听的是请求根路径
 *    使用 express 调用 http 模块中的 end 方法向客户端发送数据,可能会发生中文乱码问题
 		res.end('你好!')
 *    而使用express 调用 send 方法向客户端发送数据,不会发生中文乱码问题
 */
app.get('/', (req, res) => {
  res.send('你好!')
})

// 4. 调用 app.listen() 方法启动 express 服务器
app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

2.3 express 中的快捷方法

res.send()

  1. 支持 发送 字符串 Content-Type: text/html;
  2. 支持 发送 对象 或 数组 Content-Type: application/json
  3. 支持 发送 Buffer 此时会当作文件下载;
const express = require('express')

const app = express()

app.get('/', (req, res) => {
  // res.send('ok')
  // res.send({ name: 'zs', age: 22 })
  res.send(['nihao', '传智播客', '黑马程序员'])
  // res.send(new Buffer('123'))
})

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

res.sendFile() 向客户端发送文件

  • 用法1:res.sendFile(path.join(__dirname, './view/index.html'))
  • 用法2:res.sendFile('./view/movie.html', { root: __dirname })
  • 注意:res.sendFile() 可以向浏览器发送 静态页面;
const express = require('express')
const path = require('path')
const app = express()

/**
 *   1. 注意:res.sendFile 如果只给定一个参数的时候,这个参数必须是绝对路径,表示要发送给客户端的文件的路径
 *      res.sendFile('./views/home.html')
 *      res.sendFile(path.join(__dirname, './views/home.html'))
 * 
 *   2. 为 res.sendFile 方法,提供两个参数进行调用
 *      第一个实参就可以传递一个相对路径了;第二个实参,必须是一个绝对路径;
 */
app.get('/', (req, res) => {
  res.sendFile('./views/home.html', { root: __dirname })
})

app.get('/movie', (req, res) => {
  res.sendFile('./views/movie.html', { root: __dirname })
})

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

2.4 使用 express.static() 快速托管静态资源

如果我们网站中,有很多静态资源需要被外界访问,此时,使用 res.sendFile 就有点力不从心了;

这时候,express 框架,为我们提供了 express.static('静态资源目录')

来快速托管指定目录下的所有静态资源文件;

  1. 语法1: app.use(express.static('public'));
    • app.use()方法,是专门用来注册 中间件;
    • express.static 是express的内置中间件;
  2. 语法2:app.use('/虚拟目录', express.static('public'))
const express = require('express')

const app = express()

/**
 * app.use() 的作用,就是注册中间件
 * express.static() 方法,可以把 指定的 目录,托管为静态资源目录,
   这样,指定目录下的所有文件,都可以直接被浏览器来访问 
   使用方法:http://127.0.0.1:3000/xxx.html
   
 * 可以在托管静态资源文件的时候,指定要挂载的虚拟路径;app.use('/page', express.static('./views'))
   使用方法:http://127.0.0.1:3000/page/xxx.html
 */
app.use(express.static('./views'))

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

2.5 为 express 框架配置模板引擎渲染动态页面

ejs_pages / index.ejs
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <h1>这是 使用 EJS 模板引擎渲染的页面</h1>
  <p>姓名:<%= name %></p>
  <p>年龄:<%= age %></p>
  <% hobby.forEach(item => { %>
  <p><%= item %></p>
  <% }) %>
</body>

</html>
项目
  1. 初始化项目:npm init -y

  2. 安装 ejs 模板引擎npm i ejs -S

  3. 使用 app.set() 配置默认的模板引擎 app.set('view engine', 'ejs')

  4. 使用 app.set() 配置默认模板页面的存放路径 app.set('views', './views')

  5. 使用 res.render() 来渲染模板页面res.render('index.ejs', { 要渲染的数据对象 })

    注意,模板页面的 后缀名,可以省略不写!

const express = require('express')
const app = express()

// 1. 使用 app.set('view engine', '模板引擎的名称')  【固定写法】
app.set('view engine', 'ejs')

/**
 * 2. 设置模板页面的默认存放路径 app.set('views', '模板页面的具体存放路径')
 *    第一个参数:views 【固定写法】
 */
app.set('views', './ejs_pages')

app.get('/', (req, res) => {
  /**
   * 注意:如果想要调用 res.render 函数来渲染页面,必须先配置模板引擎
   * res.render('要渲染的模板页面',参数)
   * 要渲染的模板页面,就会去 views 所制定的路径查找 ./ejs_pages
   */
  res.render('index.ejs', { name: 'zs', age: 20, hobby: ['吃饭', '阅读', '唱歌'] })
})

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

2.6 在 express 中配置 art-template

art_page / index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <h1>这是使用 art-template 渲染的模板页面</h1>

  <p>姓名:{{name}}</p>
  <p>年龄:{{age}}</p>
  {{each hobby}}
  <p>{{$index}} -- {{$value}}</p>
  {{/each}}
</body>

</html>
项目
  1. 初始化项目:npm init -y
  2. 安装 两个包 cnpm i art-template express-art-template -S
  3. 自定义一个模板引擎 app.engine('自定义模板引擎的名称', 渲染函数)
  4. 将自定义的模板引擎,配置为 express 的默认模板引擎 app.set('view engine', '具体模板引擎的名称')
  5. 配置 模板页面得存放路径 app.set('views', '路径')
const express = require('express')
const app = express()

// 1. 使用 app.engine() 方法自定义模板引擎
app.engine('html', require('express-art-template'))

// 2. 使用 app.set('view engine', '指定模板引擎名称') 来配置项目中用到的模板引擎
app.set('view engine', 'html')

// 3. 配置模板页面的存放路径
app.set('views', './art_page')

app.get('/', (req, res) => {
  res.render('index.html', { name: 'zs', age: 22, hobby: ['玩游戏', '唱歌'] })
})

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

3. 使用 express 框架中提供的路由来分发请求

  1. 什么是路由:路由就是对应关系;

  2. 什么叫做后端路由:前端请求的URL地址,都要对应一个后端的处理函数,

    这种URL地址到 处理函数之间的对应关系,就叫做后端路由;

  3. 在Express中,路由的主要职责就是 把请求分发到对应的处理函数中;

  4. 在Express中,如何 定义并使用路由呢?

项目
const express = require('express')

const app = express()

// 1. 导入路由对象
const router = require('./router.js')

// 2. 调用 app.use 方法,安装路由模块
app.use(router)

app.listen(3000, () => {
  console.log('server running at http://127.0.0.1:3000')
})

router.js
// 这是定义了一个路由模块,专门负责创建路由对象,并挂载路由规则
const express = require('express')

// 调用 express.Router() 方法,创建路由对象
const router = express.Router()

router.get('/', (req, res) => {
  res.sendFile('./views/home.html', { root: __dirname })
})

router.get('/movie', (req, res) => {
  res.sendFile('./views/movie.html', { root: __dirname })
})

router.get('/about', (req, res) => {
  res.sendFile('./views/about.html', { root: __dirname })
})

// 最后,一定要把路由对象导出,供外界使用
module.exports = router

4. Express 框架里 中间件的概念

4.1 什么是中间件

注意:

  • 在应用程序开发中,每一个处理环节,都是中间件;

  • 中间件之间,要共享数据;中间件要有先后的调用顺序;

  • 数据如果想要从上一个中间件,流转到下一个中间件,必须调用相关的方法才可以

定义:中间件就是一个处理函数;只不过这个函数比较特殊,包含了三个参数,分别是 reqresnext

注意:中间件方法中的三个参数:

  • req:请求对象;
  • res:响应对象;
  • next:next()可以被调用,表示调用下一个中间件方法;

4.2 Express 框架中对中间件的5种分类

  1. 应用级别的中间件: 挂载到 app 上的中间件 app.get('URL地址', (req, res, next)=> {})
  2. 路由级别的中间件: 挂载到 router 对象上的中间件 router.get('url地址', (req, res, next)=>{})
  3. 错误级别的中间件: 回调函数中,有四个参数 app.use((err, req, res, next)=>{})
  4. 唯一内置的中间件: express.static()
  5. 第三方中间件: 非express框架提供的,需要程序员手动安装才能使用的中间件;body-parser 解析post 表单数据

中间件的概念,了解即可,因为实际开发中,我们都直接使用第三方现成的中间件;

4.3 自己模拟一个解析表单数据的中间件

index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <h3>演示中间件 表单 Post 提交数据</h3>

  <form action="/postdata" method="POST">
    <p>用户名:
      <input type="text" name="username">
    </p>
    <p>密码:
      <input type="password" name="password">
    </p>
    <input type="submit" value="提交">
  </form>
</body>

</html>
项目
// 导入 express 模块
const express = require('express')

/* 【node内置模块,不需要安装依赖包】
  查询字符串方法:querystring.parse(dataStr) 
  想要把 username=ls&password=123 字符串,解析为 { username: 'ls', password: 123 }
  const obj = querystring.parse(dataStr)
*/

const querystring = require('querystring') 

// 创建 express 的服务器实例
const app = express()

// 这是应用级别的中间件,get请求获取页面数据
app.get('/', (req, res) => {
  res.sendFile('./index.html', { root: __dirname })
})


/**
 * 定义 应用级别的中间件 
 * 中间件的作用:处理数据,发送数据的时候,是一段段的发送...chunk
 */
app.use((req, res, next) => {

  let dataStr = ''
  /**
   * 只要客户端向服务器提交了表单,都会触发 req 的 data 事件
   * 在 data 事件中,可以获取到客户端每次提交过来的,不完整的数据chunk;
   * chunk是个参数,只是括号中只有一个参数省略括号
   */
  req.on('data', chunk => {
    dataStr += chunk
  })

  // 只要 req 触发了 end 事件,就表示表单数据,提交完毕了,dataStr 中存储的数据,就是完整的表单数据
  req.on('end', () => {

    // 想要把 username=ls&password=123 字符串,解析为 { username: 'ls', password: 123 }
    const obj = querystring.parse(dataStr)
    // 将结果挂载到请求对象req
    req.body = obj

    /**
     * 进入下一个中间件的处理环节;
     * 注意:在中间件中,最后,一定要合理的调用一下 next() 方法,否则,服务器 无法结束这次响应!
     * 因为:如果没有next(),程序一直处于发送请求--响应请求的循环中,无法结束这次响应;下次请求--响应也没法进行!
     */
    next()

  })
})


/**
 * index.html中当点击提交按钮时,表单数据会提交给/postdata;
 * 当post请求的url地址是:/postdata,发送表单数据到页面
 */

app.post('/postdata', (req, res) => {

  console.log(req.body)
  /**
   * 需求:如何从客户端提交的表单中,获取到 客户端提交过来的数据呢? 通过设置中间件
   */
  res.send(req.body)

})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(3001, function () {
  console.log('Express server running at http://127.0.0.1:3001')
})

5. Express 中进行数据库操作

  1. 初始化项目:npm init -y
  2. 安装Express服务器:运行 npm i express -S 即可安装
  3. 安装mysql数据库:npm install mysql -S
项目
// 导入 express 模块
const express = require('express')

// 创建 express 的服务器实例
const app = express()

// 导入 mysql 模块
const mysql = require('mysql')

// 创建mysql的连接对象
const conn = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'mysql_001'
});

/**
 * --------------------查询-----------------------
 * const sqlStr1 = 'select * from 表名'
 * conn.query(要执行的sql语句,(err,result)=>{  })
 *  */

const sqlStr1 = 'select * from users'
conn.query(sqlStr1, (err, result) => {
  if (err) return console.log('获取数据失败!' + err.message)
  console.log(result)
})

/**
 * ------------------新增----------------------
 * const user = { uname: '小黄', age: 12, gender: '男' }
 * const sqlStr2 = 'insert into 表名 set ?'
 	 * ?表示一个占位符,将来要被真实的数据进行替换
 	 * 这种set?的形式只在Node中的mysql模块支持
 * conn.query(要执行的sql语句,新增的数据,(err,result)=>{ })
 *  */

const user = { uname: '小黄', age: 12, gender: '男' }
const sqlStr2 = 'insert into users set ?'
conn.query(sqlStr2, user, (err, result) => {
  if (err) return console.log('插入数据失败!' + err.message)
  console.log(result)
})

/**
 * -------------------修改-------------------------
 * const user = { id: 2, uname: '小绿', age: 22 }
 * const sqlStr3 = 'update users set ? where id=?'
 * conn.query(要执行的sql语句,[修改的数据对象,数据对象.id],(err,result)=>{ })
 
 * 注意:在 执行 conn.query 的时候,如果sql语句中,包含了 多个 ? 占位符,则,
 *      第二个实参,必须传递一个数组,数组中的每一项,都要和 sql 语句中的 ? 对应上
 *      如:  第一个?对应 user    第二个?对应 user.id
 *  */

const user = { id: 2, uname: '小绿', age: 22 }
const sqlStr3 = 'update users set ? where id=?'
conn.query(sqlStr3, [user, user.id], (err, result) => {
  if (err) return console.log('修改数据失败!' + err.message)
  console.log(result)
})

/**
 * ---------------删除---------------------
 * const sqlStr4 = 'delete from users where id=?'
 * conn.query(要执行的sql语句,数字,(err.result)=>{  })
 * 
 * 数字就是要删除的id=?
 *  */

const sqlStr4 = 'delete from users where id=?'
conn.query(sqlStr4, 2, (err, result) => {
  if (err) return console.log('删除失败!' + err.message)
  console.log(result)
})


// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(3001, function () {
  console.log('Express server running at http://127.0.0.1:3001')
})
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花流雨

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值