使用NestJS搭建服务端应用(上)

简介: 使用NestJS搭建服务端应用(上)

前言


最近有个需求需要基于前端技术栈实现一套中间层API接口,用于处理由前端维护的一套JSON配置文件。


经过一番查找后,最终选择了nest.js这个框架,由于它支持AOP编程,与SpringBoot的写法较为相似,可以将SpringBoot那套架构思想应用过来,这对于我这个全干工程师(懂亿点点Java)来说就非常友好了😁


经过3天的学习与折腾,终于搭建了一套我比较满意的架构,本文就跟大家分享下我的架构方案,欢迎各位感兴趣的开发者阅读本文。


写在前面


本文所讲内容会涉及到TypeScript,如果你对它还不够理解,请先移步:TypeScript中文文档学习下,入个门🤓。


  • 本文完整项目代码移步:nest-project


  • 本文中所安装的依赖包要求你的node版本必须在14.16.0及以上。


你可以使用node版本管理控制器n来管理你的node版本,你可以使用npm install -g n来安装它。

安装完成后,你只需使用n 版本号即可安装并切换到对应版本的node了。macos下使用可能需要使用sudo n 版本号。例如:n 14.16.0

有关n的更多使用方法请移步:n-github


环境搭建


在nest官网中,它提供了三种搭建方式:


  • 使用CLI安装
  • 使用Git安装
  • 手动创建


这三种安装方式都比较简单,感兴趣的开发者可自行查阅文档来了解学习。为了锻炼大家的动手能力,本文不采用上述方法来搭建项目,我们将从0开始使用yarn初始化一个空项目,然后安装nest的相关依赖包。


注意:如果你已经搭建好了环境,请跳过此章节,前往下一个章节:项目架构。


初始化一个空项目


本文使用yarn来初始化项目,如果你没有安装的话需要先使用npm来安装下,命令如下:


  • npm install --global yarn

安装完成后,可以使用命令:yarn --version 来验证下是否安装成功,如果成功你会看到如下所示的输出:


640.png

                                 image-20220111215750509


接下来,我们创建一个名为nest-project的空文件夹,在终端进入这个文件夹,使用命令:yarn init来初始化一个项目,如下所示,根据自己的需要填写即可,带括号的部分可以不填写保持默认,直接回车即可。


640.png

                                image-20220111222505312


随后,我们打开这个项目,文件夹中只有一个package.json文件,内容如下所示:


{
  "name": "nest-project",
  "version": "1.0.0",
  "main": "index.js", // 这个可以删除,不需要这个字段
  "author": "likai",
  "license": "MIT",
  "private": true
}


上述内容就是我们刚才在终端所选择的,因此你也可以自己创建一个空文件,创建这个json文件,写上对应的配置,达到相同的结果。


安装nest依赖包


我们打开刚才创建的package.json文件,添加如下所示的字段:


{
  "dependencies": {
    "@nestjs/common": "^8.1.1",
    "@nestjs/core": "^8.1.1",
    "@nestjs/platform-express": "^8.1.1",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.13.2",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^7.4.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^8.1.3",
    "@nestjs/schematics": "^8.0.4",
    "@types/express": "^4.17.13",
    "@types/node": "^16.11.1",
    "supertest": "^6.1.6",
    "ts-loader": "^9.2.6",
    "ts-node": "^10.3.0",
    "tsconfig-paths": "^3.11.0",
    "tslib": "^2.3.0",
    "typescript": "^4.4.4",
    "webpack": "5.0.0"
  }
}


随后,我们打开终端,进入项目目录,执行yarn install 命令,成功后的界面如下所示:


640.png

                                  image-20220111225541175


安装代码规范依赖包


本文采用eslint和prettier来规范代码,对此不了解的开发者请移步我的另一篇文章:独立使用ESLint+Prettier对代码进行格式校验。


接下来,我们打开前面所创建的package.json文件,在devDependencies对象中添加下述代码:


{
  "devDependencies": {
    "eslint": "^7.0.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^3.3.1",
    "prettier": "^2.2.1",
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
  }
}


添加完成后,执行yarn install就完成了依赖包的引入。


添加启动命令


安装完所有依赖后,接下来我们在package.json中添加6个运行脚本,用于项目的启动与打包构建,如下所示:


  • prebuild 移除dist目录
  • build 打包项目
  • start 启动项目
  • start:dev 启动项目(支持热更新)
  • start:debug 以debugger模式启动项目(支持断点调试)
  • start:prod 启动打包后的项目


{
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main"
  }
}


添加配置文件


接下来,我们还需要在项目根目录添加nest、eslint、prettier等配置文件,如下所示:


  • .editorconfig统一不同操作系统之间的代码格式相关问题的配置文件
  • .eslintrc.js eslint的配置文件
  • .gitignore git提交时需要忽略的文件
  • .prettierrc.json prettier的配置文件
  • nest-cli.json nest的配置文件
  • tsconfig.json typescript的配置文件
  • tsconfig.build.json 项目打包时ts文件的相关处理配置文件


具体的文件内容,点击上方蓝色字体可直接跳转到GitHub中对应的文件。


项目架构


本章节将跟大家下分享我的项目架构,首先在项目根目录创建src文件夹,所有项目代码将存放在此目录下。


本章节节对应的的完整项目代码移步:nest-project


控制层


这一层用于处理客户端传入的请求以及向客户端返回响应,所有的请求映射都会在这一层来实现。每个请求会对应一个控制器,一个控制器中可以有多个子方法用于处理同类型的不同操作。


举例说明


