nest起手式

安装脚手架

npm install -g @nestjs/cli
nest new projectName

项目目录创建

删除 src 中多余的文件只保留 app.module.tsmain.ts

重置 app.module.ts 文件

import { Module } from '@nestjs/common';
@Module({
  imports: [],
  controllers: [],
  providers: [],
})
export class AppModule {}

创建相关模块

nest g module user /*创建user的module*/
nest g controller User --no-spec /*创建 controller 层,忽略测试文件*/
nest g service user --no-spec /*创建 service 层,忽略测试文件*/
nest g resource use --no-spec /*创建模版(三合一),忽略测试文件*/

module 、controller 和 service 三者的关系

  • controller (控制器):负责处理HTTP请求和响应,接受来自客户端的请求,并将其委派给 service 进行处理。controller 中定义了路由和处理请求的方式
  • Module(模块):应用程序的核心组织单元,负责将应用程序的不同部分组合在一起,每一个 Module 都有自己的 Controller、Service 和 其他相关组件,他们整体构成了一个模块
  • Service (服务):应用程序的业务逻辑集中地,他包含了处理业务逻辑的方法,Service 被 Controller 调用,用于处理来自客户端的请求,并返回结果,Service 可以被多个 COntroller 和其他的 Service 共享

Nest提供了结构化的方式来组织应用程序,将不同的功能模块分开管理

接口的版本控制

main.ts中配置

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableVersioning({ /*配置版本号*/
    type:VersioningType.URI
  })
  await app.listen(3000);
}

在文件的 controller 文件设置套接口的版本号

@Controller({
  path:'user',
  version:'1'
})
export class UserController{
    ...
}

/**在这某个接口的版本号*/
@Controller('user')
export class UserController{
  @Get()
  @Version("1")
  findAll() {
    return this.userService.findAll();
  }
}

访问路径 localhost:3000/v1/user


控制器–接受get和post参数

常用控制器

控制器描述
@Request()请求的全部信息
@Query()查询字符串信息
@Body()请求体信息
@Header()获取请求头
@HttpCode()设置接口状态码

用法示例

@Post(":id")
@HttpCode(200)
postFun(
    @Requery() req,
    @Query() query,
    @Body() body,
    @Header() header,
    @Param("id") id
){
    console.log(req) /*里面包含了query,body,header,params 的所有参数*/
    console.log(query) /*只获取query*/
    console.log(body) /*只获取body*/
    console.log(header)/*只获取header*/
    console.log(id) /*只获取模版参数*/
    reurn {code:101} 
}

设置session

安装

yarn add express-session @types/express-session 

配置 main.ts

app.use(session({
    secret:"demo", /*签名[自定义]*/
    rolling:true, /*强制设置cookie,重置过期时间*/
    name:"demo.sid", /*session的字段名称*/
    cookie:{maxAge:999999} /*过期的秒数*/
 }))

controller中使用 session

@Get()
getUser(@Session() session){
    session.name = "张三" /*设置session*/
    return {code:101}
}

@Get()
getSession(@Session session){
    console.log(session.name) /*打印session*/
    return {code:101}
}

模块 @Module

共享模块

如果 a.controller.ts 想使用 b.service.ts 的通用逻辑时,要在 b.module.ts 中导出该 Service 类, 在这里配置 b.module.ts

@Module({
  ...
  exports:[BService]/*导出BService类*/
})

a.controller.ts 直接引用

import {BService} from "b.service";
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AController {
  constructor(
    private readonly aScrvice: AScrvice,
    private readonly bService:UserService
    ) {}

  @Get()
  getHello(): string {
    return this.bService.findAll();
  }
}

中间件

路由处理程序之前调用的程序,中间件函数可以访问请求对象和响应对象(类似于axios的拦截器)

解决跨域问题

安装

yarn add cors @types/cors 

配置 main.ts

import * as cors from "cors";
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(cors())
  ....
  await app.listen(3000);
}

文件上传

安装

yarn add multer @types/multer

upload.module.ts 指定存储路径

@Module({
    imports:[
        MulterModule.register({
          storage:diskStorage({
            destination:join("./public/uploaded"), /**存放目录 */
            filename:(_,file,callback) => { /*时间戳定义文件名*/
                const fileName = `${new Date().getTime() + extname(file.originalname)}`
                return callback(null,fileName)
            }
          })
        })
    ]
})

