NestJS 是什么(对着 Spring Boot 一起学习)

可以把 NestJS 理解成:

"给 Node.js 后端项目提供一套类似 Spring Boot 的工程化框架。"

如果你熟悉 Java/Spring Boot,会非常容易理解 NestJS。它本质上是基于 Node.js + TypeScript 构建的后端框架,核心目标不是"让你能写接口",而是让中大型 Node.js 后端项目更容易组织、扩展、测试和维护


一、NestJS 是什么?

NestJS 官方定位是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。

它建立在 Node.js HTTP 能力之上,可以使用:

  • Express
  • Fastify

作为底层 HTTP 平台。

但 NestJS 真正有价值的地方,不是帮你封装 app.get()app.post()

而是给 Node.js 后端引入了一套完整的工程架构

text 复制代码
                 NestJS Application
                        │
        ┌───────────────┼────────────────┐
        │               │                │
     Controller       Service          Module
        │               │                │
        ↓               ↓                ↓
      HTTP           Business         Dependency
      API             Logic           Management
        │               │                │
        └───────────────┼────────────────┘
                        ↓
                Repository / DB

这也是它和 Express 最大的区别。


二、为什么需要 NestJS?

先看最原始的 Node.js/Express 项目。

刚开始可能非常简单:

js 复制代码
app.get('/users', async (req, res) => {
  const users = await db.query('select * from users')
  res.json(users)
})

项目小的时候完全没问题。

但是项目越来越大:

text 复制代码
src/
├── user.js
├── order.js
├── product.js
├── payment.js
├── login.js
├── notification.js
├── utils.js
├── db.js
└── index.js

然后你会慢慢遇到几个问题。


1. 项目架构没有统一约束

Express 本身非常自由。

你可以这样:

text 复制代码
controller
   ↓
service
   ↓
repository

也可以直接:

text 复制代码
controller
   ↓
database

甚至:

text 复制代码
controller
   ↓
controller
   ↓
utils
   ↓
database

框架不会管你。

所以:

Express 给你的是能力,而不是架构。

NestJS 则明确规定了一套推荐的组织方式。


三、NestJS 最核心的几个概念

如果你想真正理解 NestJS,我建议重点理解这 5 个东西:

text 复制代码
Module
Controller
Provider
Dependency Injection
Guard / Pipe / Interceptor / Middleware

其中前三个是最核心的。


四、Controller:负责接收请求

比如:

typescript 复制代码
@Controller('users')
export class UserController {

  @Get()
  getUsers() {
    return ['Tom', 'Jerry']
  }

}

对应:

http 复制代码
GET /users

Controller 的职责非常明确:

处理 HTTP 请求。

所以不要把大量业务逻辑塞进 Controller。

推荐:

text 复制代码
HTTP Request
     ↓
Controller
     ↓
Service
     ↓
Database

而不是:

text 复制代码
HTTP Request
     ↓
Controller
     ├── 参数处理
     ├── 权限判断
     ├── 业务逻辑
     ├── SQL
     ├── 日志
     └── 返回数据

五、Service:负责业务逻辑

例如:

typescript 复制代码
@Injectable()
export class UserService {

  async getUser(id: number) {
    const user = await this.userRepository.findById(id)

    if (!user) {
      throw new Error('用户不存在')
    }

    return user
  }

}

Controller:

typescript 复制代码
@Controller('users')
export class UserController {

  constructor(
    private readonly userService: UserService
  ) {}

  @Get(':id')
  getUser(@Param('id') id: number) {
    return this.userService.getUser(id)
  }

}

这里出现了 NestJS 非常重要的东西:

Dependency Injection(依赖注入,DI)


六、Dependency Injection:NestJS 的核心

这个东西如果你了解 Spring,就会特别熟悉。

Java:

java 复制代码
@Service
public class UserService {
}

然后:

java 复制代码
@RestController
public class UserController {

    @Autowired
    private UserService userService;

}

NestJS:

typescript 复制代码
@Injectable()
export class UserService {
}

然后:

typescript 复制代码
@Controller('users')
export class UserController {

  constructor(
    private readonly userService: UserService
  ) {}

}

NestJS 会自动:

text 复制代码
UserController
       │
       │ 需要 UserService
       ↓
NestJS Container
       │
       ↓
创建 UserService
       │
       ↓
注入 UserController

这就是依赖注入。


七、Module:解决大型项目组织问题

假设我们的系统有:

text 复制代码
用户
订单
商品
支付
消息

NestJS 推荐拆成:

