前言
最近一年真是鸽了很久,比较忙。接触企业级框架 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 的基本使用。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于