从零开始搭建搭建nestJs

从零开始搭建搭建nestJs

Nest 概念

  • Nest的核心概念是提供一种体系结构,它帮助开发人员实现层的最大分离,并在应用程序中增加抽象。

  • 主要有三个核心概念:模块Module, 控制器Controller, 服务与依赖注入 Provider Dependency injection

    1. 模块Module: 用于将代码拆分为独立的和可重用的模块,例如用户信息模块,然后将该用户模块的控制器和服务集合进来,最后直接将用户模块导入到根Module就可以使用了。
    2. 控制器Controller: 负责处理客户端传入的请求参数并向客户端返回响应数据。nest.js提供许多http请求的装饰器,如例如@Body(),@Post()等。控制器不需要定义任何诸如从客户端获取数据、验证用户输入等工作,这些都是交给服务Provider处理,通过把任务委托给各种服务,可以让控制器类更加精简、高效。``
    3. 服务Provider :在这里处理所有请求执行逻辑,在控制器中通过constructor函数以依赖注入的方式实现。
  • 其他概念:

    1. 过滤器Exception filter:负责在整个应用程序中处理所有抛出的异常,同时可以自定义错误状态码和错误消息内容。
    2. 管道 Pipe:管道可以把你的请求参数根据特定条件验证类型、对象结构或映射数据。管道是一个纯函数,不应该从数据库中选择或调用任何服务操作。
    3. 守卫 Guard:通常用作权限认证
    4. 中间件Middleware: 中间件功能可以访问请求和响应对象,在路由处理程序之前调用

客户端请求 —> 中间件 —> 守卫 —> 拦截器之前 —> 管道 —> 控制器处理并响应 —> 拦截器之后 —> 过滤器

一、创建nest

nest -h指令介绍

class (简写: cl) 类
controller (简写: co) 控制器
decorator (简写: d) 装饰器
exception (简写: e) 异常捕获
filter (简写: f) 过滤器
gateway (简写: ga) 网关
guard (简写: gu) 守卫
interceptor (简写: i) 拦截器
middleware (简写: mi) 中间件
module (简写: mo) 模块
pipe (简写: pi) 管道
provider (简写: pr) 供应商
service (简写: s) 服务

nest 利用cli创建,会自动生成并引入模块,

  1. 安装与创建
npm i -g @nestjs/cli
nest new project-name
npm start
  1. 创建模块(用于关联路由与服务)
nest generate module news
简写
nest g mo news

news.module.ts

import { Module } from '@nestjs/common';
import { NewsService } from './news.service';
import { NewsController } from './news.controller';
//创建时会自动引入到module中管理,同时会把module导入到app.module中
@Module({
  providers: [NewsService],
  controllers: [NewsController]
})
export class NewsModule {}
  1. 创建路由(控制层,可以处理简单的业务和处理请求与响应)
nest generate controller news
简写
nest g co news

news.controller.ts

import { Controller, Get } from '@nestjs/common';
import { NewsService } from './news.service';

@Controller()
export class AppController {
  constructor(private readonly appService: NewsService) {} //将news.serbice中注入的属性,在这里注册就可以在this上使用

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

  1. 建立服务(处理复杂的业务逻辑)
nest generate service  cats
简写
nest g s cats

news.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()//注入到底层,在controller中就可以使用
export class NewsService {
    getHello(): string{
        return 'Hello World!';
    }
}

app.module.ts

这部分很关键,需要将controllers引入,等同于加入路由操作

如果使用了service 也需要在下面引用,

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DbModule } from '@libs/db';
import { NewsController } from './news/news.controller';
import { NewsService } from './news/news.service';

@Module({
  imports: [
    DbModule
  ],
  controllers: [AppController,NewsController ],
  providers: [AppService,NewsService],
})
export class AppModule {}

二、openAPI (swagger编写API文档)

  1. nest原生支持swagger,可以自动根据装饰器解析对应的文档
npm install --save @nestjs/swagger swagger-ui-express

安装过程完成后,打开main.ts文件并使用SwaggerModule类初始化Swagger:

