diff --git a/TODO b/TODO index 17b77638a..a1413a387 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,6 @@ ghttp.Response增加输出内容后自动退出当前请求机制,不需要用 Cookie&Session数据池化处理; ghttp.Client增加proxy特性; gtime增加对时区转换的封装,并简化失去转换时对类似+80500时区的支持; -gvalid包增加tag与校验规则绑定的支持特性; ghttp获取参数支持直接转struct功能; map转struct增加对tag的支持; gcache检查在i386下的int64->int转换问题; @@ -48,5 +47,5 @@ DONE: 28. ORM增加获取被执行的sql语句的方法; 29. gdb增加查询缓存特性; 30. gpage分页增加对自定义后缀的支持,如:2.html, 2.php等等; - +31. gvalid包增加struct tag的校验规则、自定义错误提示信息绑定的支持特性; diff --git a/g/util/gutil/gutil.go b/g/util/gutil/gutil.go index c68ada05e..91841cdf6 100644 --- a/g/util/gutil/gutil.go +++ b/g/util/gutil/gutil.go @@ -17,16 +17,19 @@ import ( ) // 格式化打印变量(类似于PHP-vardump) -func Dump(i interface{}) { - buffer := &bytes.Buffer{} - encoder := json.NewEncoder(buffer) - encoder.SetEscapeHTML(false) - encoder.SetIndent("", "\t") - if err := encoder.Encode(i); err == nil { - fmt.Println(buffer.String()) - } else { - fmt.Errorf("%s\n", err.Error()) +func Dump(i...interface{}) { + for _, v := range i { + buffer := &bytes.Buffer{} + encoder := json.NewEncoder(buffer) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", "\t") + if err := encoder.Encode(v); err == nil { + fmt.Print(buffer.String()) + } else { + fmt.Errorf("%s", err.Error()) + } } + fmt.Println() } // 将map键值对映射到对应的struct对象属性上,需要注意: diff --git a/g/util/gvalid/gvalid.go b/g/util/gvalid/gvalid.go index 3b88682ea..23f0119a1 100644 --- a/g/util/gvalid/gvalid.go +++ b/g/util/gvalid/gvalid.go @@ -381,7 +381,7 @@ func CheckMap(params map[string]interface{}, rules map[string]string, msgs...map var value interface{} // 自定义消息,非必须参数,因此这里需要做判断 customMsgs := make(map[string]interface{}) - if len(msgs) > 0 { + if len(msgs) > 0 && len(msgs[0]) > 0 { customMsgs = msgs[0] } errorMsgs := make(map[string]map[string]string) @@ -421,8 +421,44 @@ func CheckMap(params map[string]interface{}, rules map[string]string, msgs...map } // 校验struct对象属性,object参数也可以是一个指向对象的指针,返回值同CheckMap方法 -func CheckStruct(object interface{}, rules map[string]string, msgs...map[string]interface{}) map[string]map[string]string { - return CheckMap(structs.Map(object), rules, msgs...) +func CheckStruct(st interface{}, rules map[string]string, msgs...map[string]interface{}) map[string]map[string]string { + fields := structs.Fields(st) + if rules == nil { + rules = make(map[string]string) + } + params := make(map[string]interface{}) + errMsgs := (map[string]interface{})(nil) + if len(msgs) == 0 { + errMsgs = make(map[string]interface{}) + } else { + errMsgs = msgs[0] + } + for _, field := range fields { + params[field.Name()] = field.Value() + if tag := field.Tag("gvalid"); tag != "" { + match, _ := gregex.MatchString(`([^#]+)#{0,1}(.*)`, tag) + // 校验规则 + if _, ok := rules[field.Name()]; !ok { + rules[field.Name()] = match[1] + } + // 错误提示 + if match[2] != "" { + ruleArray := strings.Split(match[1], "|") + msgArray := strings.Split(match[2], "|") + for k, v := range ruleArray { + if len(msgArray[k]) == 0 { + continue + } + array := strings.Split(v, ":") + if _, ok := errMsgs[field.Name()]; !ok { + errMsgs[field.Name()] = make(map[string]string) + } + errMsgs[field.Name()].(map[string]string)[array[0]] = msgArray[k] + } + } + } + } + return CheckMap(params, rules, errMsgs) } // 检测单条数据的规则,其中params参数为非必须参数,可以传递所有的校验参数进来,进行多参数对比(部分校验规则需要) diff --git a/geg/other/docker/test/http.go b/geg/other/docker/test/http.go deleted file mode 100644 index be6bc7c4f..000000000 --- a/geg/other/docker/test/http.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "gitee.com/johng/gf/g" - "gitee.com/johng/gf/g/net/ghttp" -) - -func main() { - s := g.Server() - s.BindHandler("/", func(r *ghttp.Request){ - r.Response.Writeln("哈喽世界!") - }) - s.SetPort(8199) - s.Run() -} \ No newline at end of file diff --git a/geg/other/docker/test/redis.go b/geg/other/docker/test/redis.go deleted file mode 100644 index a4bb4beb1..000000000 --- a/geg/other/docker/test/redis.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "gitee.com/johng/gf/g" - "gitee.com/johng/gf/g/net/ghttp" - "gitee.com/johng/gf/g/database/gredis" -) - -func main() { - s := g.Server() - s.BindHandler("/", func(r *ghttp.Request) { - redis := gredis.New(gredis.Config{ - Host: "redis-service", - Port: 9999, - }) - defer redis.Close() - - v, err := redis.Do("GET", "k") - r.Response.Writeln(v) - r.Response.Writeln(err) - v, err = redis.Do("SET", "k", "v") - r.Response.Writeln(v) - r.Response.Writeln(err) - - }) - s.Run() -} \ No newline at end of file diff --git a/geg/other/graceful.go b/geg/other/graceful.go deleted file mode 100644 index dbe5b5168..000000000 --- a/geg/other/graceful.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - - "github.com/tabalt/gracehttp" -) - -func main() { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "hello world") - }) - - err := gracehttp.ListenAndServe(":8888", nil) - if err != nil { - fmt.Println(err) - } -} \ No newline at end of file diff --git a/geg/other/map/map_test.go b/geg/other/map/map_test.go deleted file mode 100644 index 09ab75b31..000000000 --- a/geg/other/map/map_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://gitee.com/johng/gf. - -// go test *.go -bench=".*" - -package test - -import ( - "testing" -) - -var m1 = make(map[int]int) -var m2 = make(map[interface{}]interface{}) - -func BenchmarkMapIntInt_Set(b *testing.B) { - for i := 0; i < b.N; i++ { - m1[i] = i - } -} - -func BenchmarkMapIntInt_Search(b *testing.B) { - for i := 0; i < b.N; i++ { - if _, ok := m1[i]; ok { - - } - } -} - -func BenchmarkMapIntInt_Remove(b *testing.B) { - for i := 0; i < b.N; i++ { - delete(m1, i) - } -} - - -func BenchmarkMapInterface_Set(b *testing.B) { - for i := 0; i < b.N; i++ { - m2[i] = i - } -} - -func BenchmarkMapInterface_Search(b *testing.B) { - for i := 0; i < b.N; i++ { - if _, ok := m2[i]; ok { - - } - } -} - -func BenchmarkMapInterface_Remove(b *testing.B) { - for i := 0; i < b.N; i++ { - delete(m2, i) - } -} \ No newline at end of file diff --git a/geg/other/reflect.go b/geg/other/reflect.go deleted file mode 100644 index a2a8da6da..000000000 --- a/geg/other/reflect.go +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "fmt" - //"reflect" - "reflect" -) -//import "reflect" - -type gtInterface interface { - Run() -} - -type st struct { - age int - Name string -} - -type mySt struct { - st -} - -func (_ st) Echo(str string) { - fmt.Printf("echo(%s)\n", str) -} -func (_ *st) Echo2(str string) { - fmt.Printf("echo2(%s)\n", str) -} - -func (_ st) Echo3() { - fmt.Println("echo3()") -} - -func Echo3() { - fmt.Println("echo3()") -} - -type DefaultFunc func() - -func Call(i DefaultFunc) { - i() - //reflect.ValueOf(i).Call([]reflect.Value{}) -} -func main() { - s := st {16,"john"} - - - //p := reflect.ValueOf("halloo") - v := reflect.ValueOf(s) - //v2 := reflect.ValueOf(&s) - //// 调用st结构体的方法 - //v.MethodByName("Echo").Call([]reflect.Value{p}) - //// 我们需要调用的是实体结构体指针的方法,注意v2与v2的区别,以及方法定义的区别 - //v2.MethodByName("Echo2").Call([]reflect.Value{p}) - //v.MethodByName() - fmt.Println(v.FieldByName("name")) - - - -} \ No newline at end of file diff --git a/geg/other/sleep/sleep.go b/geg/other/sleep/sleep.go deleted file mode 100644 index ea4573aa3..000000000 --- a/geg/other/sleep/sleep.go +++ /dev/null @@ -1,16 +0,0 @@ -package sleep - -import ( - "time" - "gitee.com/johng/gf/g/os/glog" -) - -func init () { - glog.Println("sleep package importing") - time.Sleep(3*time.Second) - glog.Println("sleep package imported") -} - -func Test() { - glog.Println("Test") -} diff --git a/geg/other/test_test.go b/geg/other/test_test.go deleted file mode 100644 index 40856914d..000000000 --- a/geg/other/test_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "testing" - "strings" -) - -var s = "arwerwerwerwerwerwrwerwerwerwersefsdgsdfgsddsfgsdfsd timeout" - -func Benchmark_Contains(b *testing.B) { - for i := 0; i < b.N; i ++ { - strings.Contains(s, "timeout") - } -} - -func Benchmark_EqualFold(b *testing.B) { - for i := 0; i < b.N; i ++ { - strings.EqualFold(s[len(s) - 7:], "timeout") - } -} - - diff --git a/geg/other/gvalid.go b/geg/util/gvalid/gvalid.go similarity index 96% rename from geg/other/gvalid.go rename to geg/util/gvalid/gvalid.go index 4608d6d51..ad7e7795e 100644 --- a/geg/other/gvalid.go +++ b/geg/util/gvalid/gvalid.go @@ -1,8 +1,8 @@ package main import ( - "fmt" "gitee.com/johng/gf/g/util/gvalid" + "gitee.com/johng/gf/g/util/gutil" ) func main() { @@ -60,6 +60,6 @@ func main() { "same" : "两次密码输入不相等", }, } - fmt.Println(gvalid.CheckMap(params, rules, msgs)) + gutil.Dump(gvalid.CheckMap(params, rules, msgs)) // map[passport:map[length:账号长度应当在6到16之间] password:map[same:两次密码输入不相等]] } diff --git a/geg/util/gvalid/gvalid_struct.go b/geg/util/gvalid/gvalid_struct.go new file mode 100644 index 000000000..d687c32e3 --- /dev/null +++ b/geg/util/gvalid/gvalid_struct.go @@ -0,0 +1,35 @@ +package main + +import ( + "gitee.com/johng/gf/g/util/gutil" + "gitee.com/johng/gf/g/util/gvalid" +) + +type User struct { + Uid int `gvalid:"integer|min:1"` + Name string `gvalid:"required|length:6,30#请输入用户名称|用户名称长度非法"` + Pass1 string `gvalid:"required|password3"` + Pass2 string `gvalid:"required|password3|same:Pass1#||两次密码不一致,请重新输入"` +} + +func main() { + user := &User{ + Name : "john", + Pass1: "Abc123!@#", + Pass2: "123", + } + + // 使用结构体定义的校验规则和错误提示进行校验 + gutil.Dump(gvalid.CheckStruct(user, nil)) + + // 自定义校验规则和错误提示,对定义的特定校验规则和错误提示进行覆盖 + rules := map[string]string { + "Uid" : "required", + } + msgs := map[string]interface{} { + "Pass2" : map[string]string { + "password3" : "名称不能为空", + }, + } + gutil.Dump(gvalid.CheckStruct(user, rules, msgs)) +}