NestJS 入门指南:从工厂模式到模块化 CRUD 实战

如果你已经受够了 Express 的"自由散漫",又觉得 Next.js 全栈耦合太深,那么 NestJS 或许正是你一直在找的"后端全家桶"。

本文将从设计模式聊到实际代码,带你快速上手这个企业级 Node.js 框架。


📦 一、NestJS 是什么?和 Next.js 有什么不同?

框架 定位 特点
Next.js React 全栈框架 前端渲染 + 简易 API 路由,适合 BFF 层
NestJS Node.js 后端框架 纯后端,默认 TypeScript,全面模块化,适合企业级服务

NestJS 默认使用 TypeScript ,并且大量借鉴了 Angular 的架构思想(模块、装饰器、依赖注入)。

✅ 它不仅支持 REST API ,还能做 GraphQL微服务WebSocket ,甚至可以对接 AI Infra 和底层系统集成。


🛠️ 二、快速安装与初始化

bash

bash 复制代码
# 全局安装 NestJS CLI
npm i -g @nestjs/cli

# 创建新项目
nest new hello

# 进入目录并启动
cd hello
pnpm run start

访问 http://localhost:3000,你会看到熟悉的 "Hello World!"


🏭 三、从"蜜雪冰城"理解工厂模式

工厂模式 是 23 种设计模式中最基础、最重要的一种。

它的核心思想是:你不需要关心对象怎么创建,只要告诉工厂"我要什么"就行。

举个🌰:蜜雪冰城的产品线

javascript

javascript 复制代码
// 冰淇淋
class IceCream {
  constructor() {
    this.name = '冰淇淋';
    this.price = 3;
  }
  show() {
    console.log(`${this.name} 价格 ${this.price}`);
  }
}

// 柠檬水
class LemonTea {
  constructor() {
    this.name = '柠檬水';
    this.price = 4;
  }
  show() {
    console.log(`${this.name} 价格 ${this.price}`);
  }
}

// 珍珠奶茶
class MilkTea {
  constructor() {
    this.name = '珍珠奶茶';
    this.price = 8;
  }
  show() {
    console.log(`${this.name} 价格 ${this.price}`);
  }
}

如果没有工厂模式,你每次都要 new IceCream()new LemonTea(),一旦类名变化,所有调用处都要改 ------ 耦合度极高

🏭 工厂类来解耦

javascript

typescript 复制代码
class MixueFactory {
  static create(type) {
    switch (type) {
      case 'ice':   return new IceCream();
      case 'lemon': return new LemonTea();
      case 'milk':  return new MilkTea();
      default:      throw new Error('未知产品');
    }
  }
}

// 使用工厂
const drink = MixueFactory.create('ice');
drink.show(); // 冰淇淋 价格 3

好处 :调用方只和 MixueFactory 打交道,具体产品类的变化被隔离在工厂内部。

✅ 对应到 NestJS 中,NestFactory 就是那个"蜜雪冰城",它负责创建应用实例。

typescript

javascript 复制代码
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule); // 工厂创建 App
  await app.listen(3000);
}
bootstrap();

🧱 四、模块化架构 ------ MVC 的优雅落地

NestJS 高度模块化,每个功能块都是一个 Module ,内部按 MVC 分层:

层级 文件 职责
Controller *.controller.ts 接收请求,参数校验,调用 Service,返回响应
Service *.service.ts 复杂业务逻辑、数据库操作(CRUD)
Module *.module.ts 组装 Controller + Service,并暴露给外部

📁 典型目录结构

text

ruby 复制代码
src/
├── main.ts                 # 入口文件
├── app.module.ts           # 根模块
├── app.controller.ts       # 根控制器
├── app.service.ts          # 根服务
└── todos/                  # 独立业务模块
    ├── todos.module.ts
    ├── todos.controller.ts
    └── todos.service.ts

🧩 五、装饰器模式 ------ 给类"贴标签"

装饰器模式:在不修改原有类代码的情况下,动态给类增加额外功能。

NestJS 中到处是装饰器:

  • @Module() ------ 声明一个模块
  • @Controller() ------ 声明控制器
  • @Injectable() ------ 声明可被依赖注入的服务
  • @Get()@Post() ------ 声明路由

typescript

typescript 复制代码
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TodosModule } from './todos/todos.module';

