github代码:https://github.com/zy13/koa-demo/tree/2-koa-with-mysql

1、nunjucks模板引擎的应用

官网:https://mozilla.github.io/nunjucks/cn/getting-started.html

1-1、服务端引入

  • 配置方法configure
  • 渲染方法render:二次封装后挂载到ctx.render()

1-2、模板文件

  • include语法引入公共模块
  • extends语法扩展基础模块
  • block语法引入块

1-3、数据渲染

  • 服务端挂载数据
  • 模板渲染:通过大胡子语法和for...in等语法渲染模板数据

1-4、二次封装nunjucks

二次封装的目的:将模板文件的渲染方法,将其挂载到ctx.render(),简化模板渲染方式,方便维护

const nunjucks = require('nunjucks')
const path = require('path')

module.exports = (options) => {
  const viewDir = path.resolve(__dirname, '../views')

  // 配置模板文件-动态数据渲染模板
  nunjucks.configure('views', {
    noCache: true,
    watch: true,
    autoescape: true,
    ...options
  })

  // 返回异步函数
  return async (ctx, next) => {
    if(!ctx.render) {
      ctx.render = (tplName, data) => {
        return nunjucks.render(`${viewDir}/${tplName}.html`, {
          ...data
        })
      }
    }
    
    await next()
  }
}

2、MySQL数据库的应用

数据能够提供很多功能性的函数以及底层算法支撑,帮助我们更好地管理维护和使用数据。

官网:https://mysql.com

2-1、学习数据库目的:

  • 1、了解整个后端工作流程、以及后端业务逻辑
  • 2、了解前端配合后端工作的方式
  • 3、更有利于前端和后端业务的划分

2-2、数据库的安装

  • 数据库管理
  • 图形化操作界面(GUI)管理数据库(尽量使用开源或者免费的工具)
    • 官网下载:https://dev.mysql.com/downloads/workbench/

    • 配置:连接名称、协议、数据库主机名、端口、用户名、密码

    • 连接数据库:端口、用户名、密码等

    • 数据库图形化管理界面

2-3、mysqlworkbench的使用

  • 创建一个数据库

  • 创建数据库的表格

    • 通过create table创建

    • 通过table import导入

3、第三方库mysql2的应用

官网:https://www.npmjs.com/package/mysql2

3-1、创建与数据库的连接

// get the client
const mysql = require('mysql2');
 
// create the connection to database
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  database: 'test'
});

3-2、异步查询数据库

  • 通过回调函数的方式获得数据库的数据
// simple query
connection.query(
  'SELECT * FROM `table` WHERE `name` = "Page" AND `age` > 45',
  function(err, results, fields) {
    console.log(results); // results contains rows returned by server
    console.log(fields); // fields contains extra meta data about results, if available
  }
);
  • 通过promise版本获取数据库数据
async function main() {
  // get the client
  const mysql = require('mysql2/promise');
  // create the connection
  const connection = await mysql.createConnection({host:'localhost', user: 'root', database: 'test'});
  // query database
  const [rows, fields] = await connection.execute('SELECT * FROM `table` WHERE `name` = ? AND `age` > ?', ['Morty', 14]);
}

3-3、二次封装mysql2

二次封装的目的:将连接挂载到ctx.connection, 简化数据库的操作,便于维护

// 单例模式
const mysql = require('mysql2/promise')

const config = {
  host: 'localhost',
  user: 'root',
  database: 'kkb',
  port: 3307
}
let connection
module.exports = () => {
  return async (ctx, next) => {
    if(!connection) {
      connection = await mysql.createConnection(config)
    }
    ctx.connection = connection
    await next()
  }
}

4、动态路由

  • koa-router中间件

官网:https://www.npmjs.com/package/koa-router

  • 因为url在请求过程中再携带一些动态的额外数据,这个数据会影响当前从数据库中查询的结果
  • 客户端发送请求可以发送数据:1.url 2.请求头 3.请求正文
  • koa-router会在分析当前动态url时候,把/list/1或者/list/2后面:匹配的内容单独解析出来,然后存放到ctx.request.params.categoryId
// 列表页
router.get('/list/:categoryId', async ctx => {
  let { categoryId } = ctx.request.params
  const [categories] = await ctx.connection.query(
    'select * from categories'
  )
  const [items] = await ctx.connection.query(
    'select * from items where category_id=?',
    [categoryId]
  )
  ctx.body = ctx.render('list', {
    title: '列表',
    categories,
    items
  })
})

4、post请求的数据处理

4-1、客户端

客户端请求的数据量大的情况下,使用post请求,通过表单形式提交给后端

<form method="post" action="/comment" enctype="application/x-www-form-urlencoded">
  <p>
    <textarea name="content" class="input" rows="5"></textarea>
    <input type="hidden" name="detailId" value="{{item.id}}">
  </p>
  <p>
    <button class="btn btn-primary">提交</button>
  </p>
</form> 
<!-- 浏览器会自动收集form表单里name属性的字段名称和值,并提交给`/comment`接口 -->
<!-- 点击form表单中的button按钮,浏览器会自动提交响应数据给后端 -->

4-2、服务端

koa框架只能解析url和请求头的相关数据,对应客户端请求正文携带的数据无法解析,故需要引入中间件进行解析。

  • koa-body

    • 该中间件解析请求正文携带的数据,并将数据挂载到ctx.request.body中
  • 将数据存入到数据库中

// 数据量比较大的请求,使用post提交数据
router.post('/comment', koaBody(), async ctx => {
  // 默认情况下,koa不会解析post提交的正文请求中的数据,其解析头部和url的信息
  let { content, detailId } = ctx.request.body
  let [rs] = await ctx.connection.query(
    'insert into comments (content,datatime,detail_id) values (?,?,?)',
    [content,Date.now(),detailId]
  )
  ctx.body = '评论成功'
})

5、练习

  • 1、创建一个数据库kkb
  • 2、在kkb数据库中创建一个表users
  • 3、在users表中添加至少下面两个字段:
    • 1、id(int),username(varchar)
  • 4、通过koa、koa-router构建一个webserver,端口8888
  • 5、提供一个get方式接口localhost:8888/register访问注册页面(form表单)
  • 6、提供一个post方式接口localhost:8888/register处理提交的数据,并返回操作结果(注册失败 or 注册成功)
  • 7、提交注册的数据保存到数据库users表中 通过标准:完成以上所有任务及要求,方可通过。