为什么要学习nestjs
ai的出现以及国内市场逐渐饱和,前端的生存空间被后端以及ai不断挤占,有很多前端同学都只会后台管理系统和vue或者react。这虽然在以往的招聘市场绝对是够用了。但目前2025年我的观察来看绝对不够用。前端需要有更多的突出点来让自己在一众打工牛马中脱颖而出,比如大前端,webgl,aiagent,或者像我准备学习的方向:全栈。
关于后端语言的选择。我了解到有java、go、或者nodejs,因为我本身是转行学的前端。没有太多的后端经验。综合学习成本以及心智负担以及未来发展考虑。我选择了nodejs,后来在nextjs这个全栈框架和nestjs中犯难。因为本身还是想接触后端方向最后还是选择了与java较为相似的nestjs
使用docker-desktop创建本地的数据库
为了方便后续的开发以及学习。我们需要安装docker,docker是一个在后端中经常使用到的东西。一定程度上我们可以把它看作前端的npm,哈哈。
npm是包管理器,它可以集中管理一个js项目中的项目依赖,并且我们可以使用package.json来控制版本等。 docker则有image,container,Repository的概念。image我们可以认为是package.json的加强版。它是一串代码模板。制定了配置项,安装的环境,系统工具等。Repository可以看作是类似npm远程仓库。container就是运行时的容器。可以被启动,停止,删除。
1:下载docker-desktop,这是一个可视化的docker工具
2:安装docker-desktop,注意docker-desktop在windows上需要有wsl工具才可以正常运行
3:docker-desktop中我们选择docker-hub,在这里选择mysql作为数据库工具,点击pull

4:找到左侧的images,找到已经被拉下来的mysql镜像,点击run

5:注意这里的配置项,分别对应mysql的一些启动参数,port指端口,containername这个只关系到容器名,我们还需要在EnvironmentVariables这里输入MYSQL_ROOT_PASSSWORD,value输入root,再点击run,一个基本的mysql数据库就启动了。
6:我这里选择了navicat premium来作为数据库可视化工具。毕竟我们在学习的时候非常需要这个来作为查看数据库更改是否成功
7:打开navicat premium,选择连接,选择mysql。这里的连接名称可以随便填,端口与之前在docker里填的端口需保持一致。密码和用户名就用EnvironmentVariables的值

