Koa+TypeScript+mysql+sequelize

本文介绍了如何使用Koa、TypeScript、mysql和sequelize搭建后台API,包括配置热启动、创建数据库模板、实现图片上传和Excel数据导入导出功能。详细步骤涵盖从项目结构配置到数据库关联、多图上传API和Excel操作的实现。
摘要由CSDN通过智能技术生成

使用koa、typescript、mysql、sequelize进行后台API开发

使用Koa与typescript、mysql、sequelize组合进行服务端api开发,主要案例有:数据库表生成,图片上传,热启动,excel表数据导入与导出

文章目录


运行命令

npm init
tsc --init

需要安装的依赖包:

// 必选npm包
yarn add koa koa-router
yarn add @types/koa @types/koa-router
yarn add mysql2 // mysql驱动
yarn add koa-logger koa-static // 请求日志与静态文件
yarn add koa-router-ts // 路由控制器
yarn add moment // 时间格式化
yarn add typescript // typescript依赖
yarn add ts-node 
yarn add nodemon dotenv // 热启动依赖
yarn add sequelize-typescript sequelize // sequelize依赖
yarn add @types/node @types/validator reflect-metadata // 使用sequelize-typescript必须
yarn add koa-bodyparser koa2-cors // 跨域与post请求解析 

// 可选npm包
yarn add koa-json // json格式
yarn add @koa/multer multer // 实现文件上传安装
yarn add uuid // 随机id
npm install bcrypt  // 密码加密
npm install jsonwebtoken // 生成token
yarn add joi // 校验

日志中间件也可以使用
yarn add koa-pino-logger

第一步 配置热启动项目

1.配置tsconfig.json文件
{
   
  "compilerOptions": {
   
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "ES6",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist" // 编译文件存放地址
  },
  "lib": ["es2015"]
}

