koa + sequelize 练习

权韬
2023-12-01

koa 中间件

中间件简单来说就是一个函数 自带参数 ctx,next

ctx 接收前端参数,同时可以在 ctx 上添加属性这样其他中间件都可以获取例如下方 ctx.state.userInfo
中间件逻辑处理好需要 await next(); 放行

例:验证 token
middleware/auth.js

import response from "../utils/response.js";
import { checkToken } from "../utils/token.js";
const auth = async (ctx, next) => {
  try {
    const { authorization } = ctx.request.header;
    const token = authorization.replace("Bearer ", "");
    const userInfo = checkToken(token);
    ctx.state.userInfo = userInfo;

    await next();
  } catch (error) {
    let message = "";
    switch (error.name) {
      case "TokenExpiredError":
        message = "token 过期";
        break;
      default:
        message = "token 错误";
        break;
    }
    response.error(ctx, { message, data: error });
  }
};
export { auth };

router/user.js

import { auth } from "../middleware/auth.js";

// 获取用户列表
router.get("/", auth, userController.index);

Koa 使用 es6 模块化及全局变量解决方案

使用 es6模块

package.json

{
  "type": "module"
}

遇到的问题

  • 引入文件路径要写全不能省略如 index index.js

  • 全局变量不能使用

import { fileURLToPath } from "url";
import path from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(fileURLToPath(import.meta.url));

console.log(__filename);
console.log(__dirname);

Koa 路由模块使用

下载

npm install @koa/router

使用

src/router/user.js

import KoaRouter from "@koa/router";

// 路由前缀
const router = new KoaRouter({ prefix: "/users" });
router.get("/", (ctx) => {
  ctx.body = {
    msg: "123",
  };
});

export default router;

注册

import router from "./router/user.js";

app.use(router.routes());

实现自动加载路由模块

实现了不管 router 下有多少路由文件,都可以自动导入
src/router/index.js

import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";

import KoaRouter from "@koa/router";

const router = new KoaRouter();
const __dirname = path.dirname(fileURLToPath(import.meta.url));

fs.readdirSync(__dirname).forEach(async (file) => {
  if (file !== "index.js") {
    const r = await import("./" + file);
    router.use(r.default.routes()); // require 没有 default
  }
});

export default router;

注册

import router from "./router/index.js";
app.use(router.routes()).use(router.allowedMethods());

Koa 使用 sequelize 操作 mysql 数据库

下载

npm i sequelize mysql2

链接数据库

src/db/index.js

import { Sequelize } from "sequelize";
import config from "../config/index.js";

const sequelize = new Sequelize(config.MYSQL_DB, config.MYSQL_USER, config.MYSQL_PWD, {
  host: config.MYSQL_HOST,
  dialect: "mysql",
});

// 测试连接
// (async function () {
//   try {
//     await sequelize.authenticate();
//     console.log("Connection has been established successfully.");
//   } catch (error) {
//     console.error("Unable to connect to the database:", error);
//   }
// })();

export default sequelize;

创建表结构

src/model/userModel.js

import { DataTypes } from "sequelize";

import sequelize from "../db/index.js";
import { crpytPassword } from "../utils/crypt.js";

const User = sequelize.define(
  "xr_user",
  {
    // 在这里定义模型属性
    userName: {
      type: DataTypes.STRING,
      //   不允许为 null 默认为 true
      unique: true,
      allowNull: false,
      comment: "用户名",
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
      comment: "密码",
      set(val) {
        this.setDataValue("password", crpytPassword(val));
      },
    },
    isAdmin: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: 0,
      comment: "是否为管理员 1是 0不是",
    },
  },
  {
    // 这是其他模型参数
  }
);
// 生成表
// User.sync({ alter: true });

export default User;

操作数据库

src/service/userService


import User from "../model/userModel.js";
class UserService {
  // 获取所有用户
  async findAll({ page, limit }) {
    try {
      const offset = (page - 1) * limit;
      const { count, rows } = await User.findAndCountAll({
        limit: ~~limit,
        offset,
        attributes: ["id", "userName", "isAdmin"],
      });
      return { count, rows };
    } catch (error) {
      console.error("error", error);
    }
  }
  // 查找用户
  async find(userName) {
    try {
      const res = await User.findOne({
        where: {
          userName,
        },
      });
      if (res !== null) return res?.dataValues;
      else return false;
    } catch (error) {
      console.error("error", error);
    }
  }
  // 创建用户
  async create(data) {
    try {
      const res = await User.create(data);
      // 取消 password 字段返回
      const { password, ...rest } = res?.dataValues;
      return rest;
    } catch (error) {
      console.error("error", error);
    }
  }
}
export default new UserService();

sequelize 设置器、获取器、虚拟字段使用

获取器

get/set 中使用其他属性 - this.userName

password: {
	type: DataTypes.CHAR(128),
	allowNull: false,
	comment: "密码",
	get() {
		// 获取值
		let name = this.getDataValue("password");
		return name ? name + "abc" : "zs";
	},
},

设置器

password: {
	type: DataTypes.CHAR(128),
	allowNull: false,
	comment: "密码",
	set(val) {
		// 设置值
		this.setDataValue("password", crpytPassword(val));
	},
},

虚拟字段(实际上它们不存在于数据库中)

invented: {
	type: DataTypes.VIRTUAL,
	get() {
		return `${this.userName} - ${this.password}`;
	},
},
 类似资料: