依赖注入

  • 官方文档

  • 依赖注入是一种设计模式,它可以帮助我们更好地管理这些对象之间的依赖关系。在 NestJS 中,我们可以使用依赖注入来自动创建和管理这些对象。我们只需要告诉 NestJS 我们需要哪些对象,它就会自动创建它们并将它们传递给需要它们的对象。通俗点讲,例如类,我们无需自己手动的去实例化某一个类,我们只需要告诉module层我们需要用到哪一个类即可(在module层中使用provider对外提供),随后在controller的构造函数中使用装饰符@Inject注入即可使用

源代码如下

  • 下面使用了三种依赖注入的例子,包括函数,变量以及
// module层
import { Module } from '@nestjs/common';
import { BoysController } from './boys.controller';
import { BoysService } from './boys.service';
import { TypeOrmModule } from '@nestjs/typeorm'; // 引入 TypeOrmModule 操作实体
import { Boys } from './entities/boys.entities'; // 引入我们刚刚新建的实体

@Module({
imports: [TypeOrmModule.forFeature([Boys])], // 使用方法操作实体
controllers: [BoysController],
// 提供者:provider 依赖注入
/*
我们可以发现,service层是以类的形式创建服务并在其内部编写业务逻辑的,
但是我们在controller层中使用并没有实例化service中的那个类便可以直接使用
了,这就是依赖注入,依赖注入可以减少我们实例化对象的代码,让我们专注于业务
逻辑的编写,实例化那一部分则由module层中的provider帮我们编写
*/
providers: [
// 依赖注入完整写法
// BoysService 简写形式 直接写如即可
{
provide: 'boys', //依赖名称(可以自定义)
useClass: BoysService, // 使用到的类
},

// 当然还可以写入其他类型的依赖,例如数组,字符串等
{
provide: 'boysArr',
useValue: ['小龙', '小虎', '小熊'],
},

// 还可以定义方法
{
provide: 'sayHello',
useFactory: () => {
console.log('hello nest!');
return 'hello nest!'
},
},
],
})
export class BoysModule {}
// service层 (业务逻辑的编写)
import { Injectable } from '@nestjs/common';

/*
操作数据库引入模块
1. Repository 在typeorm中引入可操作数据库实体的方法
2. InjectRepository 注入仓库,将实体中的数据注入到数据库仓库中去
3. 我们新建的实体,一一对应数据库中的数据
*/
import { Like, Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { Boys } from './entities/boys.entities';

// 设置接口限制传参数据
interface Person {
id: number;
name: string;
age: number;
}

@Injectable()
export class BoysService {
// 注入依赖以及绑定实体数据库
constructor(
// 基本是固定写法
@InjectRepository(Boys) private readonly boys: Repository<Boys>,
) {}

/* ---------- 业务逻辑的编写 ------------- */
}
// controller(路由编写层以及依赖的使用层)
// 引入请求方法以及请求参数修饰符等
import {
Controller,
Get,
Inject,
} from '@nestjs/common';
import { BoysService } from './boys.service';

/*
我们可以认为 Controller 是用户配置路由的地方
根据以下代码我们如果想要获取数据就需要输入路径为: /boys/getBoys
当然我们要想在全局中设置初识路径,可以在main.ts中设置 setGlobalPrefix('全局路径')
*/
@Controller('boys')
export class BoysController {
// 创建一个构造函数 (注入依赖)
constructor(
// 注入service依赖
@Inject('boys') private BoysService: BoysService,

// 注入其他依赖 例如数组
@Inject('boysArr') private boysArr: string[],

// 输入其他依赖 例如函数
@Inject('sayHello') private sayHello: string,
) {
/*
BoysService: BoysService 等价于 this.BoysService = new BoysService()
*/
}

@Get()
getBoys(): any {
// 直接请求依赖中的数据(使用注入的依赖)
return this.boysArr; // 依赖注入为数据
// return this.sayHello; // 依赖注入为函数
}
/*.... 其他接口的编写 ....*/
}

中间件的使用

  • nestjs中的中间件与express中的中间件非常的相似,在我做的项目以来,最常用的还是用于登录鉴权的校验,tokne的解析校验等..

  • 官方文档

  • 中间件是在路由处理程序 之前 调用的函数。 中间件函数可以访问请求和响应对象,以及应用程序请求响应周期中的 next() 中间件函数。 next() 中间件函数通常由名为 next 的变量表示。

image

局部中间件

  • 顾名思义,局部中间件是在对应模块下使用的中间件,能够在用户访问对应的请求URL路径时实现拦截操作

官方推荐使用命令行的形式去创建局部中间件

创建局部中间件

nest g mi middleWare_name

生成的中间件文件夹下的中间件文件

// middleWare.ts
import { Injectable, NestMiddleware } from '@nestjs/common';

@Injectable()
export class MyMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
//编写拦截的业务逻辑
console.log('已进入局部中间件,开始执行业务逻辑...');
next();// 逻辑完成后放行
}
}

