手记

Nest项目实战:新手入门与初级指南

概述

本文详细介绍了如何使用Nest项目实战,从安装和创建第一个Nest项目开始,逐步引导读者了解路由与控制器、服务与模块以及数据库集成等内容。文章还涵盖了中间件与装饰器的使用,并提供了项目部署与测试的指导。

Nest.js 概述
Nest.js 简介

Nest.js 是一个基于 TypeScript 的 Web 框架,它使用现代的 JavaScript 和 Node.js 生态系统。Nest.js 的设计理念是构建可维护、可扩展和强大的服务器端应用程序。它结合了面向对象编程(OOP)和面向切面编程(AOP)的思想,并利用了 TypeScript 的静态类型检查,使得开发人员能够更加高效地编写代码。

Nest.js 旨在提供一个结构化、模块化的开发环境,它允许开发人员以更加清晰和组织化的形式来构建应用程序。Nest.js 使用依赖注入(Dependency Injection, DI)来管理应用程序中的依赖关系,并通过装饰器(Decorators)来增强类型安全和代码可读性。

Nest.js 的特点和优势
  1. 模块化架构:Nest.js 使用模块化架构来组织代码,每个模块可以独立地进行开发、测试和部署。这种结构使得代码保持清晰和易于维护。
  2. 依赖注入:依赖注入允许你将模块之间的依赖关系以一种清晰、可维护的方式管理,这使得代码更加松耦合,可扩展性更强。
  3. 类型安全:使用 TypeScript 进行开发,使得代码具有静态类型检查,提高代码的健壮性和可维护性。
  4. 高性能:Nest.js 采用 Express.js 作为其底层实现,具有很高的性能。
  5. 装饰器支持:装饰器是在 Nest.js 中广泛使用的一种特性,它使得代码更加简洁和易读。
安装 Nest.js
  1. 全局安装 Nest CLI

    npm install -g @nestjs/cli
  2. 创建一个新的 Nest.js 项目

    nest new my-nest-app

    这个命令会创建一个新的空项目,并初始化项目文件夹和一些基本的文件。

  3. 进入项目目录并安装依赖

    cd my-nest-app
    npm install
  4. 运行项目
    npm run start
创建第一个 Nest.js 项目

创建一个简单的 Nest.js 应用程序,首先需要创建一个控制器(Controller),一个控制器定义了应用程序的路由(Routes)和处理这些路由的逻辑(Handlers)。

  1. 创建一个控制器

    nest generate controller hello
  2. 编辑 hello.controller.ts 文件

    import { Controller, Get } from '@nestjs/common';
    
    @Controller('hello')
    export class HelloController {
       @Get()
       getHello(): string {
           return 'Hello World!';
       }
    }
  3. app.module.ts 文件中注册控制器

    import { Module } from '@nestjs/common';
    import { HelloController } from './hello/hello.controller';
    
    @Module({
       imports: [],
       controllers: [HelloController],
       providers: [],
    })
    export class AppModule {}
  4. 启动应用程序
    npm run start

访问 http://localhost:3000/hello 即可看到返回的 "Hello World!"。

路由与控制器

路由概念

在 Nest.js 中,路由的概念与 Express.js 类似。路由定义了应用程序如何响应客户端发送的 HTTP 请求。路由通常由一个控制器来处理,控制器中定义了处理这些路由的逻辑。

创建控制器

Nest.js 中的控制器可以使用 @Controller 装饰器来定义,并通过 @Get@Post@Put@Delete 等装饰器来定义具体的路由。

  1. 创建一个新的控制器

    nest generate controller user
  2. 编辑 user.controller.ts 文件

    import { Controller, Get, Post, Body } from '@nestjs/common';
    
    @Controller('user')
    export class UserController {
       @Get()
       getUsers(): string {
           return 'List of all users';
       }
    
       @Post()
       createUser(@Body() user): string {
           return `User ${user.name} has been created`;
       }
    }

路由参数与依赖注入

路由参数

