背景

在平常开发中,特别是在web应用开发中,为了验证输入字段的合法性,都会做一些验证操作。比如对用户提交的表单字段进行验证,或者对请求的API接口字段进行验证,验证字段的合法性,保证输入字段值的安全,防止用户的恶意请求。

一般的做法是用正则表达式,一个字段一个字段的进行验证。一个一个字段验证的话,写起来比较繁琐。那有没更好的方法,进行字段的合法性验证?有, 这就是下面要介绍的 validator 这个验证组件。

代码地址:

https://github.com/go-playground/validator

文档地址:

https://github.com/go-playground/validator/blob/master/README.md

安装

go get:

go get github.com/go-playground/validator/v10

在文件中引用validator包:

import "github.com/go-playground/validator/v10"

validator使用

文档:https://github.com/go-playground/validator/blob/master/README.md#examples

例子1:验证单个字段变量值

validation1.go

package main

import (
"fmt" "github.com/go-playground/validator/v10"
) func main() {
validate := validator.New() var boolTest bool
err := validate.Var(boolTest, "required")
if err != nil {
fmt.Println(err)
}
var stringTest string = ""
err = validate.Var(stringTest, "required")
if err != nil {
fmt.Println(err)
} var emailTest string = "test@126.com"
err = validate.Var(emailTest, "email")
if err != nil {
fmt.Println(err)
} else {
fmt.Println("success") // 输出: success。 说明验证成功
} emailTest2 := "test.126.com"
errs := validate.Var(emailTest2, "required,email")
if errs != nil {
fmt.Println(errs) // 输出: Key: "" Error:Field validation for "" failed on the "email" tag。验证失败
} fmt.Println("\r\nEnd!!") }

运行输出:

go run simple1.go

Key: '' Error:Field validation for '' failed on the 'required' tag

Key: '' Error:Field validation for '' failed on the 'required' tag

success

Key: '' Error:Field validation for '' failed on the 'email' tag

End!!

例子2:验证结构体struct

from:struct validate

validation_struct.go,这个程序还列出了效验出错字段的一些信息,

package main

import (
"fmt" "github.com/go-playground/validator/v10"
) type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
Addresses []*Address `validate:"required,dive,required"`
} type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
} func main() {
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
} user := &User{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Email: "Badger.Smith@gmail.com",
Addresses: []*Address{address},
} validate := validator.New()
err := validate.Struct(user)
if err != nil {
fmt.Println("=== error msg ====")
fmt.Println(err) if _, ok := err.(*validator.InvalidValidationError); ok {
fmt.Println(err)
return
} fmt.Println("\r\n=========== error field info ====================")
for _, err := range err.(validator.ValidationErrors) {
// 列出效验出错字段的信息
fmt.Println("Namespace: ", err.Namespace())
fmt.Println("Fild: ", err.Field())
fmt.Println("StructNamespace: ", err.StructNamespace())
fmt.Println("StructField: ", err.StructField())
fmt.Println("Tag: ", err.Tag())
fmt.Println("ActualTag: ", err.ActualTag())
fmt.Println("Kind: ", err.Kind())
fmt.Println("Type: ", err.Type())
fmt.Println("Value: ", err.Value())
fmt.Println("Param: ", err.Param())
fmt.Println()
} // from here you can create your own error messages in whatever language you wish
return
}
}

运行 输出:

$ go run validation_struct.go

=== error msg ====

Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag

Key: 'User.Addresses[0].City' Error:Field validation for 'City' failed on the 'required' tag

=========== error field info ====================

Namespace: User.Age

Fild: Age

StructNamespace: User.Age

StructField: Age

Tag: lte

ActualTag: lte

Kind: uint8

Type: uint8

Value: 135

Param: 130

Namespace: User.Addresses[0].City

Fild: City

StructNamespace: User.Addresses[0].City

StructField: City

Tag: required

ActualTag: required

Kind: string

Type: string

Value:

Param:

还可以给字段加一些其他tag信息,方面form,json的解析,如下:

type User struct {
FirstName string `form:"firstname" json:"firstname" validate:"required"`
LastName string `form:"lastname" json:"lastname" validate:"required"`
Age uint8 ` form:"age" json:"age"validate:"gte=0,lte=130"`
Email string ` form:"email" json:"email" validate:"required,email"`
}