在对应的module中使用局部中间件

// module层
import {
Module,
NestModule,
MiddlewareConsumer,
RequestMethod,
} from '@nestjs/common';
import { BoysController } from './boys.controller';
import { BoysService } from './boys.service';
import { TypeOrmModule } from '@nestjs/typeorm'; // 引入 TypeOrmModule 操作实体
import { Boys } from './entities/boys.entities'; // 引入我们刚刚新建的实体
import { MyMiddleware } from '../middle-ware/my_/my_.middleware';// 引入中间件

@Module({
imports: [TypeOrmModule.forFeature([Boys])], // 使用方法操作实体
controllers: [BoysController],
// 提供者:provider 依赖注入
/*
我们可以发现,service层是以类的形式创建服务并在其内部编写业务逻辑的,
但是我们在controller层中使用并没有实例化service中的那个类便可以直接使用
了,这就是依赖注入,依赖注入可以减少我们实例化对象的代码,让我们专注于业务
逻辑的编写,实例化那一部分则由module层中的provider帮我们编写
*/
providers: [
// 依赖注入完整写法
// BoysService 简写形式 直接写如即可
{
provide: 'boys', //依赖名称(可以自定义)
useClass: BoysService, // 使用到的类
},

// 当然还可以写入其他类型的依赖,例如数组,字符串等
{
provide: 'boysArr',
useValue: ['小龙', '小虎', '小熊'],
},

// 还可以定义方法
{
provide: 'sayHello',
useFactory: () => {
console.log('hello nest!');
return 'hello nest!';
},
},
],
})

/* -------------- 导出时配置该模块的局部中间件 ---------------- */
export class BoysModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// 可以指定请求url中包含的路径以及请求方法
consumer
.apply(MyMiddleware)// 绑定的中间件
// .forRoutes('boys');// 单纯指定请求路径
.forRoutes({ path: 'boys', method: RequestMethod.GET }); // 指定请求路径以及方法
}
}

中间件层

// middleWare
import { Injectable, NestMiddleware } from '@nestjs/common';

/*
下面提供中间件的两种写法,两种写法实现的效果均是一致的
*/

// 类中间件
@Injectable()
export class MyMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
//编写拦截的业务逻辑
console.log('已进入局部中间件,开始执行业务逻辑...');
/*
可以使用res.send()想用户网页发送数据等...
*/
next(); // 逻辑完成后放行
}
}

// 函数式中间件
// export function MyMiddleware(req, res, next) {
// console.log('已进入局部中间件,开始执行业务逻辑...');
// next();
// }

结果展示

image

全局中间件

  • 全局中间件的编写就比局部中间件的编写简单一点,我们直接进入到main.ts(全局的模块引用文件)中编写即可
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

// 创建全局中间件
const allMiddleWare = (req: any, res: any, next: any): any => {
console.log('已进入全局中间件...开始执行业务逻辑');
next();
};

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(allMiddleWare); //使用全局中间件
app.setGlobalPrefix('api'); //设置全局访问路径前缀
await app.listen(3000);
}
bootstrap();

结果展示:

image

第三方中间件的使用

  • 第三方中间件的使用方法也非常的简单,与全局中间件的使用方法是比较一致的,这里我们使用cors中间件来解决跨域请求(当然官方文档中也有解决跨域的方法)

安装第三方插件

npm i cors
npm install @types/cors -D

main.ts中使用第三方插件

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cors from 'cors'; // 引入第三方插件(实现跨域请求)

// 创建全局中间件
const allMiddleWare = (req: any, res: any, next: any): any => {
console.log('已进入全局中间件...开始执行业务逻辑');
next();
};

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(cors()); // 使用第三方插件

// 官方的配置跨域方法
// app.enableCors({
// origin: '*', // 配置全部请求可以跨域
// optionsSuccessStatus: 200, // 成功码
// });
app.use(allMiddleWare); //使用全局中间件
app.setGlobalPrefix('api'); //设置全局访问路径前缀
await app.listen(3000);
}
bootstrap();

结果展示:

image

拓展一下官方的配置请求跨域的方法

  • 官方文档

  • 跨源资源共享(CORS)是一种允许从另一个域请求资源的机制。在底层,Nest 使用了 Express 的cors 包,它提供了一系列选项,您可以根据自己的要求进行自定义。

  • 配置Configuration

// 常用配置 - 直接在main.ts中配置即可
app.enableCors({
origin: '*', // 配置全部请求可以跨域
optionsSuccessStatus: 200, // 成功码
});