text 复制代码
AppModule
│
├── UserModule
│
├── OrderModule
│
├── ProductModule
│
├── PaymentModule
│
└── MessageModule

例如:

typescript 复制代码
@Module({
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

于是一个模块内部:

text 复制代码
UserModule
│
├── UserController
│       ↓
├── UserService
│       ↓
└── UserRepository

这样业务边界非常清晰。


八、NestJS 真正帮我们解决的是什么?

我认为可以归纳成 6 个问题

① 解决项目结构混乱

Express:

text 复制代码
随便组织

NestJS:

text 复制代码
Module
 ├── Controller
 ├── Service
 ├── Provider
 └── Repository

让大型项目具有统一结构。


② 解决依赖管理问题

例如:

text 复制代码
OrderService
    ↓
UserService
    ↓
UserRepository
    ↓
Database

NestJS DI Container 自动管理这些对象。

你不需要到处:

typescript 复制代码
new UserService()
new UserRepository()
new Database()

而是:

typescript 复制代码
constructor(
  private userService: UserService
) {}

九、③ 解决横切逻辑问题

这是 NestJS 非常重要的能力。

比如:

text 复制代码
所有 API
   │
   ├── 登录校验
   ├── 权限校验
   ├── 参数校验
   ├── 日志
   ├── 异常处理
   └── 数据转换

这些东西不应该每个 Controller 都写一遍。

NestJS 提供:

text 复制代码
Middleware
Guard
Pipe
Interceptor
Exception Filter

可以理解成:

text 复制代码
Request
   │
   ↓
Middleware
   │
   ↓
Guard
   │
   ↓
Pipe
   │
   ↓
Controller
   │
   ↓
Service
   │
   ↓
Interceptor
   │
   ↓
Response

例如权限:

typescript 复制代码
@UseGuards(AuthGuard)
@Get('/profile')
getProfile() {
}

这样就不需要每个接口自己判断:

typescript 复制代码
if (!user) {
   ...
}

十、④ 解决参数校验问题

例如接口:

http 复制代码
POST /users

请求:

json 复制代码
{
  "name": "张三",
  "age": 18,
  "email": "xxx"
}

NestJS 可以配合 DTO:

typescript 复制代码
export class CreateUserDto {

  @IsString()
  name: string

  @IsInt()
  @Min(0)
  age: number

  @IsEmail()
  email: string
}

Controller:

typescript 复制代码
@Post()
createUser(
  @Body() dto: CreateUserDto
) {
  return this.userService.create(dto)
}

于是:

text 复制代码
HTTP Request
      ↓
DTO
      ↓
ValidationPipe
      ↓
Controller
      ↓
Service

参数校验从业务代码里面被抽离出来。


十一、⑤ 解决大型系统扩展问题

NestJS 不只是用来写 REST API。

它还支持:

text 复制代码
REST API
GraphQL
WebSocket
Microservices
消息队列
事件驱动
定时任务

例如:

text 复制代码
                    NestJS
                       │
       ┌───────────────┼───────────────┐
       ↓               ↓               ↓
     REST           GraphQL        WebSocket
       │               │               │
       └───────────────┼───────────────┘
                       ↓
                  Business Layer
                       │
              ┌────────┼────────┐
              ↓        ↓        ↓
             MySQL    Redis    MQ

所以 NestJS 比较适合:

企业级 Node.js 后端。


十二、⑥ 解决测试问题

因为 NestJS 大量使用 DI,所以测试比较容易。

例如:

typescript 复制代码
UserController
       ↓
UserService
       ↓
UserRepository

测试 Controller 的时候,可以把真正的 UserService 换成 Mock。

text 复制代码
UserController
       ↓
MockUserService

这样不用真的连接数据库。

这对大型项目非常重要。


十三、NestJS 和 Express 到底是什么关系?

这个问题很重要。

不要理解成:

text 复制代码
Express vs NestJS

完全是两个竞争层次。

更准确:

text 复制代码
                NestJS
                   │
          ┌────────┴────────┐
          ↓                 ↓
       Express           Fastify
          ↓                 ↓
        Node.js           Node.js

NestJS 是更高层的应用框架。

Express/Fastify 更偏底层 HTTP Server。

所以:

typescript 复制代码
NestJS + Express

或者:

typescript 复制代码
NestJS + Fastify

都可以。


十四、如果你熟悉 Spring Boot,可以这样对照

这个对你理解 NestJS 非常有帮助:

NestJS Spring Boot
@Module() 配置/模块体系
@Controller() @RestController
@Injectable() @Service / Bean
Constructor Injection @Autowired
Provider Bean
Guard Interceptor / Filter / Security
Pipe 参数校验/转换
Interceptor Interceptor
Exception Filter ExceptionHandler
Middleware Filter
DTO DTO
TypeORM / Prisma JPA / MyBatis
NestJS DI Container Spring IoC Container

所以如果一句话总结:

NestJS ≈ Node.js 世界里的 Spring Boot。

当然两者底层实现不同,但在工程思想上非常接近。


十五、什么时候应该用 NestJS?

我会这样判断:

小项目

例如:

text 复制代码
一个简单 BFF
一个小工具 API
10 个接口以内

Express/Fastify 可能就够了。


中大型项目

例如:

text 复制代码
用户系统
订单系统
支付系统
权限系统
消息系统
管理后台 API

推荐 NestJS。

因为这时候最重要的问题已经不是:

"怎么写一个 HTTP 接口?"

而是:

"几十个人一起开发,半年后这个项目还能不能维护?"

这就是 NestJS 的价值。


十六、用一个实际项目理解

假设你要开发一个电商后端:

text 复制代码
                    Ecommerce
                        │
        ┌───────────────┼──────────────┐
        ↓               ↓              ↓
      User            Order          Product
        │               │              │
   UserModule       OrderModule    ProductModule
        │               │              │
   Controller       Controller     Controller
        │               │              │
     Service          Service        Service
        │               │              │
   Repository       Repository     Repository
        │               │              │
        └───────────────┼──────────────┘
                        ↓
                    Database

同时所有请求:

text 复制代码
Request
   ↓
Middleware
   ↓
AuthGuard
   ↓
ValidationPipe
   ↓
Controller
   ↓
Service
   ↓
Repository
   ↓
Database

NestJS 的核心价值就是帮你把这套东西标准化、模块化、自动化


十七、所以 NestJS 到底解决了什么?

我建议你记住这一句话:

Node.js 本身解决的是"能不能写后端",NestJS 解决的是"怎么把 Node.js 后端工程化"。

再进一步:

text 复制代码
Node.js
  ↓
提供运行时能力

Express / Fastify
  ↓
提供 HTTP 能力

NestJS
  ↓
提供企业级应用架构

DI + Module + Controller + Service
  ↓
解决代码组织和依赖管理

Guard + Pipe + Interceptor + Filter
  ↓
解决横切逻辑

DTO + Validation
  ↓
解决输入数据治理

Testing + CLI + Ecosystem
  ↓
解决工程效率和可维护性

所以如果你现在是从前端 / Node.js → AI Agent / 后端工程 这个方向学习,我会建议重点掌握 NestJS 的 Module、DI、Provider、Guard、Pipe、Interceptor,而不是先去背 API。

这几个概念掌握以后,你会发现它和你最近在研究的 Skill / Agent / Workflow / Plugin 的架构思想其实也非常相似:模块化 + 依赖注入 + 生命周期 + 中间层拦截 + 编排

下面我不只讲"注解一一对应",而是从一个完整请求是怎么进入系统、经过 Controller、Service、依赖注入、校验、权限、异常处理,最后访问数据库的角度,把 NestJS 和 Spring Boot 放在一起讲。

先记住一个核心:

NestJS 和 Spring Boot 的很多设计思想高度相似,但不是注解的机械翻译。

NestJS 更像是把 Spring 的 IoC、模块化、AOP/拦截器、参数校验等思想,用 TypeScript/Node.js 重新实现了一遍。


一、先建立整体认知

假设我们开发一个用户查询接口:

http 复制代码
GET /users/100

Spring Boot:

text 复制代码
HTTP Request
     ↓
Controller
     ↓
Service
     ↓
Repository
     ↓
Database

NestJS:

text 复制代码
HTTP Request
     ↓
Middleware
     ↓
Guard
     ↓
Pipe
     ↓
Controller
     ↓
Service
     ↓
Repository
     ↓
Database

两者的核心业务结构其实非常接近:

职责 NestJS Spring Boot
HTTP 接口 Controller Controller
业务逻辑 Service / Provider Service
数据访问 Repository / Provider Repository / Mapper
依赖注入 DI IoC / DI
模块 Module Spring Bean + Configuration / Package
参数校验 Pipe + DTO Validation + DTO
权限 Guard Spring Security
请求拦截 Interceptor Interceptor
全局异常 Exception Filter @ControllerAdvice
中间件 Middleware Filter
ORM TypeORM / Prisma JPA / MyBatis
配置 ConfigModule application.yml
定时任务 Schedule @Scheduled

下面逐个展开。


二、Controller:处理 HTTP 请求

这是最容易理解的一组。

NestJS

typescript 复制代码
import { Controller, Get, Param } from '@nestjs/common';

@Controller('users')
export class UserController {

  @Get(':id')
  getUser(@Param('id') id: string) {
    return {
      id,
      name: '张三'
    };
  }
}

请求:

http 复制代码
GET /users/100

NestJS 会匹配:

text 复制代码
@Controller('users')
       +
@Get(':id')
       ↓
GET /users/100

Spring Boot

java 复制代码
@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public User getUser(@PathVariable String id) {
        return new User(id, "张三");
    }
}

对应关系:

text 复制代码
NestJS                         Spring Boot

@Controller              →    @RestController
@Get()                    →    @GetMapping
@Post()                   →    @PostMapping
@Put()                    →    @PutMapping
@Delete()                 →    @DeleteMapping

@Param()                  →    @PathVariable
@Query()                  →    @RequestParam
@Body()                   →    @RequestBody
@Headers()                →    @RequestHeader

例如 NestJS:

typescript 复制代码
@Get()
findUsers(
  @Query('page') page: number,
  @Query('size') size: number
) {
}

Spring:

java 复制代码
@GetMapping
public List<User> findUsers(
    @RequestParam Integer page,
    @RequestParam Integer size
) {
}

三、Service:业务逻辑

这是后端项目最重要的分层之一。

假设:

text 复制代码
查询用户
↓
检查用户是否存在
↓
检查用户状态
↓
查询订单
↓
组装返回数据

这些东西不应该全部写在 Controller。


NestJS

typescript 复制代码
import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {

  async getUser(id: string) {

    const user = await this.userRepository.findById(id);

    if (!user) {
      throw new Error('用户不存在');
    }

    return user;
  }
}

Controller:

typescript 复制代码
@Controller('users')
export class UserController {

  constructor(
    private readonly userService: UserService
  ) {}

  @Get(':id')
  getUser(@Param('id') id: string) {
    return this.userService.getUser(id);
  }
}

Spring Boot

java 复制代码
@Service
public class UserService {

    public User getUser(String id) {

        User user = userRepository.findById(id);

        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        return user;
    }
}

Controller:

java 复制代码
@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public User getUser(@PathVariable String id) {
        return userService.getUser(id);
    }
}