Nest.js 支持在路由中使用参数。参数可以通过 @Param 装饰器来获取。

  1. 编辑 user.controller.ts 文件

    import { Controller, Get, Param } from '@nestjs/common';
    
    @Controller('user')
    export class UserController {
       @Get(':id')
       getUserById(@Param('id') id: string): string {
           return `User with ID ${id} has been fetched`;
       }
    }
  2. 运行应用程序
    访问 http://localhost:3000/user/1 或者其他 id,将会返回用户信息。

依赖注入

依赖注入是 Nest.js 中非常重要的一个概念,它使得组件之间的解耦更加容易,便于测试和维护。

  1. 创建一个服务

    nest generate service user
  2. 编辑 user.service.ts 文件

    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class UserService {
       getUsers(): string {
           return 'List of all users';
       }
    }
  3. 在控制器中注入服务

    import { Controller, Get, Param, Injectable, Inject } from '@nestjs/common';
    import { UserService } from './user.service';
    
    @Controller('user')
    export class UserController {
       constructor(private readonly userService: UserService) {}
    
       @Get()
       getUsers(): string {
           return this.userService.getUsers();
       }
    }
服务与模块

模块的概念

在 Nest.js 中,模块是用于组织和分组代码的一个高级概念。每个模块可以包含控制器、服务、提供者(Providers)和模块内的其他依赖关系。模块也可以依赖于其他模块,从而形成一个更加结构化的应用体系。

  1. 创建一个模块

    nest generate module users
  2. 编辑 users.module.ts 文件

    import { Module } from '@nestjs/common';
    import { UserController } from './user.controller';
    import { UserService } from './user.service';
    
    @Module({
       imports: [],
       controllers: [UserController],
       providers: [UserService],
       exports: [UserService],
    })
    export class UsersModule {}

创建服务

服务是 Nest.js 中主要的业务逻辑处理单元。服务通常包含处理数据库操作、业务逻辑等。

  1. 创建一个服务

    nest generate service user
  2. 编辑 user.service.ts 文件

    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class UserService {
       getUsers(): string {
           return 'List of all users';
       }
    }

服务与控制器的交互

控制器和服务之间的交互是通过依赖注入来实现的。控制器可以注入服务,并通过服务提供的方法来执行相应的业务逻辑。

  1. 编辑 user.controller.ts 文件

    import { Controller, Get, Param, Injectable, Inject } from '@nestjs/common';
    import { UserService } from './user.service';
    
    @Controller('user')
    export class UserController {
       constructor(private readonly userService: UserService) {}
    
       @Get()
       getUsers(): string {
           return this.userService.getUsers();
       }
    }
数据库集成

数据库连接设置

Nest.js 支持多种数据库,包括 MySQL、Postgres、MongoDB 等。这里以 MongoDB 为例。

  1. 安装 MongoDB 客户端库

    npm install @nestjs/mongoose mongoose
  2. 创建数据库模块

    nest generate module database
  3. 编辑 database.module.ts 文件

    import { Module } from '@nestjs/common';
    import { MongooseModule } from '@nestjs/mongoose';
    
    @Module({
       imports: [
           MongooseModule.forRoot('mongodb://localhost:27017/mydatabase'),
       ],
    })
    export class DatabaseModule {}
  4. 将数据库模块导入到主模块

    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { DatabaseModule } from './database/database.module';
    
    @Module({
       imports: [DatabaseModule],
       controllers: [AppController],
       providers: [AppService],
    })
    export class AppModule {}

操作数据库的基本方法

