基于Node.js + Koa2 + MySQL + TypeScript的应用示例

文章目录

    • [概要(Node.js + Koa2 + MySQL + TypeScript)](#概要(Node.js + Koa2 + MySQL + TypeScript))
    • [koa2 基础语法及应用](#koa2 基础语法及应用)
    • [koa2 与 express 的区别](#koa2 与 express 的区别)

概要(Node.js + Koa2 + MySQL + TypeScript)

基础知识

  1. Node.js:是一个基于Chrome V8引擎的JavaScript运行时,允许在服务器端运行JavaScript代码。
  2. Koa2:是一个轻量级的Node.js web框架,它使用async/await语法来处理异步操作,使得代码更加简洁易读。
  3. MySQL:是一种流行的关系型数据库管理系统,用于存储和管理数据。
  4. TypeScript:是JavaScript的超集,它为JavaScript添加了类型系统,提高了代码的可维护性和可靠性。

应用实例

  1. 初始化项目
    • 创建一个新的目录,例如koa-mysql-ts-app,并进入该目录。
    • 初始化package.json文件:
bash 复制代码
npm init -y
  • 安装所需的依赖:
bash 复制代码
npm install koa mysql2 @types/koa @types/mysql2 typescript ts-node-dev --save-dev
  1. 配置TypeScript
    • 在项目根目录下创建tsconfig.json文件,并添加以下配置:
json 复制代码
{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
    }
}
  1. 创建数据库和表
    • 使用MySQL客户端(如phpMyAdmin、Navicat等)创建一个数据库,例如koa_mysql_ts_db
    • 创建一个表,例如users
sql 复制代码
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    age INT NOT NULL
);
  1. 项目结构
    • 在项目根目录下创建src目录,用于存放TypeScript源代码。
    • src目录下创建以下文件和目录:
      • config目录:用于存放数据库配置文件。
      • controllers目录:用于存放处理业务逻辑的控制器文件。
      • routes目录:用于存放路由文件。
      • app.ts:主应用文件。
  2. 配置数据库连接
    • src/config目录下创建db.ts文件:
typescript 复制代码
import mysql from'mysql2';

const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'koa_mysql_ts_db'
});

connection.connect((err) => {
    if (err) {
        console.error('Error connecting to MySQL database:', err);
        return;
    }
    console.log('Connected to MySQL database!');
});

export default connection;
  1. 创建控制器
    • src/controllers目录下创建userController.ts文件:
typescript 复制代码
import { Context } from 'koa';
import connection from '../config/db';

class UserController {
    async getUsers(ctx: Context) {
        try {
            const [rows] = await new Promise<any>((resolve, reject) => {
                connection.query('SELECT * FROM users', (err, results) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(results);
                    }
                });
            });
            ctx.body = rows;
        } catch (error) {
            ctx.status = 500;
            ctx.body = { error: 'Error fetching users' };
        }
    }

    async createUser(ctx: Context) {
        const { name, age } = ctx.request.body;
        try {
            await new Promise<any>((resolve, reject) => {
                connection.query(
                'INSERT INTO users (name, age) VALUES (?,?)', [name, age],
                 (err, results) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(results);
                    }
                });
            });
            ctx.status = 201;
            ctx.body = { message: 'User created successfully' };
        } catch (error) {
            ctx.status = 500;
            ctx.body = { error: 'Error creating user' };
        }
    }

    async updateUser(ctx: Context) {
        const { id } = ctx.params;
        const { name, age } = ctx.request.body;
        try {
            await new Promise<any>((resolve, reject) => {
                connection.query('UPDATE users SET name =?, age =? WHERE id =?',
                [name, age, id], (err, results) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(results);
                    }
                });
            });
            ctx.status = 200;
            ctx.body = { message: 'User updated successfully' };
        } catch (error) {
            ctx.status = 500;
            ctx.body = { error: 'Error updating user' };
        }
    }

    async deleteUser(ctx: Context) {
        const { id } = ctx.params;
        try {
            await new Promise<any>((resolve, reject) => {
                connection.query(
                'DELETE FROM users WHERE id =?', [id], (err, results) => {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(results);
                    }
                });
            });
            ctx.status = 200;
            ctx.body = { message: 'User deleted successfully' };
        } catch (error) {
            ctx.status = 500;
            ctx.body = { error: 'Error deleting user' };
        }
    }
}