对应:

text 复制代码
NestJS                         Spring Boot

@Injectable()             →    @Service
UserService               →    UserService
constructor injection     →    constructor injection

这里有一个重要区别:

Spring

很多老项目会看到:

java 复制代码
@Autowired
private UserService userService;

这是字段注入

现在更推荐:

java 复制代码
public UserController(UserService userService) {
    this.userService = userService;
}

NestJS

天然推荐构造函数注入:

typescript 复制代码
constructor(
  private readonly userService: UserService
) {}

所以这一块 NestJS 和现代 Spring Boot 的思想非常接近。


四、Provider:NestJS 比较特殊的概念

这里非常容易产生误解。

很多资料会简单说:

text 复制代码
NestJS Provider ≈ Spring Bean

这个理解是对的,但要更精确一点。

NestJS:

typescript 复制代码
@Injectable()
export class UserService {
}

它是一个 Provider。

但 Provider 不一定是 Service:

typescript 复制代码
@Injectable()
export class UserService {}

@Injectable()
export class OrderService {}

@Injectable()
export class UserRepository {}

都可以是 Provider。

甚至:

typescript 复制代码
{
  provide: 'DATABASE',
  useFactory: () => {
    return createDatabase();
  }
}

也是 Provider。

所以:

Provider 是 NestJS DI 容器管理的"依赖对象"。

