写在前面:在nest.js中,底层服务被封装在service里,我们需要在controller中调用它们,但是在此之前为了做控制反转,我们需要先使用module把依赖收集起来并提供给controller,最后在controller中注册(注入)依赖供后续调用。
自定义依赖名称
先来看一个基本的使用语法糖的例子(没有自定义依赖名称):
import { UserService } from './user.service';
@Module({
controllers: [UserController],
providers: [UserService] // 依赖在这里提供
})
// 不需要额外import
@Controller('user')
export class UserController {
/* 依赖在这一行注入,由于使用的是语法糖,直接写成userService:UserService的形式就行了,无需@Inject() */
constructor(private readonly userService: UserService) {}
// 以下代码不重要不用管
@Get()
findAll() {
return this.userService.findAll();
}
}
但其实,module.ts里的provide的原始写法是这样子的
@Module({
controllers: [UserController],
/* 这里的写法变了 */
providers: [
{
provide: 'xiaoman',
useClass: UserService,
},
],
})
在这种写法下,controller.ts里构造器注入的依赖需要多加一个@Inject()装饰器,字符串的内容就是provider的内容
@Controller('user')
export class UserController {
constructor(@Inject('xiaoman') private readonly userService: UserService) {}
@Get()
findAll() {
return this.userService.findAll();
}
}
自定义注入值
除了自定义依赖外,我们也可以自定义注入值,这在所有服务都需要依赖同一个值的时候非常好用
@Module({
controllers: [UserController],
providers: [
{
provide:'JD',
useValue:['JD','TB']
}
],
})
同样的,这个依赖需要被注入到controllers.ts中
@Controller('user')
export class UserController {
constructor(
// 使用Inject()装饰器注入对应的值
@Inject('JD') private shopList: string[],
) {}
@Get()
findAll() {
return this.shopList;
}
}
工厂模式
如果服务间存在依赖,可以使用工厂模式
import { UserService3 } from './user.service3';
@Module({
controllers: [UserController],
providers: [
{
provide: 'xiaoman',
useClass: UserService,
},
{
provide: 'Test',
// 必须要先inject才能将依赖写进useFactory
inject: ["xiaoman"],
useFactory(UserService:UserService){
// 在这里将依赖传给UserService3的构造函数
return new UserService3(UserService)
}
},
],
})
import { Inject, Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Injectable()
export class UserService3 {
/* 注入Test依赖 */
constructor(@Inject('Test') private readonly test){}
create(createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
findAll() {
// 调用依赖中的方法
return this.test.findAll();
}
findOne(id: number) {
return `This action returns a #${id} user`;
}
update(id: number, updateUserDto: UpdateUserDto) {
return `This action updates a #${id} user`;
}
remove(id: number) {
return `This action removes a #${id} user`;
}
}
import { UserService3 } from './user.service3';
@Controller('user')
export class UserController {
constructor(
// 注入Test依赖,这个依赖的本质是注入了UserService服务的UserService3的实例对象
@Inject('Test') private test: UserService3,
) {}
@Get()
findAll() {
return this.test.findAll();
}
}
异步工厂模式
useFactory支持异步模式
@Module({
controllers: [UserController],
providers: [
// 准备注入Test的依赖
{
provide: 'xiaoman',
useClass: UserService,
},
// 注入controller的依赖
{
provide: 'Test',
inject: ['xiaoman'],
// 此处使用异步逻辑。注意返回的内容是一段字符串,因此没有方法
async useFactory(UserService: UserService) {
return await new Promise((r) => {
setTimeout(() => {
r(UserService.findAll());
},2000);
});
},
},
],
})
将依赖注入controller与前端交互
@Controller('user')
export class UserController {
constructor(
@Inject('Test') private test: UserService,
) {}
@Get()
findAll() {
return this.test;
}
}
以上,当我们刷新页面后,过两秒钟页面才会更新
怎样?是不是感到非常懵逼?没关系,我们来理清一下service、module和controller之间的关系
- Service:提供底层Web服务(类),是方法的实际提供者,拥有装饰器@Injectable
- Module:将服务类从Service中导入(需要import),实例化后将其提供给controller。在IOC体系中充当中间管理者,拥有装饰器@Module
- Controller:一切服务在此调用(不需要import,只要用@Inject()注入依赖即可使用),前端访问接口返回什么内容全部在此处决定,需要注意的是如果在Module里使用语法糖模式则无需额外@Inject()