Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Package validator 实现了一个支持场景/国际化/自定义错误/自定义验证规则的 map[string]interface{} 元素批量验证器

Notifications You must be signed in to change notification settings

goindow/validator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

90 Commits

Repository files navigation

validator

Package validator 实现了一个支持场景/国际化/自定义错误/自定义验证规则的 map[string]interface{} 元素批量验证器,意在支持各种框架的 model 层实现自动验证,亦可单独使用

索引

说明

  • 该验证器是 逻辑验证器(float64(10)/int32(10)/"10" 均可被 intValidator 验证通过)而不是 强类型验证器
  • 考虑到经过 encoding/json 解析后的数字类型均被解析为 float64,强类型验证器不太可用,故此设计
  • 如果需要强类型验证,可以使用 funcValidator 自定义验证函数,或使用 AddValidator 自定义验证器

特性

  • 支持场景
  • 支持国际化
  • 支持批量验证
  • 支持自定义验证器
  • 支持自定义错误信息

安装

go get github.com/goindow/validator

示例

package main
import (
 "github.com/goindow/validator"
 "fmt"
)
func main() {
 user := map[string]interface{}{
 // "username": "hyb",
 "password": "******",
 "gender": "male",
 "age": 17,
 "weight": "53kg",
 "email": "hyb76788424#163.com",
 }
 rules := validator.Rules{
 "create": {
 { Attr: []string{"username", "password"}, Rule: "required" },
 { Attr: "password", Rule: "regex", Pattern: `[A-Z]{1}\w{5,}`, Message: "密码必须由大写字母开头"},
 { Attr: "gender", Rule: "in", Enum: []string{"0", "1"} },
 { Attr: "age", Rule: "int", Min: 18 },
 { Attr: "weight", Rule: "number", Symbol: 1 },
 { Attr: "email", Rule: "email" },
 },
 "read": {
 { Attr: "id", Rule: "int", Symbol: 1 },
 },
 }
 if e := validator.New().Validate(rules, user, "create"); e != nil {
 // todo: handle errors
 for _, i := range e {
 for k, v := range i {
 fmt.Printf("%v => %v\n", k, v)
 }
 }
 // username => 不能为空
 // password => 密码必须由大写字母开头
 // gender => 只能是 [0、1] 中的一个
 // age => 必须是不小于 18 的整数
 // weight => 必须是数字
 // email => 无效的 email
 }
 // todo: do something
}

如何定义验证规则

  • validator.Rule struct 验证规则
    • Attr interface{} 必选,待验证属性,单个属性 string,多个属性 []string,其他类型或未定义将 panic
    • Rule string 必选,验证规则,即验证器,不存在的验证器或未定义将 panic
    • Message string 可选,自定义错误信息
    • Required bool 可选,可空限制,作用于除 requiredValidator 外的所有验证器,false(默认) - 有值验证/无值跳过,true - 有值验证/无值报错
    • Symbol int64 可选,符号限制,作用于 numberValidator、integerValidator、decimalValidator,0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
    • Max interface{} 可选,最大限制,作用于 stringValidator、numberValidator、integerValidator、decimalValidator
    • Min interface{} 可选,最小限制,同 Max
    • Enum []string 必选(inValidator),枚举限制,作用于 inValidator
    • Func validator.F 必选(funcValidator),自定义验证函数,作用于 funcValidator
    • Pattern string 必选(regexValidator),正则匹配模式,作用于 regexValidator
  • validator.Scence string 场景
  • validator.ScenceRules []validator.Rule 验证规则集 - 单一场景
  • validator.Rules map[Scence]ScenceRules 验证规则集 - 所有场景
rules := validator.Rules{ // validator.Rules
 // validator.ScenceRules
 "create": { // validator.Scence
 { Attr: []string{"username", "password"}, Rule: "required" }, // validator.Rule
 { Attr: "password", Rule: "regex", Pattern: `[A-Z]{1}\w{5,}`, Message: "密码必须由大写字母开头"},
 { Attr: "gender", Rule: "in", Enum: []string{"0", "1"} },
 { Attr: "age", Rule: "int", Min: 18 },
 { Attr: "weight", Rule: "number", Symbol: 1 },
 { Attr: "email", Rule: "email" },
 },
 "read": {
 { Attr: "id", Rule: "int", Symbol: 1 },
 },
}