Spring 中对应的概念更接近:

Bean

例如:

java 复制代码
@Component
public class UserRepository {
}

或者:

java 复制代码
@Service
public class UserService {
}

或者:

java 复制代码
@Bean
public DataSource dataSource() {
    return ...
}

它们最终都是进入 Spring IoC 容器的 Bean。


五、Module:NestJS 非常重要

这是 NestJS 和 Spring Boot 理解上的一个关键点。

NestJS:

typescript 复制代码
@Module({
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

可以理解成:

text 复制代码
UserModule
│
├── UserController
│
└── UserService

然后:

typescript 复制代码
@Module({
  imports: [
    UserModule
  ]
})
export class AppModule {}

形成:

text 复制代码
AppModule
    │
    └── UserModule
            │
            ├── UserController
            └── UserService

六、Spring Boot 有没有 Module?

这里不能简单说:

text 复制代码
NestJS @Module() = Spring @Module()

因为 Spring Boot 没有完全等价的 @Module()

Spring 更依赖:

text 复制代码
Package
+
@Component
+
@Service
+
@Repository
+
@Configuration
+
@Bean
+
@ComponentScan

例如:

java 复制代码
@Configuration
public class UserConfig {

    @Bean
    public UserService userService() {
        return new UserService();
    }
}

Spring 会把它加入 IoC 容器。

所以:

text 复制代码
NestJS

@Module()
   ↓
明确声明模块边界
   ↓
imports
providers
controllers
exports

而 Spring:

text 复制代码
@Component
@Service
@Repository
@Configuration
@Bean
   ↓
IoC Container
   ↓
通过 ComponentScan / Configuration 发现和组装

七、NestJS Module 最重要的四个属性

这是实际开发必须理解的。

typescript 复制代码
@Module({
  imports: [],
  controllers: [],
  providers: [],
  exports: []
})

分别是:

text 复制代码
imports
    ↓
我依赖哪些模块

controllers
    ↓
我提供哪些 HTTP Controller

providers
    ↓
我有哪些依赖对象

exports
    ↓
哪些 Provider 可以被其他 Module 使用

例如:

typescript 复制代码
@Module({
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService]
})
export class UserModule {}

然后 OrderModule:

typescript 复制代码
@Module({
  imports: [UserModule],
  providers: [OrderService]
})
export class OrderModule {}

于是:

text 复制代码
OrderModule
     │
     │ imports
     ↓
UserModule
     │
     │ exports
     ↓
UserService

这其实是在解决:

大型项目中的依赖边界问题。


八、DI:依赖注入

这是两套框架最核心的共同思想。

假设:

text 复制代码
OrderController
       ↓
OrderService
       ↓
UserService
       ↓
UserRepository

如果不用 DI,你可能写:

typescript 复制代码
const repository = new UserRepository();
const userService = new UserService(repository);
const orderService = new OrderService(userService);

非常麻烦。


NestJS

你只需要:

typescript 复制代码
constructor(
  private readonly userService: UserService
) {}

NestJS 自动完成:

text 复制代码
             NestJS Container

UserController
      ↑
      │ inject
      │
UserService
      ↑
      │ inject
      │
UserRepository

Spring Boot

同样:

java 复制代码
public UserController(UserService userService) {
    this.userService = userService;
}

Spring IoC Container:

text 复制代码
             Spring Container

UserController
      ↑
      │ inject
      │
UserService
      ↑
      │ inject
      │
UserRepository

九、为什么 DI 这么重要?

因为它解决了一个非常大的问题:

对象创建和业务使用解耦。

比如:

typescript 复制代码
class OrderService {

  constructor(
    private userService: UserService
  ) {}

}

OrderService 不关心:

text 复制代码
UserService
到底怎么创建?
有没有依赖?
依赖谁?
生命周期是什么?
是不是单例?

全部交给:

text 复制代码
DI Container

这就是 IoC:

控制反转。


十、DTO + 参数校验

这个在实际 API 开发中非常常用。

假设:

http 复制代码
POST /users

请求:

json 复制代码
{
  "name": "张三",
  "age": 18,
  "email": "test@example.com"
}

NestJS

定义 DTO:

typescript 复制代码
export class CreateUserDto {

  @IsString()
  name: string;

  @IsInt()
  @Min(0)
  age: number;

  @IsEmail()
  email: string;
}

Controller:

typescript 复制代码
@Post()
createUser(
  @Body() dto: CreateUserDto
) {
  return this.userService.createUser(dto);
}

开启:

typescript 复制代码
app.useGlobalPipes(
  new ValidationPipe()
);

请求进入:

text 复制代码
HTTP Request
      ↓
ValidationPipe
      ↓
CreateUserDto
      ↓
Controller

如果:

json 复制代码
{
  "name": 123,
  "age": -10
}

直接校验失败。


十一、Spring Boot 的 DTO 校验

Java:

java 复制代码
public class CreateUserRequest {

    @NotBlank
    private String name;

    @Min(0)
    private Integer age;

    @Email
    private String email;
}

Controller:

java 复制代码
@PostMapping
public User createUser(
    @Valid @RequestBody CreateUserRequest request
) {
    return userService.createUser(request);
}

对应关系:

text 复制代码
NestJS                         Spring Boot

DTO                       →    DTO

@IsString()               →    @Pattern / 类型约束
@IsNotEmpty()              →    @NotEmpty
@IsEmail()                 →    @Email
@Min()                     →    @Min
@Max()                     →    @Max

ValidationPipe             →    Bean Validation

class-validator            →    Jakarta Validation

所以:

text 复制代码
NestJS

DTO
 ↓
ValidationPipe
 ↓
Controller

对应:

text 复制代码
Spring

DTO
 ↓
@Valid
 ↓
Controller

十二、Guard:权限控制

NestJS 的 Guard 很重要。

例如:

typescript 复制代码
@Injectable()
export class AuthGuard implements CanActivate {

  canActivate(context: ExecutionContext): boolean {

    const request = context.switchToHttp().getRequest();

    return !!request.user;
  }
}

使用:

typescript 复制代码
@UseGuards(AuthGuard)
@Get('/profile')
getProfile() {
}

请求:

text 复制代码
Request
   ↓
AuthGuard
   ↓
是否登录?
   ↓
Controller

十三、Spring Boot 对应什么?

Spring Boot 通常使用:

text 复制代码
Spring Security

例如:

java 复制代码
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public String admin() {
    return "admin";
}

或者:

java 复制代码
.securityMatcher(...)

所以:

text 复制代码
NestJS Guard
        ↓
权限 / 登录 / RBAC

大体对应:

text 复制代码
Spring Security
        ↓
认证 / 授权 / RBAC

但是:

Guard 并不等于 Spring Security。

Guard 是 NestJS 的一个扩展点,而 Spring Security 是 Spring 生态中完整的安全框架。


十四、Middleware:中间件

Middleware 更接近 HTTP 请求最外层。

NestJS:

typescript 复制代码
@Injectable()
export class LoggerMiddleware {

  use(req, res, next) {

    console.log(req.method, req.url);

    next();
  }
}

请求:

text 复制代码
Request
   ↓
Middleware
   ↓
Controller

常用于:

text 复制代码
日志
请求 ID
Cookie
Header
原始请求处理

Spring Boot

传统 Spring:

text 复制代码
Filter

例如:

java 复制代码
@Component
public class LogFilter implements Filter {

    @Override
    public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain
    ) {

        System.out.println("request");

        chain.doFilter(request, response);
    }
}

