前言
本项目使用的数据验证工具并非midwayjs官方提供的,而是使用class-validator。我也是刚接触这个工具不久,所以这篇文章算是我对这个工具整理的一些用法和心得。
class-validator官方文档提供了很多验证器,并且在文档底部将所有的验证器都列举出来了。如果觉得看官方文档入门比较困难的话,可以先看这篇帖子。简单学会如何使用后,可以根据需要在文档底部的验证器表格中找到自己想要的验证器,如果不满足需求,可以自己定制验证器
自定义验证器
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
//对比所在对象的指定属性的长度
export function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isLongerThan',//验证器名称
target: object.constructor,//目标
propertyName: propertyName,//属性名
constraints: [property],//约束条件
options: validationOptions,//验证器执行参数
validator: {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
return typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length; // you can return a Promise<boolean> here as well, if you want to make async validation
},
},
});
};
}
class MyClass {
//将会拿name值和label值的长度进行比较
@IsLongerThan('label', { message: '$property长度小于$constraint1' })
name: string;
label: string;
}
const model = new MyClass();
model.name = 'hello world';
model.label = 'hello';
return validator.validate(model, { forbidUnknownValues: true }).then(errors => {
console.log('errors', errors);
});
验证分组
在定义DTO的时候,创建时不需要进行唯一标识的必填验证,但修改是需要判断的,其他的参数验证跟创建DTO一样。当然你也可以为不同场景创建多个DTO,但这样会增加维护成本,比如新增某些字段,你就得对去修改多个DTO代码文件。
那么有没有一种办法可以只维护一个DTO,然后根据不同场景决定使用哪些验证器。办法当然是有的。
class UserDTO {
@IsNotEmpty({groups:['put']})
id: string;
@IsNotEmpty({groups:['post','put']})
username: string;
@IsNotEmpty({groups:['post','put']})
password:string;
}
const user = new UserDTO();
user.username='123456';
user.password='123456';
//只对分组post进行验证,也就是不会使用id属性必填验证器
return validator.validate(model, {groups:['post']}).then(errors => {
console.log('errors', errors);
});
验证器执行参数整理
- groups 对验证器进行分组
- forbidUnknownValues 翻译为禁止未知值,这个设置值比较令人迷惑,经过测试得出一个结论:执行验证时,如果forbidUnknownValues 设置为true并且目标对象找不到任何验证器,验证将无法通过,并提示:”unknownValue”:”an unknown value was passed to the validate function”
- strictGroups 设置为true,将按照严格按照分组来使用验证器。
- always 设置为true 验证器将不受分组的限制,始终会执行
- 关于验证器执行参数还有其他设置,请自行探索,以上列举的是我目前常用的几个参数 ```typescript //============ forbidUnknownValues:true start ================= class UserDTO { username: string; password:string; }
const user = new UserDTO(); user.username=’123456’; user.password=’123456’; return validator.validate(user).then(errors => { console.log(‘errors’, errors); //“unknownValue”:”an unknown value was passed to the validate function” });
return validator.validate({name:”123”}).then(errors => { console.log(‘errors’, errors); //“unknownValue”:”an unknown value was passed to the validate function” });
class UserDTO { @IsNotEmpty({groups:[‘put’]}) id: string; @IsNotEmpty({groups:[‘post’,’put’]}) username: string; @IsNotEmpty({groups:[‘post’,’put’]}) password:string; } const user = new UserDTO(); user.username=’123456’; user.password=’123456’; //指定不存在的分组验证器,由于无任何验证器可以使用,所以也无法通过unknownValue验证器 return validator.validate(user, {groups:[‘delete’]}).then(errors => { console.log(‘errors’, errors); //“unknownValue”:”an unknown value was passed to the validate function” }); //============ forbidUnknownValues:true end =================
//================== strictGroups:true start ================== class UserDTO { @IsNotEmpty({groups:[‘put’]}) id: string; @IsNotEmpty() username: string; @IsNotEmpty() password:string; } const user = new UserDTO(); user.username=’123456’; user.password=’123456’; //打算只验证username和password return validator.validate(user).then(errors => { console.log(‘errors’, errors); //不符合预期:id验证器验证不通过 }); return validator.validate(user,{strictGroups:true}).then(errors => { console.log(‘errors’, errors); //符合预期:验证通过,只验证username和password }); //================== strictGroups:true end==================
//==================== always:true start ==================== class UserDTO { @IsNotEmpty({groups:[‘put’]}) id: string; @IsNotEmpty() username: string; @IsNotEmpty() password:string; } const user = new UserDTO(); user.id=’001’; //除了验证id以外,还要验证username和password return validator.validate(user,{groups:[‘put’]}).then(errors => { console.log(‘errors’, errors); //验证通过,不符合预期:除了验证id以外,还要验证username和password });
//除了验证id以外,还要验证username和password return validator.validate(user,{groups:[‘put’],always:true}).then(errors => { console.log(‘errors’, errors); //验证不通过,符合预期:验证id、username和password });
通过以上的几个例子,我们执行参数将会使用以下设置
```typescript
//验证对象至少拥有一个验证器、按照严格的分组模式使用验证器(即分组传空,只执行没有分组的),如果使用分组验证器,希望同时验证没有分组的验证器
return validator.validate(user,{groups:['put'],always:true,strictGroups:true,forbidUnknownValues:true}).then(errors => {
console.log('errors', errors);
});