export default new UserController();
  1. 创建路由
    • src/routes目录下创建userRoutes.ts文件:
typescript 复制代码
import { Router } from 'koa';
import userController from '../controllers/userController';

const router = new Router();

router.get('/users', userController.getUsers);
router.post('/users', userController.createUser);
router.put('/users/:id', userController.updateUser);
router.delete('/users/:id', userController.deleteUser);

export default router;
  1. 主应用文件
    • src目录下的app.ts文件:
typescript 复制代码
import Koa from 'koa';
import userRoutes from './routes/userRoutes';

const app = new Koa();

app.use(userRoutes.routes()).use(userRoutes.allowedMethods());

const port = 3000;
app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});
  1. 启动项目
    • package.json文件中添加启动脚本:
json 复制代码
"scripts": {
    "dev": "ts - node - dev --respawn --transpileOnly src/app.ts"
}
  • 运行以下命令启动项目:
bash 复制代码
npm run dev

接口列表

  1. 获取所有用户
    • URL : /users
    • Method: GET
  2. 创建用户
    • URL : /users
    • Method: POST
    • Body:
json 复制代码
{
    "name": "John Doe",
    "age": 30
}
  1. 更新用户
    • URL : /users/:id
    • Method: PUT
    • Body:
json 复制代码
{
    "name": "Jane Doe",
    "age": 31
}
  1. 删除用户
    • URL : /users/:id
    • Method: DELETE

这个示例展示了如何使用Node.js、Koa2、MySQL和TypeScript构建一个简单的增删改查应用。你可以根据实际需求进一步扩展和优化这个应用。

koa2 基础语法及应用

  1. Koa2基础语法
    • 安装与引入
      • 首先需要安装koa模块,可以使用npm install koa命令。在TypeScript项目中,还需要安装@types/koa类型定义文件。
      • 在JavaScript文件中引入koa如下:
javascript 复制代码
const Koa = require('koa');
const app = new Koa();
  • 在TypeScript文件中引入koa如下:
typescript 复制代码
import Koa from 'koa';
const app = new Koa();
  • 中间件(Middleware)
    • 中间件是Koa的核心概念。它是一个函数,接收两个参数:ctx(上下文对象)和next(下一个中间件函数)。ctx包含了请求和响应的信息,如ctx.request(请求对象)和ctx.response(响应对象),它们分别是http.IncomingMessagehttp.ServerResponse的增强版。
    • 一个简单的中间件示例如下:
javascript 复制代码
app.use((ctx, next) => {
    console.log('This is a middleware');
    // 调用下一个中间件
    return next();
});
  • 中间件的执行顺序是按照添加的顺序来的。可以通过app.use()方法添加多个中间件,并且每个中间件都可以对请求和响应进行处理,比如修改请求头、设置响应状态码等。
    • 路由(Routing)
      • 虽然Koa本身没有内置路由功能,但可以使用第三方路由中间件,如koa - router
      • 安装koa - routernpm install koa - router
      • 以下是一个简单的路由示例:
javascript 复制代码
const Router = require('koa - router');
const router = new Router();

// 定义GET请求路由
router.get('/hello', (ctx) => {
    ctx.body = 'Hello, World!';
});

// 将路由中间件添加到Koa应用
app.use(router.routes()).use(router.allowedMethods());
  • 在这个示例中,定义了一个GET请求的路由/hello,当访问该路径时,会返回Hello, World!router.routes()返回一个中间件函数,用于处理路由匹配,router.allowedMethods()用于设置允许的请求方法,确保遵循HTTP规范。
  • 上下文(Context)
    • ctx对象是Koa中非常重要的部分。它包含了许多有用的属性和方法,例如:
      • ctx.request.url:获取请求的URL。
      • ctx.request.method:获取请求的方法(如GETPOST等)。
      • ctx.response.status:设置响应的状态码。
      • ctx.response.body:设置响应的内容。
    • 示例:
