简介

​ Nest 是一个用于构高效,可扩展的 Node.js 服务端应用程序的框架…… 它使用渐进式 JavaScript,内置并完全支持 TypeScript
特点:
基于 Node:对前端友好
服务端应用框架:主要用于服务端接口开发
高效,可扩展:体现在 Nest 各个功能模块之间的架构是解耦的、容易进行组合的
渐进式:不需要一开始掌握它的全部功能特性,后续可根据业务需要逐步叠加功能。
Nest 由 TS 开发,完全支持 TS
应用场景:
首先是最基础的,做服务端开发;
其次,支持服务端扩展,比如:安全、鉴权、队列、日志等

技术架构的支持:微服务,序列化等

安装与使用

1
2
3
npm i @nestjs/cli
nest new project
npm run start

目录结构src如下:

img

入口文件为main.ts

创建module:

1
nest g module user server

在目录不存在时生成src/server/user目录,并在user目录下添加user.module.ts文件,同时会在跟模块app.module.ts下自动引入UserModule

创建controller:

1
nest g controller user server

controller 就类似前端的路由,负责处理客户端传入的请求服务端返回的响应

1
2
3
4
5
6
7
8
9
10
11
// user.controller.ts
import { Controller, Get } from '@nestjs/common';

@Controller('user')
export class UserController {
@Get('users')
findAll(): string {
return "用户信息";
}
}
findAll方法可以写成异步方法

创建provider:

1
nest g service user server

我们的 controller 接收到了一个用户的查询请求,但不能直接在 controller 中去查询数据库并返回,而是要将查询请求交给 provider 来处理,所以创建了一个 UserService,用来提供数据库操作服务。还可以用来做一些用户校验,比如使用 JWT 对用户权限进行校验的策略,就可以写成一个策略类,放到 provider 中,为模块提供相应的服务。

连接数据库(以MongoDB为例)

安装Mongoose:

1
npm install mongoose @nestjs/mongoose --save

Nest官方提供了Mongoose的封装,用来操作数据库,连接数据之前,我们要先在根模块,也就是 app.module.ts 中引入 Mongoose 的连接模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './server/user/user.module';

@Module({
imports: [MongooseModule.forRoot('mongodb://localhost/xxx'), UserModule],
// forRoot内MongoDB后面的为数据库地址, xxx为数据库名称
controllers: [AppController],
providers: [AppService]
})
export class AppModule {}

由于mongoose模块没有声明文件,控制台可能会报错,所以需要安装一下@types/mongoose:

1
npm install @types/mongoose --dev 或者 yarn add @types/mongoose --dev

创建数据表:

src/server/user 文件夹下创建一个 user.schema.ts 文件,定义一个数据表的格式:

1
2
3
4
5
6
7
8
// user.schema.ts
import { Schema } from 'mongoose';

export const userSchema = new Schema({
_id: { type: String, required: true }, // 覆盖 Mongoose 生成的默认 _id
user_name: { type: String, required: true },
password: { type: String, required: true }
});

修改user.module.ts文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
// user.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { UserController } from './user.controller';
import { userSchema } from './user.schema';
import { UserService } from './user.service';

@Module({
imports: [MongooseModule.forFeature([{ name: 'Users', schema: userSchema }])],
controllers: [UserController],
providers: [UserService]
})
export class UserModule {}

操作数据库:

打开 user.service.ts 文件,为 UserService 类添加一个构造函数,让其在实例化的时候能够接收到数据库 Model,这样才能在类中的方法里操作数据库。

定义方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// user.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { CreateUserDTO } from './user.dto';
import { User } from './user.interface';

@Injectable()
export class UserService {
constructor(@InjectModel('Users') private readonly userModel: Model<User>) {}

// 查找所有用户
async findAll(): Promise<User[]> {
const users = await this.userModel.find();
return users;
}

// 查找单个用户
async findOne(_id: string): Promise<User> {
return await this.userModel.findById(_id);
}

// 添加单个用户
async addOne(body: CreateUserDTO): Promise<void> {
await this.userModel.create(body);
}

// 编辑单个用户
async editOne(_id: string, body: EditUserDTO): Promise<void> {
await this.userModel.findByIdAndUpdate(_id, body);
}

// 删除单个用户
async deleteOne(_id: string): Promise<void> {
await this.userModel.findByIdAndDelete(_id);
}
}
因为 mongoose 操作数据库其实是异步的,所以这里我们使用 async 函数来处理异步的过程。

好奇的同学会发现,这里突然出现了两个文件,一个是 user.interface.ts,另一个是 user.dto.ts,我们现在来创建一下:

// user.interface.ts
import { Document } from 'mongoose';

export interface User extends Document {
readonly _id: string;
readonly user_name: string;
readonly password: string;
}
// user.dto.ts
export class CreateUserDTO {
readonly _id: string;
readonly user_name: string;
readonly password: string;
}

export class EditUserDTO {
readonly user_name: string;
readonly password: string;
}

设置路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// user.controller.ts
import {
Body,
Controller,
Delete,
Get,
Param,
Post,
Put
} from '@nestjs/common';
import { CreateUserDTO, EditUserDTO } from './user.dto';
import { User } from './user.interface';
import { UserService } from './user.service';

interface UserResponse<T = unknown> {
code: number;
data?: T;
message: string;
}

@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}

// GET /user/users
@Get('users')
async findAll(): Promise<UserResponse<User[]>> {
return {
code: 200,
data: await this.userService.findAll(),
message: 'Success.'
};
}

// GET /user/:_id
@Get(':_id')
async findOne(@Param('_id') _id: string): Promise<UserResponse<User>> {
return {
code: 200,
data: await this.userService.findOne(_id),
message: 'Success.'
};
}

// POST /user
@Post()
async addOne(@Body() body: CreateUserDTO): Promise<UserResponse> {
await this.userService.addOne(body);
return {
code: 200,
message: 'Success.'
};
}

// PUT /user/:_id
@Put(':_id')
async editOne(
@Param('_id') _id: string,
@Body() body: EditUserDTO
): Promise<UserResponse> {
await this.userService.editOne(_id, body);
return {
code: 200,
message: 'Success.'
};
}

// DELETE /user/:_id
@Delete(':_id')
async deleteOne(@Param('_id') _id: string): Promise<UserResponse> {
await this.userService.deleteOne(_id);
return {
code: 200,
message: 'Success.'
};
}
}

此时向接口发送请求,即可拿到数据库的数据…

内容转载至:https://zhuanlan.zhihu.com/p/267286129