NestJS学习笔记

一、什么是NestJS

是⼀个⽤于构建⾼效,可扩展的 Node.js 服务器端应⽤程序的框架。
它使⽤渐进式 JavaScript ,内置并完全⽀持 TypeScript (但仍然允许开发⼈员使⽤纯 JavaScript 编 写代码)并结合了 OOP (⾯向对象编程), FP (函数式编程)和 FRP (函数式响应编程)的元素
Nestjs 框架基于 Express Fastify (速度最快的 web 框架之⼀)
为什么使用NestJS?
可伸缩性:
        NestJS ⽀持模块化的架构设计,使得应⽤程序的组织和拆分变得更加容易。它提供了依赖注⼊ (DI )和控制反转( IOC )的功能,使得模块之间的解耦和测试变得更加简单,从⽽提⾼了应⽤程序的可伸缩性。
        控制反转( IOC ):降低各个模块之间的耦合度,是⼀种思想
        依赖注⼊( DI ):是控制反转的⼀种实现
//控制反转
//控制反转是一种思想,依赖注入是控制反转的实现
class A {
    constructor(b) {
        this.b = b;
    }
}

const b = new B();        //在外部进行实例化
const a = new A(b);        //依赖注入
完美⽀持 typescript
         NestJS 是基于 TypeScript 开发的,它充分利⽤了 TypeScript 提供的静态类型检查和丰富的⾯向对 象特性。这提供了更好的代码可读性、维护性和可扩展性。
强⼤的中间件⽀持
         NestJS 提供了丰富的中间件⽀持,包括路由中间件、异常处理中间件、身份验证中间件等。这使 得开发⼈员能够轻松地添加和定制中间件,以满⾜不同的应⽤程序需求。
兼容性
         NestJS 是基于 Express.js 构建的,因此可以与许多现有的 Express 中间件和库⽆缝集成。同时, NestJS 的模块化设计也使得各种第三⽅库和插件的集成变得更加简单。

二、安装NestJS CLI工具

环境检查

//查看node版本
node -v

//查看npm版本
npm -v

//查看pnpm版本
pnpm -v

//全局下载pnpm
npm install -g pnpm

安装@nest/cli

使用npm全局安装@nestjs/cli

npm i -g @nestjs/cli

查看nest版本

nest -v

结果如图:

创建nest项目

//命令行创建nest项目
nest new 【项目名】

VScode扩展下载

1、ESLint

2、Prettier

3、vscode-icons

三、实践

1、创建项目

nest new [项目名]

使用VScode打开创建的项目

cd 【项目名】
code .

启动项目

//直接启动
pnpm start


//启动dev,写业务的时候,会更新
pnpm start:dev

//在浏览器访问localhost:3000,就能看到启动之后的页面

访问3000端口的原因:

2、各文件功能介绍

各个⽂件介绍

- node_modules ——放置项⽬的依赖⽂件
- src ——放置开发的代码⽂件
 - app.controller.spec.ts ——测试 app.controller.ts ⽂件的单元测试⽂件
 
 - app.controller.ts ——根控制器⽂件,处理路由的请求和定义路由处理器
 
 - app.module.ts ——根模块⽂件,Nest 应⽤的主要⼊⼝
 
 - app.service.ts ——根服务⽂件,⽤于处理根控制器中的业务逻辑
 
 - main.ts ——应⽤程序的⼊⼝⽂件,⽤于初始化和启动 Nest 应⽤
- test ——测试⽂件,⽤于编写应⽤程序的单元测试和集成测试
 - app.e2e-spec.ts ——编写和运⾏ E2E 测试的测试规范⽂件
 
 - jest-e2e.json ——Jest 的 E2E 测试配置⽂件
- eslintrc.js ——eslint配置⽂件
- .gitignore ——git忽略⽂件
- prettierrc ——prettier配置⽂件
- nest-cli.json ——Nest CLI的配置⽂件
- package.json ——定义项⽬的配置和依赖管理
- pnpm-lock.yaml ——锁定项⽬的依赖包版本
- README.MD ——项⽬的说明⽂件
- tsconfig.build.json ——构建⽣产环境的额外配置⽂件
- tsconfig.json ——TypeScript的配置⽂件

