当前位置: 首页 > news >正文

NestJS 项目中如何使用 class-validator 进行数据验证

前言

在现代Web开发中,数据验证是必不可少的一环,它不仅能够确保数据的准确性,还能提高系统的安全性。在使用NestJS框架进行项目开发时,class-validator与class-transformer这两个库为我们提供了方便的数据验证解决方案。
本文将通过详细的步骤和实战技巧,带大家掌握如何在NestJS中使用class-validator进行数据验证。通过这篇文章,你将能够学会如何使用class-validator优雅的实现数据验证,以及11条实战中常用的验证技巧,提高项目的数据校验能力。

使用步骤

第一步:安装 class-validator 和 class-transformer

要使用 class-validator,需要安装两个库:class-validator 和 class-transformer。
npm install class-validator class-transformer

第二步:创建 DTO(数据传输对象)

在 NestJS 中,通常使用 DTO(Data Transfer Object)来定义请求数据的结构。首先,需要创建一个用于用户注册的 DTO 类,并使用 class-validator 的装饰器来定义验证规则。

// src/user/dto/create-user.dto.ts
import { IsString, IsEmail, IsNotEmpty, Length } from 'class-validator';export class CreateUserDto {@IsString()@IsNotEmpty()@Length(4, 20)username: string;@IsEmail()email: string;@IsString()@IsNotEmpty()@Length(8, 40)password: string;
}

在这个 DTO 中,定义了三个字段:username、email 和 password,并使用 class-validator 的装饰器指定了验证规则。

第三步:使用管道验证数据

接下来,需要在控制器中使用 DTO,并通过 NestJS 的管道(Pipes)来验证传入的数据。

// src/user/user.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';@Controller('user')
export class UserController {@Post('register')async register(@Body() createUserDto: CreateUserDto) {// 处理注册逻辑return { message: 'User registered successfully', data: createUserDto };}
}

在这个例子中,在 register 方法中使用了 @Body() 装饰器来获取请求体,并传入了 CreateUserDto。NestJS 会自动验证该 DTO,如果验证失败,将抛出异常并返回适当的错误响应。

第四步:全局启用验证管道

为了更方便地管理,可以全局启用验证管道,这样所有的 DTO 验证都会自动进行。

// src/main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';async function bootstrap() {const app = await NestFactory.create(AppModule);app.useGlobalPipes(new ValidationPipe());await app.listen(3000);
}bootstrap();

在 main.ts 文件中,使用 ValidationPipe 全局启用了验证管道。这样一来,无论在哪个控制器中使用 DTO,NestJS 都会自动进行数据验证。当然也可以仅对某些控制器开启验证管道,详情参考下方实战技巧。

实战使用技巧

1. 局部验证管道

可以为特定的路由或控制器方法配置验证管道,而无需全局启用。这样可以在不同的场景下灵活使用不同的验证规则。