javascript 复制代码
app.use((ctx) => {
    ctx.response.status = 200;
    ctx.response.body = {
        message: 'This is the response body',
        url: ctx.request.url
    };
});
  • 这个中间件会将响应状态码设置为200,并返回一个包含消息和请求URL的JSON对象作为响应体。
  1. Koa2基础应用的目的
    • 构建Web应用和API服务
      • Koa2提供了一个轻量级的框架来构建Web应用和API服务。它的异步处理机制(通过async/await)使得处理异步操作(如数据库查询、外部API调用等)更加简洁和高效。例如,可以轻松地构建一个RESTful API,为前端应用提供数据接口。
    • 中间件架构的灵活性
      • 中间件的架构允许开发者通过组合不同的中间件来添加各种功能,如日志记录、身份验证、请求解析、响应格式化等。这种灵活性使得Koa2可以适应各种不同的应用场景。例如,可以添加一个日志中间件来记录每个请求的信息,或者添加一个CORS中间件来处理跨域请求。
    • 高性能和简洁的代码风格
      • 相比于一些传统的Web框架,Koa2的代码风格更加简洁。它不强制开发者使用特定的模式或结构,同时通过async/await可以减少回调地狱的问题,提高代码的可读性和可维护性。其轻量级的设计也有助于提高应用的性能,减少资源占用,适用于构建高性能的Web应用和微服务。

koa2 与 express 的区别

  1. 中间件的概念相似性

    • Koa2和Express中间件的基本作用类似 :它们都是用于处理HTTP请求和响应的函数。在这两个框架中,中间件函数都可以访问请求对象(如reqctx.request)和响应对象(如resctx.response),并且能够在请求 - 响应周期中对请求进行预处理、对响应进行后处理,或者执行一些与业务逻辑相关的操作,如验证用户身份、记录日志等。
  2. 中间件的执行顺序

    • Express中间件执行顺序较为直观 :在Express中,中间件是按照添加的顺序依次执行的。当一个中间件调用next()函数时,它会将控制权传递给下一个中间件。例如:
javascript 复制代码
const express = require('express');
const app = express();

// 第一个中间件
app.use((req, res, next) => {
    console.log('First middleware');
    next();
});

// 第二个中间件
app.use((req, res, next) => {
    console.log('Second middleware');
    next();
});

// 路由处理中间件
app.get('/', (req, res) => {
    res.send('Hello from Express');
});