2.创建并配置nodemon.json文件
{
   
  "watch": ["src"],
  "ignore": ["build", ".git", "node_modules"],
  "exec": "ts-node -r dotenv/config ./src/index.ts",
  "ext": "js,json,ts,tsx"
}
3.修改package.json文件配置script
"scripts": {
   
    "build": "tsc",
    "dev": "nodemon --watch",
    "start": "node ./dist/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

通过上述步骤我们就配置成功了热启动项目,能够实时监听项目修改

当我们需要本地运行开发项目时,通过运行命令:

// 本地开发运行项目
yarn dev
或

npm run dev


// 需要在服务器上运行项目,进行编译,会生成一个dist文件夹,文件夹中就是编译后的产物;然后将编译后的产物放置到服务器上进行运行即可
yarn build
或
npm run build

第二步 进行项目开发

1.在项目根目录下创建src文件夹,并分别创建其子文件夹controllers、models、services、utils、static、middleware等文件夹以及index.ts文件

constrollers: 控制器管理文件目录,用于实现路由请求api

models: 数据库模板文件目录

services: 数据库操作服务文件目录

middleware: 自定义中间件文件目录

static: 静态文件目录(img、file)

index.ts: 项目的入口文件

2.配置项目入口文件index.ts
import Koa from "koa";
import statics from "koa-static"; // 静态文件
import {
    loadControllers } from "koa-router-ts"; // 引入路由控制器
import Logger from "koa-logger"; // 日志
import moment from "moment"; // 时间格式化
import bodyParser from "koa-bodyparser"; // post请求
import path from "path";
import cors from "koa2-cors"; // 跨域处理

// init db models
import "./models"; // 加载数据库模板文件

const staticPath = "./static";  // 静态文件地址
const logger = new Logger(str => {
    // 日志时间格式化处理
  console.log(moment().format("YYYY-MM-DD HH:mm:ss") + str);
});

// 实例化koa
const app = new Koa();

// 加载中间件
app.use(bodyParser());
app.use(logger);
app.use(statics(path.join(__dirname, staticPath)));
// 实例化路由
const router = loadControllers(path.join(__dirname, "controllers"), {
   
  recurse: true,
});
// 设置路由api前缀
router.prefix("/api/v1");

app.use(router.routes()).use(router.allowedMethods());
// 设置跨域
app.use(
  cors({
   
    origin: (ctx: any) => {
   
      if (ctx.url === "/test") {
   
        return "*";
      }
      return "http:localhost:8000"; // 允许http:localhost:8000请求跨域
    },
    maxAge: 5,
    credentials: true,
    allowMethods: ["GET", "POST", "PUT", "DELETE"],
    allowHeaders: ["Content-Type", "Authorization", "Accept"],
    exposeHeaders: ["WWW-Authenticate", "Server-Authorization"],
  })
);

const PORT = process.env.PORT || 8044;
app.listen(PORT);

3.配置连接数据库以及数据库模板
首先,在models文件夹下创建index.ts文件,配置连接数据库
import {
    Sequelize } from "sequelize-typescript";

const sequelize = new Sequelize({
   
  database: "dataapi", // 数据库名称
  dialect: "mysql", // 使用的数据库类型
  username: "root", // 用户名
  password: "123456", // 密码
  port: 3306, // 端口号
  models: [`${
     __dirname}/**/*.model.ts`, `${
     __dirname}/**/*.model.js`], // 数据库模板存放地址
});

sequelize.sync({
    force: false });

// 导出相应模块
export {
    sequelize };
export {
    Sequelize };
export default sequelize.models;
其次,创建相应的数据库模板(以user模板表为例)

在models文件夹中创建user子文件夹,并在该文件夹下创建user.model.ts文件.

// 引入sequelize-typescript相关构造器
import {
    Table, Column, DataType, Model } from "sequelize-typescript";

@Table({
   
  tableName: "user_details", // 表名称
  underscored: true, // 使用下划线
  timestamps: true, // 是否自动生成创建以及更新时间字段
  indexes: [ // 索引
    {
   
      unique: false, // 是否唯一
      fields: ["name"],
    },
  ],
})
export default class UserDetails extends Model<UserDetails> {
   
  @Column({
   
    type: DataType.UUID, // 类型
    defaultValue: DataType.UUIDV4, // 默认值
    primaryKey: true, // 是否主键
  })
  id!: string; // id 字段

  @Column({
   
    type: DataType.STRING(255),
    comment: "名称", // 描述
  })
  name!: string;

  @Column({
   
    type: DataType.STRING(20),
    comment: "性别",
  })
  gender!: string;

  @Column({
   
    type: DataType.INTEGER,
    comment: "年龄",
  })
  age: number;

  @Column({
   
    comment: "出身年月",
  })
  birth_date: Date;

  @Column({
   
    type: DataType.STRING(255),
    comment: "家庭地址",
  })
  address!: string;

  @Column({
   
    type: DataType.INTEGER,
    comment: "手机号码",
  })
  phone_number: number;

  @Column({
   
    type: DataType.STRING(50),
    comment: "邮箱",
  })
  email!: string;

  @Column({
   
    type: DataType.STRING(125),
    comment: "职业",
  })
  occupation!: string;

  @Column({
   
    type: DataType.STRING(255),
    comment: "公司",
  })
  company!: string;

  @Column({
   
    type: DataType.STRING(1024),
    comment: "爱好",
  })
  hobby!: string;
}
4.根据模板创建相应服务文件操作数据库(以user模板为例)

在utils文件夹下创建response.ts文件,该文件用于实现自定义数据返回形式

// 定义接口
export interface IResponse {
   
  status: string;
  message: string;
  getHttpStatusCode(): number;
}

// 定义类SuccessResponse ,用于处理成功类型
export class SuccessResponse implements IResponse {
   
  status: string;
  message: string;
  data: any;
  constructor(data: any, message: string = "") {
   
    this.status = "ok";
    this.message = message;
    this.data = data;
  }

  /**
   * 获取 HTTP status code
   */
  public getHttpStatusCode(): number {
   
    return 200;
  }
}

// 定义类ErrorResponse,用于处理失败类型
export class ErrorResponse implements IResponse {
   
  status: string;
  message: string;
  code: number;
  constructor(message: string, code: number) {
   
    this.status = "error";
    this.message = message;
    this.code = code;
  }
  public getHttpStatusCode(): number {
   
    return this.code;
  }
}

在services文件夹下创建user子文件夹,并在该user文件夹中创建user.ts文件

// 引入自定义响应形式
import {
   
  SuccessResponse,
  ErrorResponse,
  IResponse,
} from "../../utils/response";
// 引入表模板
import UserDetails from "../../models/user/user.model";

export default class UserService {
   
  /**
   * 根据id查询
   * @param ctx ctx
   * @param id id
   */
  async findByPK(ctx: any, id: string): Promise<IResponse> {
   
    try {
   
      const result = await UserDetails.findByPk(id);
      if (!result) {
   
        return new ErrorResponse("找不到该数据", 404);
      }
      return new SuccessResponse(result, "成功获取数据");
    } catch (error) {
   
      ctx.throw(500, error.message);
    }
  }

  /**
   * 获取全部数据
   * @param ctx ctx
   */
  async findAll(ctx: any): Promise<IResponse> {
   
    try {
   
      const result = await UserDetails.findAll();
      return new SuccessResponse(result, "成功获取数据");
    } catch (error) {
   
      ctx.throw(500, error.message);
    }
  }

  /**
   * 添加数据
   * @param form 表单
   * @param ctx ctx
   */
  async create(ctx: any, form: any): Promise<IResponse> {
   
    try {
   
      const result = await UserDetails.create(form);
      return new SuccessResponse(result, "成功创建数据");
    } catch (error) {
   
      ctx.throw(500, error.message);
    }
  }

  /**
   * 更新数据
   * @param form 表单
   * @param id id
   * @param ctx ctx
   */
  async update(ctx: any, form: any, id: string): Promise<IResponse> {
   
    try {
   
      const result = await UserDetails.update(form, {
   
        where: {
   
          id,
        },
      });
      return new SuccessResponse(result, "成功更新数据");
    } catch (error) {
   
      ctx.throw(500, error.message);
    }
  }

  /**
   * 删除数据
   * @param id id
   * @param ctx ctx
   */
  async delete(ctx: any, id: string): Promise<IResponse> {
   
    try {
   
      const result = await UserDetails.destroy({
   
        where: {
   
          id,
        },
      });
      return new SuccessResponse(result, "成功删除数据");
    } catch (error) {
   
      ctx.throw(400, error.message);
    }
  }
}
5.根据服务创建相应的路由请求(以user服务为例)

在constrollers文件夹中创建user子文件夹,并在user子文件夹下创建user.ts文件

// 引入路由构造器
import {
    Controller, Post, Get, Put, Delete } from "koa-router-ts";
// 引入操作
import UserService from "../../services/user/user_details";

// 创建服务实例
const service = new U
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值