date
Apr 2, 2024 07:06 AM
type
status
slug
summary
tags
category
updated
Oct 24, 2024 12:52 PM
icon
password
前言
NestJS是一个高效、可扩展的Node.js框架,它提供了一套成熟的模式和功能,帮助开发者构建可维护和可扩展的服务端应用。本教程将引导你使用NestJS搭建一个服务端应用,并介绍如何对接PostgreSQL数据库、配置环境变量以及实现用户密码加密。
初始化项目
请确保你的操作系统上安装了Node.js(version ≥ 16)
我们采用官网提供的Nest CLI方式设置项目。
要使用 TypeScript 更严格的功能集创建新项目,请将--strict
标志传递给nest new
命令。
目录简介
src目录
这里是主要代码,初始化的项目打开会看到
之后运行
pnpm run start:dev
。就可以访问http://localhost:3000/
会出现hello world的字眼。package.json
这个文件前端开发都熟悉,不过多解释。主要是了解初始化的项目已经安装了什么。
分别安装了主要的代码检测和格式化插件
eslint
和 prettier
nest-cli.json
这个文件主要是配置插件和库以及项目的配置,例如你需要
@nestjs/graphql
插件或者自定义插件。以下是简单的教程,基本上可以不用修改文件,仅做了解。项目文件别名
项目内引入文件的时候,我们都会使用
@
来指向src
目录。我们需要修改tsconfig.json
文件。
数据库的连接
说明以及安装
在连接数据库之前,我们需要了解数据库和orm之间的关系,orm是一种数据关系映射的工具,它用作编写纯 SQL 或使用其他数据库访问工具。这样的话,我们不用关心多种数据库的连接,改变数据库版本之后要修改代码等等问题。
初始化之后会得到prisma的文件夹(如果你初始化失败,八成是你的网络连不上国外的网络)。
新建
.env
文件,这个是本地的环境变量设置prisma配置
上面新建的环境变量文件,那么就需要prisma来连接数据库了。
打开
prisma\schema.prisma
文件创建数据库
添加如下的模型到
prisma\schema.prisma
文件中之后做如下操作,同步本地的表结构到数据库中。
后续数据库有更新,用
npx prisma db push/pull
来操作。Nestjs上使用
安装客户端
安装完之后为了让项目结构更加清晰,这里新建src/prismac文件夹,用来存放客户端创建prisma的操作。
该目录下新建prisma.service.ts
之后再在该目录下新建
prisma.module.ts
之后在
users.module.ts
中导入prisma命令说明
命令 | 说明 |
init | 在应用中初始化 Prisma |
generate | 主要用来生成 Prisma Client |
db | 管理数据库的模式和生命周期 |
migrate | 迁移数据库 |
studio | 启动一个Web 端的工作台来管理数据 |
validate | 检查 Prisma 的模式文件的语法是否正确 |
format | 格式化Prisma的模式文件,默认就是 prisma/schema.prisma |
项目架构
这里我通过我的一个项目来分享大致的项目架构是什么样子的,我这里写一个users的接口。
在src文件夹下新建users文件夹。
然后新建如下文件
因为代码都是要使用到服务层,所以我们先写服务层代码
users.service.ts
编写服务代码,主要这层就是操作orm,来实现数据库的操作。
users.controller.ts
这里就是调用前面写的service层的函数,这里主要负责请求的参数解析等,请求的连接定义等,我这里的就是/users/sign post类型的接口
users.modules.ts
这里主要是负责注册或者抛出模块,,因为cotroller层需要PrismaService ,所以注册进来。让后表明controller层。
最后在app.module.ts中导入这个UsersModule
以上就是最基础的操作,为了项目的规范化,下面还有其他层。
Dto层
在前面的例子中,我们获取客户端的参数都是直接写在控制器内每个方法的参数中的,这样做引发的问题有:
- 会降低代码的可读性,一大串参数写在方法里很不优雅。
- 当很多方法都都需要传入相同参数时,要写很多重复代码,可维护性大大降低。
- 参数的有效性验证需要写在控制器内的方法中,会产生冗余代码。
DTO层的作用就是解决上述问题的,我们用
class
来处理客户端传入的参数。新建
src/users/users.dto.ts
之后在
src/users/users.controller.ts
中使用使用管道验证参数的有效性
下面的需要安装包
接下来,我们使用管道来解决第3个问题,在nest官网中,它提供了8个开箱即用的内置管道,此处我们需要用它的
ValidationPipe
管道来验证参数。根据文档所述,在使用前我们需要先绑定管道,官网给出了两种方法:
- 绑在 controller 或是其方法上,我们使用
@UsePipes()
装饰器并创建一个管道实例,并将其传递给 Joi 验证。
- 在入口处将其设置为全局作用域的管道,用于整个应用程序中的每个路由处理器。
此处我们使用全局作用域的管道,修改main.ts文件,代码如下所示:
随后,我们即可在dto层中使用它的相关装饰器来校验参数了
之后你测试
127.0.0.1:3000/users/user
接口,输入名字就1个字的时候,接口会返回提示。VO层(返回给客户端的视图)
通常情况下,我们返回给客户端的字段是固定的,在本文前面的controller层中,两个方法我们都返回了
code
、data
、msg
这三个字段,只是数据不同。那么我们就应该把它封装起来,将数据作为参数传入,这样就大大的提高了代码的可维护性,也就是我们所说的VO层。封装工具类
我们在src目录下创建
VO
文件夹,在其目录下创建 result.vo.ts
文件,代码如下所示:- 简单创建了一个类,添加了三个字段
- 为每个字段写了get和set方法
随后,我们在src目录下创建utils文件夹,在其目录下创建
voUtils.ts
文件,封装常用方法,便于其他层直接调用,代码如下所示:- 我们封装了
success
与error
方法
- 成功时,传入data进来
- 失败时,传入code与msg告知客户端错误原因
注意:success
方法支持传入的参数是任意类型的,实际的业务需求中,data这一层会很复杂,你在实际使用时,可以根据具体的业务需求创建对应业务的vo类,然后对其进行实例化,为每个字段赋值。最后在调用success方法时将你实例化后的对象传入即可。
在业务代码中使用
随后,我们就可以在
service
层来使用我们创建好的工具类了,示例代码如下所示:然后修改一些Controller层
返回的结果就会变成
接口层
这一层用于声明每个service类中都有哪些方法,可以很大程度提升代码的可读性。如果没有这一层,当service中的方法越来越多时,代码也会特别长,想快速找到某个方法,将会变得很费时。
举例说明
接下来我们在src目录下创建
interface
文件夹,在其目录下新建一个AppInterface.ts
文件。举个例子,我们需要在声明5个方法,分别如下所示:
- getTitle
- getName
- getAge
- setName
- setTitle
实现代码
在TypeScript中用
interface
关键字来声明一个接口,那么上述例子转换为代码后就如下所示:做完上述操作后,我们还需要改造下service层的代码,让其实现这个接口,部分代码如下所示:
在TypeScript中,我们使用implements关键字来实现一个接口。
模块层
这一层是使用
@Module()
装饰器的类,它提供了元数据,Nest 用它来组织应用程序结构。我们有了控制层和服务层后,它们还无法运行,因为它们缺少一个组织。实现代码
接下来,我们在src目录下创建
module
文件夹,在其目录下创建AppModule.ts
文件,代码如下所示:- controllers 是一个数组类型的数据,我们把controller层的控制器在这里一一引入即可。
- providers 也是一个数组类型的数据,我们把service层的服务在这里一一引入即可。
有关controllers与providers的详细介绍,请移步:Nest-@module