koa结构化开发

2024年 1月 24日 48.3k 0

1.1项目结构

index.png

1.2 babel环境配置

下载

yarn add @babel/cli @babel/core @babel/node @babel/preset-env babel-loader babel-plugin-module-resolver -D

配置

{
    "presets": ["@babel/preset-env"],
    "plugins": [
      ["module-resolver", {
        "root": ["./src"],
        "alias": {
          "@": "./src"
        }
      }]
    ]
  }
  

1.3webpack打包配置

下载

yarn add webpack-cli webpack webpack-dev-middleware webpack-hot-middleware webpack-merge

配置

根目录下新建webpack.common.js,webpack.pro.js,webpack.dev.js

拆分webpack

分公共,生产,开发不同环境打包配置

image.png
配置代码

公共配置

const path = require('path');
const webpack = require('webpack');
module.exports = {
  target: 'node',
  entry: './src/app.js',
  output: {
    path: path.resolve(__dirname, 'dist/js'),
    filename: '[name].[contenthash].js',
    clean: true,
  },
  mode: "production",
  resolve:{
    alias:{
      extensions: ['.js', '.json'],
    //@符号表示 src 这一层目录
    '@': path.resolve(__dirname, './src')
    }
  },
  module: {
    rules: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  externals: {
    'sequelize':"require('sequelize')"
  },
  resolve: {
    extensions: ['.js'],
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
    },
    minimize: true,
  },
  plugins: [
    new webpack.ProgressPlugin(),
  ],

};

开发环境

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common');

module.exports = merge(commonConfig, {
  mode: 'development',
});

生产环境

const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common');

module.exports = merge(commonConfig, {
  mode: 'production',
});

1.4package.json配置

{
  "name": "koa_service",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon --watch @/ --exec babel-node ./src/app.js",
    "build": "webpack --config ./build/webpack.prod.js && xcopy .env dist && xcopy ecosystem.config.js dist",
    "build:dev": "webpack --config ./build/webpack.dev.js && xcopy .env dist && xcopy ecosystem.config.js dist"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/cli": "^7.23.4",
    "@babel/core": "^7.23.7",
    "@babel/node": "^7.22.19",
    "@babel/preset-env": "^7.23.8",
    "babel-loader": "^9.1.3",
    "babel-plugin-module-resolver": "^5.0.0",
    "dotenv": "^16.3.1",
    "fs": "^0.0.1-security",
    "koa": "^2.14.2",
    "koa-bodyparser": "^4.4.1",
    "koa-cors": "^0.0.16",
    "koa-ip": "^2.1.3",
    "koa-router": "^12.0.1",
    "mysql2": "^3.6.3",
    "sequelize": "^6.35.0",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-middleware": "^6.1.1",
    "webpack-hot-middleware": "^2.25.4",
    "webpack-merge": "^5.10.0"
  },
  "devDependencies": {
    "@babel/plugin-transform-runtime": "^7.23.7",
    "@babel/runtime": "^7.23.8",
    "nodemon": "^3.0.1"
  }
}

2.配置koa

2.1安装 Koa 框架

yarn add koa

2.2 编写入口文件

const Koa = require('koa')

const app = new Koa()

app.use((ctx, next) => {
  ctx.body = 'ws'
})

app.listen(3000, () => {
  console.log('server is running on http://localhost:3000')
})

2.3使用nodemon

安装nodemon

yarn add nodemon -D

配置nodemon

{
  "name": "koa_service",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "nodemon ./src/app.js",
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "koa": "^2.14.2",
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}

nodemon使用成功

image.png

2.4解析body参数

安装koa-bodyparser

yarn add koa-bodyparser

在app/index.js入口配置文件注册

const koa = require("koa");
const app = new koa();
// 处理post参数解析中间件
app.use(bodyParser());
module.exports = app;

2.5解决跨域

安装koa-cors

yarn add koa-cors

const Koa = require("koa");
const cors = require("koa-cors");
const app = new Koa();
//处理跨域问题中间件
app.use(cors());

2.6获取ip

安装koa-ip

yarn add koa-ip

配置

/*
 * @Description:
 * @Author: Wang Su
 * @Date: 2023-09-16 23:31:37
 * @LastEditors: Wang Su
 * @LastEditTime: 2023-09-21 14:36:46
 */
