Skip to content

Nestjs 快速入门

学习文档

创建项目

  • 全局安装脚手架
bash
$ npm i -g @nestjs/cli
  • 创建项目
bash
$ nest new project-name
  • 启动项目
bash
$ npm run start:dev

项目结构

常用命令

  • 生成模块
bash
$ nest g module users
  • 生成控制器
bash
$ nest g controller users --no-spec   # --no-spec 不生成测试文件
  • 生成服务
bash
$ nest g service users --no-spec

核心架构

  • 业务模块

通过nest g module user生成

ts
import { Module } from '@nestjs/common'
import { UserController } from './user.controller'
import { UserService } from './user.service';

@Module({
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule { }
  • 路由控制器

通过nest g controller user生成

ts
import { Controller, Get } from '@nestjs/common'
import { UserService } from './user.service'

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) { }
  // 相当于 userService = new UserService()
  @Get()
  getUsers () {
    return this.userService.getUsers()
  }
}
  • 业务逻辑服务

通过nest g service user生成

ts
import { Injectable } from '@nestjs/common'

@Injectable()
export class UserService {
  getUsers () {
    return {
      users: [
        {
          name: 'John Doe',
          email: 'john.doe@example.com',
          age: 25
        }
      ],
      message: 'successfully'
    }
  }
}
  • 添加API全局前缀
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()

增删改查 快速上手例子

详情:
ts
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common'
import { User, UserService } from './user.service'

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) { }
  // 相当于 userService = new UserService()
  // params 是路径参数,body 是请求体, query 是查询参数

  /** 增 */
  @Post()
  add (@Body() body: User) {
    return this.userService.add(body)
  }

  /** 删 */
  @Delete(':id')
  del (@Param() params: { id: string }) {
    const id = parseInt(params.id)
    return this.userService.del(id)
  }

  /** 改 */
  @Put()
  update (@Body() body: User) {
    return this.userService.update(body)
  }

  /** 查 */
  @Get()
  getUsers () {
    return this.userService.getUsers()
  }
}
ts
import { Injectable } from '@nestjs/common'

export interface User {
  id: number
  name: string
  age: number
  tel: string
}

/** 模拟数据库 */
let users: User[] = [
  {
    id: 1,
    name: 'zs',
    age: 18,
    tel: '13033474321'
  }
]

@Injectable()
export class UserService {
  /** 增 */
  add (user: User) {
    users.push({ ...user, id: users.length + 1 })
    return {
      code: 200,
      message: 'success',
      user
    }
  }

  /** 删 */
  del (id: number) {
    users = users.filter(user => user.id !== id)
    return {
      code: 204,
      message: '记录删除成功!',
    }
  }

  /** 改 */
  update (user: User) {
    users = users.map(item => item.id === user.id ? user : item)
    return {
      code: 200,
      message: '记录修改成功!',
      user
    }
  }

  /** 查 */
  getUsers () {
    return {
      code: 200,
      message: '获取数据列表成功!',
      users,
    }
  }
}
http
### 新增
POST http://localhost:3000/api/users/
Content-Type: application/json

{
  "name": "ls",
  "age": 20,
  "tel": "00154896"
}



### 删除
DELETE http://localhost:3000/api/users/1



### 修改
PUT http://localhost:3000/api/users/
Content-Type: application/json

{
  "name": "ls",
  "age": 25,
  "tel": "13047894321",
  "id": 1
}



### 查询
GET http://localhost:3000/api/users/

数据库交互

可以安装一个VSCode数据库可视化插件Database Client.

  • 安装依赖
bash
$ npm i --save @nestjs/typeorm typeorm mysql2
  • 配置数据库连接
ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { UserModule } from './user/user.module'

@Module({
  imports: [
    TypeOrmModule.forRoot({   
      type: 'mysql',          
      host: 'localhost',      
      port: 3306,             
      username: 'root',       
      password: '123456',     
      database: 'blog',       
      retryDelay: 1000,       
      retryAttempts: 3,       
      synchronize: true,      
      autoLoadEntities: true, 
    }),                       
    UserModule,   // 用户模块
  ],
  controllers: [],
  providers: [],
})
export class AppModule { }
  • 创建ORM实体

在模块下创建entities文件夹,然后创建实体文件,如:user.entity.ts

ts
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm"

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number

  @Column({ type: 'varchar' })
  name: string

  @Column({ type: 'tinyint' })
  age: number

  @Column({ type: 'varchar', length: 11 })
  tel: string

  @CreateDateColumn({ type: 'timestamp' })
  entryTime: Date
}
ts
import { Module } from '@nestjs/common'
import { UserController } from './user.controller'
import { UserService } from './user.service';
import { TypeOrmModule } from '@nestjs/typeorm'
import { User } from './entities/user.entity'