app.listen(3000, () => {
    console.log('Express server running on port 3000');
});
  • 在上述Express示例中,当有请求进入时,会先执行第一个中间件,打印First middleware,然后通过next()调用第二个中间件,打印Second middleware,最后执行路由处理中间件返回响应。
  • Koa2中间件执行顺序更具灵活性(基于async/await :Koa2的中间件也是按照添加顺序执行,但是由于它基于async/await语法,中间件可以是异步函数。这使得在中间件中处理异步操作更加自然和方便,并且可以更好地控制中间件的执行顺序和流程。例如:
javascript 复制代码
const Koa = require('koa');
const app = new Koa();

// 第一个中间件
app.use(async (ctx, next) => {
    console.log('First middleware');
    await next();
    console.log('Back to first middleware after next');
});

// 第二个中间件
app.use(async (ctx, next) => {
    console.log('Second middleware');
    await next();
    console.log('Back to second middleware after next');
});

// 路由处理中间件
app.use((ctx) => {
    ctx.body = 'Hello from Koa2';
});

app.listen(3000, () => {
    console.log('Koa2 server running on port 3000');
});
  • 在Koa2示例中,当请求进入时,先执行第一个中间件,打印First middleware,然后调用next()执行第二个中间件,打印Second middleware。当路由处理中间件执行完返回响应后,执行流程会反向回到第二个中间件的await next()之后的代码,打印Back to second middleware after next,最后回到第一个中间件的await next()之后的代码,打印Back to first middleware after next。这种执行顺序的灵活性可以让开发者更方便地在中间件中进行后置处理,如清理资源、记录响应相关的日志等。
  1. 中间件的编写方式和语法糖差异
    • Express中间件的编写方式传统一些 :Express中间件通常采用传统的回调函数形式,如(req, res, next) => {... }。虽然也支持async/await,但不是其主要的编写风格。例如,一个简单的Express中间件用于记录请求时间可能如下:
javascript 复制代码
const express = require('express');
const app = express();

// 记录请求时间的中间件
app.use((req, res, next) => {
    const startTime = Date.now();
    res.on('finish', () => {
        const endTime = Date.now();
        console.log(`Request took ${endTime - startTime}ms`);
    });
    next();
});

// 路由处理中间件
app.get('/', (req, res) => {
    res.send('Hello from Express');
});

app.listen(3000, () => {
    console.log('Express server running on port 3000');
});
  • Koa2中间件更倾向于使用async/await语法 :Koa2中间件利用async/await语法,使得代码更加简洁和易读,尤其是在处理异步操作时。例如,同样是记录请求时间的中间件在Koa2中可以写成:
javascript 复制代码
const Koa = require('koa');
const app = new Koa();

// 记录请求时间的中间件
app.use(async (ctx, next) => {
    const startTime = Date.now();
    await next();
    const endTime = Date.now();
    console.log(`Request took ${endTime - startTime}ms`);
});

// 路由处理中间件
app.use((ctx) => {
    ctx.body = 'Hello from Koa2';
});

app.listen(3000, () => {
    console.log('Koa2 server running on port 3000');
});
  • 可以看到,在Koa2的中间件中,通过async/await可以更自然地暂停和恢复中间件的执行,等待异步操作完成,而在Express中可能需要更多地使用回调函数或者Promise来处理异步操作。
  1. 中间件的错误处理机制不同
    • Express中间件错误处理通常通过回调函数传递错误 :在Express中,如果一个中间件内部发生错误,可以将错误对象传递给next函数,然后在全局错误处理中间件(通过app.use((err, req, res, next) => {... }))中捕获和处理错误。例如:
javascript 复制代码
const express = require('express');
const app = express();

// 一个可能出错的中间件
app.use((req, res, next) => {
    throw new Error('This is an error in the middleware');
});

// 全局错误处理中间件
app.use((err, req, res, next) => {
    console.error(err);
    res.status(500).send('Internal Server Error');
});

app.listen(3000, () => {
    console.log('Express server running on port 3000');
});
  • Koa2中间件错误处理可以利用async/awaittry - catch :在Koa2中,由于中间件可以是异步函数,所以可以使用try - catch块来捕获中间件内部的错误。同时,Koa2应用本身也是一个事件发射器,可以监听error事件来处理未被中间件捕获的错误。例如:
javascript 复制代码
const Koa = require('koa');
const app = new Koa();

// 一个可能出错的中间件
app.use(async (ctx, next) => {
    try {
        throw new Error('This is an error in the middleware');
    } catch (error) {
        console.error(error);
        ctx.status = 500;
        ctx.body = 'Internal Server Error';
    }
});

// 监听应用的error事件
app.on('error', (err, ctx) => {
    console.error('Uncaught error:', err);
});

app.listen(3000, () => {
    console.log('Koa2 server running on port 3000');
});
相关推荐
加勒比之杰克12 分钟前
【数据库初阶】MySQL中表的约束(上)
android·数据库·mysql
胡桃夹夹子7 小时前
前端,npm install安装依赖卡在sill idealTree buildDeps(设置淘宝依赖)
前端·npm·node.js
LLLuckyGirl~8 小时前
node.js之---CommonJS 模块
node.js
m0_748249548 小时前
node.js下载、安装、设置国内镜像源(永久)(Windows11)
node.js
猿java9 小时前
字节2面:为了性能,你会违反数据库三范式吗?
java·mysql·面试
wahahaman11 小时前
OceanBase到MySQL实时同步方案
数据库·mysql·oceanbase
山林竹笋12 小时前
数据库入门级SQL优化
数据库·sql·mysql
m0_7482313112 小时前
Node.js使用教程
node.js·编辑器·vim
soragui13 小时前
【Mysql】如何轻松管理用户和数据库
数据库·mysql
高hongyuan13 小时前
linux 系统 mysql :8.4.3 主从复制 教程及运维命令
linux·数据库·mysql·自动化