Nest.js是一个基于Node.js的后端开发框架,它实现了MVC模式,也就是Model、View、Controller的分层,也支持了IOC,也就是可以自动注入依赖,比Express这类处理请求响应的库高了一个层次。而且也很容易集成GraphQL、WebSocket等功能,适合用来做大规模企业级开发。
Nest.js在国内外用的都挺多的,今天我们就来入门下吧:做一个笔记管理功能,实现对mysql单表的增删改查并提供Restful的接口。
完整代码:https://github.com/QuarkGluonPlasma/nestjs-exercize
Nest.js+Typeorm基础mysql数据库和Typeorm首先从离前端比较远的数据库讲起。
在mysql的官网下载mysql,安装并启动服务。
这时候就可以用命令行来写sql操作数据库了。
但是命令行操作不够方便,所以我们还要下载一个有界面的mysql客户端,我这里用的是navicat。
它可以可视化的创建数据库、表等,可以在编辑器里写sql然后执行。比如图中我创建了hello的数据库和一堆表。
Node.js代码里同样可以连接上数据库服务,然后远程执行sql来对数据库表做增删改查。
但直接执行sql比较繁琐,能不能我只操作对象,对象属性变了就自动去执行sql来同步数据库呢?就像vue的数据变了自动同步视图一样。
数据库和对象关系的映射就叫做ORM(ObjectRelationalMapping),也就是把表映射成对象,把表与表之间的关联映射成对象之间的关系。之后对对象的操作会通过sql同步到数据库。
Typeorm就是一个实现orm的框架,可以通过装饰器来描述映射关系,比如@Entity(实体)、@Column(列)、@PrimaryGeneratedColumn(主键ID自动生成)
import{Entity,PrimaryGeneratedColumn,Column}from"typeorm";@Entity()exportclassNote{@PrimaryGeneratedColumn()id:number;@Column()title:string;@Column()content:string;}通过装饰器声明了关系,那么在建立了数据库连接之后,我们只需要操作对象,Typeorm就会自动去执行sql来把变动同步到数据库。
这样,我们对数据库的表的操作和增删改查就实现了。
数据库部分搞定之后,我们再往前看一下处理请求的部分。
http请求和Nest.js处理请求的后端框架我们使用Nest.js,它提供了Controller、Service等划分,这是对MVC模式的实现。
Controller里面负责处理请求,把处理过的参数传递给service。
Service负责业务逻辑的实现,基于Typeorm的增删改查功能来实现各种上层业务逻辑。
除此以外,Nest.js还划分了Module,这个Module是逻辑上的模块,和我们常说的文件对应的模块不同,它包含了Controller、Service等,是对这些资源的逻辑划分。
Module和Module之间还可以有依赖关系,也就有imports和exports。
所以,模块的声明就是这样的:
import{Module}from'@nestjs/common';@Module({imports:[AaaModule],controllers:[BbbController],providers:[BbbService],exports:[BbbService]})exportclassBbbModule{}这里通过@Module的装饰器来声明了Bbb的模块,它依赖了Aaa模块,也就是在imports引入的AaaModule。controllers是控制器,包含BbbController,providers是提供商,有service、factory等类型,这里包含BbbService,同时,还导出了BbbService可以被其他模块引入。
Controller的声明也是通过装饰器:
@Controller()exportclassBbbController{}Service的声明也是用装饰器,只不过不叫Service,而叫Injectable。
@Injectable()exportclassBbbService{}至于为什么叫Injectable,就涉及到了IOC的概念了。
IOC(InverseOfControl)是控制反转的意思,就是只需要声明你的依赖,不需要创建依赖的对象,容器会注入给你。
因为所有的对象都是由容器管理的,那么自然就可以在创建对象的时候注入它需要的依赖,这就是IOC的原理。
Service是可以被作为依赖注入到其他类的实例中去的,所以用Injectable装饰器。
所有的Module会有一个根Module作为入口,启动IOC容器就是从这个模块开始的:
import{NestFactory}from'@nestjs/core';import{AppModule}from'./app.module';import"reflect-metadata";asyncfunctionbootstrap(){constapp=awaitNestFactory.create(AppModule);awaitapp.listen(3000);}bootstrap();上面就是典型的Nest.js启动代码,从AppModule这个根Module开始创建IOC容器,处理从3000端口发过来的请求。
reflect-metadata模块是用于解析类的装饰器的,因为要给某个类的实例注入依赖就得能解析出它通过装饰器声明了哪些依赖,然后注入给它。所以要实现IOC需要依赖这个包。
这就是Nest.js大概的设计了:IOC+MVC,通过IOC容器来管理对象的依赖关系,通过Controller、Service、Module来做职责上的划分。
Nest.js结合TypeormTypeorm是做把对象的操作通过sql同步为对数据库操作的orm的,而Nest.js是做Web后端应用的MVC分层以及通过IOC管理对象的创建和依赖的。这俩很自然的可以结合,结合的方式就是@nestjs/typeorm包。
@nestjs/typeorm包提供了TypeOrmModule这个Module,它有两个静态方法forRoot、forFeature。
forRoot用于创建数据库连接,传入一些配置参数,在入口Module引入。
@Module({imports:[TypeOrmModule.forRoot({type:'mysql',host:'localhost',port:3306,username:'root',password:'你的密码',database:'数据库名',synchronize:true}),NotesModule]})exportclassAppModule{}forFeature用于创建不同实体类对应的Repository,在用到该实体的Module里引入。
@Module({imports:[TypeOrmModule.forFeature([Aaa])],controllers:[AaaController],providers:[AaaService],exports:[AaaService]})exportclassAaaModule{}我们知道了Typeorm和Nest.js都是做什么的和怎么用,简单小结一下:
Typeorm是ORM框架,用于把对象的操作同步为对数据库的操作,会自动执行sql语句。
Nest.js是MVC框架,用于Web后端应用的逻辑分层,还提供了Module用来进一步划分Controller和Service。此外,Nest.js提供了IOC容器,统一管理对象的创建和依赖关系,根据声明来自动注入依赖。
两者的结合就是通过@nestjs/typeorm的包,它有两个静态方法用于生成Module。
说了这么多,大家可能还理解的不是很清楚,那么我们就来做下笔记管理的实战案例吧。
实战案例Nest.js样板代码比较多,自己写还是比较费事的,@nestjs/cli的命令行工具对这些做了自动化。
首先要搭项目的骨架,用
nestnewproject-name然后生成某个Module的代码
nestgresourcexxx生成的代码就是带有Controller、Service、Module的,并且也有了CRUD的样板代码。
我们重点来看下Controller的代码:
import{Controller,Get,Post,Body,Patch,Param,Delete}from'@nestjs/common';import{XxxService}from'./xxx.service';import{CreateXxxDto}from'./dto/create-xxx.dto';import{UpdateXxxDto}from'./dto/update-xxx.dto';@Controller('xxx')exportclassXxxController{constructor(privatereadonlyxxxService:XxxService){}@Post()create(@Body()createXxxDto:CreateXxxDto){returnthis.xxxService.create(createXxxDto);}@Get()findAll(){returnthis.xxxService.findAll();}@Get(':id')findOne(@Param('id')id:string){returnthis.xxxService.findOne(+id);}@Patch(':id')update(@Param('id')id:string,@Body()updateXxxDto:UpdateXxxDto){returnthis.xxxService.update(+id,updateXxxDto);}@Delete(':id')remove(@Param('id')id:string){returnthis.xxxService.remove(+id);}}@Controller的参数可以声明URL路径,@Get、@Post、@Patch、@Delete也可以通过参数声明URL路径,最终会把两个拼起来。比如/xxx/:id的get方法。
@Get、@Post、@Patch、@Delete分别对应不同的请求方式。
@Param是取路径中的参数,@Query是取查询字符串的参数。
@Body是把请求参数设置到对象的属性上,被用来传递数据的对象叫做dto(datatransferobject)。
再就是返回的对象会被序列化成JSON,不需要手动序列化。
然后再看下Service:
import{Module}from'@nestjs/common';@Module({imports:[AaaModule],controllers:[BbbController],providers:[BbbService],exports:[BbbService]})exportclassBbbModule{}0这些service的方法都没有具体实现。
我们引入Typeorm来做数据库的CRUD。
在根模块引入用于数据库连接的Module
在刚创建的模块引入实体对应的Module:
创建笔记实体,用@Entity标识。并且用@Column、@PrimaryGeneratedColumn来标识列和主键。
import{Module}from'@nestjs/common';@Module({imports:[AaaModule],controllers:[BbbController],providers:[BbbService],exports:[BbbService]})exportclassBbbModule{}1之后在service里注入实体对应的操作类Repository,就可以实现对笔记的增删改查了。
用到的dto就是参数对应的对象,他们是实体的一部分属性的集合。比如updatedto:
import{Module}from'@nestjs/common';@Module({imports:[AaaModule],controllers:[BbbController],providers:[BbbService],exports:[BbbService]})exportclassBbbModule{}2这样,就实现了对笔记的增删改查。
我们用postman来测试下效果:
运行npmstart把项目跑起来
可以看到4个接口的路由映射都成功了。
数据库一开始有两条记录:
通过查询接口能正确的查出来:
然后测试下修改接口:
数据库中确实被修改了:
经过测试,对笔记单表的CRUD的功能正常。
我们完成了第一个Nest.js的后端应用!
完整代码上传了github:https://github.com/QuarkGluonPlasma/nestjs-exercize
总结Typeorm是一个ORM框架,通过映射表和对象的对应关系,就可以把对对象的操作转换为对数据库的操作,自动执行sql语句。
Nest.js是一个MVC框架,提供了Module、Controller、Service的逻辑划分,也实现了IOC模式,集中管理对象和自动注入依赖。
Typeorm和Nest.js的结合使用@nestjs/typeorm的包,它提供了一个TypeormModule的模块,有forRoot和forFeature两个静态方法。forRoot方法用于生成连接数据库的Module,forFeature用于生成实体对应的Repository的Module。
Nest.js有很多样板代码,可以用@nestjs/cli的命令行工具生成,包括整体的和每个Module的。
总之,理解了IOC,理解了Module、Controller、Service的划分,就算是初步掌握了Nest.js,结合Typeorm的ORM框架可以轻松的做数据库表的CRUD。
Nest.js是比较强大比较流行的一个后端框架,还是有必要好好学一下的。这篇文章我们入了下门,后面会继续深入。
logo设计
创造品牌价值
¥500元起
APP开发
量身定制,源码交付
¥2000元起
商标注册
一个好品牌从商标开始
¥1480元起
公司注册
注册公司全程代办
¥0元起
查
看
更
多