新建项目
新建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行构造函数的入参里声明过,怎么就能在类的其他地方使用了呢?
以上即本节全部内容,如果你喜欢本节内容,来个点赞👍🏻吧~