在 Nest.js 中,可以使用 Mongoose 模型来定义数据库中的集合(collections)。

  1. 定义 Mongoose 模型

    import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
    import { Document } from 'mongoose';
    
    export type UserDocument = User & Document;
    
    @Schema()
    export class User {
       @Prop()
       name: string;
    
       @Prop()
       email: string;
    }
    
    export const UserSchema = SchemaFactory.createForClass(User);
  2. 创建用户服务

    import { Injectable } from '@nestjs/common';
    import { Model } from 'mongoose';
    import { User, UserDocument } from './user.schema';
    import { InjectModel } from '@nestjs/mongoose';
    
    @Injectable()
    export class UserService {
       constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) {}
    
       async addUser(user: User): Promise<UserDocument> {
           const newUser = new this.userModel(user);
           return newUser.save();
       }
    
       async getUsers(): Promise<UserDocument[]> {
           return this.userModel.find().exec();
       }
    
       async updateUser(id: string, user: User): Promise<UserDocument> {
           return this.userModel.findOneAndUpdate({ _id: id }, user, { new: true }).exec();
       }
    
       async deleteUser(id: string): Promise<UserDocument> {
           return this.userModel.findByIdAndRemove(id).exec();
       }
    }
  3. 在控制器中调用服务

    import { Controller, Get, Post, Body, Put, Param } from '@nestjs/common';
    import { UserService } from './user.service';
    
    @Controller('user')
    export class UserController {
       constructor(private readonly userService: UserService) {}
    
       @Get()
       getUsers(): Promise<UserDocument[]> {
           return this.userService.getUsers();
       }
    
       @Post()
       addUser(@Body() user: User): Promise<UserDocument> {
           return this.userService.addUser(user);
       }
    
       @Put(':id')
       updateUser(@Param('id') id: string, @Body() user: User): Promise<UserDocument> {
           return this.userService.updateUser(id, user);
       }
    
       @Delete(':id')
       deleteUser(@Param('id') id: string): Promise<UserDocument> {
           return this.userService.deleteUser(id);
       }
    }
实战案例:创建、读取、更新与删除数据
  1. 创建数据

    @Post()
    addUser(@Body() user: User): Promise<UserDocument> {
       return this.userService.addUser(user);
    }
  2. 读取数据

    @Get()
    getUsers(): Promise<UserDocument[]> {
       return this.userService.getUsers();
    }
  3. 更新数据

    @Put(':id')
    updateUser(@Param('id') id: string, @Body() user: User): Promise<UserDocument> {
       return this.userService.updateUser(id, user);
    }
  4. 删除数据
    @Delete(':id')
    deleteUser(@Param('id') id: string): Promise<UserDocument> {
       return this.userService.deleteUser(id);
    }
常用中间件与装饰器

中间件的使用

在 Nest.js 中,中间件可以在请求到达控制器之前进行处理。中间件可以读取请求、响应,还可以执行一些额外的操作,比如身份验证、日志记录等。

  1. 创建中间件

    nest generate class logger
  2. 编辑 logger.ts 文件

    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';
    
    @Injectable()
    export class LoggerMiddleware implements NestMiddleware {
       use(req: Request, res: Response, next: NextFunction) {
           console.log('Request...', req.method, req.url);
           next();
       }
    }

3..

   import { Module } from '@nestjs/common';
   import { LoggerMiddleware } from './logger.middleware';

   @Module({
       providers: [],
       controllers: [],
       middlewares: [LoggerMiddleware],
   })
   export class AppModule {}
  1. 在控制器中使用中间件

    import { Controller, Get, Post, Body, UseInterceptors, UsePipes, ValidationPipe, UseGuards, UseMiddleware } from '@nestjs/common';
    import { LoggerMiddleware } from './logger.middleware';
    
    @Controller('user')
    export class UserController {
       @UseMiddleware(LoggerMiddleware)
       @Get()
       getUsers(): string {
           return 'List of all users';
       }
    }

装饰器的使用

Nest.js 中的装饰器可以用于定义路由、控制 HTTP 请求和响应、处理依赖关系等。装饰器使代码更加简洁和易读。

  1. 定义一个装饰器

    import { SetMetadata } from '@nestjs/common';
    
    export const Public = () => SetMetadata('isPublic', true);
  2. 在控制器中使用装饰器

    import { Controller, Get, Post, Body, UsePipes, ValidationPipe, UseGuards, Public } from '@nestjs/common';
    
    @Controller('user')
    export class UserController {
       @Get()
       @Public()
       getUsers(): string {
           return 'List of all users';
       }
    }
  3. 在服务中使用装饰器

    import { Injectable, Inject } from '@nestjs/common';
    
    @Injectable()
    export class UserService {
       @Inject()
       private readonly logger: LoggerService;
    
       getUsers(): string {
           this.logger.log('Fetching users...');
           return 'List of all users';
       }
    }
