golang 利用reflect实现validator参数检测
其实golang开源的validator 也有一些,但是出于学习的目的还是手动实现了一把,写的比较挫,轻喷。
实现思路
golang 的reflect可以获取到很多信息,对象的tag,tag的值,对象类型,对象的值等等
validator的实现基于reflect通过自定义tag,设定一组值作为validator的标准设定到tag的值下面,然后通过reflect包取到结构体每个字段的tag的值,和字段的值,两者进行匹配,不符合规则就直接报错返回,这样就实现了最简单的validator
代码如下,只定义了2种规则
- “not empty”
- “>0”
package main
import (
"errors"
"fmt"
"reflect"
)
type Common struct {
Name string `validate:"not empty"`
Class int `validate:">1"`
}
func Validate(obj interface{}) error {
st := reflect.TypeOf(obj)
// 检测传入是否为结构体
if st.Kind() != reflect.Struct {
return errors.New("not struct")
}
v := reflect.ValueOf(obj)
for i := 0; i < st.NumField(); i++ {
field := st.Field(i)
// 获取tag为alias的值
if tagVal, ok := field.Tag.Lookup("validate"); ok {
if tagVal == "" {
continue
}
var val interface{}
switch tagVal {
case ">1":
if v.Field(i).Kind() == reflect.Uint {
if v.Field(i).Interface().(int) <= 0 {
return failed(field.Name, val, tagVal)
}
}
case "not empty":
if v.Field(i).Kind() == reflect.String {
val := v.Field(i).Interface().(string)
if val == "" {
return failed(field.Name, val, tagVal)
}
}
}
}
}
return nil
}
func failed(str string, val interface{}, expect string) error {
err := errors.New(fmt.Sprintf("invalid %s,expect %v,acutal %s,", str, val, expect))
fmt.Println(err.Error())
return err
}
func main() {
a := []Common{
{
Name: "1",
Class: 0,
},
{
Name: "",
Class: 1,
},
{
Name: "1",
Class: 1,
},
}
for i, v := range a {
err := Validate(v)
if err != nil {
fmt.Printf("index:%d,validate failed:%s\n", i, err.Error())
continue
}
fmt.Printf("index:%d validate success\n", i)
}
return
}