1、.eslintrc.js文件

        Eastland是一个存在长时间的库,lynching可以帮我们创建 

2、.prettierrc文件

        定义格式化的配置

3、nest-cli.json文件

        添加或覆盖一些特定的配置

4、package.json

        在npm或yorn的项目中都能找到,关于节点项目的一些元数据,使用nest-cli运行的脚本或依赖等,当我们使用npm或yorn安装一个包到项目时,就会被添加到dependencies中

5、tsconfig.json

        告诉类型完整的编译器所有需要知道的关于如何编译项目、配置等信息

6、tsconfig.build.json

        扩展文件 

7、src文件夹

        实际代码所在

删除上图三个文件

一个模块可以被其他多个模块导入

NestJS的特点之一:允许我们生成原理图,即一个模块。一个模块就是一个原理图

NestJS在终端查看原理图

nest g

nest g命令执行报错,解决笔记见:

nest : 无法加载文件 C:\Users\admin\AppData\Roaming\npm\nest.ps1,因为在此系统上禁止运行脚本。-CSDN博客

如图所示,问题已经解决,但是,并没有原理图展示,因为没有指定原理图

使用nest g --help可以查看可用原理图列表

nest g --help

//提供模块名字,查看原理图
nest g module tasks

执行上述命令

创建一个新的子文件夹,tasks

app.module.ts文件更新

再次运行项目,确保无误。

快速创建接口服务 

nest g res 【服务名】

选中需要的风格,即可创建出该服务 

具体学习:

装饰器

装饰器分为:类装饰器、属性装饰器、方法装饰器、参数装饰器

类装饰器

属性装饰器

const doc1:PropertyDecorator = (target:any, propertyKey:string|symbol):void => {
  console.log(target,propertyKey);
}

class H2Lclass {
    @doc1             // 属性装饰器,将修饰的属性打印出来
    public title:string;
    constructor(){
        this.title = "H2L,无人知晓!";
    }
}

方法装饰器

const doc2:MethodDecorator = (target:any, propertyKey:string|symbol, descriptor:any):void => {
  console.log(target,propertyKey,descriptor);
}

class H2HLclass {
    public title:string;
    constructor(){
        this.title = "H2L,无人知晓!";
    }
    @doc2               //方法修饰器
    getTitle(){}
}

参数装饰器

const doc3:ParameterDecorator = (target:any, propertyKey: string | symbol | undefined, parameterIndex: number):void => {
    console.log(target,propertyKey,parameterIndex);
  }
  
  class HX2HLclass {
      public title:string;
      constructor(){
          this.title = "H2L,无人知晓!";
      }
      //在函数中接受两个参数
      getTitle(title:string, @doc3 length:number){}
  }
Nestjs控制器中的装饰器 

NestJS控制器中的装饰器

Controllers

负责处理传入的请求并将相应返回给客户端,会绑定一个特殊的路径。

包含处理程序,这些处理程序将处理端点和某些请求方法,比如get、post、delete等

控制器可以利用依赖性注入的优势,在同一模块中消费供应商或服务

如何定义一个控制器?

通过装饰一个类来实现,该装饰器接受一个字符串,即是控制器的处理路径。

@Controller('/tasks')
export class TasksController {
    // ....
}

如何在控制器中找到一个处理程序?

在控制器类中有一些简单方法,用装饰器进行装饰,如@get、@post、@delete等,等代表他们的处理方法

@Controller('/tasks')
export class TasksController {
    @Get()
    getAllTasks() {
        return ...;
    }

    @Post()
    createTask() {
        return ...;
    }
}

创建一个控制器

//不需要规格文件
nest g controller tasks --no-spec
Providers

提供一个模块,以便于使用,或者说可以注入的

可以从Amadeu导出,然后对导入该模块的其他模块使用

如何理解 Nestjs 的提供者 Providers