const Koa = require("koa");
const ip = require("koa-ip");
//获取用户ip的中间件
app.use(
  ip({
    checkProxyHeaders: true, // 选项示例
  })
);

const port = 19001;
app.listen(port, () => {
  console.log(`19001端口服务启用`);
});

3.config配置层

3.1根目录新建.env文件

# 后端服务端口号
APP_PORT=19801
# 数据库主机
MYSQL_HOST="localhost"
# 数据库端口号
MYSQL_PORT=3306
# 数据库用户名
MYSQL_USERNAME="root"
# 数据库的密码
MYSQL_PASSWORD="123456"
# 连接数据库连接名
MYSQL_DB="koa"

3.2使用dotenv

安装dotenv

yarn add dotenv 

配置dotenv

const dotenv=require("dotenv")
dotenv.config()
module.exports=process.env

在入口文件引入config.default.js

const {APP_PORT}=require("./config/config.default.js")
const app =require("./app/index.js")
app.listen(APP_PORT,()=>{
    console.log(`服务启动成功:http://localhost:${APP_PORT}`);
})

4.app启动层

4.1app入口文件

const {APP_PORT}=require("./config/config.default.js")
const app =require("./app/index.js")
app.listen(APP_PORT,()=>{
    console.log(`服务启动成功:http://localhost:${APP_PORT}`);
})

4.2app配置文件

const koa = require("koa");
const bodyParser = require("koa-bodyparser");
const errHandle = require("./err.handle");
const userRouter = require("../router/users");

const app = new koa();

// 处理post参数解析中间件
app.use(bodyParser());
app.use(userRouter.routes()).use(userRouter.allowedMethods());

//错误处理
app.on("error", errHandle);
module.exports = app;

5.router路由层

image.png

5.1新增路由中间件

const koa = require("koa");
const userRouter = require("../router/users");
const app = new koa();
app.use(userRouter.routes()).use(userRouter.allowedMethods());

5.2路由层配置

根据功能划分路由层

const Router=require("koa-router")
const {userValidator,usernameValidator}=require("../../middlewares/users.middleware")
const router=new Router({prefix:"/users"})

const {regiest}=require("../../controller/users/index")

router.post("/regiest",userValidator,usernameValidator,regiest)


module.exports=router

image.png

6.controller业务控制层

处理对应路由的业务逻辑实现

image.png

6.1路由层注册controller层服务

const Router=require("koa-router")
const {userValidator,usernameValidator}=require("../../middlewares/users.middleware")
const router=new Router({prefix:"/users"})
//这里注册业务层代码
const {regiest}=require("../../controller/users/index")

router.post("/regiest",userValidator,usernameValidator,regiest)


module.exports=router

6.2controller代码实现

const { createUser } = require("../../service/user/index");
class UseController {
  //用户注册逻辑
  async regiest(ctx, next) {
    //获取前端传入结果
    const { user_name, password } = ctx.request.body;
    //操作数据库
    const res = await createUser(user_name, password);
    //返回给前端结果
    ctx.body = {
      code: 0,
      message: "用户注册成功",
      result: {
        id: res.id,
        user_name: res.user_name,
      },
    };
  }
}

module.exports = new UseController();


7.service服务层

image.png

7.1控制层注册服务层

下面的createUser方法来源于服务层

const { createUser } = require("../../service/user/index");
class UseController {
  //注册逻辑
  async regiest(ctx, next) {
    //获取前端传入结果
    const { user_name, password } = ctx.request.body;
    //操作数据库,
    const res = await createUser(user_name, password);
    //返回给前端结果
    ctx.body = {
      code: 0,
      message: "用户注册成功",
      result: {
        id: res.id,
        user_name: res.user_name,
      },
    };
  }
}

module.exports = new UseController();

7.2服务层代码实现

const User = require("../../model/users/index");

class UserService {
  //创建,使用async,数据库操作是异步的
  async createUser(user_name, password) {
    try {
      const res = await User.create({
        user_name,
        password,
      });
      return res.dataValues;
    } catch (error) {
      return error;
    }
  }
  // 根据任意字段查询
  async getUserInfo({id, user_name, password, is_admin}) {
    try {
      const whereOpt = {};
      id && Object.assign(whereOpt, { id });
      user_name && Object.assign(whereOpt, { user_name });
      password && Object.assign(whereOpt, { password });
      is_admin && Object.assign(whereOpt, { is_admin });
      console.log(whereOpt,'whereOpt');
      const res = await User.findOne({
        attributes: ["id", "user_name", "password", "is_admin"],
        where: whereOpt,
      });
      return res ? res.dataValues : null;
    } catch (error) {
      return error;
    }
  }
}