国际化

  • Lang(lang string) *validator
  • 在 i18n 下,新建错误信息对应的语言文件,格式参考已有文件,包本身自带两种语言(zh_cn、en_us),默认语言为 zh_cn
// touch ./i18n/en_us.go
v := validator.New().Lang("en_us")

自定义错误信息

  • Rule.Message string
rules := validator.Rules{
 "create": {
 { Attr: "password", Rule: "regex", Pattern: `[A-Z]{1}\w{5,}`, Message: "密码必须由大写字母开头"},
 }
}

自定义验证器

  • AddValidator(name string, customValidator F)
package main
import (
 "github.com/goindow/validator"
 "fmt"
)
func main() {
 v := validator.New()
 // 自定义验证器,类型为 validator.F
 var oneValidator validator.F = func(attr string, rule validator.Rule, obj validator.M) validator.E {
 if _, ok := obj[attr]; !ok {
 return validator.E{attr: "not found"}
 }
 if obj[attr] != 1 {
 e := rule.Message
 if e == "" {
 e = "必须等于一"
 }
 return validator.E{attr: e} 
 }
 return nil
 }
 // 挂载
 v.AddValidator("one", oneValidator)
 // 使用
 user := map[string]interface{}{
 "name": "hyb",
 }
 rules := validator.Rules{
 "someone": {
 {Attr: "name", Rule: "one"},
 },
 }
 e := v.Validate(rules, user, "someone")
 fmt.Println(e)
 // [map[name:必须等于一]]
}

内置验证器

funcValidator

  • 使用 Rule.Func 定义的函数来验证本条规则,Rule.Func 的类型是 validator.F
  • Rule.Rule string 必选 func
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Func validator.F 必选 使用 Rule.Func 来验证本条 Rule
rule := {Attr: "password", Rule: "func", Func: func(attr string, rule validator.Rule, obj validator.M) validator.E {
 if obj["password"] != obj["rpassword"] {
 return validator.E{attr: "两次输入不一致"}
 }
 return nil
}}

requiredValidator

  • 必填
  • Rule.Rule string 必选 required
rule := {Attr: []string{"username", "password"}, Rule: "required"}

inValidator

  • 枚举,被验证字段支持类型 int64、int32、int16、int8、int、float64、float32、string、bool
  • Rule.Rule string 必选 in
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Enum []string 必选 被验证字段必须在 Rule.Enum 中
rule := {Attr: "gender", Rule: "in", Enum: {"male", "female", "unknown"}} // 默认,所有规则,有值验证,无值跳过
rule := {Attr: "gender", Rule: "in", Enum: {"male", "female", "unknown"}, Required: true} // 有值验证,无值报 required 错误

stringValidator

  • 字符串
  • Rule.Rule string 必选 string
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Max int 可选 被验证字段长度不能大于 Rule.Max
  • Rule.Min in 可选 被验证字段长度不能小于 Rule.Min
rule := {Attr: "name", Rule: "string"}
rule := {Attr: "name", Rule: "string", Min: 6} // utf8 字符数,即字符串长度,兼容中文
rule := {Attr: "name", Rule: "string", Min: 6, Max: 18}
rule := {Attr: "name", Rule: "string", Min: 6, Max: 18, Required: true}

integerValidator

  • 整数,被验证字段支持类型 int64、int32、int16、int8、int、float64、float32、string
  • Rule.Rule string 必选 integer/int
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
  • Rule.Max int 可选 被验证字段大小不能大于 Rule.Max
  • Rule.Min int 可选 被验证字段大小不能小于 Rule.Min