providers
        可以将其视为⼀个服务容器,通过 providers 可以提供各种服务,也就是可重复使⽤的代码块,⽤于处 理应⽤程序中的特定任务和逻辑
        在代码中就是⽤ @Injectable() 装饰器注释的类
Service

什么是服务?

服务是提供者(providers)实现的,但不是所有的providers都是服务

服务是软件开发中的一个常见概念,并不是Nestjs、JavaScript

服务可以被实现为单子,这是一种设计模式,是可注入的,装饰器包装后提供给一个模块,意味着一个实例可以在整个应用中共享

大部分重业务逻辑将驻留在一个服务中

注入

任何组件都可以注入一个用可注入装饰器装饰的提供者,在类的构造函数中定义依赖关系,处理注入

NestJS提供的Get和Post请求

get请求

//Get请求
    //控制器

@Get('get')
getHello():string {
    return this.appService.getHello();
}

    //服务

getHello(): string {
    return 'Hello,World!';
}

post请求

//Post请求
    //控制器

@Post('post')
postHello():string {
    return this.appService.postHello();
}

    //服务

postHello(): string {
    return 'Hello,World!';
}
Nest Cli常用命令

使用Nest Cli命令提高开发效率

查看所有快捷命令

//查看所有快捷命令
nest --help

//生成模块
nest g mo 【模块名】

//生成控制器
nest g co 【控制器名】

//生成服务
nest g s 【服务名】

//生成用户相关接口
nest g resource user

//快捷生成模块
nest g res 【模块名】
选择风格,一般选REST API即可

Nestjs RESful风格API开发        

RESful

        是一种风格,不是标准,也不是协议,主要使用Get和Post完成接口开发

一般接口,调用不同的接口

        注册接口,需要再数据库增加用户信息,post方法

        删除接口,需要在数据库删除用户信息,post方法

        修改接口,需要在数据库修改用户信息,post方法

        查询接口,需要在数据库查询用户信息,get方法

RESful接口,调用相同接口的不同方法

        查询接口,GET方法

        增加接口,POST方法

        更新接口,PUT PATCH方法

        删除接口,DELETE方法

版本控制

在main.ts文件中,加入内容

//版本控制
app.enableVersioning({
    type:VersioningType.URI,
});

在user.controller.ts中改写@Controller中的内容

/*

原本@Controller中的内容为
@Controller('user')

*/

//改写为
@Controller({
    path:'user',
    version:'1',
})

//以上代码的意思为,路由为user,版本为1
Moudle模块
模块 Module
定义
        在 Nest 中,模块( Module )是组织和管理应⽤程序功能的⼀种⽅式
        它可以看作是⼀个容器,⽤于将相关的组件、提供者和路由等聚合在⼀起
        通过模块,我们可以将应⽤程序拆分成更⼩的可重⽤组件,并将其组织成⼀个整体
共享模块(需要共享的服务需要抛出)
import { Module, Global } from '@nestjs/common';
import { CourseService } from './course.service';
import { CourseController } from './course.controller';

@Global()
@Module({
    controllers: [CourseController],
    providers: [CourseService],
    exports: [CourseService],
})

export class CourseModule {}
全局模块
import { Module, Global } from '@nestjs/common';
import { CourseService } from './course.service';
import { CourseController } from './course.controller';

@Global()
@Module({
    controllers: [CourseController],
    providers: [
        CourseService,
 { provide: 'globalUrl', useValue: { baseUrl: 'https:xdclass.net' } },
 ],
exports: [
    CourseService,
     { provide: 'globalUrl', useValue: { baseUrl: 'https:xdclass.net' } },
 ],
})

export class CourseModule {}


// 在需要使⽤的控制器中进⾏注⼊
@Inject('globalUrl') private readonly globalUrl: any,
动态模块
import { Module, Global, DynamicModule } from '@nestjs/common';
import { CourseService } from './course.service';
import { CourseController } from './course.controller';

interface Options {
    path: string;
}