接口端 upload.controller.ts

@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @Post()
  @UseInterceptors(FilesInterceptor("files"))
  create(@UploadedFiles() files) {
    console.log(files)
    return {code:101}
  }

}

public/uploaded 文件配置静态资源,供外部访问,在upload.module.ts配置

@Module({
    imports:[
        ...
        ServeStaticModule.forRoot({
          rootPath: join('./', 'public/uploaded'),
        })
    ]
})

文件流下载

安装

yarn add compressing

接口层

  @Get("steamDown")
  async steamDown(@Res() res){
    const url = join("./public/uploaded");
    const tarStream = new zip.Stream();
    await tarStream.addEntry(url);
    res.setHeader("Content-Type","application/octet-stream")
    res.setHeader("Content-Disposition","attachment; filename=xxx")
    tarStream.pipe(res)
  }

响应拦截器

新建 common / response.ts

import { CallHandler, Injectable, NestInterceptor } from "@nestjs/common";
import { map } from "rxjs";

@Injectable()
export class Response<T> implements NestInterceptor {
  intercept(context,next:CallHandler){
    return next.handle().pipe(map(data => ({ 
      data,
      message:"nibi"
    })));
  }
}

在全局注入 main.ts

import {Response} from "./common/response"
...
app.useGlobalInterceptors(new Response())
...

异常拦截器

新建 common \ filter.ts

import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from "@nestjs/common";
import {Request,Response} from "express"

@Catch()
export class  HttpFilter implements ExceptionFilter {
  catch(exception:HttpException,host:ArgumentsHost){
    const ctx = host.switchToHttp()
    const request = ctx.getRequest<Request>()
    const response = ctx.getResponse<Response>()
    response.status(500).json({
      success:false,
      time:new Date(),
      data:exception.message,
      path:request.url
    })

  }
}

全局注册拦截器

import { HttpFilter } from './common/filter';
...
app.useGlobalFilters(new HttpFilter())
...

管道

守卫

在中间件之后,管道和拦截器之前执行

创建命令

nest g gu role

在路由中使用 xxx.controller.ts

import {RoleGuard} from "../role/role.guard"

@Controller('guard')
@UseGuards(RoleGuard)
export class GuardController{...}

全局注册守卫

import {RoleGuard} from "./role/role.guard"
...
app.useGlobalGuards(new RoleGuard())
...

Swagger

安装

yarn add @nestjs/swagger  swagger-ui-express

main.ts 配置标题等相关操作

async function bootstrap(){
    ...
  const options = new DocumentBuilder().addBearerAuth().setTitle("标题").setDescription("描述").setVersion("1").build()
  const document = SwaggerModule.createDocument(app,options)
  SwaggerModule.setup("/api-docs",app,document)
    ...
    await app.listen(3000);
}

在路由层分组,设置每个接口 xxx.controller.ts

/*路由层*/
@ApiTags("接口分组标题")
@ApiBearerAuth() /*是否携带token*/
/*接口层配置*/
@ApiOperation({summary:"get接口",description:'接口的功能描述'})
@ApiParam({name:"id",description:"要传递参数表述",required:true})
@ApiQuery({name:"page",description:"要传递的参数表述"})
@ApiResponse({status:403,description:"返回示例"})
/*Post请求需要再 dto 文件中配置*/
import { ApiProperty } from "@nestjs/swagger";
export class XxxDto {
  @ApiProperty({example:'xxx'}) /*默认值*/
  name:string; /*参数:类型*/

  @ApiProperty({example:0})
  age:number
}

连接数据库

安装

yarn add typeorm mysql2 @nestjs/typeorm

app.module.ts 中配置

@Module({
    ...
    imports:[
        TypeOrmModule.forRoot({
          type: "mysql", //数据库类型
          username: "root", //账号
          password: "", //密码
          host: "localhost", //host
          port: 3306, //
          database: "nestDB", //库名
          //entities: [__dirname + '/**/*.entity{.ts,.js}'], //实体文件
          synchronize:true, //synchronize字段代表是否自动将实体类同步到数据库(生产环境关闭)
          retryDelay:500, //重试连接数据库间隔
          retryAttempts:10,//重试连接数据库的次数
          autoLoadEntities:true, //如果为true,将自动加载实体 forFeature()方法注册的每个实体都将自动添加到配置对象的实体数组中
        }),
        ...
    ],
    ...  
})

