Part3-Koa与MySQL

一、Koa2安装

创建一个空白目录,然后进入终端,并在终端对koa进行安装:

# 项目初始化
$ npm init -y

# 安装koa2
$ npm i koa2 -S

# 安装nodemon
$ npm i nodemon -D

二、入口文件

在项目根目录创建 app.js 文件,并在上一步操作中生成的 package.json 里配置:

{
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon app.js"
  },
}

app.js 中:

const Koa = require('koa2');
const app = new Koa();
const port = 9000;

/* 
	解释下面这段代码:
	app.use()方法是:将给定的中间件方法添加到此应用程序。简单说就是调用中间件
	app.use() 返回 this, 因此可以链式表达
*/
app.use(async (ctx)=>{
    ctx.body = "Hello, Koa";
  	// ctx.body是ctx.response.body的简写
})

app.listen(port, ()=>{
    console.log('Server is running at http://localhost:'+port);
})

然后运行 npm run start ,并在浏览器输入 http://localhost:9000/ 即可看到页面效果。

提示:

为了以后对端口和IP的管理方便,其实可以将IP与端口放在一个文件导出,然后导入使用,这样就可以方便管理:

// 生产环境域名:http://xxx.com    开发环境域名:http://localhost
const host = "http://localhost";
// 生产环境端口:自定义         开发环境域名:9000
const port = 9000;

module.exports = {
    host, port
}

然后到app.js或者需要使用IP与端口的文件中导入使用:

const {host, port} = require("./utils")

app.listen(port, ()=>{
    console.log(`Server is running at ${host}:${port}`);
})

三、洋葱模型

学Koa必须要了解 洋葱模型 :

KoaExpress 都会使用到中间件,Express的中间件是顺序执行,从第一个中间件执行到最后一个中间件,发出响应:

Koa是从第一个中间件开始执行,遇到 next 进入下一个中间件,一直执行到最后一个中间件,在逆序,执行上一个中间件 next 之后的代码,一直到第一个中间件执行结束才发出响应。

对于这个洋葱模型,我们用代码来解释一下。假如把上面的代码改写成:

const Koa = require('koa2');
const app = new Koa();
const port = 9000;

app.use(async (ctx, next)=>{
    console.log(1)
    await next();
    console.log(2)
})

app.use(async (ctx, next)=>{
    console.log(3)
    await next();
    console.log(4)
})

app.use(async (ctx)=>{
    console.log(5)
})

app.listen(port, ()=>{
    console.log('Server is running at http://localhost:'+port);
})

那么在浏览器刷新后,控制台得到的顺序是:

1
3
5
4
2

现在可以看到,我们通过 next可以先运行下个中间件,等中间件结束后,再继续运行当前 next() 之后的代码。

四、路由安装

当需要匹配不同路由时,可以安装:

$ npm i koa-router

app.js 修改:

const Koa = require('koa2');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
const port = 9000;

router.get('/', async (ctx)=>{
    ctx.body = "根路径";
})

router.get('/manage', async (ctx)=>{
    ctx.body = "管理系统";
})

app.use(router.routes(), router.allowedMethods());

app.listen(port, ()=>{
    console.log(`Server is running at http://localhost:${port}`);
})

此时,到浏览器刷新并在地址栏最后添加 /manage 即可得到根路径内容和列表模块内容。

备注:

// 调用router.routes()来组装匹配好的路由,返回一个合并好的中间件
// 调用router.allowedMethods()获得一个中间件,当发送了不符合的请求时,会返回 `405 Method Not Allowed` 或 `501 Not Implemented`

allowedMethods方法可以做以下配置:
app.use(router.allowedMethods({ 
    // throw: true, // 抛出错误,代替设置响应头状态
    // notImplemented: () => '不支持当前请求所需要的功能',
    // methodNotAllowed: () => '不支持的请求方式'
}))

五、路由拆分

当项目较大,路由较多时,我们需要划分模块。此时,就需要对路由进行拆分。这个项目的后端要服务于Web官网和后台管理系统,因此我们将路由划分成两个模块:web与manage。

1、创建 router 文件夹

创建router文件夹,并在其中创建:index.js (路由总入口文件)、manage/index.js (manage模块路由入口文件)、web/index.js (web模块路由入口文件):

// app.js
const Koa = require("koa2");
const router = require("./router")
const app = new Koa();
const port = 9000;

// 调用router中间件
app.use(router.routes(), router.allowedMethods());

app.listen(port, ()=>{
    console.log(`Server is running at http://localhost:${port}`);
})

// index.js
const Router = require("koa-router");
const manage = require("./manage");
const web = require("./web");
const router = new Router();

router.get("/", async ctx=>{
    ctx.body = "根路径"
})