@Global()
@Module({})
export class CourseModule {
    static forRoot(options: Options): DynamicModule {
        return {
            module: CourseModule,
            controllers: [CourseController],
            providers: [
                CourseService,
             {
                provide: 'globalUrl',
                useValue: { baseUrl: `https:xdclass.net${options.path}` },
             },
         ],
        exports: [
            CourseService,
             {
                provide: 'globalUrl',
                useValue: { baseUrl: `https:xdclass.net${options.path}` },
             },
          ],
         };
     }
}

Nestjs 中间件的使用

 中间件

        定义
                请求到达处理程序之前或之后,对请求和响应进⾏处理,类似 express 中间件
                中间件可以⽤于执⾏各种任务,例如身份验证、⽇志记录、数据转换等
⾃定义依赖注⼊中间件
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class Test implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction) {
    console.log('测试中间件执⾏');
    next();
// res.send('拦截了')
 }
}
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { Test } from '../middleware/Test';
@Module({
    controllers: [UserController],
    providers: [UserService],
    exports: [UserService],
})
export class UserModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
    consumer.apply(Test).forRoutes('user');
// consumer.apply(Test).forRoutes({ path: 'user', method: RequestMethod.GET
});
// consumer.apply(Test).forRoutes(UserController);
 }
}
⾃定义全局中间件
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Request, Response, NextFunction } from 'express';
const passPath = ['/user'];
function middleWareAll(req: Request, res: Response, next: NextFunction) {
    console.log(req.originalUrl, '全局中间件输出的');
    if (passPath.includes(req.originalUrl)) {
        next();
     } else {
        res.send('user 接⼝才能请求');
     }
}
async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.use(middleWareAll);
    await app.listen(3000);
}
bootstrap();
第三⽅中间件 cors
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Request, Response, NextFunction } from 'express';
import * as cors from 'cors';
const passPath = ['/user'];
function middleWareAll(req: Request, res: Response, next: NextFunction) {
    console.log(req.originalUrl, '全局中间件输出的');
    if (passPath.includes(req.originalUrl)) {
        next();
     } else {
    res.send('user 接⼝才能请求');
 }
}
async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.use(cors());
    app.use(middleWareAll);
    await app.listen(3000);
}
bootstrap();
Nest ⾃带跨域配置
app.enableCors()
Nestjs上传文件

下载依赖

pnpm i multer @types/multer
import { Module } from '@nestjs/common';
import { UploadService } from './upload.service';
import { UploadController } from './upload.controller';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { join, extname } from 'path';
@Module({
    imports: [
        MulterModule.register({
            storage: diskStorage({
            destination: join(__dirname, '../images'),
            filename: (_, file, callback) => {
                const fileName = `${
                    new Date().getTime() + extname(file.originalname)
                }`;
                return callback(null, fileName);
             },
         }),
     }),
 ],
 controllers: [UploadController],
 providers: [UploadService],
})

export class UploadModule {}
// 控制器

@Post('img')
@UseInterceptors(FileInterceptor('file'))
upload(@UploadedFile() file) {
    console.log(file);
    return true;
}
静态资源访问
async function bootstrap() {
    const app = await NestFactory.create<NestExpressApplication>(AppModule);
    app.useStaticAssets(join(__dirname, 'images'), {
        prefix: '/xd',
 });
    app.use(cors());
    app.use(middleWareAll);
    await app.listen(3000);
}

bootstrap();
Rxjs
定义
        RxJS 是⼀种功能强⼤的响应式编程库,使⽤的是观察者模式,简洁⽽直观的⽅式处理异步操作和事件流
        在 Nest 框架中⾃带的,⽆需安装
Rxjs 核⼼功能
        发布可观察的任务
        subscribe 订阅任务
        interval 操作符:不停⽣成值的操作符
        take 操作符:限制⽣成值的数量
        of 操作符:⾃定义数据
Nest响应拦截器
响应拦截器
        ⽤于全局处理 HTTP 响应的中间件,提供了⼀种统⼀的⽅式来处理和修改从后端返回给前端的数据
        例如对响应数据进⾏格式化、加密或⽇志记录
{
    message: '请求成功了'
    data: {token:'xxxxx'},
    code: 0,
}
import type { CallHandler, NestInterceptor } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import type { Observable } from 'rxjs';
import { map } from 'rxjs';
/**
 * 拦截器 成功返回的统⼀响应格式
 */
