Skip to content

新建配置服务

安装依赖

shell
npm i -S dotenv
npm i -D @types/dotenv
npm install -S @hapi/joi
npm install -D @types/hapi__joi
ts
// config.service.ts
import * as dotenv from "dotenv"
import * as fs from "fs"
import * as Joi from "@hapi/joi"

const configSchema = {}

export type EnvConfig = Record<string, string>
export class ConfigService {
  private readonly envConfig: Record<string, string>
  // 配置的合并顺序
  // .env.[type].local => .env.[type] => .env
  constructor(filePath?: string) {
    if (filePath) {
      this.envConfig = dotenv.parse(fs.readFileSync(filePath))
    } else {
      // 读取默认配置 .env
      // 读取[type].env 配置
      // 读取 local.[type].env配置
      let defaultEnvConfig
      let typeEnvConfig = {}
      let localEnvConfig = {}
      try {
        defaultEnvConfig = dotenv.parse(fs.readFileSync(".env"))
        typeEnvConfig = dotenv.parse(
          fs.readFileSync(`${process.env.NODE_ENV}.env`)
        )
        localEnvConfig = dotenv.parse(
          fs.readFileSync(`local.${process.env.NODE_ENV}.env`)
        )
      } catch (err) {}
      if (!defaultEnvConfig) {
        throw new Error("默认配置文件未找到!")
      }
      this.envConfig = Object.assign(
        defaultEnvConfig,
        typeEnvConfig,
        localEnvConfig
      )
    }
    // todo
    // this.envConfig = this.validateConfig(this.envConfig);
  }
  private validateConfig(envConfig: EnvConfig): EnvConfig {
    const envVarSchema: Joi.ObjectSchema = Joi.object(configSchema)
    const { error, value: validateEnvConfig } = envVarSchema.validate(envConfig)
    if (error) {
      throw new Error("配置文件验证出错")
    }
    return validateEnvConfig
  }
  get(key: string): string {
    return this.envConfig[key]
  }
}

// config.module.ts
import { Module } from "@nestjs/common"
import { ConfigService } from "./config.service"

@Module({
  providers: [
    {
      provide: ConfigService,
      useValue: new ConfigService()
    }
  ],
  exports: [ConfigService]
})
export class ConfigModule {}

// .env
PORT = 3000

注册到全局模块

mysql typeorm 集成

安装依赖

shell
npm i -S @nestjs/typeorm typeorm mysql

mysql typeorm curd 集成

shell
npm i --save @nestjsx/crud @nestjsx/crud-typeorm class-transformer class-validator

默认情况下 module 是单列的,意味着模块中 提供者也是单列

认证

shell
npm install --save @nestjs/passport passport passport-local
npm install --save-dev @types/passport-local

JWT 功能

npm i -S @nestjs/jwt passport-jwt
npm i -S @types/passport-jwt

请求的执行顺序

客户端请求 ---> 中间件 ---> 守卫 ---> 拦截器之前 ---> 管道 ---> 控制器处理并响应 ---> 拦截器之后 ---> 过滤器

重点:在示例给出了它们的写法,注意全局管道、守卫、过滤器和拦截器,只能 new,全局中间件是纯函数,全局管道、守卫、过滤器和拦截器,中间件都不能依赖注入。中间件模块注册也不能用 new,可以依赖注入。管道、守卫、过滤器和拦截器局部注册可以使用 new 和类名,除了管道以为其他都可以依赖注入。拦截器和守卫可以写成高阶方法来传参,达到定制目的

泛型中&是啥意思

&指的是并集类型, | 指的是交集类型

别人的项目结构

main.ts 入口 main.hmr.ts 热更新入口 app.service.ts APP 服务(选择) app.module.ts APP 模块(根模块,必须) app.controller.ts APP 控制器(选择) app.controller.spec.ts APP 控制器单元测试用例(选择) config 配置模块 core 核心模块(申明过滤器、管道、拦截器、守卫、中间件、全局模块) feature 特性模块(主要业务模块) shared 共享模块(共享 mongodb、redis 封装服务、通用服务) tools

装饰器的集中写法

ts
declare type ClassDecorator = <TFunction extends Function>(
  target: TFunction
) => TFunction | void

declare type PropertyDecorator = (
  target: Object,
  propertyKey: string | symbol
) => void

declare type MethodDecorator = <T>(
  target: Object,
  propertyKey: string | symbol,
  descriptor: TypedPropertyDescriptor<T>
) => TypedPropertyDescriptor<T> | void

declare type ParameterDecorator = (
  target: Object,
  propertyKey: string | symbol,
  parameterIndex: number
) => void

动态模块中 service 如何被注册到其他动态模块上

configModule 是个动态模块, 现在需要注册到typeormModule 上面, 最好的方式直接申明全局模块

采坑记录

ConfigModule 不能读取 module 目录下的 json 配置文件

开发代码都在 src 里,生成代码在 dist (打包自动编译),typescript 打包只会编译 ts 到 dist 下,静态文件 public 和模板 views 不会移动,所以需要放到根目录下, 同理,配置 json 需要放在根目录下。

管道

安装

npm i -S class-validator class-transformer

直接在 DTO 中装饰器定义

ts
// create-cat.dto.ts
export default CreateCatDto {
  @IsString()
  readonly name: string;
}

配置管道 控制器中使用方法装饰器注入 @UsePipes(new ValidationPipe({transform: true}))

class-validator 装饰器大全

@Length @contains('text')

entity 中定义类型和装饰器相比优先级低

ts
@CreateDateColumn({ comment: '创建时间' })
createdAt: Date

@UpdateDateColumn({ comment: '更新时间' })
updatedAt: boolean   // 这样也是可以的, 最后也会被解释成 datetime 类型的