创建表实体

在 entity 文件中创建实体

import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class User{ ... }

在 mudule 中创建关联

@Module({
  imports:[TypeOrmModule.forFeature([User])],
  ...
})

自增的主键

@PrimaryGeneratedColumn()
id:number

自增uuid

@PrimaryGeneratedColumn("uuid")
id:number

列类型

@Column({type:"varchar",length:200}) /*可以调整数据库数据类型*/
    password: string

@Column({ type: "int"})
    age: number

@CreateDateColumn({type:"timestamp"}) /*自动存个时间戳*/
    create_time:Date

自动生成一列

@Generated('uuid')
uuid:string

列选项

@Column({
        type:"varchar",
        name:"ipaaa", //数据库表中的列名
        nullable:true, //在数据库中使列NULL或NOT NULL。 默认情况下,列是nullable:false
        comment:"注释",
        select:true,  //定义在进行查询时是否默认隐藏此列。 设置为false时,列数据不会显示标准查询。 默认情况下,列是select:true
        default:"xxxx", //加数据库级列的DEFAULT值
        primary:false, //将列标记为主要列。 使用方式和@ PrimaryColumn相同。
        update:true, //指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。 默认值为"true"
        collation:"", //定义列排序规则。
    })
    ip:string

typeorm对数据库的增删改查

*.service .ts 层用于业务处理

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity'; /*需要引入定义好的 entity*/
import { Repository,Like  } from 'typeorm';
@Injectable()
export class UserService{
    constructor(@InjectRepository(User) private readonly user:Repository<User>){}

    创建(){
        const data = new User()
        data.name = "张三"
        data.doc = "法外狂徒"
        const result = this.user.save(data)
        return result
    }

    async 查全部(){
        const data =  await this.user.find({
          where:{
            name:Like('%')
          }
        })
        return data;
    }

    async 查一条(){
        /*查询 user 表中 id 字段等于 1 的数据*/
        const data = await this.user.finOne({where:{id:1}})
    }

    async 条件查(){
        const data =  await this.user.find({
          where:{
            name:Like(`%${name}%`)
          }
        })
        return data
    }

    async 改(){
        const result = await this.user.update(1, {name:'赵四',doc:"象牙山二付"});
        return {
          code:101,
          data:result,
          message:"修改成功"
        }
    }

    async 删除(){
        const result = await this.user.delete(id);
        console.log(result)
        return {
          code:101,
          data:result,
          message:"删除成功"
        }
    }

}

分页查询

@Injectable()
export class UserService{
    constructor(@InjectRepository(User) private readonly user:Repository<User>){}
    async findAll(query:{page:number,pageSize:number}) {
        console.log((query.page-1)*query.pageSize)
        const data =  await this.user.find({
          where:{
            name:Like('%')
          },
          /**根据id字段进行排序 DESC倒序 ASC正序*/
          order:{
              id:"DESC"
          }  
          /**分页配置 skip 偏移量;take 要显示的个数*/
          skip:(query.page-1)*query.pageSize,
          take:query.pageSize 
        })
        /**获取总数 */
        const total = await this.user.count({
          where:{
            name:Like("%")
          }
        })
        return {
          code:101,
          data:{data:data,total:total},
          message:"请求成功"
        };
    }
}

多表关联及联查

示例 user表 和 tags表 相互关联

user.entity.ts

import { Tags } from "./tags.entity";
@Entity()
export class User {
  ...
  /*和 tags 表建立一对多关系,第一个参数表示关联的实体类,第二个参数指定关联实体中的反向关系字段*/
  @OneToMany(()=>Tags,(tags)=>tags.user )
  tags:Tags[]

}

rags.entity.ts

