跳到主要内容

基础

  • 文档:https://midwayjs.org/
  • 默认选用 EggJS 作为我们的 Web 框架,也可以使用 Express 或者 Koa。

目录结构​

  • src
    • app.ts 和 agent.ts 用于自定义启动时的初始化工作
      • app.ts : EggJS 扩展 Worker 生命周期文件(可选)
      • agent.ts: EggJS 扩展 Agent 生命周期文件(可选)
    • app文件夹
      • EggJS 固定的根目录(可选 )
    • config 文件夹
      • 配置文件

Controller 控制器​

  • 在常见的 MVC 架构中,C 即代表控制器,控制器用于负责解析用户的输入,处理后返回相应的结果。
js
//路由前缀
@Controller('/')
  • @Controller() 装饰器标注控制器,其中装饰器有一个可选参数,用于进行路由前缀(分组),这样这个控制器下面的所有路由都会带上这个前缀。

路由​

控制器文件一般来说在 src/controller 目录中,我们可以在其中创建控制器文件。Midway 使用 @Controller() 装饰器标注控制器,其中装饰器有一个可选参数,用于进行路由前缀(分组),这样这个控制器下面的所有路由都会带上这个前缀。

service 服务​

  • 用来编写业务逻辑

使用服务​

  • 在controller控制器中来调用某个服务

  • 只需在controller中利用依赖注入 装饰器 很方便的来调用服务

    • 使用 @Provide 装饰器暴露你的服务

    • 使用 @Inject 装饰器注入你的服务到属性上

理解IOC容器​

ioc表示为控制反转

  • 控制 :指的是对象创建(实例化、管理)的权力
  • 反转 :控制权交给外部环境(IoC 容器)
  • @Provide() ,作用就是暴露IoC id ,能被 IoC容器 扫描到

    • 暴露一个 class,让 IoC 容器能够获取元数据
  • @Inject,作用是注入一个IoC容器的对象

  • providerWrapper 函数作用来包裹一个函数,并且指定提供的 key,供其他 IoC 对象使用,否则其他ioc对象无法使用

依赖注入​

@Provide 的作用是告诉 依赖注入容器,我需要被容器所加载。 @Inject 装饰器告诉容器,我需要将某个实例注入到属性上。

  • 通过这两个装饰器的搭配,我们可以方便的在任意类中拿到实例对象

@Provide 和 @Inject 装饰器是有可选参数的,并且他们是成对出现。

Midway 的核心 “依赖注入” 容器会自动关联你的控制器(Controller) 和服务(Service),在运行过程中会自动初始化所有的代码,你无需手动初始化这些 Class

@Provide 装饰器的作用:

  • 1、这个 Class,被依赖注入容器托管,会自动被实例化(new)
  • 2、这个 Class,可以被其他在容器中的 Class 注入

而对应的 @Inject 装饰器,作用为:

  • 1、在依赖注入容器中,找到对应的属性名,并赋值为对应的实例化对象

@Inject 的类中,必须有 @Provide 才会生效。

默认情况下:

  • 1、 @Provide 取 类名的驼峰字符串 作为依赖注入标识符
  • 2、 @Inject 根据 规则 获取 key

规则如下:

  • 1、如果装饰器包含参数,则以 参数字符串 作为 key
  • 2、如果没有参数,标注的 TS 类型为 Class,则将类 @Provide 的 key 作为 key
  • 3、如果没有参数,标注的 TS 类型为非 Class,则将 属性名 作为 key

getAsync​

  • MidwayContainer 有 getAsync 方法用来异步处理对象的初始化 (很多依赖都是有异步初始化的需求)
    • 初始化sequelize
  • app.applicationContext 用于全局作用域的 IoC 容器,所有的单例对象都存放于该属性,可以从中获取到单例对象。
js
await app.applicationContext.getAsync('xxx')

动态函数注入​

在某些场景下,我们需要函数作为某个逻辑动态执行,而 IoC 中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。

比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个函数,并且在函数中拿到上下文

  • midway 通过 providerWrapper 函数来包裹一个函数,并且指定提供的 key,供其他 IoC 对象使用

  • 通过 providerWrapper 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理

  • providerWrapper 来暴露方法, 注意这个方法要被export导出,否则midway是无法识别这个工厂函数

    • 注意,动态方法必须 export,才会被依赖注入扫描到,默认为请求作用域(获取的 Container 是请求作用域容器)。

请求和响应 (Context)和应用(application)​

所有的上层框架导出 请求和响应(Context)和 应用(Application)定义,我们都保持一致。即 Context 和 Application 。

生命周期​

Midway 的生命周期是通过 src/configuration.ts 文件,实现 ILifeCycle 接口,就可以在应用 ready 的时候处理这类需求。

方法拦截器(切面)​

  • 拦截器一般会放在 src/aspect 目录
  • 在继承的情况下,拦截器不会对父类的方法生效。

切面很强大的功能,场景

  • 校验、鉴权

比如,修改入参,我们只需要简单做个拦截,然后修改即可。

js
// src/controller/home.ts
export class HomeController {

@Get('/')
async home(data1, data2) {
return data1 + data2; // 因为拦截了方法,这里的返回值是 3
}
}

// src/aspect/
@Provide()
@Aspect(HomeController, 'home') // 这里只对 home 方法做拦截
export class ReportInfo implements IMethodAspect {
async before(point: JoinPoint) {
console.log(point.args); // 这里因为对 Controller 方法做切面,原本的参数为 [ctx, next]
point.args = [1, 2]; // 修改入参
}
}

参数校验和转换​

文档:https://www.yuque.com/midwayjs/midway_v2/validate

方法调用时执行一些类型检查,参数转换的操作,Midway 提供了 @Validate 和 @Rule 装饰器,用来快速定义校验的规则,帮助用户减少这些重复的代码

  • 最常用参数校验的地方是 控制器(Controller),同时你也可以在任意的 Class 中使用这个能力。

定义检查规则​

利用@Rule装饰器

  • @Rule 装饰器用于 修饰需要被校验的属性,它的参数为 RuleType 对象提供的校验规则的链式方法。
js
import { Rule, RuleType } from "@midwayjs/decorator";

export class UserDTO {
@Rule(RuleType.number().required())
id: number;
}
  • 这里的 RuleType 即为 joi 对象本身。
    • joi是校验库

开启检验能力​

利用@Validate装饰器

  • 开启校验能力还需要 @Validate 装饰器

日志​

@midwayjs/logger 包导出的方法,可以方便的接入不同场景的日志系统

  • Midway 的日志系统基于社区的 winston

文件上传​

egg框架内置了 Multipart 插件:

  • 解析浏览器上传的 multipart/form-data 的数据。
  • 提供 file 和 stream 两种处理接口模式供开发者选择。
    • file模式:适合简单的文件上传,前端传来的图片存到服务器
    • stream模式:适合对文件进行进一步的处理,如压缩,解压等
  • 默认提供了安全的限制。

获取到用户上传的数据后,开发者可以:

上传/接受文件​

前端

  • 表单使用formData对象
    • formData:表示表单数据的键值对key/value的形式提交到后台

后台

file模式:

  • 单个文件 可使用ctx.request.files[0]获取

  • 多个文件,ctx.request.files 属性进行遍历,然后分别进行处理

stream模式

  • ctx.getFileStream() 接口能获取到上传的文件流。
  • 要通过 ctx.getFileStream 便捷的获取到用户上传的文件,需要满足两个条件:
    • 只支持上传一个文件。
    • 上传文件必须在所有其他的 fields 后面,否则在拿到文件流时可能还获取不到 fields。

定时任务​

生成excel​

extend 扩展​

  • 在src/extend文件夹扩展
    • application.tx
    • context.tx
    • request.tx
    • response.tx
  • 增加扩展定于之后,需要在 src/interface.ts 中扩展增加的 扩展的 属性

数据库​

  • 插件是 EggJS 的特色之一,Midway 也支持 EggJS 的插件体系。
text
npm i egg-mysql --save

src/config/plugin.js 中声明开启

js
import { EggPlugin } from 'egg';
export default {
static: false, // default is true
mysql: {
enable: true,
package: 'egg-mysql'
}
} as EggPlugin;

ORM​

TypeORM​

参考:https://www.yuque.com/midwayjs/midway_v2/orm

sequelize​

中文: https://www.sequelize.com.cn/

官方: https://www.sequelize.com.cn/

sequelize-cli​
  • 迁移来跟踪对数据库的更改
  • 现有数据库转移到另一个状态
    • 这些状态转换保存在迁移文件中,这些文件描述如何进入新状态以及如何还原更改以返回旧状态
sequelize-typescript​
reflect-metadata​
  • Reflect Metadata 是 ES7 的一个提案,它主要用来在声明的时候添加和读取元数据