ThinkJS 数据校验
数据校验
- Logic 层
- 数据校验配置
- 配置格式
- 参数格式
- 支持的数据类型
- 默认值
- 获取数据的方式
- 错误信息
- 数据校验方法
- 支持的校验类型
- required
- requiredIf
- requiredNotIf
- requiredWith
- requiredWithAll
- requiredWithout
- requiredWithoutAll
- contains
- equals
- different
- before
- after
- alpha
- alphaDash
- alphaNumeric
- alphaNumericDash
- ascii
- base64
- byteLength
- creditcard
- currency
- date
- decimal
- divisibleBy
- fqdn
- float
- fullWidth
- halfWidth
- hexColor
- hex
- ip
- ip4
- ip6
- isbn
- iso8601
- in
- noin
- int
- min
- max
- length
- minLength
- maxLength
- lowercase
- uppercase
- mobile
- mongoId
- multibyte
- url
- order
- field
- image
- startWith
- endWith
- string
- array
- boolean
- object
- 扩展校验类型
当在 Action 里处理用户的请求时,经常要先获取用户提交过来的数据,然后对其校验,如果校验没问题后才能进行后续的操作。当参数校验完成后,有时候还要进行权限判断,等这些都判断无误后才能进行真正的逻辑处理。如果将这些代码都放在一个 Action 里,势必让 Action 的代码非常复杂且冗长。
为了解决这个问题, ThinkJS 在控制器前面增加了一层 Logic
,Logic 里的 Action 和控制器里的 Action 一一对应,系统在调用控制器里的 Action 之前会自动调用 Logic 里的 Action。
Logic 层
Logic 目录在 src/[module]/logic
,在通过命令 thinkjs controller [name]
创建 Controller 时会自动创建对应的 Logic。Logic 代码类似如下:
"use strict";
/**
* logic
* @param {} []
* @return {} []
*/
export default class extends think.logic.base {
/**
* index action logic
* @return {} []
*/
indexAction(){
}
}
其中,Logic 里的 Action 和 Controller 里的 Action 一一对应。Logic 里也支持 __before
和 __after
等魔术方法。
数据校验配置
数据校验的配置如下:
export default class extends think.logic.base {
indexAction(){
let rules = {
doc: "string|default:index",
version: "string|in:1.2,2.0|default:2.0"
}
}
}
配置格式
配置格式为 字段名
-> 配置
,每个字段的配置支持多个校验类型,校验类型之间用 |
隔开,校验类型和参数之间用 :
隔开,参数之间用 ,
隔开来支持多个参数。
参数格式
校验类型后面可以接参数,除了支持用逗号隔开的简单参数外,还可以支持 JSON 格式的复杂参数。如:
export default class extends think.logic.base {
indexAction(){
let rules = {
field1: "array|default:[1,2]", //参数为数组
field2: "object|default:{\"name\":\"thinkjs\"}" //参数为对象
}
}
}
支持的数据类型
支持的数据类型有:boolean
、string
、int
、float
、array
、object
,默认为 string
。
默认值
使用 default:value
来定义字段的默认值,如果当前字段值为空,会将默认值覆盖过去,后续获取到的值为该默认值。
获取数据的方式
默认根据当前请求的类型来获取字段对应的值,如果当前请求类型是 GET,那么会通过 this.get('version')
来获取 version
字段的值。如果请求类型是 POST,那么会通过 this.post
来获取字段的值。
但有时候在 POST 类型下,可能会获取上传的文件或者获取 URL 上的参数,这时候就需要指定获取数据的方式了。支持的获取数据方式为 get
,post
和 file
。
export default class extends think.logic.base {
/**
* 保存数据,POST 请求
* @return {} []
*/
saveAction(){
let rules = {
name: "required",
image: "object|file|required",
version: "string|get|in:1.2,2.0|default:2.0"
}
}
}
上面示例指定了字段 name
通过 post
方法来获取值,字段 image
通过 file
方式来获取值,字段 version
通过 get
方式来获取值。
错误信息
上面的配置只是指定了具体的校验规则,并没有指定校验出错后给出的错误信息。错误信息支持国际化,需要在配置文件 src/common/config/locale/[lang].js
中定义。如:
// src/common/config/locale/en.js
export default {
validate_required: "{name} can not be blank",
validate_contains: "{name} need contains {args}",
}
其中 key 为 validate_
+ 校验类型名称
,值里面支持 {name}
和 {args}
2个参数,分别代表字段名称和传递的参数。
如果想定义个特定字段某个错误类型的具体信息,可以通过在后面加上字段名。如:
// src/common/config/locale/en.js
export default {
validate_required: "{name} can not be blank",
validate_required_email: "email can not be blank", //指定字段 email 的 required 错误信息
}
数据校验方法
配置好校验规则后,可以通过 this.validate
方法进行校验。如:
export default class extends think.logic.base {
indexAction(){
let rules = {
doc: "string|default:index",
version: "string|in:1.2,2.0|default:2.0"
}
let flag = this.validate(rules);
if(!flag){
return this.fail("validate error", this.errors());
}
}
}
如果返回值为 false
,那么可以通过 this.errors
方法获取详细的错误信息。拿到错误信息后,可以通过this.fail
方法把错误信息以 JSON 格式输出,也可以通过 this.display
方法输出一个页面。
错误信息通过 errors
字段赋值到模版里,模版里通过下面的方式显示错误信息(以 ejs 模版为例):
<%for(var field in errors){%>
<%-field%>:<%errors[field]%>
<%}%>
自动校验
一般情况下,都是校验有问题后,输出一个 JSON 信息。如果每次都要在 Logic 的 Action 手动调用this.validate
进行校验,势必比较麻烦。可以通过将校验规则赋值给 this.rules
属性进行自动校验。如:
export default class extends think.logic.base {
indexAction(){
this.rules = {
doc: "string|default:index",
version: "string|in:1.2,2.0|default:2.0"
}
}
}
将校验规则赋值给 this.rules
属性后,会在这个 Action 执行完成后自动校验,如果有错误则直接输出 JSON 格式的错误信息。自动校验是通过魔术方法 __after
来完成的。
支持的校验类型
required
必填项。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "required" //name 的值必填
}
}
}
requiredIf
当另一个项的值为某些值其中一项时,该项必填。如:
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredIf:email,admin@example.com,admin1@example.com"
}
}
}
当 email
的值为 admin@example.com
,admin1@example.com
等其中一项时, name
的值必填。
requiredNotIf
当另一个项的值不在某些值中时,该项必填。如:
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredNotIf:email,admin@example.com,admin1@example.com"
}
}
}
当 email
的值不为 admin@example.com
,admin1@example.com
等其中一项时, name
的值必填。
requiredWith
当其他几项有一项值存在时,该项必填。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredWith:email,title"
}
}
}
当 email
, title
等项有一项值存在时,name
的值必填。
requiredWithAll
当其他几项值都存在时,该项必填。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredWithAll:email,title"
}
}
}
当 email
, title
等项值都存在时,name
的值必填。
requiredWithout
当其他几项有一项值不存在时,该项必填。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredWithout:email,title"
}
}
}
当 email
, title
等项其中有一项值不存在时,name
的值必填。
requiredWithoutAll
当其他几项值都存在时,该项必填。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "requiredWithoutAll:email,title"
}
}
}
当 email
, title
等项值都不存在时,name
的值必填。
contains
值需要包含某个特定的值。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "contains:thinkjs" //需要包含字符串 thinkjs。
}
}
}
equals
和另一项的值相等。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "equals:firstname"
}
}
}
name
的值需要和 firstname
的值相等。
different
和另一项的值不等。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "different:firstname"
}
}
}
name
的值不能和 firstname
的值相等。
before
值需要在一个日期之后,默认为需要在当前日期之前。
export default class extends think.logic.base {
indexAction(){
let rules = {
start_time: "before", //需要在当前日期之前。
start_time1: "before:2015/10/12 10:10:10" //需要在 2015/10/12 10:10:10 之前。
}
}
}
after
值需要在一个日期之后,默认为需要在当前日期之后。
export default class extends think.logic.base {
indexAction(){
let rules = {
end_time: "after", //需要在当前日期之后。
end_time1: "after:2015/10/10" //需要在 2015/10/10 之后。
}
}
}
alpha
值只能是 [a-zA-Z] 组成。
export default class extends think.logic.base {
indexAction(){
let rules = {
en_name: "alpha"
}
}
}
en_name
的值只能是 [a-zA-Z] 组成。
alphaDash
值只能是 [a-zA-Z_] 组成。
alphaNumeric
值只能是 [a-zA-Z0-9] 组成。
alphaNumericDash
值只能是 [a-zA-Z0-9_] 组成。
ascii
值只能是 ascii 字符组成。
base64
值必须是 base64 编码。
byteLength
字节长度需要在一个区间内。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "byteLength:10" //字节长度不能小于 10
name1: "byteLength:10,100" //字节长度需要在 10 - 100 之间
}
}
}
creditcard
需要是信用卡数字。
currency
需要是货币。
date
需要是个日期。
decimal
需要是个小数。
divisibleBy
需要被一个数整除。
export default class extends think.logic.base {
indexAction(){
let rules = {
count: "divisibleBy:3" //可以被 3 整除
}
}
}
需要是个 email 格式。
fqdn
需要是个合格的域名。
float
需要是个浮点数。
export default class extends think.logic.base {
indexAction(){
let rules = {
money: "float" //需要是个浮点数
money1: "float:3.2" //需要是个浮点数,且最小值为 3.2
money2: "float:3.2,10.5" //需要是个浮点数,且最小值为 3.2,最大值为 10.5
}
}
}
fullWidth
包含宽字节字符。
halfWidth
包含半字节字符。
hexColor
需要是个十六进制颜色值。
hex
需要是十六进制。
ip
需要是 ip 格式。
ip4
需要是 ip4 格式。
ip6
需要是 ip6 格式。
isbn
需要是图书编码。
isin
需要是证券识别编码。
iso8601
需要是 iso8601 日期格式。
in
在某些值中。
export default class extends think.logic.base {
indexAction(){
let rules = {
version: "in:1.2,2.0" //需要是 1.2,2.0 其中一个
}
}
}
noin
不能在某些值中。
export default class extends think.logic.base {
indexAction(){
let rules = {
version: "noin:1.2,2.0" //不能是 1.2,2.0 其中一个
}
}
}
int
需要是 int 型。
export default class extends think.logic.base {
indexAction(){
let rules = {
value: "int" //需要是 int 型
value1: "int:1" //不能小于1
value2: "int:10,100" //需要在 10 - 100 之间
}
}
}
min
不能小于某个值。
export default class extends think.logic.base {
indexAction(){
let rules = {
value: "min:10" //不能小于10
}
}
}
max
不能大于某个值。
export default class extends think.logic.base {
indexAction(){
let rules = {
value: "max:10" //不能大于10
}
}
}
length
长度需要在某个范围。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "length:10" //长度不能小于10
name1: "length:10,100" //长度需要在 10 - 100 之间
}
}
}
minLength
长度不能小于最小长度。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "minLength:10" //长度不能小于10
}
}
}
maxLength
长度不能大于最大长度。
export default class extends think.logic.base {
indexAction(){
let rules = {
name: "maxLength:10" //长度不能大于10
}
}
}
lowercase
需要都是小写字母。
uppercase
需要都是大小字母。
mobile
需要手机号。
export default class extends think.logic.base {
indexAction(){
let rules = {
mobile: "mobile:zh-CN" //必须为中国的手机号
}
}
}
mongoId
是 MongoDB 的 ObjectID。
multibyte
包含多字节字符。
url
是个 url。
order
数据库查询 order,如:name DESC。
field
数据库查询的字段,如:name,title。
image
上传的文件是否是个图片。
startWith
以某些字符打头。
endWith
以某些字符结束。
string
值为字符串。
array
值为数组。
boolean
值为布尔类型。
object
值为对象。
扩展校验类型
如果默认支持的校验类型不能满足需求,可以通过 think.validate
方法对校验类型进行扩展。如:
// src/common/bootstrap/validate.js
think.validate("validate_name", (value, ...args) => {
//需要返回 true 或者 false
//true 表示校验成功,false 表示校验失败
})
上面注册了一个名为 validate_name
的校验类型,这样在 Logic 里就可以直接使用该校验类型了。
参数解析
如果要解析后面的 args
,如:该字段值跟其他字段值进行比较,这时拿到的参数是其他字段名称,但比较的时候肯定需要拿到这个字段值,所以需要将字段名称解析为对应的字段值。
可以通过注册一个解析参数函数来完成。如:上面的校验类型名称为 validate_name
,那么对应的解析参数的名称必须为 _validate_name
,即:_
+ 校验类型
。
think.validate("_validate_name", (args, data) => {
let arg0 = args[0];
args[0] = data[arg0].value; //将第一个参数字段名称解析为对应的参数值
return args;
})
更多建议: