新建项目
新建Nest项目可以通过以下两条命令:
npm i -g @nestjs/cli
nest new project-name
首先,我们在终端执行npm i -g @nestjs/cli,全局安装Nest的脚手架nestjs/cli。
接着,我们随便选择一个位置,打开终端后继续执行nest new project-name,这里的project-name可以输入你建的nest项目名称,这里我的项目名称是demo1。之后选择完包管理器,回车!等待依赖安装完毕后,我们的第一个Nest项目就装好了。
通过命令cd demo1进入项目后,执行npm run start,即可成功启动Nest服务:
然后打开浏览器,访问localhost:3000,即可看到Nest服务的响应结果:
到这一步后,恭喜你,你已经成功创建了一个后端的服务。至此,后端的大门正式为你打开!
目录结构和流程梳理
创建的项目会具有以下的目录:
demo1
┣━━ src
┃ ┣━━ app.controller.spec.ts
┃ ┣━━ app.controller.ts
┃ ┣━━ app.module.ts
┃ ┣━━ app.service.ts
┃ ┗━━ main.ts
┣━━ .eslintrc.js
┣━━ .gitignore
┣━━ .prettierrc
┣━━ .nest-cli.json
┣━━ package.json
┣━━ pnpm-lock.yaml
┣━━ README.md
┣━━ tsconfig.build.json
┗━━ tsconfig.json
我们着重了解Nest项目独有的,也就是根目录下的.nest-cli.json文件和src里的文件。
配置文件.nest-cli.json
在.nest-cli.json里有如下内容:
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
这是一个json配置的对象,首先$schema字段是个JSON Schema文件的地址,可以用来验证本JSON 文件是否符合预期的格式和规范。我们可以复制它的值到浏览器里,里面会有每个字段的详细解释。
其次collection字段指定了schematic 集合,这种集合是一种集合了多种自动化任务的schema形式工具集。这里使用了 @nestjs/schematics,表示使用Nest.js 的 schematics 集合来生成代码和配置项目。我们可以通过执行npm show @nestjs/schematics --json查看具体信息。
接着是sourceRoot,它指定了项目源代码的根目录,默认是src。
最后是compilerOptions,它是一个编译选项集合的对象,这里声明的deleteOutDir属性的值为true,表示每次删掉之前的编译目录。而编译目录的位置就在根目录下的tsconfig.json文件的outDir字段里指定。
src目录
src目录下有五个文件,我们详细说下前面四个文件的含义和作用。
| 文件名 | 含义 |
|---|---|
main.ts | 应用程序的入口文件,它使用核心函数 NestFactory 创建一个Nest应用程序实例。 |
app.service.ts | 声明了一个模块的服务。 |
app.module.ts | 这是一个模块,且是应用程序的根模块。作用是将service和controller链接起来。 |
app.controller.ts | 声明了路由的控制器。 |
app.controller.spec.ts | 控制器的单元测试。 |
main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
首先是main.ts,这个文件是Nest服务的入口文件。上述代码首先引入了Nest的构造器NestFactory,该构造器对象有一个create方法,此方法能接收一个主模块,生成一个Nest实例,然后在第六行,我们让Nest实例监听3000端口。
以上便是Nest模块的入口代码,非常简单。
app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
上述代码首先引入Module函数,该函数是一个装饰器,其入参是一个包含输入模块数组imports字段、路由控制器数组controllers字段、以及提供了服务处理的providers字段的对象。被Module装饰器装饰后的AppModule类,便成为了一个合法的Nest模块。
那么Module装饰器里接收的AppController和ApService具体又是干什么的呢?我们继续往下看代码。
app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
在app.controller.ts里,类AppController经过装饰器Controller函数装饰过后,将变成一个合法的Nest路由监听器,这里监听的路由在第8行@Get()装饰器声明,Get装饰器的入参为空,代表监听的是最简单的路由/,监听的请求类型是get类型。同理,Post装饰器监听的就是post类型,这里我们后面再说。
我们浏览器访问localhost:3000的时候,其实是在访问localhost:3000/,这时/路由就被@Get()装饰器捕捉。路由被捕捉后的处理方法是被@Get()装饰的getHello方法,该方法返回了AppService类的实例对象的getHello方法的处理结果。
这里有两个getHello方法,我们需要注意区分:一个是路由监听器的处理方法,另一个是AppService服务里定义的getHello方法。
不知道大家是否注意到,我们在第10行用到了实例
appService对象,但是这个对象却只是在第6行构造函数的入参里声明过,怎么就能在类的其他地方使用了呢?构造函数入参里声明的变量不是只能在构造函数内部使用吗?这个问题我们留在后面IoC和DI一节讲。
app.service.ts
接下来我们继续讲最后的app.service.ts文件。
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
上述代码更加简单,只是返回了一个AppService类,该类提供了一个getHello的方法,并在该方法内部返回了一个Hello World!的字符串。唯一一个与普通类不同的地方在于,这个类是被装饰器函数Injectable装饰过的。
最后还剩一个app.controller.spec.ts文件,这个文件有点特殊,它是以.spec.ts结尾。这种结尾的文件在Nest中是测试文件,它不用参与主流流程的构建,为了降低学习的心智负担,因此我们这里就先不介绍,感兴趣的同学可以自行了解。
src下的主要文件main.ts、app.module.ts、app.controller.ts、app.module.ts我们就介绍完了,接下来我们再梳理一下整体的流程:
Nest在main.ts中通过NestFactory.create方法创建了一个Nest实例,然后让该实例监听3000端口。这里是整个Nest服务的入口。create需要一个模块作为入参,故Nest在app.module.ts中声明了AppModule,并传给了create方法。AppModule类通过装饰器Module关联了AppController和AppService。AppService类也有一个装饰器Injectable,同时声明了一个getHello方法,并返回了我们熟悉的Hello World!字符串。AppController稍微复杂一点,被Controller装饰器装饰后的它成为了一个路由监听器。同时在类内部,通过@Get装饰器监听了一个/路由的get请求。我们在浏览器里访问localhost:3000就会被@Get()装饰器捕获。捕获后执行了getHello方法,该方法内部返回了一个AppService类实例的getHello方法的执行结果,最后我们就看到了Hello World!。
总结
这节介绍了如何安装NestJS脚手架,并通过脚手架快速搭建一个基础的Nest服务,接着我们介绍了Nest项目的目录结构,并详细讲解了Nest服务的基础流程。
同时我们遗留了一个问题作为大家的思考题:
- 在文件
app.controller.ts里,第10行用到了实例appService对象,但是这个对象却只是在第6行构造函数的入参里声明过,怎么就能在类的其他地方使用了呢?
以上即本节全部内容,如果你喜欢本节内容,来个点赞👍🏻吧~