module.exports = new UserService();

8.DB数据层

8.1集成sequlize

官网
Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。
Sequelize 遵从 语义版本控制。 支持 Node v10 及更高版本以便使用 ES6 功能。
请通过 Getting started - 入门 来学习更多相关内容. 如果你想要学习 Sequelize API 请通过 API 参考 (英文)。
image.png
ORM: 对象关系映射

  • 数据表映射(对应)一个类
  • 数据表中的数据行(记录)对应一个对象
  • 数据表字段对应对象的属性
  • 数据表的操作对应对象的方法

8.2安装mysql和 sequelize

yarn add mysql2 sequelize

8.3连接mysql数据库

image.png

const { Sequelize } = require("sequelize");
//连接数据库
const {
  MYSQL_HOST,
  MYSQL_PORT,
  MYSQL_USERNAME,
  MYSQL_PASSWORD,
  MYSQL_DB,
} = require("../config/config.default.js");
const seq = new Sequelize(MYSQL_DB, MYSQL_USERNAME, MYSQL_PASSWORD, {
  host: MYSQL_HOST,
  port: MYSQL_PORT,
  dialect: "mysql",

});
//检测数据库是否连接成功
seq
  .authenticate()
  .then((res) => {
    console.log("数据库连接成功");
  })
  .catch((err) => {
    console.log("数据库连接失败");
  });

module.exports = seq;

9.model模型层

image.png

9.1服务层注册模型层

image.png

9.2模型层代码实现,引入数据层

const { Sequelize, DataTypes } = require("sequelize");
const seq = require("../../db/seq");

const User = seq.define(
  "iotUser",
  {
    // 在这里定义模型属性
    user_name: {
      type: DataTypes.STRING,
      unique: true,
      allowNull: false,
      comment: "用户名,唯一",
    },
    password: {
      type: DataTypes.CHAR(64),
      allowNull: false,
      comment: "密码",
    },
    is_admin: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: 0,
      comment: "是否是管理员,0不是,1是",
    },
  },
  {
    // 这是其他模型参数
    tableName: "iot_users",
  }
);

//如果数据库没有这张表会强制创建
User.sync();


module.exports=User

10.middlewares中间件层

10.1路由层引入

const Router=require("koa-router")
const {userValidator,usernameValidator}=require("../../middlewares/users.middleware")
const router=new Router({prefix:"/users"})

const {regiest}=require("../../controller/users/index")

router.post("/regiest",userValidator,usernameValidator,regiest)


module.exports=router

image.png

10.2代码实现

const { getUserInfo } = require("../service/user/index");
const { userFormateError, userAlreadyExit } = require("../constant/err.type");
const userValidator = async (ctx, next) => {
  const { user_name, password } = ctx.request.body;
  if (!user_name || !password) {
    ctx.app.emit("error", userFormateError, ctx);
    return;
  }
  await next();
};

const usernameValidator = async (ctx, next) => {
  const { user_name } = ctx.request.body;
  if (await getUserInfo({ user_name })) {
    ctx.app.emit("error", userAlreadyExit, ctx);
    return;
  }
  await next();
};
module.exports = {
  userValidator,
  usernameValidator,
};

10.3公共错误处理

定义错误类型字典

module.exports = {
  userFormateError: {
    code: "1001",
    message: "用户名密码为空",
    result: [],
  },
  userAlreadyExit: {
    code: "1002",
    message: "用户已存在",
    result: [],
  },
};

错误映射表,映射状态码

module.exports = (err, ctx) => {
  let status = 500;
  switch (err.code) {
    case "1001":
      status = 400;
      break;
    case "1002":
      status = 401;
      break;
    default:
      status = 500;
      break;
  }
  ctx.status=status;
  ctx.body=err
};

全局注册错误处理中间件

const koa = require("koa");
const bodyParser = require("koa-bodyparser");
const errHandle = require("./err.handle");
const userRouter = require("../router/users");

const app = new koa();

// 处理post参数解析中间件
app.use(bodyParser());
app.use(userRouter.routes()).use(userRouter.allowedMethods());

//错误处理
app.on("error", errHandle);
module.exports = app;

image.png

用户已存在

image.png

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论