所以:

text 复制代码
NestJS Middleware
        ≈
Spring Filter

但不是严格的一一对应。


十五、Interceptor:拦截器

这个概念 NestJS 非常有意思。

例如:

typescript 复制代码
@Injectable()
export class LoggingInterceptor
  implements NestInterceptor {

  intercept(context: ExecutionContext, next: CallHandler) {

    console.log('before');

    return next.handle().pipe(
      tap(() => console.log('after'))
    );
  }
}

执行:

text 复制代码
Request
   ↓
Interceptor
   ↓
Controller
   ↓
Service
   ↓
Interceptor
   ↓
Response

它可以同时处理:

text 复制代码
请求前
+
请求后

所以可以做:

text 复制代码
日志
耗时统计
Response 包装
缓存
数据转换

十六、Spring Boot Interceptor

Spring:

java 复制代码
@Component
public class LoggingInterceptor
        implements HandlerInterceptor {

    @Override
    public boolean preHandle(...) {
        System.out.println("before");
        return true;
    }

    @Override
    public void afterCompletion(...) {
        System.out.println("after");
    }
}

所以:

text 复制代码
NestJS Interceptor
        ≈
Spring HandlerInterceptor

两者思想非常接近。


十七、Exception Filter vs @ControllerAdvice

这是另一组非常重要的对应关系。