// int 为 integer 的别名,都指向 integerValidator 验证器
rule := {Attr: "age", Rule: "int"}
rule := {Attr: "age", Rule: "integer", Symobl: 1} // 正整数
rule := {Attr: "age", Rule: "integer", Min: 18}
rule := {Attr: "age", Rule: "integer", Min: 18, Max: 18} // == 18
rule := {Attr: "age", Rule: "integer", Min: 18, Max: 35, Required: true}
// float64(18)、float32(18)、"18" 都会被认为是整数

decimalValidator

  • 小数,被验证字段支持类型 float64、float32、string
  • Rule.Rule string 必选 decimal/float
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
  • Rule.Max int|float64 可选 被验证字段大小不能大于 Rule.Max
  • Rule.Min int|float64 可选 被验证字段大小不能小于 Rule.Min
// float 为 decimal 的别名,都指向 decimalValidator 验证器
rule := {Attr: "field", Rule: "float"}
rule := {Attr: "field", Rule: "decimal", Symobl: -1} // 负小数
rule := {Attr: "field", Rule: "decimal", Min: 2}
rule := {Attr: "field", Rule: "decimal", Min: 3.14, Max: 3.14} // == 3.14
rule := {Attr: "field", Rule: "decimal", Min: 3, Max: 3.14, Required: true}
// float64(18)、float32(18)、"18" 没有小数位会验证失败

numberValidator

  • 数字,被验证字段支持类型 int64、int32、int16、int8、int、float64、float32、string
  • Rule.Rule string 必选 number
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Symbol int64 可选 0(默认) - 正/负数,>0 - 正数(不包含0),<0 - 负数(不包含0)
  • Rule.Max int|float64 可选 被验证字段大小不能大于 Rule.Max
  • Rule.Min int|float64 可选 被验证字段大小不能小于 Rule.Min
rule := {Attr: "weight", Rule: "number"}
rule := {Attr: "weight", Rule: "number", Symobl: 1}
rule := {Attr: "weight", Rule: "number", Min: 45}
rule := {Attr: "weight", Rule: "number", Min: 45, Max: 45} // == 45
rule := {Attr: "weight", Rule: "number", Min: 45, Max: 49.9, Required: true}

booleanValidator

  • 布尔,被验证字段支持类型 bool、string
  • Rule.Rule string 必选 boolean/bool
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
// bool 为 boolean 的别名,都指向 booleanValidator 验证器
rule := {Attr: "admin", Rule: "bool"}
rule := {Attr: "admin", Rule: "boolean"}
// 布尔值[true、false]、字符串表示的布尔值["1"、"0"、"t"、"f"、"true"、"false"(忽略大小写)] 都会被认为是布尔

ipValidator

  • ipv4/ipv6,被验证字段支持类型 string
  • Rule.Rule string 必选 ip
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
rule := {Attr: "ip", Rule: "ip"}

regexValidator

  • 正则,被验证字段支持类型 string
  • Rule.Rule string 必选 regex
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
  • Rule.Pattern string 必选 正则模式字符串
rule := {Attr: "password", Rule: "regex", Pattern: `[A-Z]{1}\w{5,}`},

emailValidator

  • email,被验证字段支持类型 string
  • Rule.Rule string 必选 email
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
rule := {Attr: "email", Rule: "email"}
// pattern = `^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`

telValidator

  • 中国大陆座机号,被验证字段支持类型 string
  • Rule.Rule string 必选 tel
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
rule := {Attr: "tel", Rule: "tel"}
// pattern = `^(0\d{2,3}(\-)?)?\d{7,8}$`

mobileValidator

  • 中国大陆手机号,被验证字段支持类型 string
  • Rule.Rule string 必选 mobile
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
rule := {Attr: "mobile", Rule: "mobile"}
// pattern = `^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][01356789]|[4][579]))\d{8}$`

zipcodeValidator

  • 中国大陆邮编,被验证字段支持类型 string
  • Rule.Rule string 必选 zipcode
  • Rule.Required bool 可选 false(默认) - 被验证字段有值验证/无值跳过,true - 被验证字段无值,验证失败,报 reqired 错误
