NestJs 搭建从零开始 (一)

本贴最后更新于 1367 天前,其中的信息可能已经时移俗易

前言

最近一年真是鸽了很久,比较忙。接触企业级框架 SpringBoot 的相关连续文章也没有再继续。趁着现在还有部分时间,把之前写过 demo 示例的 NestJs 框架拿出来溜溜。

主旨在于如何从零搭建 NestJs 框架,在过程中可能会发现很多与 SpringBoot 类似的地方,其实可以说 NestJs 就是仿照 SpringBoot 的相关架构来设计的,之前先开篇了 SpringBoot 的基本功能也是基于这个先导的想法。

大的架构问题就不说太多了,直接用实际框架结构与代码来进行梳理。

首先先放整体的 Demo 地址:

官方文档地址:

正文

NestJs 介绍

目前以个人见解,后端框架繁多的情况下,主流分类主要有以下几种:

1.适合用于大项目,约束性较强,市场应用较多,相当成熟的框架,比较有代表性的是:

Java:SpringBoot

Python:Django

2.适合互联网快餐,业务驱动型团队的首选,没有相对约束性的框架,可以自由构建体系,比较有代表性的:

Python:FastApi,Flask

3.偏向于性能要求,技术驱动型团队的首选,大部分用于性能优化,比较有代表性的:

Go:Gin,Beego

还有其他的很多后台框架就不一一列举了。其实大体上框架理念在后端结构上都相差不大,差距在于各自的语言特性差异,语法差异,和结构设计上。

NestJs 的思想借鉴于 SpringBoot,使用 TypeScript 来达到前后端开发语言统一的效果,同时又能支撑复杂的后端业务,又有自己的框架结构思想。介于 1 类与 2 类之间,在开放强约束限制的同时,又能达到较为良好的可读性。

Demo 结构,基本使用

├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── common │   └── filters │   └── exception.filters.ts ├── config │   ├── env.ts │   ├── env-utils.ts │   ├── loanApplyNode.json │   └── log4js.ts ├── customer │   ├── customer.module.ts │   ├── customer.service.ts │   ├── dto │   │   ├── customer.dto.ts │   │   └── customerRegister.dto.ts │   ├── manageCustomer.controller.ts │   ├── userCustomer.controller.ts │   └── vo │   └── customer.vo.ts ├── customerAdmin │   ├── customerDetail │   │   ├── customerDetail.apiProperty.ts │   │   ├── customerDetail.controller.ts │   │   ├── customerDetailManager.controller.ts │   │   ├── customerDetail.module.ts │   │   └── customerDetail.service.ts │   └── loanCustomer │   ├── loanCustomer.apiProperty.ts │   ├── loanCustomer.controller.ts │   ├── loanCustomer.module.ts │   └── loanCustomer.service.ts ├── entities │   ├── AntiFraud.entity.ts │   ├── BankCard.entity.ts │   ├── Contract.entity.ts │   ├── ContractOperation.entity.ts │   ├── customer │   │   ├── customerAudit.entity.ts │   │   └── customer.entity.ts │   ├── CustomerDetail.entity.ts │   ├── EmergencyContact.entity.ts │   ├── FAOperation.entity.ts │   ├── FPOperation.entity.ts │   ├── FunderAccountDetail.entity.ts │   ├── FunderAccount.entity.ts │   ├── Funder.entity.ts │   ├── FunderProduct.entity.ts │   ├── IDVerification.entity.ts │   ├── JobInformation.entity.ts │   ├── LAOperation.entity.ts │   ├── LivenessDetection.entity.ts │   ├── LoanApply.entity.ts │   ├── LoanCustomer.entity.ts │   ├── LoanRecordProcess.entity.ts │   ├── RepaymentRecord.entity.ts │   ├── RepaymentTask.entity.ts │   ├── ReviewByFunder.entity.ts │   ├── Risk.entity.ts │   ├── RTOperation.entity.ts │   ├── TelephoneInterview.entity.ts │   └── Urge.entity.ts ├── funderAdmin │   ├── funder │   │   ├── funder.apiProperty.ts │   │   ├── funder.controller.ts │   │   ├── funderManager.controller.ts │   │   ├── funder.module.ts │   │   └── funder.service.ts │   └── funderProduct │   ├── funderProduct.apiProperty.ts │   ├── funderProduct.controller.ts │   ├── funderProductManager.controller.ts │   ├── funderProduct.module.ts │   └── funderProduct.service.ts ├── guard │   └── customerAuth.guard.ts ├── loanAdmin │   ├── loanApply │   │   ├── loanApply.apiProperty.ts │   │   ├── loanApply.controller.ts │   │   ├── loanApplyManager.controller.ts │   │   ├── loanApply.module.ts │   │   └── loanApply.service.ts │   └── loanRecordProcess │   ├── loanRecordProcess.apiProperty.ts │   ├── loanRecordProcess.controller.ts │   ├── loanRecordProcessManager.controller.ts │   ├── loanRecordProcess.module.ts │   └── loanRecordProcess.service.ts ├── main.ts ├── middleware │   ├── CheckToken.middleware.ts │   ├── logger.middleware.spec.ts │   └── logger.middleware.ts ├── minioService │   └── minio.service.ts ├── public │   └── test.jpg ├── redisDB │   └── cache.service.ts ├── repaymentAdmin │   ├── repaymentRecord │   │   ├── repaymentRecord.apiProperty.ts │   │   ├── repaymentRecord.controller.ts │   │   ├── repaymentRecord.Managercontroller.ts │   │   ├── repaymentRecord.module.ts │   │   └── repaymentRecord.service.ts │   └── repaymentTask │   ├── repaymentTask.apiProperty.ts │   ├── repaymentTask.Managercontroller.ts │   ├── repaymentTask.module.ts │   └── repaymentTask.service.ts ├── support │   ├── apiResult.ts │   ├── index.ts │   ├── pageParams.dto.ts │   ├── ResponseErrorEvent.ts │   ├── responsePage.ts │   └── support.module.ts └── utils ├── log4js.ts └── numberUtil.ts