NestJS:

typescript 复制代码
@Catch(HttpException)
export class HttpExceptionFilter
  implements ExceptionFilter {

  catch(exception, host) {

    const response = host
      .switchToHttp()
      .getResponse();

    response.status(500).json({
      code: 500,
      message: '服务器错误'
    });
  }
}

可以全局注册:

typescript 复制代码
app.useGlobalFilters(
  new HttpExceptionFilter()
);

Spring Boot

通常:

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> handle(Exception e) {

        return ResponseEntity
            .status(500)
            .body(...);
    }
}

所以:

text 复制代码
NestJS ExceptionFilter
        ↓
全局异常处理

Spring @RestControllerAdvice
        ↓
全局异常处理

这个对应非常强。


十八、完整请求生命周期对比

现在把前面所有东西串起来。

NestJS

text 复制代码
                    HTTP Request
                         │
                         ↓
                    Middleware
                         │
                         ↓
                       Guard
                         │
                         ↓
                        Pipe
                         │
                         ↓
                    Interceptor
                         │
                         ↓
                    Controller
                         │
                         ↓
                      Service
                         │
                         ↓
                    Repository
                         │
                         ↓
                      Database
                         │
                         ↓
                    Interceptor
                         │
                         ↓
                      Response
                         │
                         ↓
                  Exception Filter

