ThinkJS 數(shù)據(jù)校驗(yàn)

2021-09-17 14:26 更新

數(shù)據(jù)校驗(yàn)

當(dāng)在 Action 里處理用戶的請(qǐng)求時(shí),經(jīng)常要先獲取用戶提交過來的數(shù)據(jù),然后對(duì)其校驗(yàn),如果校驗(yàn)沒問題后才能進(jìn)行后續(xù)的操作。當(dāng)參數(shù)校驗(yàn)完成后,有時(shí)候還要進(jìn)行權(quán)限判斷,等這些都判斷無誤后才能進(jìn)行真正的邏輯處理。如果將這些代碼都放在一個(gè) Action 里,勢(shì)必讓 Action 的代碼非常復(fù)雜且冗長(zhǎng)。

為了解決這個(gè)問題, ThinkJS 在控制器前面增加了一層 Logic,Logic 里的 Action 和控制器里的 Action 一一對(duì)應(yīng),系統(tǒng)在調(diào)用控制器里的 Action 之前會(huì)自動(dòng)調(diào)用 Logic 里的 Action。

Logic 層

Logic 目錄在 src/[module]/logic,在通過命令 thinkjs controller [name] 創(chuàng)建 Controller 時(shí)會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的 Logic。Logic 代碼類似如下:

"use strict";
/**
 * logic
 * @param  {} []
 * @return {}     []
 */
export default class extends think.logic.base {
  /**
   * index action logic
   * @return {} []
   */
  indexAction(){

  }
}

其中,Logic 里的 Action 和 Controller 里的 Action 一一對(duì)應(yīng)。Logic 里也支持 __before 和 __after 等魔術(shù)方法。

數(shù)據(jù)校驗(yàn)配置

數(shù)據(jù)校驗(yàn)的配置如下:

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      doc: "string|default:index",
      version: "string|in:1.2,2.0|default:2.0"
    }
  }
}

配置格式

配置格式為 字段名 -> 配置,每個(gè)字段的配置支持多個(gè)校驗(yàn)類型,校驗(yàn)類型之間用 | 隔開,校驗(yàn)類型和參數(shù)之間用 : 隔開,參數(shù)之間用 , 隔開來支持多個(gè)參數(shù)。

參數(shù)格式

校驗(yàn)類型后面可以接參數(shù),除了支持用逗號(hào)隔開的簡(jiǎn)單參數(shù)外,還可以支持 JSON 格式的復(fù)雜參數(shù)。如:

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      field1: "array|default:[1,2]", //參數(shù)為數(shù)組
      field2: "object|default:{\"name\":\"thinkjs\"}" //參數(shù)為對(duì)象
    }
  }
}

支持的數(shù)據(jù)類型

支持的數(shù)據(jù)類型有:boolean、string、int、floatarray、object,默認(rèn)為 string。

默認(rèn)值

使用 default:value 來定義字段的默認(rèn)值,如果當(dāng)前字段值為空,會(huì)將默認(rèn)值覆蓋過去,后續(xù)獲取到的值為該默認(rèn)值。

獲取數(shù)據(jù)的方式

默認(rèn)根據(jù)當(dāng)前請(qǐng)求的類型來獲取字段對(duì)應(yīng)的值,如果當(dāng)前請(qǐng)求類型是 GET,那么會(huì)通過 this.get('version')來獲取 version 字段的值。如果請(qǐng)求類型是 POST,那么會(huì)通過 this.post 來獲取字段的值。

但有時(shí)候在 POST 類型下,可能會(huì)獲取上傳的文件或者獲取 URL 上的參數(shù),這時(shí)候就需要指定獲取數(shù)據(jù)的方式了。支持的獲取數(shù)據(jù)方式為 getpost 和 file。