@Injectable()
export class Response implements NestInterceptor {
    intercept(context, next: CallHandler): Observable<any> {
        return next.handle().pipe(
            map((data) => {
                return {
                    data,
                    code: 0,
                 };
             }),
         );
     }
}
Nest异常拦截器
异常拦截器
        ⽤于全局处理 HTTP 异常的中间件,提供了⼀种统⼀的⽅式来处理和修改从后端返回给前端的错误
        例如统⼀错误格式、向客户端发送适当的错误响应
{
    code: -1,
    data: null,
    msg: message,
}
import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common'
import { Catch, HttpException } from '@nestjs/common'
/**
 * 异常过滤器 异常返回统⼀响应
 * 捕获作为HttpException类实例的异常,并为它们设置⾃定义响应逻辑
 */
@Catch(HttpException)
export class AbnormalFilter implements ExceptionFilter {
    catch(exception: HttpException, host: ArgumentsHost) {
    // 获取请求上下⽂
    const ctx = host.switchToHttp()
    // 获取请求上下⽂中的 response对象
    const response = ctx.getResponse()
    // 获取异常状态码
    const status = exception.getStatus()
    // 异常消息
    const message = exception.message ? exception.message : 'Service Error'
    // Response.json()⽅法,使⽤ Response对象直接控制发送的响应。
    response.status(status).json({
        code: -1,
        data: null,
        msg: message,
     })
   }
}
Nest的管道PIpe转换
Pipe 的类型转换
        ParseIntPipe 数据类型
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
    console.log(typeof id);
    return this.userService.findOne(+id);
}
        ParseFloatPipe 浮点类型
        ParseBoolPipe boolean 类型
@Get(':id')
findOne(@Param('id', ParseBoolPipe) id: boolean) {
    console.log(typeof id);
    return this.userService.findOne(+id);
}
        ParseArrayPipe 数组
        ParseUUIDPipe uuid
        ParseEnumPipe 枚举
        DefaultValuePipe 默认值
Nest的管道验证DTO

创建DTO文件

// create-user.dto.ts

import { IsString, IsEmail, Length } from 'class-validator';

export class CreateUserDto {
    @IsString()
    @Length(3, 20)
    name: string;

    @IsEmail()
    email: string;

    @IsString()
    @Length(6, 20)
    password: string;
}
// main.ts

app.useGlobalPipes(new ValidationPipe());
// user.controller.ts

@Post()
create(@Body() createUserDto: CreateUserDto) {
    return this.userService.create(createUserDto);
}

3、Nest ORM框架和数据库

本地安装Docker

网址:https://www.docker.com/get-started/

Nest通过TypeORM链接数据库

TypeORM安装(以MySQL为例)

pnpm i typeorm @nestjs/typeorm mysql2

链接数据库

// config.ts文件

import type { TypeOrmModuleOptions } from '@nestjs/typeorm'

export const typeOrmConfig: TypeOrmModuleOptions = {
    type: 'mysql',
    host: '127.0.0.1',
    port: 3306,
    username: 'root',
    password: 'xdclass.net168',
    database: 'xdclass-nest', // 创建的数据库名字为准,⽽不是容器名
    entities: ['dist/**/*.entity{.ts,.js}'],
    autoLoadEntities: true,
    synchronize: true,
}
// app.module.ts文件

imports: [
    TypeOrmModule.forRoot(typeOrmConfig),
]

TypeORM配置实体和操作数据库

实体entity

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number = 0;

    @Column()
    name: string = '';

    @Column()
    phone: string = '';

    @Column()
    password: string = '';
}

配置

// user.module.ts文件

import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
imports: [TypeOrmModule.forFeature([User])]
// user.controller.ts文件

import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
@InjectRepository(User) private readonly userRepository: Repository<User>,

TypeORM官网

        英⽂官⽹: https://typeorm.io/
        中⽂官⽹: https://www.typeorm.org/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值