基本结构如上,main 示例如下:

import {NestFactory} from '@nestjs/core'; import {AppModule} from './app.module'; import {DocumentBuilder, SwaggerModule} from "@nestjs/swagger"; import {logger} from "./middleware/logger.middleware"; import {CheckTokenMiddleware} from "./middleware/CheckToken.middleware"; import { HttpExceptionFilter } from './common/filters/exception.filters'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 监听所有的请求路由,并打印日志 app.use(logger); // 监听所有的请求路由,处理token // app.use(new CheckTokenMiddleware().use); // 错误过滤器 app.useGlobalFilters(new HttpExceptionFilter()) app.enableCors(); const options = new DocumentBuilder() .setTitle("APItest") .setDescription("The test docs") .setVersion("1.0") .addTag("app") .addTag("admin") .build(); const document=SwaggerModule.createDocument(app,options) SwaggerModule.setup("api",app,document) // await app.setGlobalPrefix("public"); await app.listen(3001); } bootstrap();

其中增加了错误过滤器,Token 验证中间件不过并没有挂载,开启了默认使用 swagger,监听 3001 等等。

const app = await NestFactory.create(AppModule); 创建时会调用 app.mudule.ts 读取配置。配置文件如下:

import {MiddlewareConsumer, Module, NestModule, RequestMethod} from '@nestjs/common'; import {ConfigModule} from 'nestjs-config'; import * as path from 'path'; import {AppController} from './app.controller'; import {AppService} from './app.service'; import {TypeOrmModule} from '@nestjs/typeorm'; import {Connection} from 'typeorm'; import {LoanCustomerModule} from './customerAdmin/loanCustomer/loanCustomer.module'; import './config/env'; import {envBoolean, envNumber, envString} from './config/env-utils'; import {RedisModule} from "nestjs-redis"; import {FunderModule} from "./funderAdmin/funder/funder.module"; import {FunderProductModule} from "./funderAdmin/funderProduct/funderProduct.module"; import {LoanApplyModule} from "./loanAdmin/loanApply/loanApply.module"; import {CacheService} from "./redisDB/cache.service"; import {LoanRecordProcessModule} from "./loanAdmin/loanRecordProcess/loanRecordProcess.module"; import {ServeStaticModule} from "@nestjs/serve-static"; import {CheckTokenMiddleware} from "./middleware/CheckToken.middleware"; import {CustomerDetailModule} from "./customerAdmin/customerDetail/customerDetail.module"; import {RepaymentRecordModule} from "./repaymentAdmin/repaymentRecord/repaymentRecord.module"; import {RepaymentTaskModule} from "./repaymentAdmin/repaymentTask/repaymentTask.module"; import {SupportModule} from "./support/support.module"; import {CustomerModule} from "./customer/customer.module"; @Module({ imports: [ ConfigModule.load(path.resolve(__dirname, 'config', '**/!(*.d).{ts,js}')), TypeOrmModule.forRoot({  //数据库连接配置 type: 'mysql', host: envString('DB_HOST', 'localhost'), port: envNumber('DB_PORT', 3306), username: envString('DB_USERNAME', 'root'), password: envString('DB_PASSWORD', 'root'), database: envString('DB_DATABASE', 'ts_test'), entities: [__dirname + '/**/*.entity{.ts,.js}'], //装载全部实体 synchronize: envBoolean('DB_SYNCHRONIZE', true),    //自动迁移同步数据库表结构 }), RedisModule.register({ port: envNumber("REDIS_PORT",6379), host: envString("REDIS_HOST","127.0.0.1"), password: envString("REDIS_PASSWORD",""), db: envNumber("REDIS_DB",0) }), // ServeStaticModule.forRoot({ // rootPath:path.join(__dirname,"..","public"), // exclude:["/public*"], // }), CustomerModule, SupportModule, LoanCustomerModule, FunderModule, FunderProductModule, LoanApplyModule, LoanRecordProcessModule, CustomerDetailModule, RepaymentRecordModule, RepaymentTaskModule, ], controllers: [AppController], providers: [AppService,CacheService], }) export class AppModule implements NestModule{ constructor(private readonly connection: Connection) { } configure(consumer: MiddlewareConsumer) { // token 中间件拦截 // consumer.apply(CheckTokenMiddleware).forRoutes({path:"*",method:RequestMethod.ALL}) } }

这里要注意的是。我们所有的基层组件 Module,都要在这里引入,并加入到框架启动的扫描。Demo 里配置了 Mysql,Redis,还有业务相关的 CustomerModule 等等。因为各个业务的 Controller 为了方便示例,都做在各业务单独的 Module 里面,所以在 Controllers 里面只有 AppController 用于测试。CacheService 等基层服务也要一同引入。如果是在业务的 Module 里面进行引入,这里可以忽略。

接下来其实已经走过了 router 的过程。app.Controller 已经可以直接引入路由导航了。

import {Body, Controller, Get, Post, Req} from '@nestjs/common'; import {json, Request} from 'express'; import {AppService} from './app.service'; import {Redirect} from "@nestjs/common"; import {createConnection} from "typeorm"; @Controller("/") export class AppController { constructor(private readonly appService: AppService) { } @Post("uploadLoanProcessJson") async uploadJson(@Body() jsonData): Promise<any> { this.appService.upload(jsonData) return jsonData } @Get("") async Index(): Promise<string> { return "<a href=\"weixin://dl/business/?ticket=te1e2ba9afbaa76e79a6185e74ef8b1ab\">手机浏览器打开测试<a/>" } }

在这里做了简单的示例。与 SpringBoot 的结构类似。NestJs 也采用了注解的形式,习惯使用 Python 的同学们可以理解为装饰器。

constructor(private readonly appService: AppService) { } 中引用了所需服务。依赖注入。调用方式直接使用 this.service。这里的的 service 执行业务逻辑。直接到了 app.service

import { Injectable } from '@nestjs/common'; import {CacheService} from "./redisDB/cache.service"; import {Repository} from "typeorm"; import {LoanRecordProcess} from "./entities/LoanRecordProcess.entity"; @Injectable() export class AppService { constructor(private readonly cache: CacheService, ){} async upload(jsonData):Promise<number>{ this.cache.set("loanApllyProcess:config",JSON.stringify(jsonData)); return 1 } getHello(): string { return 'Hello World!'; } getTwo():string{ return "here is two"; } }

@Injectable()的作用为可以注入实例化,在这里也通过依赖注入了 CacheService,可以调用其他 service 封装的函数。

以上是 NestJs 的基本使用。

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...