router.use("/manage", manage.routes(), manage.allowedMethods());
router.use("/web", web.routes(), web.allowedMethods());

module.exports = router;


// manage/index.js
const Router = require("koa-router")
const router = new Router();

router.get('/', async ctx=>{
    ctx.body = "管理系统"
})

module.exports = router;


// web/index.js
const Router = require("koa-router")
const router = new Router();

router.get('/', async ctx=>{
    ctx.body = "官网"
})

module.exports = router;

到浏览器刷新 localhost:9000/managelocalhost:9000/web 即可得到manage和web两个模块返回的数据。

2、路由重定向(了解)

那么有同学会问了,如果我想直接从 localhost:9000 重定向到 localhost:9000/home 该怎么办?

我们可以在 router/index.js 中做如下配置:

router.use('/home', home.routes(), home.allowedMethods());
...
router.redirect('/', '/home');

3、404无效路由

如果被访问到无效路由,那么我们可以统一返回404页面:

routererrorPage.js :

const Router = require('koa-router');
const errorPage = new Router();

errorPage.get('/', async (ctx) => {
    ctx.body = "访问页面不存在";
})

module.exports = errorPage;

router/index.js 中:

const errorPage = require("./errorPage")

// 404页面路由
router.use("/404", errorPage.routes(), errorPage.allowedMethods());

app.js 中引用:

// 匹配不到页面的全部跳转去404
app.use(async (ctx, next) => {
    await next();
    if (parseInt(ctx.status) === 404) {
        ctx.response.redirect("/404")
    }
})
app.use(router.routes(), router.allowedMethods());

六、后端允许跨域(了解)

前端想跨域,可以设置proxy。如果后端允许跨域,可以如下操作:

// 安装koa2-cors
$ cnpm i koa2-cors

// 引入koa2-cors中间件
const cors = require("koa2-cors");
// 这里cors中间件一定要写在路由之前
app.use(cors());

app.use(router.routes(), router.allowedMethods())

七、读取静态资源文件

首先安装 koa-static,命令行代码如下:

$ yarn add koa-static

然后在项目的根目录下创建 assets 后,将图片资源(图片自己随便找一张)文件夹 images 放到其中。我们假定404页面需要返回一张错误警告图,可以在 app.js 中执行以下操作:

// 引入
const path = require('path')
const static = require('koa-static')

// 获取静态资源文件夹
app.use(static(path.join(__dirname, '/assets')));
...
app.use(router.routes(), router.allowedMethods())

假设其中有一张图片叫做 404.gif,那么我们打开浏览器,访问:http://localhost:9000/images/404.gif 即可得到图片。这里注意:

路径上不需要写assets,因为我们已经指定了访问资源时, http://localhost:9000 自动指向 assets 文件夹。由此,我们知道数据库中图片的地址只需要填写 /images/404.gif 即可。

如果我们希望打开404页面就显示这张图,就需要做如下步骤:

1、安装mime-types

$ npm i mime-types

2、使用fs读取文件

修改errorPage.js:

const Router = require("koa-router")
const router = new Router();
const fs = require("fs")
const path = require("path")
const mime = require("mime-types")

router.get('/', async ctx=>{
    const filePath = path.join(__dirname, "../assets/images/404.gif");
    const file = fs.readFileSync(filePath); // 读取文件
    const mimeType = mime.lookup(filePath)  // 读取文件类型
    ctx.set("content-type", mimeType);  // 设置返回类型(这一步很重要)
    ctx.body = file;    // 返回图片
})

module.exports = router;

八、MySQL安装【软件还需整理】

1、Windows卸载MySQL

如果你曾装过MySQL,请务必先卸载干净。

首先检查电脑是否安装过MySQL,Windows执行:开始->运行->输入 services.msc。如果看到有MySQL,就代表安装了,如图:

如果没有,就可以忽略删除MySQL这一步了。但如果看到了这一项,请右键先停止这项服务,然后:

快捷键 win+r 输入 regedit 进入注册表,找到 HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL 文件夹并对其进行删除。

如果有以下两个文件夹:

删除 HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL文件夹。 删除 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL的文件夹。 注册表里没有这两个文件,就不用删除了。

然后找到mysql的安装位置,将mysql文件夹删掉:

再到控制面板搜索 mysql ,确认已经没有了才可以,否则也进行卸载。

然后是另一个地方的:C:\Program Files (x86)\MySQL

还有一个隐藏文件下的,先点击【查看】->勾选【隐藏的项目】:

然后返回 C:/,可以看到一个名为ProgramData的文件夹,点开找到里面的MySQL,删除就行了

到此位置,恭喜你将mysql删干净了。

2、MySQL安装(Mac)

