验证篇章 — 创建基本模板
最后更新于:2022-04-02 08:10:52
>[success] # 开始实战
~~~
1.现在有个需求有一个接口是创建人员的,要求人员的名字不能为空,剩下
的都可以为空,随着业务可能后续还会增加越来越多和人有关的字段,例如
身高,体重,职业,这个接口也会在多个页面重复使用,但如果页面挨个添
加,容易出现遗漏,因此根据这个我们构建了一套管理数据分离
~~~
>[info] ## 从'Model' 模块文件夹开始
~~~
1.model 文件夹下的'BaseModel.js' 文件是所有自定义接口类的
基类,这里基类可以帮我们将字段 和 字段验证方法进行匹配,可以帮我们
进行数据自动赋值,也可以根据我们自己的业务需求进行二次添加
2.model 文件下的'MyPerson.js' 文件是一个本章节的接口验证管理类,需要
根据业务不同,自己维护各自的模块类
~~~
>[danger] ##### BaseModel -- 模块管理基类
~~~
1.说明文件中导入的'KEY_DECO_VALIDATORS' 是一个'Symbol'变量:
KEY_DECO_VALIDATORS = Symbol('validators')
2.'reflect-metadata' 是一个第三方的用来强化'Reflect' 映射的一个库
~~~
~~~
import {KEY_DECO_VALIDATORS} from '../untils/decorators'
import 'reflect-metadata'
export default class BaseModel{
// 查当前类生成的实例,对应的指定字段映射的验证类
decoratorsOf( property, metaKey = KEY_DECO_VALIDATORS) {
const rs = Reflect.getMetadata(metaKey, this, property)
return Array.isArray(rs) ? rs : [rs]
}
async validatorOf(property, args) {
const vArr = this.decoratorsOf(property)
if (vArr) {
// 获取当前验证属性值
const val = this[property]
for (const it of vArr) {
// 调用当前映射的验证装饰所对应的类验证方法
if (it.validate && !(await it.validate(val, args))) {
return new Error(it.errorMessage)
}else{
return new Error('当前验证方法不存在')
}
}
}
}
}
~~~
>[danger] ##### 需要根据需要实现 -- MyPerson类
~~~
1.这个类应该根据你的需要和业务去实现,现在虚拟想出的业务就是有个接
口用来提交个人的信息
2.所有这系列的类都需要继承'BaseModel.js',因为'BaseModel. js' 有这些模
块共同的方法
3.需要对需要验证的字段加上对应验证的装饰器用来修饰
~~~
~~~
import BaseModel from './BaseModel'
import required from '../baseValidator/RequiredValidator'
export default class MyPerson extends BaseModel{
@required(false,'不能为空')
name = ''
}
~~~
>[info] ## 从'baseValidator' 开始验证
~~~
1.'baseValidator' 文件夹跟'model' 文件夹的思路一致的,有一个基类'BaseModel.js'
文件,这个是所有验证的基类,可以根据自己的业务做二次开发
2.'baseValidator' 文件夹也会提供一些常用的基本验证规则的类,这些类都是通过
继承'BaseModel.js' 基类实现,例如常见的'必填','正则'等
3.最后的使用其实调用就是'validatorOf'方法
~~~
>[danger] ##### BaseValidator 验证的基类
~~~
1.验证的基类,用来规定后续验证,可以自定义格式,需要指定对应的报错提示
~~~
~~~
/**
* 验证的基础模板 类似验证的接口
* @param {string} errorMessage - 验证的报错信息
*/
export default class BaseValidator {
constructor(errorMessage = 'Invalid Data') {
this.errorMessage = errorMessage
}
/**
* @return {boolean} 验证规则返回的需要是布尔类型
*
**/
async validate(value, args) {
return false
}
}
~~~
>[danger] ##### 常用的验证类 必填-- Required
~~~
1.必填装饰验证的封装
~~~
~~~
import BaseValidator from './BaseValidator'
import {validatorImpl} from'../untils/decorators'
/**
* 验证是否必填
* @param {string} errorMessage - 验证的报错信息
* @param {boolean} allowEmptyString - 自定义验证规则
*/
class Required extends BaseValidator {
constructor(allowEmptyString=false, errorMessage) {
super(errorMessage)
this.allowEmptyString = allowEmptyString
}
/**
* @return {boolean} 通过正则验证必填
*
**/
async validate(value, args) {
return value !== null && (this.allowEmptyString || !/^\s*$/.test(value))
}
}
export default function required(allowEmptyString,errorMessage) {
return validatorImpl( new Required(allowEmptyString,errorMessage))
}
~~~
>[info] ## untils -- 编写配合工具
~~~
1.做映射关系,和映射全局'key'
~~~
>[danger] ##### 装饰器开始 -- decorators.js
~~~
1.可以发现这个方法是配合,装饰器方法使用,例子:
export default function required(allowEmptyString,errorMessage) {
return validatorImpl( new Required(allowEmptyString,errorMessage))
}
2.整个方法思路就是用一个数组去保存对应属性的映射验证,往往有时候
字段是需要多个验证规则,因此可能需要多个装饰器来修饰,
'Reflect.getMetadata'用来判断当前装饰器是否有对应映射关系,如果没有
就会返回'undefind',在利用'defineMetadata' 添加一个空数组作为映射
的'value',再将对应的验证类添加到这个映射数组中
~~~
~~~
export const KEY_DECO_VALIDATORS = Symbol('validators')
export function validatorImpl (ins) {
return (target, propKey) => {
let vArr = Reflect.getMetadata(KEY_DECO_VALIDATORS, target, propKey)
if (!vArr) {
vArr = []
Reflect.defineMetadata(KEY_DECO_VALIDATORS, vArr, target, propKey)
}
vArr.push(ins)
}
}
~~~
';