import { Column, CreateDateColumn, Entity, Generated, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { User } from "./user.entity";

@Entity()
export class Tags{
  ...
  /*表示和User实体之前存在多对一的关系*/
  @ManyToOne(()=>User)
  user:User
}

多表联查

const data = await this.user.find({
    relatons:['tags'],
    ...
})

事务

定义: 作为一个单独逻辑工作单元执行的一系列操作,这些操作要么全部执行成功,要么全部失败回滚。事务的目的是确保数据库的一致性和完整性

  • 原子性:事务中的操作要么全部成功,要么全部失败回滚,不会出现部分操作失败和成功的情况
  • 一致性:事务执行前后,数据库的状态保持一致。如果事务执行成功,数据库的状态会从一个一致的情况转换另一个一致的状态
  • 隔离性:事务的执行是相互隔离的,每个事务的操作对其他事务是不可见的,事务之间的操作是相互独立的,不会相互干扰
  • 持久性:一旦事务成功提交,其他数据库的修改将永久保存,即将发生系统故障或断电等情况,数据库也能恢复到事务提交的状态

语法

this.moeny.manage.tarnsaction(async manage=>{
    manage.save(moeny,{id:1,money:100})
})

配置环境变量

安装

yarn add @nestjs/config  --save

在根目录创建 .env 文件,设置环境变量

DB = Mysql
DB_HOOST = localhost
DB_PROT = 3306
DB_NAME = test
DB_USER = root

app.module.ts 文件.全局导入

import {ConfigModule} from "@nestjs/config";
@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal:true
    }),
    ...
  ],
  controllers: [],
  providers: [],
})

在其他模块中调用环境变量

import {ConfigService} from "@nestjs/config"
export class TsetCOntroller{
    @Get()
    getUSer(){
        console.log(this.configService.get("DB"));
        return ...
    }
}

Log日志操作

设置日志级别

main.ts 中配置

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule,{
    /**关闭nest日志 */
    logger:false
    /**选择日志级别*/
    logger:["log","error","warn"]
  });
  await app.listen(3000);
}
bootstrap();

在控制器中打印log

@Controller()
export class UserController{
    private logger = new Logger(UserController.name)
    constructor(){}

    @Get()
    getUser():any{
        this.logger.log("请求成功");
    }
}

使用第三方日志管理 pino

安装

yarn add pino-http pino-pretty  pino-roll

在全局配置日志系统 app.module.ts

@Module({
  imports: [
      ...
    LoggerModule.forRoot({
      pinoHttp:{
        transport:{
          targets:[
            {
              level:"info",
              target:"pino-pretty",
              options:{
                colorize:true,
              },
            },
            {
              level:"info",
              target:"pino-roll",
              options:{
                file:join("logs","log.txt"),
                frequency:"daily",
                size:"10m",
                mkdir:true
              }
            }
          ]
        }
      }
    })
       ...
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

使用第三方日志管理 winston

安装

yarn add --save nest-winston winston winston-daily-rotate-file

配置main.ts

async function bootstrap() {
  /*配置winston相关参数*/
  const instance = createLogger({
    transports:[
      new winston.transports.Console({
        format:winston.format.combine(
          winston.format.timestamp(),
          winston.format.simple()
        )
      }),
      new winston.transports.DailyRotateFile({
        dirname:"logs",
        level:"warn",
        filename:"application-%DATE%.log",
        datePattern:"YYYY-MM-DD-HH",
        zippedArchive:true,
        maxSize:"20m",
        maxFiles:"14d",
        format:winston.format.combine(
          winston.format.timestamp(),
          winston.format.simple()
        )
      })
    ]
  })

  const app = await NestFactory.create(
    AppModule,
    {
      logger:WinstonModule.createLogger({instance}) /*全局使用*/
    }
  );
  await app.listen(3000);
}

nest登录鉴权(JWT)

安装

yarn add @nestjs/jwt @types/passport-jwt @passport-jwt

app.module.ts 中配置

import { JwtModule } from '@nestjs/jwt';
@Module({
    imports:[
        ...
        JwtModule.register({
          secret:"secret", /*秘钥*/
          signOptions:{expiresIn:"1d"} /*过期时间*/
        })
    ]
})

controller 层中创建 jwt

import { BadRequestException, Body, Controller, Get, Post, Req, Res, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import {Response,Request} from "express"

@Controller()
export class userController{
    constructor(
    	private jwtService:JwtService
    ) {}
    
    @Post("login")
    async login(@Body() Body){
        /*创建jwt*/
        const jwt = await this.jwtService.signAsync({id:Body.id})
        return jwt
    }
    
    @Get()
    async user(@Req() require:Request){
        /*解析jwt*/
        const data = await this.jwtService.verifyAsync(jwt)
        return data
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