Mac安装包:链接:https://pan.baidu.com/s/1InjXljIzRO945iXlN6Pn3w 提取码:ndpb

3、MySQL安装(Windows)

Windows64位安装包:链接:https://pan.baidu.com/s/1OmdD-QldkvPGl0kQokbxJg 提取码:ndpb

下载完成后,直接解压并放到指定的目录中。例如:D:\server\mysql-5.7.23-winx64。

在mysql目录中新建 my.ini,并进行如下配置:

[client]
# 设置mysql客户端默认字符集
default-character-set=utf8

[mysqld]
# skip-grant-tables
#设置3306端口
port = 3306
# 设置mysql的安装目录
basedir=D:\\server\\mysql-5.7.23-winx64
# 设置mysql数据库的数据的存放目录
datadir=D:\\server\\mysql-5.7.23-winx64\\data
# 允许最大连接数
max_connections=200
# 服务端使用的字符集默认为8比特编码的latin1字符集
character-set-server=utf8
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB

进入 mysql目录 下的 bin目录,命令行执行:

# 初始化数据库
$ .\mysqld --initialize --console

假如你得到:

...
2018-04-20T02:35:05.464644Z 5 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: sQjjZSffo6)C
...

代表初始化成功,并且 sQjjZSffo6)C 就是你的登录密码,可以在登陆后修改。你可以通过以下命令查询mysql版本:

$ .\mysqladmin --version

# 得到:mysqladmin  Ver 8.42 Distrib 5.7.23, for Win64 on x86_64

然后以管理员身份进入这个bin目录,并输入以下安装命令:

$ .\mysqld install

启动输入以下命令即可启动mysql:

$ net start mysql

如果你出现了上图的错误,可以执行:

$ .\mysqld --remove
Service successfully removed.

$ .\mysqld --install
Service successfully installed.

$ net start mysql
MySQL 服务正在启动 .
MySQL 服务已经启动成功。

这样就算是mysql安装并启动成功了。

4、修改MySQL密码

现在修改mysql密码,重新打开 my.ini,把这一行的注释解掉:

skip-grant-tables

然后重启mysql:

$ net stop mysql
$ net start mysql

此时的mysql密码已经被取消,可以随意输入密码进入:

$ .\mysql -uroot -p

然后修改密码:

$ mysql> use mysql;
$ mysql> update user set authentication_string=password("123456") where user="root";
$ mysql> flush privileges;  # 刷新权限
$ mysql> quit;				# 退出mysql

注意:密码字段名 5.7 版本的是 authentication_string,之前的为 password

然后重新回到 my.ini 把刚刚那行注释掉:

# skip-grant-tables;

重启mysql:

$ net stop mysql
$ net start mysql

再一次尝试连接mysql:

$ .\mysql -uroot -p123456

出现以下界面,代表成功:

由于版本等问题,建议在连接mysql成功后,再一次执行:

$ mysql> alter user user() identified by "123456";

十、Navicat安装【软件还需整理】

Navicat for MySQL 是一套全面的前端工具为数据库管理、开发和维护提供了一款直观而强大的图形界面,能同时连接 MySQL 和 MariaDB 数据库。

有关 Navicat for MySQL 软件的下载和安装,大家可以百度搜索,当然,我这里也给大家找到一篇文章:

https://www.cnblogs.com/yanghongtao/p/10976526.html

1、Windows安装

Windows64位版本:链接:https://pan.baidu.com/s/1fly3pVOE_6oyauOEbLj1Vw 提取码:ndpb

下载解压后直接双击两个.exe程序进行安装与绿化:

2、Mac安装

M1 Mac版本:链接:https://pan.baidu.com/s/14xIcYUKIbSBAynNS7eD15w 提取码:ndpb

打开直接拽入应用程序即可。

十一、数据库基本操作语句

1、数据库的连接与断开

如果希望在系统全局均可连接mysql,可以在系统环境变量配置mysql的bin目录。

# 连接数据库
$ mysql -uroot -p123456

# 断开数据库
$ mysql> quit;
# 或者
$ mysql> exit;

2、数据库基本操作

数据库的创建、删除、显示与选择。

# 创建数据库
$ mysql> create database test;

# 删除数据库(不要轻易使用)
$ mysql> drop database test;

# 显示数据库
$ mysql> show databases;

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
8 rows in set (0.04 sec)

# 选择数据库
$ mysql> use test;

3、表操作

每个数据库都是由若干张表构成,每张表都是用来存储字段与数据的。以下是常用的表操作:

a. 创建表:

# 创建一张用户表(包含id、用户名与密码)
/*
	INT 			整数型
	PRIMARY KEY   	主键约束
	AUTO_INCREMENT	自增约束
	VARCHAR			长字符串
	COMMENT			字段注释
*/
create table user (
	id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(30) COMMENT '用户名称',
    password VARCHAR(30) COMMENT '用户密码'
);

