mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
gvalid包增加struct tag的校验规则、自定义错误提示信息绑定的支持特性
This commit is contained in:
3
TODO
3
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的校验规则、自定义错误提示信息绑定的支持特性;
|
||||
|
||||
|
||||
@ -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对象属性上,需要注意:
|
||||
|
||||
@ -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参数为非必须参数,可以传递所有的校验参数进来,进行多参数对比(部分校验规则需要)
|
||||
|
||||
@ -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()
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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"))
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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:两次密码输入不相等]]
|
||||
}
|
||||
35
geg/util/gvalid/gvalid_struct.go
Normal file
35
geg/util/gvalid/gvalid_struct.go
Normal file
@ -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))
|
||||
}
|
||||
Reference in New Issue
Block a user