import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const options = new DocumentBuilder()
    .setTitle('nest博客api') //标题
    .setDescription('我的第一个nest项目') //描述
    .setVersion('1.0') //版本
    //.addTag('cats') //添加标签
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api-doc', app, document);//定义挂载到那个路径下

  await app.listen(3000);
    console.log('http://localhost:3000/api-doc')
    
}
bootstrap();
  1. 结合swagger使用 文档

    //参数装饰器
    //@Body(key?:string),@Query(key?:string),@Param(key?:string)

    等同于 res.body[key] 指定获取某一值

    import { Controller, Get, Post, Body, Query, Param, Put, Delete } from '@nestjs/common';
    import { ApiTags, ApiOperation, ApiProperty,ApiQuery,ApiCreatedResponse, ApiParam } from '@nestjs/swagger';
    import { query } from 'express';
    // 这里不使用interface 原因是 interface编译成js后会被删除,同时用不了装饰器,无法在swagger显示
    class CreatePostDto{ //用于对参数的限制
      @ApiProperty({description:'帖子标题',example:'111'}) 
      title:string
      @ApiProperty({description:'帖子内容',example:'222'})
      content:string
    }
    
    @Controller('posts') //相当于添加一个路由前缀
    @ApiTags('帖子') //添加一个api标签
    export class PostsController {
      @Get()
      @ApiOperation({summary:'显示博客列表'})//Api注解
      // 帖子列表页
      @ApiQuery({ name: 'id',example:1,description:'列表id'})
      index(@Query()query){
        return[
          {id:1,title:'博客1'},
          {id:1,title:'博客2'},
          {id:1,title:'博客3'},
        ]
      }
    
      @Post()
    
      @ApiOperation({summary:'创建帖子'})
    
      @ApiCreatedResponse({ //编写响应的api注解
        status:200,
        description: 'The record has been successfully created.',
        type: CreatePostDto,
      })
      create(@Body()createPostDto:CreatePostDto){
        return{
          data:createPostDto,
          success:true
        }
      }
    //params 和query获取的都是一个对象,可以在装饰器中指定获取的参数    
      @Get(':id')
      @ApiParam({ name: 'id',example:1,description:'帖子id'})
      @ApiOperation({summary:'获取帖子详情'})
     async detail(@Param('id')id:string){
          return {
            data:data,
            success:true
          }
      }
    
    
      @Put(':id')
      @ApiOperation({summary:'修改帖子详情'})
      updatePostDto(@Param()id,@Body() updatePostDto:CreatePostDto){
          return {
            data:{
              id:id.id,
              data:updatePostDto
            },
            success:true
          }
      }
      @Delete(':id')
      @ApiOperation({summary:'删除帖子'})
      remove(@Param()param){
        return{
          data:param.id,
          success:true
        }
      }
    }
    
    
  2. RESTful接口规范 GET/POST/PUT/DELETE

    REST 是Representational State Transfer的缩写,翻译是”表现层状态转化”.
    
    面向资源是REST最明显的特征,对于同一个资源的一组不同的操作。资源是服务器 上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。
    get 获取  post 创建  put 更新  delete 删除
    
    状态码
    200(OK) - 表示已在响应中发出
    204(无内容) - 资源有空表示
    301(Moved Permanently) - 资源的URI已被更新 303(See Other) - 其他(如,负载均衡)
    304(not modified)- 资源未更改(缓存)
    400 (bad request)- 指代坏请求(如,参数错误) 404 (not found)- 资源不存在
    406 (not acceptable)- 服务端不支持所需表示
    500 (internal server error)- 通用错误响应
    503 (Service Unavailable)- 服务端当前无法处理请求
    
    

三、配置静态资源与模板引擎

在根目录新建public文件夹

main.ts

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>( //注入平台
    AppModule,
  );

  app.useStaticAssets(join(__dirname, '..', 'public'));//配置静态资源
   // 或者
 //  app.useStaticAssets('public',{
   //    prefix:'/static/'   //配置虚拟目录 上面一样
 //  })
  app.setBaseViewsDir(join(__dirname, '..', 'views'));//配置模板文件存储文件夹
  app.setViewEngine('ejs');//配置模板引擎需要安装不需要引入

  await app.listen(3000);
}
bootstrap();

在根目录创建views文件夹,然后在下面创建index.ejs

之后在需要的controller中引入,

import { Controller, Post, Render, Get } from '@nestjs/common';
import { NewsService } from './news.service';

@Controller('news')
export class NewsController {
  constructor(private readonly newsSerbice:NewsService){}
  @Get()
  @Render('index')
  getEl(){
    return {} //要么没有返回值,要么返回一个json
  }
}

四、创建子项目(运用于多个项目共用model)

在一个nest项目创建同级项目中统一管理
cd project-name 
nest g app  children
//或者
nest g 整体项目名 子项目名 


指定子项目中增加模块/控制器
nest g mo/co/s -p 子项目名 模块名
neest g mo -p admin users

这个时候在整体项目下会出现2个子项目这个时候的启动命令变成

//dev时需要加-w监听,子项目名是什么就会监听谁
nest start -w chidren-name 

五、创建公用库(存放类似db之类)

//创建一个db公用库
nest g lib db
//默认是@app, 最好改成@libs方便记忆
? What prefix would you like to use for the library (default: @app)? @libs

安装完成后在需要使用的模块的app.module.ts中引入dbmodule

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DbModule } from '@libs/db';

@Module({
  imports: [
    DbModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

在lib文件下的src下的db.module.ts中连接数据库

import { Module } from '@nestjs/common';
import { DbService } from './db.service';
import { TypegooseModule } from "nestjs-typegoose"

@Module({
  imports:[
    TypegooseModule.forRoot("mongodb://localhost:27017/nest-MDemo",{
      useNewUrlParser:true,
      useUnifiedTopology: true,
    	useCreateIndex: true,
    	useFindAndModify: false
    })
  ],
  providers: [DbService],
  exports: [DbService],
})
export class DbModule {}

然后在src下创建文件夹models 例如:创建一个user.model.ts

import {prop} from "@typegoose/typegoose"
export class User {
  @prop()
  username:string
  @prop()
  password:string
}

注册模块(可以在需要的模块中注册,也可以这样全局注册,就可以任意使用)

import { Module, Global } from '@nestjs/common';
import { DbService } from './db.service';
import { TypegooseModule } from "nestjs-typegoose"
import { User } from './models/user.model';
const models = TypegooseModule.forFeature([User])//注册模块
@Global()//定义为全局
@Module({
  imports:[
    TypegooseModule.forRoot("mongodb://localhost:27017/nest-MDemo",{
      useNewUrlParser:true,
      useUnifiedTopology: true,
    	useCreateIndex: true,
    	useFindAndModify: true
    }),
    models
  ],
  providers: [DbService],
  exports: [DbService,models],
})
export class DbModule {}

使用方式和单个项目一样 需要把lib下定义的user.model 导入然后注入

发布了61 篇原创文章 · 获赞 98 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/marendu/article/details/105744963
今日推荐