前言
作为一名前端开发者,虽然还是菜鸟级别,但是作为一名有着优秀的开发人员的思想,还是要多学习其他的技术的,所谓技多不压身。这不是在后端的路上慢慢探究,前有node.js 的koa、express,这不是最近又出现了nest.js,手比较痒,就替大伙先尝试尝试,官网在此,同学们可前去查看:Nest.js官方文档
Nest.js介绍
Nest (NestJS) 是一个用于构建高效、可扩展的
Node.js
服务器端应用程序的开发框架。它利用JavaScript
的渐进增强的能力,使用并完全支持TypeScript
(仍然允许开发者使用纯 JavaScript 进行开发),并结合了 OOP (面向对象编程)、FP (函数式编程)和 FRP (函数响应式编程)。在底层,Nest 构建在强大的 HTTP 服务器框架上,例如 Express (默认),并且还可以通过配置从而使用 Fastify !
Nest 在这些常见的 Node.js 框架 (Express/Fastify) 之上提高了一个抽象级别,但仍然向开发者直接暴露了底层框架的 API。这使得开发者可以自由地使用适用于底层平台的无数的第三方模块。
Nest.js项目创建
// 全局安装Nest
npm i -g @nestjs/cli
// 创建项目
nest new project-name
创建项目成功之后,会让你选择依赖包管理工具,这里我选择更快的yarn
,如果你有安装yarn
,最好也选择yarn
,能更快一些,npm
在国内安装速度会慢一些。
注意:
Nest.js
要求Node.js
(>= 10.13.0,v13 除外), 如果你的Node.js
版本不满足要求,可以通过nvm
包管理工具安装符合要求的Node.js
版本
之后等待安装
安装完之后可以按照其提示,运行项目
目录
打开文件之后,就是这样一个目录
src还是一成不变,作为其核心文件,我简要说一下:
文件 | 描述 |
---|---|
app.controller.ts | 单个路由的基本控制器(Controller) |
app.controller.spec.ts | 针对控制器的单元测试 |
app.module.ts | 应用程序的根模块(Module) |
app.service.ts | 具有单一方法的基本服务(Service) |
main.ts | 应用程序的入口文件,它使用核心函数NestFactory 来创建 Nest 应用程序的实例。 |
Nest.js剖析
package.json
我们去查看package.json的文件配置,其中两个关乎两个项目启动的最常用的命令行
- `yarn start`:运行项目(未启用热更新)
- `yarn start:dev`:运行项目(启用热更新)
个人强烈建议使用热更新的命令,如果嫌命令行麻烦,可以自己手动更改项目启动的命令行,二者合并也是可以的,我就为了方便将其合并为yarn run start
就可以启动热更新了。
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();
此处使用了Nest.js
的工厂函数NestFactory
来创建了一个AppModule
实例,之后启动了 HTTP 侦听器,侦听main.ts
中所定义的3000
端口。
此处的端口如若被占用,可以改为其他的端口号,之后我们在前端页面访问
熟悉的Hello Word
app.module.ts
那么Hello Word
是怎么来的呢?我们看到此处引入了当前文件夹下面的app.module
,查看代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
看到该文件的时候,是不是有的人就要惊呼了,我靠,这不是Java里的springBoot吗?反正我是呆了一下,这可不就是吗?继续看下去,学过的会更加震惊。
.mudule
文件需要使用了一个@Module()
装饰器的类,装饰器可以理解成一个封装好的函数,@Module()
装饰器接收四个属性:providers
、controllers
、imports
、exports
。
- providers:
Nest.js
注入器实例化的提供者(服务提供者),处理具体的业务逻辑,各个模块之间可以共享 - controllers:处理http请求,包括路由控制,向客户端返回响应,将具体业务逻辑委托给providers处理;
- imports:导入模块的列表,如果需要使用其他模块的服务,需要通过这里导入;
- exports:导出服务的列表,供其他模块导入使用。如果希望当前模块下的服务可以被其他模块共享,需要在这里配置导出;
这里呢,在我看来,providers就是提供者,也就说谁支撑起这个模块,能让这模块得以使用,也就是所谓的方法函数;控制器更是如其名,控制这个模块的路由,更像是一个中间轴,而imports和exports相信前端的各位对其也是容易理解,就是引入其他模块供自己使用或者抛出自己的模块供其他模块使用
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();
}
}
使用@Controller
装饰器来定义控制器, 在其中定义AppController
类并抛出,将引入进来的AppService
作为构造器的私有只读属性,@Get
是请求方法的装饰器,对getHello
方法进行修饰,表示这个方法会被GET请求调用,而该方法调用了AppService
下的 getHello
方法
每一个要成为控制器的类,都需要借助@Controller
装饰器的装饰,该装饰器可以传入一个路径参数,作为访问这个控制器的主路径,比如@Controller('home')
,那么该路径就可以通过本地localhost:3000
拼接home
来访问,同样在接口当中可以定义其他的路由后缀。比如如果定义 @Get('home)
,那么该路径也可以通过本地localhost:3000
拼接home
来访问
在更改@Get
里面的内容后,本地3000端口变成了404
加上后缀之后才访问正常
并且该@Get
装饰器还可以替换为@Post
@Put
等装饰器,需要前端用相同的方法访问。
全局路由前缀
在公司中,一般都有api
为开头的接口,那在每个controller.ts
文件加这个前缀就太麻烦了,可以选择在main.ts
文件中使用setGlobalPrefix
设置全局路由前缀
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 设置全局路由前缀
app.setGlobalPrefix('api');
await app.listen(3000);
}
bootstrap();
app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
@Injectable
修饰后的 AppService
,抛出该类, 在AppModule
中注册之后,在app.controller.ts
中使用,我们就不需要使用new AppService()
去实例化,直接引入过来就可以使用里面定义的方法。
app.service.spec.ts
这个后缀为spec
的文件是测试文件,在快速开发的情况下,比较少用到这个文件,如果不需要每次都生成这个文件,可以在nest-cli.json
文件中添加如下配置,禁用测试用例生成
"generateOptions": { "spec": false }
Nest简便命令行
在编写代码前,先说几个命令行
我们就使用该命令行来创建
//语法
nest g [文件类型] [文件名] [文件目录]
nest g mo xxx 创建模块
nest g co xxx 创建控制器
nest g service xxx 创建服务类
-
注意创建顺序: 先创建
Module
, 再创建Controller
和Service
, 这样创建出来的文件在Module
中自动注册,如果后创建Module
,Controller
和Service
,会被注册到外层的app.module.ts
,所以创建顺序需要注意一下。 -
如果忘记命令可以使用
nest --help
进行查看
当然还有一个很好用的命令行,三个文件给你一块创建,省时省力,你值得拥有
nest g resource user
使用简写 nest g res user
-
在此选择
REST API
风格 -
nest g res user
就是创建完整的user
模块,这个命令执行完后会生成一个user
文件夹,在这个文件夹中包含如下图所示的文件dto
用于定义系统内的接口或者输入和输出entities
是mysql
数据库中的一张表的实体文件,但要在文件中使用@Entity
装饰器,这个在下文中介绍数据库连接、增删改查时会使用到- 这个后缀为
spec
的文件是测试文件,在快速开发的情况下,比较少用到这个文件,如果不需要每次都生成这个文件,可以在nest-cli.json
文件中添加如下配置,禁用测试用例生成."generateOptions": { "spec": false }
这里第二个问题是与数据库相关的,此处不过多解释,默认yes,多多益善嘛
创建成功之后,目录结构就改变了
看完了里面的文件之后,好家伙,增删改查都给你写完了,真省事!老铁直呼666!真贴心啊
//user.service.ts
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Injectable()
export class UserService {
create(createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
findAll() {
return `This action returns all user`;
}
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`;
}
}
swagger
后端开发,必不可少的就是开发文档了,这nest不是我说,是真滴贴心,贼方便,早早给你想好了。
安装
npm install --save @nestjs/swagger
接下来需要在main.ts
中设置Swagger
文档信息:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { NestExpressApplication } from '@nestjs/platform-express';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// 设置swagger文档
const config = new DocumentBuilder()
.setTitle('swagger文档')
.setDescription('接口文档')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('/api/swagger', app, document);
await app.listen(3030);
}
bootstrap();
配置完成,我们就可以访问:http://localhost:3000/api/swagger
,此时就能看到Swagger
生成的文档:
swagger装饰器
ApiTags
:设置swagger文档标签分类ApiOperation
:接口描述信息
我们可以根据Controller
来分类, 只要添加@ApiTags
就可以,分类接口标签
import { ApiTags } from '@nestjs/swagger';
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common';
@ApiTags("用户")
@Controller('post')
export class PostsController {...}
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
@ApiTags("用户")
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}
@ApiOperation({ summary: '创建用户' })
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
@ApiOperation({ summary: '获取用户' })
@Get()
findAll() {
return this.userService.findAll();
}
@ApiOperation({ summary: '根据id获取用户' })
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(+id);
}
@ApiOperation({ summary: '根据id修改用户' })
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.userService.update(+id, updateUserDto);
}
@ApiOperation({ summary: '删除用户' })
@Delete(':id')
remove(@Param('id') id: string) {
return this.userService.remove(+id);
}
}
总结
以上仅仅是Nest入门级别的操作,主要是一些文件创建以及理解、使用,对springBoot熟悉的可能更容易上手,学习Vue和React的可能没这么块,但是感觉思想转变还是需要的。 接触了Nest一段时间了,个人感觉Nest.js作为一个开源项目,对ts的支持也不错,用起来还是很不错的,也是像koa、express的大框架,还是值得去学习的,
我是小白,我们一起学习!