export default class extends think.logic.base {
  /**
   * 保存數(shù)據(jù),POST 請(qǐng)求
   * @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 方式來獲取值。

錯(cuò)誤信息

上面的配置只是指定了具體的校驗(yàn)規(guī)則,并沒有指定校驗(yàn)出錯(cuò)后給出的錯(cuò)誤信息。錯(cuò)誤信息支持國(guó)際化,需要在配置文件 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_ + 校驗(yàn)類型名稱,值里面支持 {name} 和 {args} 2個(gè)參數(shù),分別代表字段名稱和傳遞的參數(shù)。

如果想定義個(gè)特定字段某個(gè)錯(cuò)誤類型的具體信息,可以通過在后面加上字段名。如:

// 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 錯(cuò)誤信息
}

數(shù)據(jù)校驗(yàn)方法

配置好校驗(yàn)規(guī)則后,可以通過 this.validate 方法進(jìn)行校驗(yàn)。如:

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 方法獲取詳細(xì)的錯(cuò)誤信息。拿到錯(cuò)誤信息后,可以通過this.fail 方法把錯(cuò)誤信息以 JSON 格式輸出,也可以通過 this.display 方法輸出一個(gè)頁(yè)面。

錯(cuò)誤信息通過 errors 字段賦值到模版里,模版里通過下面的方式顯示錯(cuò)誤信息(以 ejs 模版為例):

<%for(var field in errors){%>
  <%-field%>:<%errors[field]%>
<%}%>

自動(dòng)校驗(yàn)

一般情況下,都是校驗(yàn)有問題后,輸出一個(gè) JSON 信息。如果每次都要在 Logic 的 Action 手動(dòng)調(diào)用this.validate 進(jìn)行校驗(yàn),勢(shì)必比較麻煩。可以通過將校驗(yàn)規(guī)則賦值給 this.rules 屬性進(jìn)行自動(dòng)校驗(yàn)。如:

export default class extends think.logic.base {
  indexAction(){
    this.rules = {
      doc: "string|default:index",
      version: "string|in:1.2,2.0|default:2.0"
    }
  }
}

將校驗(yàn)規(guī)則賦值給 this.rules 屬性后,會(huì)在這個(gè) Action 執(zhí)行完成后自動(dòng)校驗(yàn),如果有錯(cuò)誤則直接輸出 JSON 格式的錯(cuò)誤信息。自動(dòng)校驗(yàn)是通過魔術(shù)方法 __after 來完成的。

支持的校驗(yàn)類型

required

必填項(xiàng)。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "required" //name 的值必填
    }
  }
}

requiredIf

當(dāng)另一個(gè)項(xiàng)的值為某些值其中一項(xiàng)時(shí),該項(xiàng)必填。如:

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredIf:email,admin@example.com,admin1@example.com"
    }
  }
}

當(dāng) email 的值為 admin@example.comadmin1@example.com 等其中一項(xiàng)時(shí), name 的值必填。

requiredNotIf

當(dāng)另一個(gè)項(xiàng)的值不在某些值中時(shí),該項(xiàng)必填。如:

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredNotIf:email,admin@example.com,admin1@example.com"
    }
  }
}

當(dāng) email 的值不為 admin@example.com,admin1@example.com 等其中一項(xiàng)時(shí), name 的值必填。

requiredWith

當(dāng)其他幾項(xiàng)有一項(xiàng)值存在時(shí),該項(xiàng)必填。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredWith:email,title"
    }
  }
}

當(dāng) emailtitle 等項(xiàng)有一項(xiàng)值存在時(shí),name 的值必填。

requiredWithAll

當(dāng)其他幾項(xiàng)值都存在時(shí),該項(xiàng)必填。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredWithAll:email,title"
    }
  }
}

當(dāng) emailtitle 等項(xiàng)值都存在時(shí),name 的值必填。

requiredWithout

當(dāng)其他幾項(xiàng)有一項(xiàng)值不存在時(shí),該項(xiàng)必填。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredWithout:email,title"
    }
  }
}

當(dāng) emailtitle 等項(xiàng)其中有一項(xiàng)值不存在時(shí),name 的值必填。

requiredWithoutAll

當(dāng)其他幾項(xiàng)值都存在時(shí),該項(xiàng)必填。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "requiredWithoutAll:email,title"
    }
  }
}

當(dāng) emailtitle 等項(xiàng)值都不存在時(shí),name 的值必填。

contains

值需要包含某個(gè)特定的值。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "contains:thinkjs" //需要包含字符串 thinkjs。
    }
  }
}

equals

和另一項(xiàng)的值相等。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "equals:firstname" 
    }
  }
}

name 的值需要和 firstname 的值相等。

different

和另一項(xiàng)的值不等。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "different:firstname"
    }
  }
}

name 的值不能和 firstname 的值相等。

before

值需要在一個(gè)日期之后,默認(rèn)為需要在當(dāng)前日期之前。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      start_time: "before", //需要在當(dāng)前日期之前。
      start_time1: "before:2015/10/12 10:10:10" //需要在 2015/10/12 10:10:10 之前。
    }
  }
}

after

值需要在一個(gè)日期之后,默認(rèn)為需要在當(dāng)前日期之后。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      end_time: "after", //需要在當(dāng)前日期之后。
      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

字節(jié)長(zhǎng)度需要在一個(gè)區(qū)間內(nèi)。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "byteLength:10" //字節(jié)長(zhǎng)度不能小于 10
      name1: "byteLength:10,100" //字節(jié)長(zhǎng)度需要在 10 - 100 之間
    }
  }
}

creditcard

需要是信用卡數(shù)字。

currency

需要是貨幣。

date

需要是個(gè)日期。

decimal

需要是個(gè)小數(shù)。

divisibleBy

需要被一個(gè)數(shù)整除。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      count: "divisibleBy:3" //可以被 3 整除
    }
  }
}

email

需要是個(gè) email 格式。

fqdn

需要是個(gè)合格的域名。

float

需要是個(gè)浮點(diǎn)數(shù)。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      money: "float" //需要是個(gè)浮點(diǎn)數(shù)
      money1: "float:3.2" //需要是個(gè)浮點(diǎn)數(shù),且最小值為 3.2
      money2: "float:3.2,10.5" //需要是個(gè)浮點(diǎn)數(shù),且最小值為 3.2,最大值為 10.5
    }
  }
}

fullWidth

包含寬字節(jié)字符。

halfWidth

包含半字節(jié)字符。

hexColor

需要是個(gè)十六進(jìn)制顏色值。

hex

需要是十六進(jìn)制。

ip

需要是 ip 格式。

ip4

需要是 ip4 格式。

ip6

需要是 ip6 格式。

isbn

需要是圖書編碼。

isin

需要是證券識(shí)別編碼。

iso8601

需要是 iso8601 日期格式。

in

在某些值中。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      version: "in:1.2,2.0" //需要是 1.2,2.0 其中一個(gè)
    }
  }
}

noin

不能在某些值中。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      version: "noin:1.2,2.0" //不能是 1.2,2.0 其中一個(gè)
    }
  }
}

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

不能小于某個(gè)值。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      value: "min:10" //不能小于10
    }
  }
}

max

不能大于某個(gè)值。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      value: "max:10" //不能大于10
    }
  }
}

length

長(zhǎng)度需要在某個(gè)范圍。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "length:10" //長(zhǎng)度不能小于10
      name1: "length:10,100" //長(zhǎng)度需要在 10 - 100 之間
    }
  }
}

minLength

長(zhǎng)度不能小于最小長(zhǎng)度。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "minLength:10" //長(zhǎng)度不能小于10
    }
  }
}

maxLength

長(zhǎng)度不能大于最大長(zhǎng)度。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      name: "maxLength:10" //長(zhǎng)度不能大于10
    }
  }
}

lowercase

需要都是小寫字母。

uppercase

需要都是大小字母。

mobile

需要手機(jī)號(hào)。

export default class extends think.logic.base {
  indexAction(){
    let rules = {
      mobile: "mobile:zh-CN" //必須為中國(guó)的手機(jī)號(hào)
    }
  }
}

mongoId

是 MongoDB 的 ObjectID。

multibyte

包含多字節(jié)字符。

url

是個(gè) url。

order

數(shù)據(jù)庫(kù)查詢 order,如:name DESC。

field

數(shù)據(jù)庫(kù)查詢的字段,如:name,title。

image

上傳的文件是否是個(gè)圖片。

startWith

以某些字符打頭。

endWith

以某些字符結(jié)束。

string

值為字符串。

array

值為數(shù)組。

boolean

值為布爾類型。

object

值為對(duì)象。

擴(kuò)展校驗(yàn)類型

如果默認(rèn)支持的校驗(yàn)類型不能滿足需求,可以通過 think.validate 方法對(duì)校驗(yàn)類型進(jìn)行擴(kuò)展。如:

// src/common/bootstrap/validate.js
think.validate("validate_name", (value, ...args) => {
  //需要返回 true 或者 false
  //true 表示校驗(yàn)成功,false 表示校驗(yàn)失敗
})

上面注冊(cè)了一個(gè)名為 validate_name 的校驗(yàn)類型,這樣在 Logic 里就可以直接使用該校驗(yàn)類型了。

參數(shù)解析

如果要解析后面的 args,如:該字段值跟其他字段值進(jìn)行比較,這時(shí)拿到的參數(shù)是其他字段名稱,但比較的時(shí)候肯定需要拿到這個(gè)字段值,所以需要將字段名稱解析為對(duì)應(yīng)的字段值。

可以通過注冊(cè)一個(gè)解析參數(shù)函數(shù)來完成。如:上面的校驗(yàn)類型名稱為 validate_name,那么對(duì)應(yīng)的解析參數(shù)的名稱必須為 _validate_name,即:_ + 校驗(yàn)類型。

think.validate("_validate_name", (args, data) => {
  let arg0 = args[0];
  args[0] = data[arg0].value; //將第一個(gè)參數(shù)字段名稱解析為對(duì)應(yīng)的參數(shù)值
  return args;
})
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)