实战案例:实现日志记录与权限控制

实现日志记录

  1. 创建一个日志服务

    nest generate service logger
  2. 编辑 logger.service.ts 文件

    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class LoggerService {
       log(message: string): void {
           console.log('Logger:', message);
       }
    }
  3. 在服务中使用日志服务

    import { Injectable } from '@nestjs/common';
    import { LoggerService } from './logger.service';
    
    @Injectable()
    export class UserService {
       constructor(private readonly logger: LoggerService) {}
    
       getUsers(): string {
           this.logger.log('Fetching users...');
           return 'List of all users';
       }
    }

实现权限控制

  1. 创建一个权限管理服务

    nest generate service auth
  2. 编辑 auth.service.ts 文件

    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class AuthService {
       checkPermission(req): boolean {
           // 实现权限检查逻辑
           return true;
       }
    }
  3. 创建一个权限控制中间件

    nest generate class auth-middleware
  4. 编辑 auth.middleware.ts 文件

    import { Injectable, NestMiddleware } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';
    import { AuthService } from './auth.service';
    
    @Injectable()
    export class AuthMiddleware implements NestMiddleware {
       constructor(private readonly authService: AuthService) {}
    
       use(req: Request, res: Response, next: NextFunction) {
           if (this.authService.checkPermission(req)) {
               next();
           } else {
               res.status = 403;
               res.send('Forbidden');
           }
       }
    }
  5. 在控制器中使用权限中间件

    import { Controller, Get, Post, Body, UsePipes, ValidationPipe, UseGuards, UseMiddleware } from '@nestjs/common';
    import { AuthMiddleware } from './auth.middleware';
    
    @Controller('user')
    export class UserController {
       @UseMiddleware(AuthMiddleware)
       @Get()
       getUsers(): string {
           return 'List of all users';
       }
    }
项目部署与测试

项目打包与部署

  1. 打包项目

    npm run build
  2. 部署到生产环境
    打包后的项目将生成在 dist 文件夹中,可以将 dist 文件夹中的内容部署到生产环境中。

单元测试与集成测试

在 Nest.js 中,可以使用 Jest 和 Supertest 进行单元测试和集成测试。

  1. 安装测试依赖

    npm install --save-dev @types/jest @types/supertest jest ts-jest supertest
  2. 创建测试文件

    nest generate service user-tests
  3. 编辑 user.service.spec.ts 文件

    import { Test, TestingModule } from '@nestjs/testing';
    import { UserService } from './user.service';
    
    describe('UserService', () => {
       let service: UserService;
    
       beforeEach(async () => {
           const module: TestingModule = await Test.createTestingModule({
               providers: [UserService],
           }).compile();
    
           service = module.get<UserService>(UserService);
       });
    
       it('should be defined', () => {
           expect(service).toBeDefined();
       });
    
       it('should get users', async () => {
           const result = await service.getUsers();
           expect(result).toBe('List of all users');
       });
    });
  4. 运行测试
    npm run test

项目优化与维护建议

  1. 代码审查:定期进行代码审查,确保代码质量。
  2. 持续集成/持续部署(CI/CD):使用 CI/CD 工具自动化测试和部署过程。
  3. 性能优化:使用工具进行性能监控和分析,优化数据库查询和缓存策略。
  4. 文档编写:编写详细的技术文档,包括 API 文档和开发指南。
  5. 代码重构:定期进行代码重构,保持代码的清晰和可维护性。

通过上述步骤,你可以创建一个健壮、可维护的 Nest.js 应用程序,并且可以通过测试、部署和优化来确保其长期稳定运行。

0人推荐
随时随地看视频
慕课网APP