rule := {Attr: "zipcode", Rule: "zipcode"}
// pattern = `^[1-9]\d{5}$`

自动验证

  • 本例以 beego 框架为例,扩展其 model,实现自动验证,使用常见的 base model/controller 模式,为子类提供统一方法

base/BaseController

package base
import (
 "encoding/json"
 "github.com/astaxie/beego"
)
type JSON struct {
 Code int64 `json:"code"` 
 Data interface{} `json:"data"`
 Errors interface{} `json:"errors"`
}
type BaseController struct {
 beego.Controller
}
func (this *BaseController) LoadJson() (beego.M, error){
 var js beego.M
 return js, json.Unmarshal(this.Ctx.Input.RequestBody, &js)
}
func (this *BaseController) ReturnJson(code int64, data interface{}, e interface{}) {
 this.Data["json"] = &JSON{
 Code: code,
 Data: data,
 Errors: e,
 }
 this.ServeJSON()
}

base/BaseModel

package base
import (
 "reflect"
 "github.com/goindow/validator"
)
// 为了避免每个子 model 文件都要写 import validator,在这里定义几个变量别名,供子 model 直接使用
type E = validator.E
type M = validator.M
type Rule = validator.Rule
type Rules = validator.Rules
type Scence = validator.Scence
type BaseModel struct {}
// 定义验证规则
func (this *BaseModel) Rules() Rules{
 return nil
}
// 自动验证
func (this *BaseModel) Validate(ptrChildModel interface{}, js map[string]interface{}, scence Scence) []E {
 // 获取 ptrChildModel 的 Rules
 if rules := reflect.ValueOf(ptrChildModel).MethodByName("Rules").Call(make([]reflect.Value, 0))[0].Interface().(Rules); len(rules) != 0 {
 return validator.New().Validate(rules, js, scence) 
 }
 return nil
}

models/User

package models
import (
 "explore/base"
)
type User struct {
 base.BaseModel
 Id int64
 Username string
 Password string
}
func (this *User) Rules() base.Rules {
 return base.Rules{
 "signup": {
 {Attr: []string{"username", "password", "rpassword"}, Rule: "required"},
 {Attr: "username", Rule: "string"},
 {Attr: "password", Rule: "regex", Pattern: `[a-zA-Z].\d{5,}`},
 {Attr: "rpassword", Rule: "func", Func: func(attr string, rule base.Rule, obj base.M) base.E {
 if obj["password"] != obj["rpassword"] {
 return base.E{attr: "两次输入不一致"}
 }
 return nil
 }},
 },
 "signin": {
 {Attr: []string{"username", "password"}, Rule: "required"},
 {Attr: "password", Rule: "func", Func: func(attr string, rule base.Rule, obj base.M) base.E {
 if obj["username"] != "admin" || obj["password"] != "admin" {
 return base.E{attr: "用户名或密码错误"}
 }
 return nil
 }},
 },
 }
}

controllers/UserController

package controllers
import (
 "explore/base"
 "explore/models"
)
type UserController struct {
 base.BaseController
}
// @router /signup [post]
func (this *UserController) Signup() {
 if js, err := this.LoadJson(); err != nil {
 this.ReturnJson(4000, nil, "Json 解析失败")
 } else {
 var user models.User
 if e := user.Validate(&user, js, "signup"); len(e) != 0 {
 this.ReturnJson(3000, nil, e)
 } else {
 // todo:
 this.ReturnJson(2000, nil, "注册成功")
 }
 }
}
// @router /signin [post]
func (this *UserController) Signin() {
 if js, err := this.LoadJson(); err != nil {
 this.ReturnJson(4000, nil, "Json 解析失败")
 } else {
 var user models.User
 if e := user.Validate(&user, js, "signin"); len(e) != 0 {
 this.ReturnJson(3001, nil, e)
 } else {
 // todo:
 this.ReturnJson(2000, nil, "登陆成功")
 }
 }
}

About

Package validator 实现了一个支持场景/国际化/自定义错误/自定义验证规则的 map[string]interface{} 元素批量验证器

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /