一、前提:认识reflect.TypeOf及reflect.ValueOf
TypeOf:
-
动态的获取从函数接口中传进去的变量的类型,如果为空则返回值为 nil(获取类型对象)
-
可以从该方法获取的对象中拿到字段的所属类型,字段名,以及该字段是否是匿名字段等信息。
-
还可以获取到与该字段进行绑定的 tag。
ValueOf:
-
获取从函数入口传进去变量的值(获取值对象)该方法获取到的对象是对应的数据信息区域(具体的值可以通过 Filed(index) 直接拿到对应位置的值)FieldByName(字段名)
-
可以通过该函数拿到成员属性的详细信息(返回值与ValueOf一样)
-
注:指针类型经过以上函数拿到的还是指针类型,结构体还是结构体类型。
Elem()方法:
- 该方法只接受指针类型与接口类型,如果不是这两种类型就会抛出异常(相当于对指针进行取元素)
示例:
package main
import (
"fmt"
"reflect"
)
// 定义一个结构体
type stu struct {
id string
name string
age int
}
func main() {
//对结构体进行初始化
var stu1 stu
stu1.age = 20
stu1.id = "hahaha"
stu1.name = "小明"
sTructType := reflect.TypeOf(stu1)
sTructValue := reflect.ValueOf(stu1)
// 1. 类型
fmt.Println("类型:", sTructType)
// 2. 结构体值
fmt.Println("值是:", sTructValue)
// 3. 获取属性个数
fmt.Println(sTructType.NumField())
// 4. 获取指定位置属性的详细类型
fmt.Println(sTructType.Field(0))
// 5. 直接获取到结构体名
fmt.Println("类型是:", sTructType.Name())
// 6. 获取该类型最初的基本
fmt.Println(sTructType.Kind())
//打印结果
// 1. 类型: main.stu
// 2. 值是: {hahaha 小明 20}
// 3. 3
// 4. {id main string 0 [0] false}
// Field输出以上结果含义为
// | Type Type // field type字段名
// | Tag StructTag // field tag string所在包
// | Offset uintptr // offset within struct, in bytes//基类型名称
// | Index []int // index sequence for Type.FieldByIndex//下标
// | Anonymous bool // is an embedded field//是不是匿名字段
// 5. 类型是: stu
// 6. struct
}
二、实现请求结构体验证器
1. 对reqStruct设置规则
示例,登录接口请求结构体规则:
LoginVerify = Rules{"CaptchaId": {NotEmpty()}, "Username": {NotEmpty()}, "Password": {NotEmpty()}}
2. validator实现
1. Rules结构,RulesMap结构
type Rules map[string][]string
type RulesMap map[string]Rules
2. 规则名称定义
//@description: 非空 不能为其对应类型的0值
func NotEmpty() string {
return "notEmpty"
}
// @description: 正则校验 校验输入项是否满足正则表达式
func RegexpMatch(rule string) string {
return "regexp=" + rule
}
//@description: 小于入参(<) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
func Lt(mark string) string {
return "lt=" + mark
}
//@description: 等于入参(==) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
func Eq(mark string) string {
return "eq=" + mark
}
//@description: 不等于入参(!=) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
func Ne(mark string) string {
return "ne=" + mark
}
//@description: 大于入参(>) 如果为string array Slice则为长度比较 如果是 int uint float 则为数值比较
func Gt(mark string) string {
return "gt=" + mark
}
3. 校验方法
func Verify(st interface{}, roleMap Rules) (err error) {
compareMap := map[string]bool{
"lt": true,
"le": true,
"eq": true,
"ne": true,
"ge": true,
"gt": true,
}
sTructType := reflect.TypeOf(st)
sTructValue := reflect.ValueOf(st) // 获取reflect.Type类型
kd := sTructValue.Kind() // 获取到st对应的类别
if kd != reflect.Struct {
return errors.New("expect struct")
}
num := sTructValue.NumField()
// 遍历结构体的所有字段
for i := 0; i < num; i++ {
tagVal := sTructType.Field(i)
val := sTructValue.Field(i)
if tagVal.Type.Kind() == reflect.Struct {
if err = Verify(val.Interface(), roleMap); err != nil {
return err
}
}
if len(roleMap[tagVal.Name]) > 0 {
for _, v := range roleMap[tagVal.Name] {
switch {
case v == "notEmpty":
if isBlank(val) {
return errors.New(tagVal.Name + "值不能为空")
}
case strings.Split(v, "=")[0] == "regexp":
if !regexpMatch(strings.Split(v, "=")[1], val.String()) {
return errors.New(tagVal.Name + "格式校验不通过")
}
case compareMap[strings.Split(v, "=")[0]]:
if !compareVerify(val, v) {
return errors.New(tagVal.Name + "长度或值不在合法范围," + v)
}
}
}
}
}
return nil
}
4. 检验各类方法
//@description: 非空校验
func isBlank(value reflect.Value) bool {
switch value.Kind() {
case reflect.String, reflect.Slice:
return value.Len() == 0
case reflect.Bool:
return !value.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return value.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return value.Uint() == 0
case reflect.Float32, reflect.Float64:
return value.Float() == 0
case reflect.Interface, reflect.Ptr:
return value.IsNil()
}
return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}
//@description: 正则校验
func regexpMatch(rule, matchStr string) bool {
return regexp.MustCompile(rule).MatchString(matchStr)
}
//@description: 长度和数字的校验方法 根据类型自动校验
func compareVerify(value reflect.Value, VerifyStr string) bool {
switch value.Kind() {
case reflect.String:
return compare(len([]rune(value.String())), VerifyStr)
case reflect.Slice, reflect.Array:
return compare(value.Len(), VerifyStr)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return compare(value.Uint(), VerifyStr)
case reflect.Float32, reflect.Float64:
return compare(value.Float(), VerifyStr)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return compare(value.Int(), VerifyStr)
default:
return false
}
}
//@description: 比较函数
func compare(value interface{}, VerifyStr string) bool {
VerifyStrArr := strings.Split(VerifyStr, "=")
val := reflect.ValueOf(value)
switch val.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
VInt, VErr := strconv.ParseInt(VerifyStrArr[1], 10, 64)
if VErr != nil {
return false
}
switch {
case VerifyStrArr[0] == "lt":
return val.Int() < VInt
case VerifyStrArr[0] == "le":
return val.Int() <= VInt
case VerifyStrArr[0] == "eq":
return val.Int() == VInt
case VerifyStrArr[0] == "ne":
return val.Int() != VInt
case VerifyStrArr[0] == "ge":
return val.Int() >= VInt
case VerifyStrArr[0] == "gt":
return val.Int() > VInt
default:
return false
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
VInt, VErr := strconv.Atoi(VerifyStrArr[1])
if VErr != nil {
return false
}
switch {
case VerifyStrArr[0] == "lt":
return val.Uint() < uint64(VInt)
case VerifyStrArr[0] == "le":
return val.Uint() <= uint64(VInt)
case VerifyStrArr[0] == "eq":
return val.Uint() == uint64(VInt)
case VerifyStrArr[0] == "ne":
return val.Uint() != uint64(VInt)
case VerifyStrArr[0] == "ge":
return val.Uint() >= uint64(VInt)
case VerifyStrArr[0] == "gt":
return val.Uint() > uint64(VInt)
default:
return false
}
case reflect.Float32, reflect.Float64:
VFloat, VErr := strconv.ParseFloat(VerifyStrArr[1], 64)
if VErr != nil {
return false
}
switch {
case VerifyStrArr[0] == "lt":
return val.Float() < VFloat
case VerifyStrArr[0] == "le":
return val.Float() <= VFloat
case VerifyStrArr[0] == "eq":
return val.Float() == VFloat
case VerifyStrArr[0] == "ne":
return val.Float() != VFloat
case VerifyStrArr[0] == "ge":
return val.Float() >= VFloat
case VerifyStrArr[0] == "gt":
return val.Float() > VFloat
default:
return false
}
default:
return false
}
}
标签:case,reflect,return,string,val,接口,golang,Validator,value
From: https://www.cnblogs.com/brandonv/p/18235120