@Module({
  imports: [ 
    TypeOrmModule.forFeature([User]), 
  ], 
  controllers: [UserController,],
  providers: [UserService]
})
export class UserModule { }

提示

重新启动项目, npm run start:dev会自动根据创建的实体文件生成数据库表

  • 编写控制器和服务
详情:
ts
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common'
import { User } from './entities/user.entity'
import { UserService } from './user.service'


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

  /** 增 */
  @Post()
  add (@Body() body: User) {
    return this.userService.add(body)
  }

  /** 删 */
  @Delete(':id')
  delete (@Param() params: Pick<User, 'id'>) {
    const { id } = params
    return this.userService.delete(Number(id))
  }

  /** 改 */
  @Put(':id')
  update (@Param() params: Pick<User, 'id'>, @Body() body: User) {
    const { id } = params
    return this.userService.update(Number(id), body)
  }

  /** 查 - 所有 */
  @Get()
  getList () {
    return this.userService.all()
  }

  /** 查 - 单个 */
  @Get(':id')
  find (@Param() params: Pick<User, 'id'>) {
    const { id } = params
    return this.userService.find(Number(id))
  }
}
ts
import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from './entities/user.entity'

@Injectable()
export class UserService {
  constructor(@InjectRepository(User) private readonly user: Repository<User>) { }

  /** 增 */
  add (user: User) {
    return this.user.save(user)
  }

  /** 删 */
  delete (id: number) {
    return this.user.delete(id)
  }

  /** 改 */
  update (id: number, user: User) {
    return this.user.update(user.id, user)
  }

  /** 查 - 单个 */
  find (id: number) {
    return this.user.findOneBy({ id })
  }

  /** 查 - 所有 */
  all () {
    return this.user.find()
  }
}

依赖注入

基本概念

在 NestJS 中,依赖注入(Dependency Injection,简称 DI)是一种设计模式,它用于管理组件(如类)之间的依赖关系。其核心思想是将组件所依赖的其他组件(或服务)的创建和管理交给外部容器(在 NestJS 中是一个依赖注入容器),而不是由组件自身来创建和管理这些依赖。

ts
import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { User } from './entities/user.entity'
import { UserController } from './user.controller'
import { UserService } from './user.service'

@Module({
  imports: [
    TypeOrmModule.forFeature([User]),
  ],
  controllers: [UserController,],
  providers: [
    // 提供业务逻辑服务
    {
      provide: 'user',
      useClass: UserService
    },
    // 提供自定义值
    {
      provide: 'database-config',
      useValue: {
        host: 'localhost',
        port: 3000,
        username: 'root',
        password: '123456',
        database: 'test'
      }
    },
    // 提供工厂函数
    {
      provide: 'myFactory',
      useFactory: () => {
        console.log('this is myFactory.')
        return ['a', 'b', 'c', 'e', 'f', 'g']
      }
    }
  ]
})
export class UserModule { }
ts
import { Body, Controller, Delete, Get, Inject, Param, Post, Put } from '@nestjs/common'
import { User } from './entities/user.entity'
import { UserService } from './user.service'


@Controller('users')
export class UserController {
  constructor(
    @Inject('user') private readonly userService: UserService,  
    @Inject('database-config') private readonly config: Record<string, string | number>,  
    @Inject('myFactory') private readonly myFactory: string[],  
  ) { }

  /** 使用自定义值 */
  @Get('config')
  getConfig () {
    return this.config
  }

  /** 使用工厂函数返回值 */
  @Get('factory')
  getFactory () {
    return this.myFactory
  }

  // ...
}

中间件

局部中间件

  • 快速生成中间件模块
bash
$ nest g mi counter --no-spec
  • *.module.ts中引入使用局部中间件
ts
// other something...
export class UserModule implements NestModule {
  configure (consumer: MiddlewareConsumer) {  // 配置中间件
    consumer.apply(CounterMiddleware).forRoutes('users')	// 针对哪个路由起作用
    // consumer.apply(CounterMiddleware).forRoutes({ path: 'users', method: RequestMethod.GET })	// 也可以让中间件针对某一种请求方法生效
  }
}

全局中间件

  • main.tsapp对象身上注册全局中间件
ts
// 全局中间件的业务逻辑
function globalMiddleware (req: any, res: any, next: () => void) {
  console.log('Already in globalMiddleware...')
  next()
}

async function bootstrap () {
  const app = await NestFactory.create(AppModule)
  app.use(globalMiddleware) // 使用全局中间件	// ![code++]
  // 可以添加API全局前缀
  app.setGlobalPrefix('api')
  await app.listen(3000)
}
bootstrap()

解决跨域问题

  • 按照第三方包
bash
$ npm install cors
$ npm i @types/cors
  • main.ts注册全局中间件
ts
import * as cors from 'cors'

async function bootstrap () {
  const app = await NestFactory.create(AppModule)
  app.use(cors())
  // ...
}

模块化

bash
$ nest g res posts