用户自定义函数验证

用户自定义函数验证字段是否合法,效验是否正确。

例子3: 通过字段tag自定义函数

validate.RegisterValidation

customer_tag.go:

package main

import (
"fmt" "github.com/go-playground/validator/v10"
) type User struct {
Name string `form:"name" json:"name" validate:"required,CustomerValidation"` //注意:required和CustomerValidation之间不能有空格,否则panic。CustomerValidation:自定义tag-函数标签
Age uint8 ` form:"age" json:"age" validate:"gte=0,lte=80"` //注意:gte=0和lte=80之间不能有空格,否则panic
} var validate *validator.Validate func main() {
validate = validator.New()
validate.RegisterValidation("CustomerValidation", CustomerValidationFunc) //注册自定义函数,前一个参数是struct里tag自定义,后一个参数是自定义的函数 user := &User{
Name: "jimmy",
Age: 86,
} fmt.Println("first value: ", user)
err := validate.Struct(user)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
} user.Name = "tom"
user.Age = 29
fmt.Println("second value: ", user)
err = validate.Struct(user)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
} // 自定义函数
func CustomerValidationFunc(f1 validator.FieldLevel) bool {
// f1 包含了字段相关信息
// f1.Field() 获取当前字段信息
// f1.Param() 获取tag对应的参数
// f1.FieldName() 获取字段名称 return f1.Field().String() == "jimmy"
}

运行输出:

$ go run customer.go

first value: &{jimmy 86}

Err(s):

Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag

second value: &{tom 29}

Err(s):

Key: 'User.Name' Error:Field validation for 'Name' failed on the 'CustomerValidation' tag

**注意

上面代码user struct定义中 ,validate里的required和CustomerValidation之间不能有空格,否则运行时报panic错误:panic: Undefined validation function ' CustomerValidation' on field 'Name'

例子4:自定义函数-直接注册函数1

不通过字段tag自定义函数,直接注册函数。

RegisterStructValidation

https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go

customer1.go

package main

import (
"fmt" "github.com/go-playground/validator/v10"
) type User struct {
FirstName string `json:firstname`
LastName string `json:lastname`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"`
} var validate *validator.Validate func main() {
validate = validator.New() validate.RegisterStructValidation(UserStructLevelValidation, User{}) user := &User{
FirstName: "",
LastName: "",
Age: 30,
Email: "TestFunc@126.com",
FavouriteColor: "#000",
} err := validate.Struct(user)
if err != nil {
fmt.Println(err)
}
} func UserStructLevelValidation(sl validator.StructLevel) {
user := sl.Current().Interface().(User) if len(user.FirstName) == 0 && len(user.LastName) == 0 {
sl.ReportError(user.FirstName, "FirstName", "firstname", "firstname", "")
sl.ReportError(user.LastName, "LastName", "lastname", "lastname", "")
}
}

运行输出:

$ go run customer1.go

Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'firstname' tag

Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'lastname' tag

例子5:自定义函数-直接注册函数2

RegisterCustomTypeFunc

https://github.com/go-playground/validator/blob/master/_examples/custom/main.go

validate.RegisterCustomTypeFunc:验证类型的自定义函数

customer2.go:

package main

import (
"database/sql"
"database/sql/driver"
"fmt"
"reflect" "github.com/go-playground/validator/v10"
) type DbBackedUser struct {
Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"`
} var validate *validator.Validate func main() {
validate = validator.New() validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{}) // build object for validation
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}} err := validate.Struct(x)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
} func ValidateValuer(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value()
if err == nil {
return val
}
// handle the error how you want
}
return nil
}

运行输出:

$ go run customer.go

Err(s):

Key: 'DbBackedUser.Name' Error:Field validation for 'Name' failed on the 'required' tag

Key: 'DbBackedUser.Age' Error:Field validation for 'Age' failed on the 'required' tag

注意,这个函数

RegisterCustomTypeFunc,它上面有2行注释:

// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types

//

// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation

它是一个验证数据类型自定义函数,NOTE:这个方法不是线程安全的