import { Controller, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';@Controller('user')
export class UserController {@Post('register')@UsePipes(new ValidationPipe({transform: true,whitelist: true,forbidNonWhitelisted: true,}))async register(@Body() createUserDto: CreateUserDto) {// 处理注册逻辑return { message: 'User registered successfully', data: createUserDto };}
}

2. 自定义错误消息

class-validator 允许为每个验证规则定义自定义错误消息。例如:

import { IsString, IsNotEmpty, Length, IsEmail } from 'class-validator';export class CreateUserDto {@IsString({ message: '用户名必须是字符串' })@IsNotEmpty({ message: '用户名不能为空' })@Length(4, 20, { message: '用户名长度必须在4到20个字符之间' })username: string;@IsEmail({}, { message: '邮箱格式不正确' })email: string;@IsString({ message: '密码必须是字符串' })@IsNotEmpty({ message: '密码不能为空' })@Length(8, 40, { message: '密码长度必须在8到40个字符之间' })password: string;
}

3. 嵌套对象验证

如果 DTO 中包含嵌套对象,可以使用 @ValidateNested() 装饰器进行验证。例如:

import { Type } from 'class-transformer';
import { ValidateNested, IsString, IsNotEmpty } from 'class-validator';class AddressDto {@IsString()@IsNotEmpty()street: string;@IsString()@IsNotEmpty()city: string;
}export class CreateUserDto {@IsString()@IsNotEmpty()username: string;@ValidateNested()@Type(() => AddressDto)address: AddressDto;
}

3. 组合验证装饰器

有时可能需要将多个验证规则组合在一起,这时可以使用 @ValidatorConstraint() 来创建自定义验证装饰器。例如:

  1. 判断数据库中是否已经存在用户名
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';@ValidatorConstraint({ async: false })
export class IsUsernameUniqueConstraint implements ValidatorConstraintInterface {validate(username: any) {// 这里可以添加验证逻辑,例如查询数据库return true; // 如果验证通过返回 true}
}export function IsUsernameUnique(validationOptions?: ValidationOptions) {return function (object: Object, propertyName: string) {registerDecorator({target: object.constructor,propertyName: propertyName,options: validationOptions,constraints: [],validator: IsUsernameUniqueConstraint,});};
}// 使用自定义装饰器
export class CreateUserDto {@IsUsernameUnique({ message: '用户名已存在' })username: string;
}
  1. 验证密码强度
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
export function IsStrongPassword(validationOptions?: ValidationOptions) {return function (object: Object, propertyName: string) {registerDecorator({name: 'isStrongPassword',target: object.constructor,propertyName: propertyName,options: validationOptions,validator: {validate(value: any, args: ValidationArguments) {return /(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}/.test(value);},defaultMessage(args: ValidationArguments) {return '密码必须包含大小写字母、数字和特殊字符,并且至少8个字符长';},},});};
}
export class ChangePasswordDto {@IsStrongPassword({ message: '密码不符合强度要求' })newPassword: string;
}
  1. 条件验证
    根据条件进行验证,可以使用 @ValidateIf 装饰器。
import { ValidateIf, IsNotEmpty, IsEmail } from 'class-validator';
export class UpdateUserDto {@IsEmail()email: string;@ValidateIf(o => o.email)@IsNotEmpty({ message: '新邮件地址不能为空' })newEmail: string;
}
  1. 使用 @Matches 进行正则表达式验证
    使用 @Matches 装饰器,可以验证字符串是否与指定的正则表达式匹配。
import { Matches } from 'class-validator';
export class ChangePasswordDto {@Matches(/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}/, { message: '密码必须包含大小写字母、数字和特殊字符,并且至少8个字符长' })newPassword: string;
}
  1. 全局验证选项
    全局启用验证管道时,可以配置全局验证选项,比如剥离非白名单字段、自动转换类型等。
// src/main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {const app = await NestFactory.create(AppModule);app.useGlobalPipes(new ValidationPipe({whitelist: true, // 剥离非白名单字段forbidNonWhitelisted: true, // 禁止非白名单字段transform: true, // 自动转换类型}));await app.listen(3000);
}
bootstrap();
  1. 动态验证消息
    有时可能需要根据具体的验证条件动态生成错误消息,可以使用 ValidationArguments 来实现。
import { IsString, MinLength, ValidationArguments } from 'class-validator';export class CreateUserDto {@IsString()@MinLength(4, {message: (args: ValidationArguments) => {return `用户名太短了,至少需要 ${args.constraints[0]} 个字符`;},})username: string;
}
  1. @Validate 自定义验证逻辑
    如果内置装饰器无法满足需求,可以使用 @Validate 装饰器添加自定义验证逻辑。
import { Validate, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';@ValidatorConstraint({ name: 'customText', async: false })
class CustomTextConstraint implements ValidatorConstraintInterface {validate(text: string, args: ValidationArguments) {return text.startsWith('prefix_'); // 任何自定义逻辑}defaultMessage(args: ValidationArguments) {return '文本 ($value) 必须以 "prefix_" 开头';}
}export class CustomTextDto {@Validate(CustomTextConstraint)customText: string;
}
  1. 属性分组验证
    通过分组,可以在不同情境下验证不同的字段。比如在创建和更新时可能需要验证不同的字段。
import { IsString, IsNotEmpty } from 'class-validator';export class CreateUserDto {@IsString()@IsNotEmpty({ groups: ['create'] })username: string;@IsString()@IsNotEmpty({ groups: ['create', 'update'] })password: string;
}// 使用时指定组
import { ValidationPipe } from '@nestjs/common';const createUserValidationPipe = new ValidationPipe({ groups: ['create'] });
const updateUserValidationPipe = new ValidationPipe({ groups: ['update'] });在控制器中使用不同的管道进行验证:
import { Controller, Post, Put, Body, UsePipes } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { createUserValidationPipe, updateUserValidationPipe } from './validation-pipes';@Controller('user')
export class UserController {@Post('create')@UsePipes(createUserValidationPipe)async createUser(@Body() createUserDto: CreateUserDto) {// 处理创建用户逻辑return { message: 'User created successfully', data: createUserDto };}@Put('update')@UsePipes(updateUserValidationPipe)async updateUser(@Body() updateUserDto: CreateUserDto) {// 处理更新用户逻辑return { message: 'User updated successfully', data: updateUserDto };}
}
  1. 仅执行部分属性验证
    有时可能需要只验证对象的一部分属性,可以使用 PartialType 来实现。
import { PartialType } from '@nestjs/mapped-types';export class UpdateUserDto extends PartialType(CreateUserDto) {}
以下是如何在控制器中使用 UpdateUserDto。
// src/user/user.controller.ts
import { Controller, Post, Put, Body, Param } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
@Controller('user')
export class UserController {@Post('create')async createUser(@Body() createUserDto: CreateUserDto) {// 处理创建用户逻辑return { message: 'User created successfully', data: createUserDto };}@Put('update/:id')async updateUser(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {// 处理更新用户逻辑return { message: 'User updated successfully', data: updateUserDto };}
}

在这个示例中,UpdateUserDto 继承自 PartialType(CreateUserDto),这意味着 UpdateUserDto 包含 CreateUserDto 中的所有属性,但这些属性都是可选的。这在更新操作中非常有用,因为我们可能只想提供那些需要更新的字段,而不是所有字段。

  1. 验证消息的国际化
    通过使用自定义验证装饰器和消息生成函数,可以实现验证消息的国际化。
import { IsString, IsNotEmpty, Length, ValidationArguments } from 'class-validator';
import { i18n } from 'i18next'; // 假设在项目中使用 i18nexport class CreateUserDto {@IsString()@IsNotEmpty({ message: (args: ValidationArguments) => i18n.t('validation.usernameRequired') })@Length(4, 20, { message: (args: ValidationArguments) => i18n.t('validation.usernameLength', { min: 4, max: 20 }) })username: string;
}

总结

使用 class-validator 结合 NestJS,可以让轻松地在应用中进行数据验证,不仅提高了代码的可读性,还保证了数据的准确性和安全性。通过本文的介绍和技巧,大家应该大致掌握了如何在 NestJS 中使用 class-validator 进行数据验证,大家都在项目中实践起来吧。

相关文章:

NestJS 项目中如何使用 class-validator 进行数据验证

前言 在现代Web开发中,数据验证是必不可少的一环,它不仅能够确保数据的准确性,还能提高系统的安全性。在使用NestJS框架进行项目开发时,class-validator与class-transformer这两个库为我们提供了方便的数据验证解决方案。 本文将…...

【AI抠图整合包及教程】Meta SAM2:引领图像和视频分割技术的新纪元

在人工智能的浪潮中,Meta公司再次以Segment Anything Model 2(SAM 2)引领了图像和视频分割技术的新纪元。SAM 2的发布不仅为计算机视觉领域的研究和发展注入了新的活力,还预示着这一技术将在多个行业中找到广泛的应用场景。这一创…...

小菜家教平台(三):基于SpringBoot+Vue打造一站式学习管理系统

目录 前言 今日进度 详细过程 相关知识点 前言 昨天重构了数据库并实现了登录功能,今天继续进行开发,创作不易,请多多支持~ 今日进度 添加过滤器、实现登出功能、实现用户授权功能校验 详细过程 一、添加过滤器 自定义过滤器作用&…...

ArcGIS/QGIS按掩膜提取或栅格裁剪后栅格数据的值为什么变了?

问题描述: 现有一栅格数据,使用ArcGIS或者QGIS按照矢量边界进行按掩膜提取或者栅格裁剪以后,其值的范围发生了变化,如下: 可以看到,不论是按掩膜提取还是进行栅格裁剪后,其值的范围均与原来栅…...

Linux的基本指令(一)

1.ls指令 功能:对于目录,该命令列出该目录下的所有子目录与文件。对于文件,将列出文件名以及信息。 常用选项: -a列出目录下的所有文件,包括以 . 开头的隐含文件。 -l列出文件的详细信息 举例: rooti…...

python导入包失败 in <module> import pandas as pd

如果安装不成功就更新一下pip python.exe -m pip install --upgrade pip 再删掉原来的pandas pip uninstall pandas 再安装一次 pip install pandas...

不惧风雨,硬核防护!雷孜LaCie小金刚三防移动硬盘颠覆认知

不惧风雨,硬核防护!雷孜LaCie小金刚三防移动硬盘颠覆认知 哈喽小伙伴们好,我是Stark-C~ 说到移动硬盘大家潜意识的认为是一件很娇贵的数码产品,很怕湿,摔不得。所以我们在使用传统移动硬盘的时候不能摔,远…...

Yocto 项目下通过网络更新内核、设备树及模块

Yocto 项目下通过网络更新内核、设备树及模块 前言 在 Yocto 项目的开发过程中,特别是在进行 BSP(Board Support Package)开发时,经常需要调整特定软件包的版本,修改内核、设备树以及内核模块。然而,每次…...

Scheduled Sampling工作原理【小白记笔记】

Scheduled Sampling(计划采样)是一种在序列生成任务中用于逐步引导模型的训练策略。该方法最早由 Bengio 等人在 2015 年提出,主要用于解决序列到序列(sequence-to-sequence)模型中的曝光偏差(exposure bia…...

C++:C++的IO流

目录 一.C标准IO流 1.operator bool 二.C文件IO流 1.文件读取 ifstream (1)ifstream继承istream (2)ifstream 构造函数 (3)ifstream,get读取整个文件 (4)>&g…...

「QT」几何数据类 之 QLine 整型直线类

✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…...

day58 图论章节刷题Part09(dijkstra(堆优化版)、Bellman_ford 算法)

dijkstra(堆优化版) 朴素版的dijkstra解法的时间复杂度为 O(n^2),时间复杂度只和 n(节点数量)有关系。如果n很大的话,可以从边的角度来考虑。因为是稀疏图,从边的角度考虑的话,我们在堆优化算法中最好使用…...

【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】试卷(1)

前言 大家好吖,欢迎来到 YY 滴计算机网络 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的计算机网络题目,供yy应对期中考试复习。大家可以参考 本章是去答案版本。带答案的版本在下…...

智能出行助手:SpringBoot共享汽车管理平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理共享汽车管理系统的相关信息成为必然。开发…...

【月之暗面kimi-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …...

Flink实现实时数据处理

代码如下: #!/usr/bin/python # -*- coding: UTF-8 -*-from pyflink.datastream import StreamExecutionEnvironment from pyflink.table import StreamTableEnvironment, EnvironmentSettings, DataTypes# 初始化执行环境 s_env StreamExecutionEnvironment.get_…...

11.9.2024刷华为

文章目录 HJ31 单词倒排HJ32 密码提取语法知识记录 傻逼OD题目又不全又要收费,看毛线,莫名奇妙 HW这叼机构别搁这儿害人得不得? 我觉得我刷完原来的题目 过一遍华为机考的ED卷出处,就行了 HJ31 单词倒排 游戏本做过了好像 HJ3…...

Chromium 中chrome.system.storage扩展接口定义c++

一、chrome.system.storage 您可以使用 chrome.system.storage API 查询存储设备信息,并在连接和分离可移动存储设备时收到通知。 权限 system.storage 类型 EjectDeviceResultCode 枚举 "success" 移除命令成功执行 - 应用可以提示用户移除设备。…...

【Qt聊天室客户端】登录窗口

1. 验证码 具体实现 登录界面中创建验证码图片空间&#xff0c;并添加到布局管理器中 主要功能概述&#xff08;创建一个verifycodewidget类专门实现验证码操作&#xff09; 详细代码 // 头文件#ifndef VERIFYCODEWIDGET_H #define VERIFYCODEWIDGET_H#include <QWidget>…...

如何显示模型特征权重占比图【数据分析】

可视化模型的特征权重 1、流程 1、导入库: numpy:用于处理数组和矩阵。 matplotlib.pyplot:用于绘图。 sklearn.datasets:用于加载数据集。 sklearn.ensemble.RandomForestClassifier:用于训练随机森林模型。2、加载数据集: 使用load_iris函数加载Iris数据集。3、训练模…...

【Echarts】Y轴标签优化:动态调整与智能截断的实战技巧

1. Y轴标签显示问题的根源分析 当使用Echarts绘制图表时&#xff0c;Y轴标签过长导致显示不全是个常见痛点。这个问题通常发生在两种场景&#xff1a;一是数据来自后端接口&#xff0c;标签长度不可控&#xff1b;二是图表容器宽度有限&#xff0c;无法容纳完整标签。 我遇到过…...

Ubuntu 20.04 无头服务器福音:5分钟搞定虚拟显示器,让NoMachine远程桌面丝滑如本地

Ubuntu 20.04 无头服务器虚拟显示器终极配置指南 当你面对一台没有物理显示器的Ubuntu服务器时&#xff0c;远程桌面连接往往会遇到各种令人抓狂的问题——黑屏、卡顿、分辨率异常。作为长期管理分布式服务器的运维工程师&#xff0c;我深刻理解这种困境对工作效率的影响。本文…...

实战分享:如何用Altium Designer高效搞定PCB的定位孔、散热孔和屏蔽孔?

Altium Designer实战&#xff1a;PCB定位孔、散热孔与屏蔽孔的高效设计指南 在PCB设计领域&#xff0c;机械孔的设计往往被工程师视为"简单任务"而草率处理&#xff0c;直到量产时才发现定位偏差、散热不足或EMI超标等问题。作为从业十年的硬件设计师&#xff0c;我曾…...

Captain AI vs DeepSeek:Ozon 卖家专属 AI,垂直深耕更懂俄语区

做Ozon跨境&#xff0c;选 AI 工具别只看 “全能”&#xff0c;更要看 “专业”和“精通”。DeepSeek 是通用型跨境AI&#xff0c;覆盖多平台、多场景&#xff1b;而Captain AI是Ozon垂直定制 AI&#xff0c;聚焦俄语区与Ozon规则&#xff0c;四大核心功能精准解决卖家从新品到…...

Tree of Thoughts终极指南:5分钟掌握思维树算法原理与实战应用

Tree of Thoughts终极指南&#xff1a;5分钟掌握思维树算法原理与实战应用 【免费下载链接】tree-of-thought-llm [NeurIPS 2023] Tree of Thoughts: Deliberate Problem Solving with Large Language Models 项目地址: https://gitcode.com/gh_mirrors/tr/tree-of-thought-l…...

Dankoe新作《使命与收益》读书笔记 7|你不是迷茫,你只是不敢面对真正的自己

"我不知道自己想要什么。" 这大概是30岁前后最常说的一句话。辞职不敢&#xff0c;创业不会&#xff0c;留下来又不甘心。于是我们把迷茫当成一种身份&#xff0c;穿在身上&#xff0c;仿佛承认迷茫就不必为停滞负责。 但Dan Koe在《使命与收益》里说了一句扎心的话…...

如何用ScanNetv2复现Stratified和SWIN3D论文实验?完整数据集配置指南

如何用ScanNetv2复现Stratified和SWIN3D论文实验&#xff1f;完整数据集配置指南 在3D点云分割领域&#xff0c;ScanNetv2数据集已成为评估算法性能的黄金标准。对于想要复现Stratified Transformer或SWIN3D这类前沿论文的研究者来说&#xff0c;数据集的正确配置往往是第一个…...

深度解析:Element Plus架构设计与实现原理

深度解析&#xff1a;Element Plus架构设计与实现原理 【免费下载链接】element-plus &#x1f389; A Vue.js 3 UI Library made by Element team 项目地址: https://gitcode.com/GitHub_Trending/el/element-plus Element Plus作为Vue.js 3生态中最具影响力的企业级UI…...

Qwen-Image镜像实战:基于RTX4090D,轻松实现图片问答与内容分析

Qwen-Image镜像实战&#xff1a;基于RTX4090D&#xff0c;轻松实现图片问答与内容分析 1. 引言&#xff1a;Qwen-Image镜像的核心价值 在当今多模态AI技术快速发展的背景下&#xff0c;能够同时理解图像和文本的视觉语言模型正变得越来越重要。Qwen-Image作为通义千问系列中的…...

洛雪音乐音源项目:免费高品质音乐资源获取的终极方案

洛雪音乐音源项目&#xff1a;免费高品质音乐资源获取的终极方案 【免费下载链接】lxmusic- lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/gh_mirrors/lx/lxmusic- 1 价值定位&#xff1a;重新定义音乐资源获取体验 洛雪音乐音源项目作为一款开源…...