Spring Boot

text 复制代码
                    HTTP Request
                         │
                         ↓
                       Filter
                         │
                         ↓
                  Spring Security
                         │
                         ↓
                    Interceptor
                         │
                         ↓
                    Controller
                         │
                         ↓
                      Service
                         │
                         ↓
                    Repository
                         │
                         ↓
                      Database
                         │
                         ↓
                    Interceptor
                         │
                         ↓
                      Response
                         │
                         ↓
                @ControllerAdvice

你会发现:

两者解决的问题高度相似。


十九、ORM:TypeORM / Prisma vs JPA / MyBatis

NestJS 本身并不强制你使用某个 ORM。

常见:

text 复制代码
NestJS
├── TypeORM
├── Prisma
├── Sequelize
└── Drizzle

例如 TypeORM:

typescript 复制代码
@Entity()
export class User {

  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;
}

Repository:

typescript 复制代码
@Injectable()
export class UserRepository {

  constructor(
    @InjectRepository(User)
    private repository: Repository<User>
  ) {}

  findById(id: number) {
    return this.repository.findOneBy({ id });
  }
}

Spring Boot:

java 复制代码
@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String name;
}

Repository:

java 复制代码
public interface UserRepository
        extends JpaRepository<User, Long> {

}

对应:

text 复制代码
NestJS TypeORM
       ↓
Entity
       ↓
Repository

Spring JPA
       ↓
Entity
       ↓
Repository

但如果 Spring 使用 MyBatis:

text 复制代码
Service
   ↓
Mapper
   ↓
SQL

这又是另一种数据访问模式。


二十、配置管理

NestJS:

typescript 复制代码
ConfigModule.forRoot({
  isGlobal: true
});

然后:

typescript 复制代码
constructor(
  private configService: ConfigService
) {}

const port =
  this.configService.get('PORT');

配置:

text 复制代码
.env

PORT=3000
DATABASE_URL=xxx

Spring Boot:

yaml 复制代码
server:
  port: 8080

database:
  url: xxx

Java:

java 复制代码
@Value("${server.port}")
private Integer port;

或者更推荐:

java 复制代码
@ConfigurationProperties(prefix = "database")

所以:

text 复制代码
NestJS ConfigModule
        ≈
Spring Boot Configuration

二十一、一个完整 User 模块对照

现在我们写一个真正的 CRUD。

NestJS

text 复制代码
user/
├── user.module.ts
├── user.controller.ts
├── user.service.ts
├── user.repository.ts
├── user.entity.ts
└── dto/
    └── create-user.dto.ts

Module

typescript 复制代码
@Module({
  controllers: [UserController],
  providers: [
    UserService,
    UserRepository
  ],
  exports: [
    UserService
  ]
})
export class UserModule {}

Controller

typescript 复制代码
@Controller('users')
export class UserController {

  constructor(
    private userService: UserService
  ) {}

  @Get(':id')
  getUser(@Param('id') id: string) {
    return this.userService.getUser(id);
  }

  @Post()
  createUser(
    @Body() dto: CreateUserDto
  ) {
    return this.userService.createUser(dto);
  }
}

Service

typescript 复制代码
@Injectable()
export class UserService {

  constructor(
    private userRepository: UserRepository
  ) {}

  getUser(id: string) {
    return this.userRepository.findById(id);
  }

  createUser(dto: CreateUserDto) {
    return this.userRepository.create(dto);
  }
}

二十二、Spring Boot 对应结构

text 复制代码
user/
├── UserController.java
├── UserService.java
├── UserRepository.java
├── User.java
└── CreateUserRequest.java

Controller:

java 复制代码
@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    public UserController(
        UserService userService
    ) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public User getUser(
        @PathVariable String id
    ) {
        return userService.getUser(id);
    }

    @PostMapping
    public User createUser(
        @Valid @RequestBody CreateUserRequest request
    ) {
        return userService.createUser(request);
    }
}

Service:

java 复制代码
@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(
        UserRepository userRepository
    ) {
        this.userRepository = userRepository;
    }

    public User getUser(String id) {
        return userRepository.findById(id);
    }

    public User createUser(
        CreateUserRequest request
    ) {
        return userRepository.save(...);
    }
}

