验证数组
package main
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
"log"
"micro/AppLib"
)
type Users struct {
Username string `validate:"required,min=6,max=20" vmsg:"用户名必须6位以上"`
Userpwd string `validate:"required,min=6,max=18" vmsg:"用户密码必须6位以上"`
Testname string `validate:"username" vmsg:"用户名规则不正确"` //这里的username对应v.RegisterValidation(tagName中的tagName,随便写写abc都可以但是要和它对应起来
Usertags []string `validate:"required,min=1,max=5,unique"` //切片中min和max表示切片最大长度和最小长度,unique表示切片数据集不可以重复
}
func main() {
userTags := []string{"a", "b", "a", "d", "e"}
user := &Users{Username: "shenyi", Userpwd: "123123", Testname: "wqeqdasd", Usertags: userTags}
valid := validator.New()
//加入自定义的正则验证tag
err := AppLib.AddRegexTag("username", "[a-zA-Z]\\w{5,19}", valid)
if err != nil {
log.Fatal(err)
}
err = AppLib.ValidErrMsg(user, valid.Struct(user))
if err != nil {
log.Fatal(err)
}
fmt.Println("验证成功")
}
更改需求之后我们上面的代码就不满足条件了,所以需要使用到正则,这里有一个坑,先改一下原来的自定义错误处理函数
package AppLib
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
"reflect"
"regexp"
)
//封装一个通用的正则方法,省去每次都要写下面这段很长的代码
func AddRegexTag(tagName string, pattern string, v *validator.Validate) error {
return v.RegisterValidation(tagName, func(fl validator.FieldLevel) bool {
m, _ := regexp.MatchString(pattern, fl.Field().String()) //返回bool和错误类型
return m
}, false) //为true则值为null也做判断,为false则不判断
}
func ValidErrMsg(obj interface{}, err error) error {
getObj := reflect.TypeOf(obj) //获取tag要用TypeOf
if err != nil {
if errs, ok := err.(validator.ValidationErrors); ok {
for _, e := range errs {
if f, exist := getObj.Elem().FieldByName(e.Field()); exist {
if value, ok := f.Tag.Lookup("vmsg"); ok { //查找tag中有没有我们自定义的错误消息,有就用自定义的没有就用默认的
return fmt.Errorf("%s", value)
} else {
return fmt.Errorf("%s", e)
}
} else {
return fmt.Errorf("%s", e) //因为当切片中某个字段验证错误了,这时候e.Field()是Usertags[i],而针对Users这个结构体的字段没有Usertags[i]这个字段,所以上面的exist会是false,这时候如果我们不处理,返回值就是nil,验证就通过了,所以我们需要另外一个else额外处理一下
}
}
}
}
return nil
}
调用代码
package main
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
"log"
"micro/AppLib"
)
type Users struct {
Username string `validate:"required,min=6,max=20" vmsg:"用户名必须6位以上"`
Userpwd string `validate:"required,min=6,max=18" vmsg:"用户密码必须6位以上"`
Testname string `validate:"username" vmsg:"用户名规则不正确"` //这里的username对应v.RegisterValidation(tagName中的tagName,随便写写abc都可以但是要和它对应起来
//下面的tag中有一个特别的dive标签,作用是进到切片内部对元素进行校验,写在dive之前是对切片的校验,dive之后是对元素的校验
Usertags []string `validate:"required,min=1,max=5,unique,dive,usertag" vmsg:"用户标签不合法"` //切片中min和max表示切片最大长度和最小长度,unique表示切片数据集不可以重复,usertag是绑定到自定义的正则验证用的
}
func main() {
userTags := []string{"aa", "#b", "c", "d", "e"}
user := &Users{Username: "shenyi", Userpwd: "123123", Testname: "wqeqdasd", Usertags: userTags}
valid := validator.New()
//加入自定义的正则验证tag
err := AppLib.AddRegexTag("username", "[a-zA-Z]\\w{5,19}", valid)
if err != nil {
log.Fatal(err)
}
err = AppLib.AddRegexTag("usertag", "^[a-zA-Z0-9]{1,}", valid)
if err != nil {
log.Fatal(err)
}
err = AppLib.ValidErrMsg(user, valid.Struct(user)) //这里才是真正调用验证,包括我们设置的正则验证
if err != nil {
log.Fatal(err)
}
fmt.Println("验证成功")
}