NestJS 企业级应用开发实战
使用 NestJS 构建可扩展、可维护的企业级后端应用,涵盖架构设计、模块化、数据库集成等。
4 天前
8 分钟阅读
421 次浏览
NestJS 企业级应用开发实战
NestJS 是一个用于构建高效、可扩展的 Node.js 服务器端应用的框架。它使用渐进式 JavaScript,完全支持 TypeScript。
为什么选择 NestJS?
- TypeScript 优先:完整的类型安全
- 模块化架构:易于组织和维护
- 依赖注入:松耦合、易测试
- 开箱即用:集成常用功能
- 企业级架构:适合大型项目
项目结构
text
src/
├── app.module.ts
├── main.ts
├── common/ # 公共模块
│ ├── filters/
│ ├── guards/
│ ├── interceptors/
│ └── pipes/
├── config/ # 配置
│ └── database.config.ts
├── modules/
│ ├── users/
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── users.module.ts
│ │ ├── dto/
│ │ └── entities/
│ └── posts/
└── shared/ # 共享资源基础模块
Controller
typescript
import { Controller, Get, Post, Body, Param, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
@ApiTags('posts')
@Controller('posts')
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@Get()
@ApiOperation({ summary: '获取所有文章' })
findAll() {
return this.postsService.findAll();
}
@Post()
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: '创建文章' })
create(@Body() createPostDto: CreatePostDto) {
return this.postsService.create(createPostDto);
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.postsService.findOne(id);
}
}Service
typescript
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Post)
private postsRepository: Repository<Post>,
) {}
async findAll(): Promise<Post[]> {
return this.postsRepository.find({
relations: ['author', 'tags'],
});
}
async findOne(id: string): Promise<Post> {
const post = await this.postsRepository.findOne({
where: { id },
relations: ['author', 'tags'],
});
if (!post) {
throw new NotFoundException(`Post with ID ${id} not found`);
}
return post;
}
async create(createPostDto: CreatePostDto): Promise<Post> {
const post = this.postsRepository.create(createPostDto);
return this.postsRepository.save(post);
}
}Module
typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
import { Post } from './entities/post.entity';
@Module({
imports: [TypeOrmModule.forFeature([Post])],
controllers: [PostsController],
providers: [PostsService],
exports: [PostsService],
})
export class PostsModule {}DTO 和验证
typescript
import { IsString, IsNotEmpty, MinLength, IsOptional } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreatePostDto {
@ApiProperty({ description: '文章标题' })
@IsString()
@IsNotEmpty()
@MinLength(3)
title: string;
@ApiProperty({ description: '文章内容' })
@IsString()
@IsNotEmpty()
content: string;
@ApiProperty({ description: '摘要', required: false })
@IsString()
@IsOptional()
excerpt?: string;
}数据库集成(TypeORM)
Entity
typescript
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, ManyToMany } from 'typeorm';
@Entity('posts')
export class Post {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
title: string;
@Column('text')
content: string;
@Column({ nullable: true })
excerpt: string;
@Column({ default: 0 })
viewCount: number;
@ManyToOne(() => User, user => user.posts)
author: User;
@ManyToMany(() => Tag, tag => tag.posts)
tags: Tag[];
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;
}认证与授权
JWT 策略
typescript
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET,
});
}
async validate(payload: any) {
return { userId: payload.sub, email: payload.email, role: payload.role };
}
}Guards
typescript
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some(role => user.role === role);
}
}
// 使用
@Post()
@Roles('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
create(@Body() createPostDto: CreatePostDto) {
return this.postsService.create(createPostDto);
}拦截器
typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => ({
success: true,
data,
timestamp: new Date().toISOString(),
})),
);
}
}异常过滤器
typescript
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception.getStatus();
response.status(status).json({
success: false,
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.message,
});
}
}配置管理
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.env.${process.env.NODE_ENV}`,
}),
],
})
export class AppModule {}测试
单元测试
typescript
describe('PostsService', () => {
let service: PostsService;
let repository: Repository<Post>;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [
PostsService,
{
provide: getRepositoryToken(Post),
useValue: {
find: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
save: jest.fn(),
},
},
],
}).compile();
service = module.get<PostsService>(PostsService);
repository = module.get<Repository<Post>>(getRepositoryToken(Post));
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});最佳实践
- 使用 DTO 验证输入
- 合理使用依赖注入
- 模块化设计
- 编写测试
- 使用环境变量
- 日志记录
- API 文档(Swagger)
- 错误处理
总结
NestJS 提供了构建企业级应用所需的一切:
- 强大的架构模式
- 完整的 TypeScript 支持
- 丰富的生态系统
- 易于测试和维护
标签:NestJS, Node.js, TypeScript
周温
全栈开发工程师,专注于前端技术栈和物联网应用开发。拥有丰富的 React、Next.js、Nest.js 项目经验,擅长构建高性能、可扩展的 Web 应用。
相关文章
浏览相关文章,深入了解技术主题
前端救星:Mock、Express 与 JSON Server 助力前后端联调与独立开发
前端救星:在前端开发中,等待后端接口的日子,是所有前端工程师共同的噩梦,Mock、Express 与 JSON Server 助力前后端联调与独立开发。
React Hooks 完全指北(2025 版)
React Hooks 是 React 16.8 引入的革命性特性,它让函数组件拥有了状态管理和副作用处理的能力。本文将从设计哲学、核心 Hooks、高级应用、性能优化、最佳实践等多个维度,为你提供一份完整的 React Hooks 学习指南。
欢迎来到 Code Compass
一个极简的技术博客,专注于分享前端开发经验和技术见解