你会发现两者几乎是同一种架构思想。


二十三、最重要的不是"注解对应",而是思想对应

我建议你把这张图记下来:

text 复制代码
                 NestJS                          Spring Boot

                   │                                  │
                   │                                  │
              @Module()                         Configuration
                   │                                  │
                   ↓                                  ↓
             DI Container                       IoC Container
                   │                                  │
          ┌────────┼────────┐                ┌────────┼────────┐
          ↓        ↓        ↓                ↓        ↓        ↓
      Controller Service Repository       Controller Service Repository
          │        │        │                │        │        │
          └────────┼────────┘                └────────┼────────┘
                   ↓                                  ↓
                Database                           Database

横切能力:

text 复制代码
NestJS                              Spring Boot

Middleware                     →   Filter
Guard                          →   Spring Security
Pipe                           →   Validation
Interceptor                    →   HandlerInterceptor
ExceptionFilter                →   ControllerAdvice

二十四、如果你从前端转 NestJS,最应该先学什么?

结合你本身前端 + Node.js 的背景,我建议不要一上来学一堆 NestJS API。

按照这个顺序:

第一阶段:理解 NestJS 基础架构

text 复制代码
Module
   ↓
Controller
   ↓
Provider / Service
   ↓
DI

先搞懂:

NestJS 到底是怎么创建和管理对象的。


第二阶段:掌握请求生命周期

text 复制代码
Middleware
    ↓
Guard
    ↓
Pipe
    ↓
Interceptor
    ↓
Controller
    ↓
Service

这部分理解后,你基本就知道 NestJS 为什么这样设计。


第三阶段:数据库

学习:

text 复制代码
Entity
Repository
Transaction
ORM
Migration

建议选一个:

text 复制代码
NestJS + Prisma

或者:

text 复制代码
NestJS + TypeORM

第四阶段:企业级能力

再学习:

text 复制代码
JWT
RBAC
Redis
MQ
WebSocket
Microservices
Logging
Config
Testing

二十五、最后给你一张"脑图"

如果让我用最少的概念解释两者:

text 复制代码
                 后端应用
                    │
        ┌───────────┴───────────┐
        │                       │
      NestJS                Spring Boot
        │                       │
        ↓                       ↓
      Module                  IoC
        │                       │
        └───────────┬───────────┘
                    ↓
               Dependency
               Injection
                    │
                    ↓
        ┌───────────┼───────────┐
        ↓           ↓           ↓
   Controller    Service    Repository
        │           │           │
        └───────────┼───────────┘
                    ↓
                 Database

横切能力:

Middleware    → Filter
Guard         → Spring Security
Pipe          → Validation
Interceptor   → Interceptor
Exception     → ControllerAdvice

最核心的一句话:

Spring Boot 和 NestJS 都是在解决"如何把一个简单的 HTTP Server,发展成一个可维护、可扩展、可测试的企业级后端系统"。

其中 Spring Boot 的核心是 IoC/DI + Spring 容器 + 自动配置 + Spring 生态 ;NestJS 的核心则是 Module + DI/Provider + Controller + 生命周期/请求管道 + TypeScript 工程化

如果你接下来想真正掌握 NestJS,我建议下一步直接讲一个非常关键的主题:"NestJS 启动时到底发生了什么?main.ts → AppModule → Module → Provider → DI Container → Controller 是怎么一步步把整个应用启动起来的。" 这会把前面这些概念真正串起来。

相关推荐
码事漫谈1 小时前
DeepSeek 明天又降价(涵历史价格对比)
后端
国奉1 小时前
从零设计一个 iOS 文件浏览器:Sandbox、FileManager、Document Picker 与文件架构
后端
前端兰博2 小时前
04-数据库-MySQL
后端·mysql
她的男孩2 小时前
接口加密做成框架级能力有多难?我扒了 3600 行源码:从 RSA 握手到落库密文迁移
人工智能·后端·架构
掘金挖土2 小时前
前端手摸手跑路之 AI 应用开发(二)
前端·后端
kyrie_sakura2 小时前
MySQL数据库学习笔记2--系统函数(分组,单行,窗口函数)
数据库·学习·mysql
dadaobusi2 小时前
学习:XS-Gem5参数
学习
遨翔在知识的海洋里2 小时前
nest(5)-文件上传和静态资源
后端
遨翔在知识的海洋里3 小时前
nest(3)-jwt和RBAC
后端