@Module({
  imports: [TodosModule],      // 引入外部模块
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

🧪 六、实战:Todos 模块 ------ 从 Controller 到 Service

1️⃣ 定义模块(组装层)

typescript

typescript 复制代码
// todos.module.ts
import { Module } from '@nestjs/common';
import { TodosController } from './todos.controller';
import { TodosService } from './todos.service';

@Module({
  controllers: [TodosController], // 注册控制器
  providers: [TodosService],      // 注册服务
})
export class TodosModule {}

2️⃣ 控制器(接收请求,返回响应)

typescript

less 复制代码
// todos.controller.ts
import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
} from '@nestjs/common';
import { TodosService } from './todos.service';
import { Todo } from './todos.service';

@Controller('todos') // 路由前缀 /todos
export class TodosController {
  constructor(private readonly todosService: TodosService) {}

  @Get(':id')
  findOne(@Param('id') id: string): Todo {
    console.log(`查询 id: ${id}`);
    return this.todosService.findOne(Number(id));
  }

  @Post()
  create(@Body('title') title: string): Todo {
    return this.todosService.create(title);
  }

  @Delete(':id')
  remove(@Param('id') id: string): { message: string } {
    this.todosService.remove(Number(id));
    return { message: '删除成功' };
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Body() patch: Partial<Todo>,
  ): Todo {
    return this.todosService.update(Number(id), patch);
  }
}

@Param()@Body() 是参数装饰器,自动从请求中提取数据。

✅ 控制器只做"调度",真正的数据操作交给 Service。


3️⃣ 服务层(真实业务逻辑 + 异常处理)

typescript

typescript 复制代码
// todos.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';

// 定义 Todo 类型
export interface Todo {
  id: number;
  title: string;
  completed: boolean;
}

// 模拟数据库
let todos: Todo[] = [
  { id: 1, title: '学习 NestJS', completed: false },
  { id: 2, title: '学习 CRUD', completed: true },
];
let nextId = 3;

@Injectable()
export class TodosService {
  // 查询所有
  findAll(): Todo[] {
    return todos;
  }

  // 查询单个
  findOne(id: number): Todo {
    const todo = todos.find((t) => t.id === id);
    if (!todo) {
      throw new NotFoundException(`Todo ${id} 不存在`);
    }
    return todo;
  }

  // 创建
  create(title: string): Todo {
    const newTodo: Todo = {
      id: nextId++,
      title,
      completed: false,
    };
    todos.push(newTodo);
    return newTodo;
  }

  // 删除
  remove(id: number): void {
    const index = todos.findIndex((t) => t.id === id);
    if (index === -1) {
      throw new NotFoundException(`Todo ${id} 不存在`);
    }
    todos.splice(index, 1);
  }

  // 更新
  update(id: number, patch: Partial<Todo>): Todo {
    const todo = this.findOne(id); // 复用 findOne 做校验
    Object.assign(todo, patch);
    return todo;
  }
}

⚠️ 异常处理 :使用 NestJS 内置的 NotFoundException,会自动返回标准错误格式(状态码 + 消息)。

Partial<Todo> 表示只传部分字段也可更新,非常灵活。


🧠 七、关于错误处理的思考

面试常问:你是如何处理后端报错的?

在 NestJS 中,我们不需要到处 try-catch,而是:

  1. 使用内置异常类(如 NotFoundExceptionBadRequestException)抛出错误。
  2. 框架自动捕获并返回标准 JSON:

json

json 复制代码
{
  "statusCode": 404,
  "message": "Todo 99 不存在",
  "error": "Not Found"
}
  1. 也可以自定义全局异常过滤器,统一错误格式。

✅ 八、总结

知识点 说明
工厂模式 NestFactory.create() 帮你创建应用,解耦细节
模块化 每个业务独立成 Module,内部 MVC 分层
装饰器 @Module@Controller@Injectable 等标记类职责
控制器 只负责参数提取和调用 Service,不写业务逻辑
服务 写真正的数据操作,支持依赖注入
异常处理 使用内置异常类,框架自动标准化输出

🎯 NestJS 不是玩具框架,它是能支撑起企业级后端架构的"重器"。

从工厂模式到装饰器,从模块化到依赖注入,每一处设计都体现着"可维护性"和"可扩展性"。

如果你正在寻找一个 结构清晰、TypeScript 友好、适合团队协作 的后端框架,NestJS 绝对值得一试

相关推荐
凌涘1 小时前
NestJS 的模块化后端组织方式
nestjs
HjhIron1 小时前
手把手教你用 Next.js 14 + Redis 从零搭建一个全栈 Markdown 笔记系统
前端·全栈·next.js
WIN赢1 小时前
【抽象思想-从复杂中抽离简单、收敛的口子】
java·前端·javascript
martindelophy1 小时前
Codex Chrome 插件 + Timeline Studio:构建可编辑的 AI 视频剪辑 Agent 工作流
前端·人工智能·chrome
whyutianict_vv2 小时前
从 Web 前端到 HarmonyOS ArkTS:一次 AI 鸿蒙全栈智能体开发的迁移实录
前端·人工智能·harmonyos
qziovv3 小时前
前端转flutter——项目架构、初始化
前端·flutter
Ali885203 小时前
Python字符串方法速查表大全
前端·python
前端_刘师兄3 小时前
FAE工程师学习路线-进程
前端