创建nestjs本地项目
接下来创建nestjs项目。nestjs提供了官方脚手架来直接创建项目,
css
npm i -g @nestjs/cli
nest new project-name
nestjs基本语法和结构
nestjs项目创建完成之后,项目内会包含有3种文件,分别是controller、service、以及module。
module
nestjs最基础的一个单元就是一个module,当我们用nestjs提供的@module装饰器来注解一个类,那这个类就是一个module
ts
import { Module } from '@nestjs/common';
@Module({
imports[],
exports:[],
controllers: [],
providers: [],
})
export class CatsModule {}
providers | 声明该module内可以使用的注入器,一般是该module的service |
---|---|
controllers | 声明该module内可以使用的路由,一般是该module的controller层 |
imports | 声明该module内使用的其他module的功能,如果需要使用其他module提供的注入就需要在这里声明 |
exports | 声明该module可提供给其他模块使用的功能。 |
需要注意。模块只能通过imports来引入其他module的功能。它如果需要提供功能也必须通过exports
controller
我们可以把controller层当作一个路由中转。nestjs通过注解的@controller来将不同路由的请求分发给不同的controller层。每个controller层都是一个类,每个类又可以自己接管不同的路由。
ts
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get('find')
findAll(): string {
return 'This action returns all cats';
}
}
比如上述代码就指向了/cats/find这个路由。由controller
装饰器修饰的类就是一个控制层(controller)
注意每个controller都可以拥有多个路由
还可以通过@Get @Put @Post @Delete
等多种装饰器来声明https请求类型。
我们还可以通过nestjs内置的装饰器来拿到请求体
ts
import { Controller, Get, Req } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
console.log(request.body)
return 'This action returns all cats';
}
}
这里的@Req
指的就是请求体。如果使用的是url传参,则可以使用@Query
装饰器来获取路由传参
ts
import { Controller, Get, Query } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findOne(@Query() query: any): string {
console.log(query.id);
return `This action returns a cat with id=${query.id}`;
}
}
Provider
一般情况下,provider就是该模块的注入器,或者叫service,我们可以理解它是一个可以注入到其他路由中的服务,或者说在nestjs的推荐做法中,路由只需要处理路由的逻辑,具体的业务逻辑则由service来进行实现.
注入 这是一个nestjs中很重要的概念。nestjs可以通过import导入的services,通过特殊语法自动注入。 例:
ts
@Injectable()
export class CatsService {
constructor(private readonly dbService: DbService) {}
}
通过@Injectable()
装饰器标记的类,会被 NestJS 注册为一个 可注入的服务(Provider),它可以被注入到其他类中,也可以接收其他依赖(通过构造函数注入)来完成自己的功能.
构造函数中的 private readonly dbService: DbService 是 依赖注入语法糖,它的作用是告诉 NestJS:
- 这个类(如 Controller)需要一个 DbService 实例;
- Nest 会查找是否有注册的 DbService 并注入进来;
- 这个实例会赋值给 this.dbService,你可以在类中使用它的方法;
所以我们可以通过这个功能将一个具体的https请求分为controller
和services
,services通过注入来注入到控制层。
ts
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findOne(@Query() query: any): string {
const id = query.id;
return this.catsService.getCatById(id);
}
}
使用prisma连接本地数据库
在我们了解了 NestJS 的基本语法并成功启动了本地数据库之后,接下来就可以进入更实战的阶段了。
在正式操作数据库之前,我们需要先认识一个非常重要的工具 ------ ORM(对象关系映射)。
通俗点讲,ORM 就是一种让我们更轻松、更直观地操作数据库的库。它帮助我们屏蔽复杂的 SQL 语句,改用更加贴近编程语言(比如 JavaScript 或 TypeScript)风格的方式来进行增删改查。
我们即将使用的 ORM 工具是 Prisma ,它允许我们通过 JavaScript/TypeScript 的方式与数据库交互,像操作对象一样操作数据表,非常适合前端同学上手。
对于没有深厚后端经验的开发者来说,Prisma 极大降低了数据库操作的门槛,让我们能专注于业务逻辑,而不是 SQL 细节。
- 下载依赖
npm install @prisma/client
- 初始化prisma配置文件
npx prisma generate
- 执行完成后项目内会出现一个prisma文件夹和一个env文件。prisma文件内是储存的我们对数据库的映射以及操作。 env文件内储存的是数据库地址,以特殊的协议写成,参考该协议规则:
数据库类型://用户名:密码@地址:端口/数据库名?schema=表名
- 现在关注prisma文件,文件应该有一个
schema.prisma
文件。格式如下:
ts
generator client {
provider = "prisma-client-js"
output = "../generated/prisma"
}
datasource db {
provider = "mysql" //填入我们的数据库类型
url = env("DATABASE_URL")
}
我们可以通过这种格式来创建表,每次我们对数据库的操作都会在该文件下生成对应的操作日志。这里有一些prisma自带的api或者关键词可以通过该文章检查:prisma
ts
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
该方式就是声明一个新表。创建完成表后我们使用npx prisma migrate dev --name init
命令来让prisma对表进行操作。
crud
接下来是最重要的环节,之前的这么多操作都是为了完成crud。我们需要知道nestjs在常规情况下需要每个module都一个单独文件夹,我们在src目录下创建一个blog文件夹。并创建好blog.controller.ts
、blog.module.ts
、blog.service.ts
。分别对应module,控制层和服务层
- 服务层:
ts
import { Body, Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
@Injectable()
export class BlogService {
constructor(private prisma: PrismaService) {}
async findAll() {
return this.prisma.blog.findMany();
}
async findOne(id: number) {
return this.prisma.blog.findUnique({ where: { id } });
}
async update(id: number, body: any) {
return this.prisma.blog.update({
where: { id },
data: {
title: body.title,
content: body.content,
},
});
}
async remove(id: number) {
return this.prisma.blog.delete({ where: { id } });
}
}
- 控制层
ts
@Controller('blog')
export class BlogController {
constructor(private readonly blogService: BlogService) {}
@Post()
async create(@Body() body: CreateBlogDto) {
return this.blogService.add(body);
}
@Get()
async findAll() {
return this.blogService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string) {
return this.blogService.findOne(Number(id));
}
@Patch(':id')
async update(@Param('id') id: string, @Body() body: CreateBlogDto) {
return this.blogService.update(Number(id), body);
}
@Delete(':id')
async remove(@Param('id') id: string) {
return this.blogService.remove(Number(id));
}
}
基本的prisma Api可以参考 API
总结
通过本篇教程,我们从 NestJS 的基本语法、模块结构出发,逐步了解了如何连接数据库,并使用 Prisma 快速构建完整的 CRUD 接口。
对于前端转全栈的同学来说,NestJS + Prisma 提供了一个非常现代、强类型、安全且上手门槛不高的开发体系,能帮助你快速构建后端项目,同时保留前端思维方式,值得一试。