Query OK, 0 rows affected (0.02 sec)

什么是自增约束?

如果字段id被定义为AUTO_INCREMENT,在插入一行数据的时候,自增值的行为如下:

1.如果插入数据时id字段指定为0、null或未指定值,那么就把这个表当前的AUTO_INCREMENT值填到自增字段

2.如果插入数据时id字段指定了具体的值,就直接使用语句里指定的值

b. 删除表(不要随便使用):

drop table user;

Query OK, 0 rows affected (0.01 sec)

c. 查看表:

show tables;

+----------------+
| Tables_in_test |
+----------------+
| user           |
+----------------+
1 row in set (0.00 sec)

d. 描述表(查看该表的字段):

describe user;

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(30) | YES  |     | NULL    |                |
| password | varchar(30) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

4、Navicat使用

打开安装好的Navicat软件,连接后其实也可以看到刚刚的这些数据:

5、表数据的增删改查

以上表操作中我们创建了一张user表,现在我们通过对这张表进行CRUD(增删改查)。

a. 增加表数据

$ mysql> INSERT INTO user VALUES (null, "张三", "123456");
$ mysql> INSERT INTO user VALUES (null, "李四", "234567");

这里要注意:id是自增的字段,填写0或null都会从1开始自增。

b. 查询表数据

如果想要查询user表中所有的数据:

$ mysql> SELECT * FROM user;

+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 张三     | 123456   |
|  2 | 李四     | 234567   |
+----+----------+----------+
2 rows in set (0.00 sec)

c. 更新表数据

假设现在想要修改李四的密码:

$ mysql> UPDATE user SET password="999999" WHERE username="李四";

# 更新后可以查询李四的密码
$ mysql> SELECT password FROM user WHERE username="李四";

+----------+
| password |
+----------+
| 999999   |
+----------+
1 row in set (0.00 sec)

d. 删除表数据

假设现在想要删除张三这条数据:

$ mysql> DELETE FROM user WHERE username="张三";

# 删除后查询表数据
$ mysql> SELECT * FROM user;

+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  2 | 李四     | 999999   |
+----+----------+----------+
1 row in set (0.00 sec)

有关数据库基本操作语句的介绍就到这里,后续在项目中会有更多实战性应用。

十二、NodeJs中操作MySQL

1、创建连接池

NodeJs中想要连接MySQL,需要先在项目内安装mysql库:

npm i mysql

在操作下面的代码时,先创建一个数据库,本项目将创建一个名为cms的数据库。另外,在cms中添加一张user表,然后填充部分数据:

# 创建数据库cms
$ mysql> CREATE DATABASE cms;
# 选择数据库cms
$ mysql> USE DATABASE cms;
# 创建user表
$ mysql> CREATE TABLE user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(30) COMMENT "用户名称",
    password VARCHAR(30) COMMENT "用户密码"
);
# 新增user表数据
$ mysql> INSERT INTO user VALUES (null, "张三", "123456");
$ mysql> INSERT INTO user VALUES (null, "李四", "aaasss");

然后到utils.js中,引入mysql并创建连接池:

// 引入mysql
const mysql = require("mysql");

// 创建连接池
const pool = mysql.createPool({
    host: "localhost",  // 连接的服务器(代码托管到线上后,需改为内网IP,而非外网)
    port: 3306, // mysql服务运行的端口
    database: "cms", // 选择某个数据库
    user: "root",   // 用户名
    password: "123456", // 用户密码
})

//对数据库进行增删改查操作的基础
const query = (sql,callback) => {
    pool.getConnection(function(err,connection){
        connection.query(sql, function (err,rows) {
            callback(err,rows)
            connection.release()
        })
    })
}

module.exports = {
    host, port, query
}

2、Node中使用连接池

假设用户访问/manage即可查询数据库cms中表user的数据。这样的话,需要找到manage/index.js:

const Router = require("koa-router")
const router = new Router();
const utils = require("../../utils")

router.get('/', async ctx=>{
    let data = await new Promise((resolve, reject)=>{
        // 写一句sql语句
        var sql = `SELECT * FROM user`;
        utils.query(sql, (err, data)=>{
            if(err) reject(err);
            resolve(data);  // 返回拿到的数据
        })
    })
    ctx.body = data;    // 将查询结果返回到页面中
})

module.exports = router;

打开浏览器访问http://localhost:9000,即可得到返回的数据:

3、查询指定字段

使用逗号隔开字段,这种选择方式会返回一个数组

SELECT username,password 	FROM user

至此,我们已经可以实现在Koa中操作数据库。

最后更新于