概念介绍和文件结构
概念介绍
后端中,常用的概念有:模块、控制器、路由和服务
后端开发过程中,实际的开发业务需要分成不同的模块进行,在互联网应用中,客户通过路由,路由将内容带到控制器中,控制器通过需求,去请求其他模块,其他模块来提供具体的服务
模块是一个个独立的功能,每一个模块会向外面暴露出一些服务(有些服务是模块自己独享的,有些服务是可以暴露给第三方的,即暴露给其他模块)。一个模块中,有可能有路由、有可能有控制器、有可能有服务,但是不一定全有。我们在编写网站时,不会自己编写每一个模块,一般使用一些社区完善的框架,社区中会有一些第三方的包,我们直接拿过来使用即可
总之,我们就是借用模块,来配置路由、配置控制器来完善我们的应用
文件结构介绍
初始化项目后的文件结构如下所示:
.prettierrc
文件:代码格式化文件,本身提供了一个格式化操作,但是远远不够,我们需要进行修改,可以参考下面内容进行修改:json{ "arrowParens": "always", "bracketSameLine": true, "bracketSpacing": true, "embeddedLanguageFormatting": "auto", "htmlWhitespaceSensitivity": "css", "insertPragma": false, "jsxSingleQuote": false, "printWidth": 120, "proseWrap": "never", "quoteProps": "as-needed", "requirePragma": false, "semi": false, "singleQuote": true, "tabWidth": 2, "trailingComma": "all", "useTabs": false, "vueIndentScriptAndStyle": false, "singleAttributePerLine": false }
src
文件夹存放的是源文件,是项目的主要文件,我们在这里面进行逻辑的编写,其主要文件有:app.controller.spec.ts
文件是做测试的文件,一般不使用,可以进行删除main.ts
是项目的入口文件,也就是主文件tsimport { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; // 挂载一个根模块 async function bootstrap() { const app = await NestFactory.create(AppModule); // 后端服务,需要向用户提供服务,因此需要做一个端口监听,监听的端口设置为3000 await app.listen(process.env.PORT ?? 3000); } bootstrap();
监听的端口是3000,启动项目后,可以通过
localhost:3000
进行访问,就会出现Hello World!
系统配置的默认路由所对应的服务事件app.module.ts
:模块定义文件,在根上定义模块Module
,让这个模块注册到Nest
中,使其可以识别到,之后在模块内部定义控制器,控制器中要声明装饰器,使系统路由表中可以知道对于具体的路由,需要使用哪个控制器中的哪个方法进行匹配,这个就是控制器和模块路由的关系tsimport { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; // 定义一个装饰器 @Module({ imports: [], controllers: [AppController], // 定义控制器,定义完后,nest就会分析这个控制器 providers: [AppService], }) export class AppModule {}
装饰器可以分为类装饰、属性装饰器、方法装饰器和参数装饰器
使用装饰器后,可以改变后续类的原型对象,为其他类的原型对象上增加一些功能。将一个干净的类,定义为
Nest
的模块,用户通过路由访问的时候,我们就会遍历全局模块modules
列表,查找哪些模块中设置了这个路由,我们就调用这个控制器,具体可以理解为:ts// 对于新创建的类,就会继承模块的属性,增强了这个类的功能 function a(){} a.prototype._module={ { imports: [], controllers: [AppController], providers: [AppService], } } const modules = [] modules.push(a)
总之,根上需要有一个模块
Module
,让模块注册到Nest
中,使其可以被识别,之后再定义控制器,控制器中要声明装饰器,这样系统路由表中就会知道哪个控制器中的哪个方法用来匹配不同的路由app.controller.ts
:控制器定义文件,提供路由访问功能tsimport { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; // 也加了装饰器,下面定义的类就可以被NestJs进行作用,会识别出内部定义的路由 @Controller() export class AppController { constructor(private readonly appService: AppService) {} // 定义路由:定义一个装饰器,在方法上进行装饰器的声明 @Get() getHello(): string { return this.appService.getHello(); } }
@符号修饰的是装饰器,是一个函数,装饰器可以作用在类、属性、方法和参数上
路由定义:
我们对路由进行定义,默认情况是不进行任何路由的添加,直接主页访问:
localhost:3000
ts@Get() getHello(): string { return this.appService.getHello(); }
在页面中就可以看到,
appService
服务的getHello()
方法返回的内容如果将路由定义为a,如下所示:
ts@Get('a') getHello(): string { return 'a'; }
使用域名访问:
http://localhost:3000/a
进行访问,就会显示对应的内容a如果在控制器中进行路由的填写:实际的路由会进行继承
ts@Controller('a') export class AppController { constructor(private readonly appService: AppService) {} @Get() getHello(): string { return this.appService.getHello(); } }
使用域名访问:
http://localhost:3000/a
进行访问,网页中会显示appService
服务的getHello()
方法返回的内容如果在控制器和实际路由中都进行路由的配置:
ts@Controller('a') export class AppController { constructor(private readonly appService: AppService) {} @Get('b') getHello(): string { return this.appService.getHello(); } }
使用域名访问:
http://localhost:3000/a/b
进行访问,网页中会显示appService
服务的getHello()
方法返回的内容
app.service.ts
:服务内容文件,存放一些服务的响应事件,提供业务的逻辑代码tsimport { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } }
NestJs
后端也可以进行非前后端分离,可以进行页面的渲染,但是目前推荐使用前后端分离的开发思路,所以,主要用它来进行接口的编写