接下来,我们在src目录下创建controller文件夹,在其目录下新建一个AppController.ts文件。


我们从一个例子入手:


  1. 处理/home/setTitlepost请求,它的参数在http body中
  2. 处理/home/getTitleget请求,它的参数在请求url中


实现代码


翻阅官方文档后,我们就可以写出如下所示的代码:


import { Body, Controller, Get, Query, Post } from "@nestjs/common";
@Controller("home")
export class AppController {
  @Post("setTitle")
  setTitle(@Body() data: { id: number; title: string }): {
    code: number;
    data: null | string;
    msg: string;
  } {
    // 客户端传入的数据
    console.log(data);
    // 返回给客户端的数据
    return { code: 0, data: null, msg: "post方法调用成功" };
  }
  @Get("getTitle")
  getTitle(@Query("id") id: number): {
    code: number;
    data: string;
    msg: string;
  } {
    console.log("客户端传入的数据", id);
    return { code: 0, data: null, msg: "get方法调用成功" };
  }
}


我们来看下上述代码中各个装饰器的作用:


  • @Controller 用于标识此文件是一个控制器,它接受一个参数,此处我写了home,代表所有/home的请求都会进到这里。
  • @Post 用于处理post格式的请求,它也接受一个参数,此处我写了setTitle,代表/home/setTitle的post请求会进到这里。
  • @Body用于获取http body中的数据
  • @Query用于获取请求url中的数据


在nest文档中,它提供的装饰器还有很多,可以应付各种开发场景,详情请移步:控制器- request。


服务层


服务层用于处理具体的业务逻辑,当我们收到客户端的请求后,取出参数编写具体的业务代码。


举例说明


接下来,我们在src目录下创建service文件夹,在其目录下新建一个AppService.ts文件。


举个例子:


  • 写一个方法,根据id来做一些事情,做完后返回操作结果。


实现代码


查阅文档后,我们知道了需要使用@Injectable()来装饰这个类,代码如下所示:

import { Injectable } from "@nestjs/common";
@Injectable()
export class AppService {
  public setTitle(id: string): {
    code: number;
    data: null | string;
    msg: string;
  } {
    // 根据id做一些事情,此处省略
    console.log(id);
    // 返回操作结果
    return { code: 0, data: null, msg: "设置成功" };
  }
}


做完上述操作后,我们还需要改造下AppController,在constructor中引入我们刚才创建好的service,部分代码如下所示:


export class TextAttributeController {
  constructor(private readonly appService: AppService) {}
  @Post("setTitle")
  setTitle(){
    // 此处省略了较多代码,这里的重点是演示如何调用我们刚才写好的方法
    return this.appService.setTitle();
  }
}


一个service类中会有很多方法,我们会根据控制层的映射建立与之对应的处理方法

,这样就可以让控制层更专心的处理它的分内之事,提升代码可读性。


接口层


这一层用于声明每个service类中都有哪些方法,可以很大程度提升代码的可读性。如果没有这一层,当service中的方法越来越多时,代码也会特别长,想快速找到某个方法,将会变得很费时。


举例说明


接下来我们在src目录下创建interface文件夹,在其目录下新建一个AppInterface.ts文件。


举个例子,我们需要在声明5个方法,分别如下所示:


  1. getTitle
  2. getName
  3. getAge
  4. setName
  5. setTitle


实现代码


在TypeScript中用interface关键字来声明一个接口,那么上述例子转换为代码后就如下所示:


export interface AppInterface {
  getTitle(): string;
  getName(): string;
  getAge(): string;
  setName(): string;
  setTitle(): string;
}


做完上述操作后,我们还需要改造下service层的代码,让其实现这个接口,部分代码如下所示:


@Injectable()
export class AppService implements AppInterface {
  getAge(): string {
    return "";
  }
  getName(): string {
    return "";
  }
  //  其他方法省略
}


在TypeScript中,我们使用implements关键字来实现一个接口。

相关文章
|
7月前
|
安全 JavaScript 应用服务中间件
vue-cli搭建代理服务器,将请求转发到后台服务器
vue-cli搭建代理服务器,将请求转发到后台服务器
88 0
|
4月前
|
移动开发 JavaScript 网络协议
SpringBoot:Netty-SocketIO + VUE:SocketIO实现前后端实时双向通信
SpringBoot:Netty-SocketIO + VUE:SocketIO实现前后端实时双向通信
138 0
|
1月前
|
缓存 中间件 API
|
7月前
|
JavaScript 前端开发 Java
SpringBoot+Vue搭建一个WebSocket的实时聊天室
SpringBoot+Vue搭建一个WebSocket的实时聊天室
144 0
|
8月前
|
JavaScript 前端开发 Java
带你入门——如何在nestjs中体验websocket
带你入门——如何在nestjs中体验websocket
|
8月前
|
开发框架 JavaScript 前端开发
如何使用SpringBoot和Netty实现一个WebSocket服务器,并配合Vue前端实现聊天功能?
如何使用SpringBoot和Netty实现一个WebSocket服务器,并配合Vue前端实现聊天功能?
196 0
|
9月前
|
前端开发 JavaScript 网络协议
集成websocket实现实时通信(ruoyi 使用笔记)
集成websocket实现实时通信(ruoyi 使用笔记)
678 1
|
消息中间件 缓存 前端开发
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
1644 1
Springboot 整合 WebSocket ,使用STOMP协议 ,前后端整合实战 (一)
|
中间件
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
338 1
eggjs 怎么使用 egg-jwt 实现登录验证中间件?
|
前端开发
flask+vue的前端发送与后端验证
前端发送与后端验证
135 0