golang常用库:字段参数验证库-validator的更多相关文章

  1. Django基础——ORM字段和字段参数

    ORM概念: 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象( 1. 不同的程序员写的SQL水平参差不齐 2. ...

  2. golang常用库:cli命令行/应用程序生成工具-cobra使用

    golang常用库:cli命令行/应用程序生成工具-cobra使用 一.Cobra 介绍 我前面有一篇文章介绍了配置文件解析库 Viper 的使用,这篇介绍 Cobra 的使用,你猜的没错,这 2 个 ...

  3. spring boot:使用validator做接口的参数、表单、类中多字段的参数验证(spring boot 2.3.1)

    一,为什么要做参数验证? 永远不要相信我们在后端接收到的数据, 1,防止别人通过接口乱刷服务:有些不怀好意的人或机构会乱刷我们的服务,例如:短信接口, 相信大家可能很多人在工作中遇到过这种情况 2,防 ...

  4. 15个最佳的 JavaScript 表单验证库

    客户端验证在任何项目都是不够的,因为 JavaScript 可以直接忽略,人们可以提交请求到服务器. 然而这并不意味着客户端验证都没必要了,很多时候我们需要在用户提交到服务器之前给予提示.JavaSc ...

  5. Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven)

    Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven) 本篇和 Spring 没有什么关系,只是学习 Spring,必备一些知识,所以放在这里了. 本篇内容: (1)M ...

  6. jQuery.Validate验证库详解

    一.用前必备官方网站:http://bassistance.de/jquery-plugins/jquery-plugin-validation/ API: http://jquery.bassist ...

  7. jQuery.Validate验证库

    一.用前必备官方网站:http://bassistance.de/jquery-plugins/jquery-plugin-validation/ API: http://jquery.bassist ...

  8. 前端工具 - 15个最佳的 JavaScript 表单验证库

    客户端验证在任何项目都是不够的,因为 JavaScript 可以直接忽略,人们可以提交请求到服务器. 然而这并不意味着客户端验证都没必要了,很多时候我们需要在用户提交到服务器之前给予提示.JavaSc ...

  9. Django --ORM常用的字段和参数 多对多创建形式

    1 ORM字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. IntegerField 一个整数类型 ...

随机推荐

  1. Bypass windous/mac 登陆密码

    前言 如题,在52破解里看到一个非常好用的工具 Kon-Boot 2.7 功能 不会去擦除windows密码 不会修改windows文件 此外,Kon-Boot的最新版是目前世界上唯一的一个能够绕过W ...

  2. HTML模仿实现京东登录页面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 如何《快速搭建LAMP环境》

    阿里云体验平台简介 阿里云开发者实验室提供免费云资源和丰富的场景化实践,旨在帮助开发者在学习应用技术,了解阿里云产品的特性. 教程介绍 本教程引用自阿里云体验实验室介绍如何快速搭建Docker环境,并 ...

  4. Jenkins下Vue自动部署(一)

    1,服务器上安装docker http://www.runoob.com/docker/ubuntu-docker-install.html?tdsourcetag=s_pctim_aiomsg 2, ...

  5. ui自动化--鼠标操作ActionChains

    需要先引入鼠标操作模块:from selenium.webdriver.common.action_chains import ActionChains 实际上ActionChains这个模块的实现的 ...

  6. oracle之二物化视图

    物化视图 18.1.物化视图作用 1) 物化视图起源于数据仓库,早期的考虑是用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免在基表上进行这些耗时的操作,从而快速的得 ...

  7. Oracle命令类别

    Oracle命令类别: 数据操纵语言:DML: select; insert; delete; update; merge. 数据定义语言:DDL: create; alter; drop; trun ...

  8. JVM强引用、软引用、弱引用、虚引用、终结器引用垃圾回收行为总结

    JVM引用 我们希望能描述这样一类对象: 当内存空间还足够时,则能保留在内存中:如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象. -[既偏门又非常高频的面试题]强引用.软引用.弱引用.虚引 ...

  9. 面向对象技术-原文转载自jingwhale

    面向对象技术 --原文转载自jingwhale,文章底部附原文链接 对象是面向对象的程序设计的核心,它由描述状态的属性(变量)和用来实现对象行为的方法(函数)组成,完成了从数据模型到处理模型的结合与统 ...

  10. JavaScript的this到底代表谁?(this指向哪里?)

    在很多编程语言中都有this这个特殊关键字的存在,比如Java中的this,还有本文要说到的JavaScript中的this.那么,JavaScript中this究竟有什么特性和用法呢?它又是如何定义 ...