From ff126dfbaaa2515933586baf3f408cdd09d4795c Mon Sep 17 00:00:00 2001 From: John Date: Tue, 30 Oct 2018 23:58:10 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E6=A1=86=E6=9E=B6=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E7=BB=86=E8=8A=82=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 2 ++ g/frame/gins/gins.go | 11 ++++--- g/g_func.go | 10 ------ g/g_logger.go | 16 ++++++++++ g/net/ghttp/ghttp_server.go | 9 ++++-- g/net/ghttp/ghttp_server_config.go | 8 ++++- g/os/gcfg/gcfg.go | 37 ++++++++++++---------- g/os/glog/glog_logger.go | 13 +------- g/os/gspath/gspath.go | 51 +++++++++++++++++------------- g/os/gview/gview.go | 22 ++++++++++--- g/util/gregex/gregex.go | 6 ++-- geg/other/test2.go | 16 ++++++++-- 12 files changed, 121 insertions(+), 80 deletions(-) diff --git a/TODO b/TODO index 7ba360abe..740646c93 100644 --- a/TODO +++ b/TODO @@ -43,6 +43,8 @@ ghttp hook回调使用方式在注册路由比较多的时候,优先级可能 gform参考 https://gohouse.github.io/gorose/dist/index.html 进行改进 完善配置管理章节,说明默认的配置文件更改方式; 完善gform配置管理说明,g.DB/Database和gdb.New的区别; +改进gconv.Struct方法,支持不区分大小写的属性-键名匹配,便于开发者执行对象转换; + DONE: diff --git a/g/frame/gins/gins.go b/g/frame/gins/gins.go index 76d409407..6404848e6 100644 --- a/g/frame/gins/gins.go +++ b/g/frame/gins/gins.go @@ -12,6 +12,7 @@ import ( "gitee.com/johng/gf/g/os/gcfg" "gitee.com/johng/gf/g/os/gcmd" "gitee.com/johng/gf/g/os/genv" + "gitee.com/johng/gf/g/os/glog" "gitee.com/johng/gf/g/os/gview" "gitee.com/johng/gf/g/os/gfile" "gitee.com/johng/gf/g/container/gmap" @@ -125,7 +126,7 @@ func Database(name...string) *gdb.Db { db := instances.GetOrSetFuncLock(key, func() interface{} { m := config.GetMap("database") if m == nil { - panic(fmt.Sprintf(`incomplete configuration for database: "database" node not found in config file "%s"`, config.GetFilePath())) + glog.Errorfln(`incomplete configuration for database: "database" node not found in config file "%s"`, config.GetFilePath()) } for group, v := range m { cg := gdb.ConfigGroup{} @@ -181,7 +182,7 @@ func Database(name...string) *gdb.Db { if db, err := gdb.New(name...); err == nil { return db } else { - panic(err) + glog.Error(err) } return nil }) @@ -213,13 +214,13 @@ func Redis(name...string) *gredis.Redis { Pass : array[4], }) } else { - panic(fmt.Sprintf(`invalid redis node configuration: "%s"`, line)) + glog.Errorfln(`invalid redis node configuration: "%s"`, line) } } else { - panic(fmt.Sprintf(`configuration for redis not found for group "%s"`, group)) + glog.Errorfln(`configuration for redis not found for group "%s"`, group) } } else { - panic(fmt.Sprintf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.GetFilePath())) + glog.Errorfln(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.GetFilePath()) } return nil }) diff --git a/g/g_func.go b/g/g_func.go index bef7e7fd5..78459c0e0 100644 --- a/g/g_func.go +++ b/g/g_func.go @@ -33,16 +33,6 @@ func Wait() { ghttp.Wait() } -// 是否显示调试信息 -func SetDebug(debug bool) { - glog.SetDebug(debug) -} - -// 设置日志的显示等级 -func SetLogLevel(level int) { - glog.SetLevel(level) -} - // 打印变量 func Dump(i...interface{}) { gutil.Dump(i...) diff --git a/g/g_logger.go b/g/g_logger.go index 6532bc601..ac9f1d6cf 100644 --- a/g/g_logger.go +++ b/g/g_logger.go @@ -6,3 +6,19 @@ package g +import "gitee.com/johng/gf/g/os/glog" + +// 是否显示调试信息 +func SetDebug(debug bool) { + glog.SetDebug(debug) +} + +// 设置日志的显示等级 +func SetLogLevel(level int) { + glog.SetLevel(level) +} + +// 获取设置的日志显示等级 +func GetLogLevel() int { + return glog.GetLevel() +} \ No newline at end of file diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 3ac8f322f..2a4979588 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -213,9 +213,14 @@ func (s *Server) Start() error { // 如果设置了静态文件目录,那么优先按照静态文件目录进行检索,其次是当前可执行文件工作目录; // 并且如果是开发环境,默认也会添加main包的源码目录路径做为二级检索。 if s.config.ServerRoot != "" { - s.paths.Set(s.config.ServerRoot) + if rp, err := s.paths.Set(s.config.ServerRoot); err != nil { + glog.Error("ghttp.SetServerRoot failed:", err.Error()) + return err + } else { + glog.Debug("ghttp.SetServerRoot:", rp) + } } - s.paths.Add(gfile.SelfDir()) + s.AddSearchPath(gfile.SelfDir()) if p := gfile.MainPkgPath(); p != "" && gfile.Exists(p) { s.paths.Add(p) } diff --git a/g/net/ghttp/ghttp_server_config.go b/g/net/ghttp/ghttp_server_config.go index 3b84a7652..ae3bd90ed 100644 --- a/g/net/ghttp/ghttp_server_config.go +++ b/g/net/ghttp/ghttp_server_config.go @@ -303,7 +303,13 @@ func (s *Server) SetDumpRouteMap(enabled bool) { // 添加静态文件搜索目录,必须给定目录的绝对路径 func (s *Server) AddSearchPath(path string) error { - return s.paths.Add(path) + if rp, err := s.paths.Add(path); err != nil { + glog.Error("ghttp.AddSearchPath failed:", err.Error()) + return err + } else { + glog.Debug("ghttp.AddSearchPath:", rp) + } + return nil } // 获取 diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index a7e5094d4..08530608e 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -9,14 +9,14 @@ package gcfg import ( - "gitee.com/johng/gf/g/container/gvar" - "gitee.com/johng/gf/g/os/gspath" - "gitee.com/johng/gf/g/os/gfsnotify" - "gitee.com/johng/gf/g/container/gmap" - "gitee.com/johng/gf/g/encoding/gjson" - "gitee.com/johng/gf/g/container/gtype" "errors" + "gitee.com/johng/gf/g/container/gmap" + "gitee.com/johng/gf/g/container/gtype" + "gitee.com/johng/gf/g/container/gvar" + "gitee.com/johng/gf/g/encoding/gjson" + "gitee.com/johng/gf/g/os/gfsnotify" "gitee.com/johng/gf/g/os/glog" + "gitee.com/johng/gf/g/os/gspath" ) const ( @@ -37,14 +37,14 @@ func New(path string, file...string) *Config { if len(file) > 0 { name = file[0] } - s := gspath.New() - s.Set(path) - return &Config { + c := &Config { name : gtype.NewString(name), - paths : s, + paths : gspath.New(), jsons : gmap.NewStringInterfaceMap(), vc : gtype.NewBool(), } + c.SetPath(path) + return c } // 判断从哪个配置文件中获取内容,返回配置文件的绝对路径 @@ -58,12 +58,13 @@ func (c *Config) filePath(file...string) string { // 设置配置管理器的配置文件存放目录绝对路径 func (c *Config) SetPath(path string) error { - if err := c.paths.Set(path); err != nil { - glog.Error("gcfg.SetPath failed:", path, err) + if rp, err := c.paths.Set(path); err != nil { + glog.Error("gcfg.SetPath failed:", err.Error()) return err + } else { + c.jsons.Clear() + glog.Debug("gcfg.SetPath:", rp) } - c.jsons.Clear() - glog.Debug("gcfg.SetPath:", path) return nil } @@ -76,11 +77,12 @@ func (c *Config) SetViolenceCheck(check bool) { // 添加配置管理器的配置文件搜索路径 func (c *Config) AddPath(path string) error { - if err := c.paths.Add(path); err != nil { - glog.Debug("gcfg.AddPath failed:", path, err) + if rp, err := c.paths.Add(path); err != nil { + glog.Debug("gcfg.AddPath failed:", err.Error()) return err + } else { + glog.Debug("gcfg.AddPath:", rp) } - glog.Debug("gcfg.AddPath:", path) return nil } @@ -95,6 +97,7 @@ func (c *Config) GetFilePath(file...string) string { // 设置配置管理对象的默认文件名称 func (c *Config) SetFileName(name string) { + glog.Debug("gcfg.SetFileName:", name) c.name.Set(name) } diff --git a/g/os/glog/glog_logger.go b/g/os/glog/glog_logger.go index fce9a5a18..83bd7b051 100644 --- a/g/os/glog/glog_logger.go +++ b/g/os/glog/glog_logger.go @@ -246,19 +246,8 @@ func (l *Logger) GetBacktrace(skip...int) string { } backtrace := "" index := 1 - from := 0 - // 首先定位业务文件开始位置 - for i := 0; i < 10; i++ { - if _, cfile, _, ok := runtime.Caller(i); ok { - if !gregex.IsMatchString("/g/os/glog/glog.+$", cfile) { - from = i - break - } - } - } - // 从业务文件开始位置根据自定义的skip开始backtrace goroot := runtime.GOROOT() - for i := from + customSkip + l.btSkip.Val(); i < 10000; i++ { + for i := customSkip + l.btSkip.Val(); i < 10000; i++ { if _, cfile, cline, ok := runtime.Caller(i); ok && cfile != "" { // 不打印出go源码路径及glog包文件路径,日志打印必须从业务源码文件开始,且从glog包文件开始检索 if (goroot == "" || !gregex.IsMatchString("^" + goroot, cfile)) && !gregex.IsMatchString(``, cfile) { diff --git a/g/os/gspath/gspath.go b/g/os/gspath/gspath.go index c0d25edee..38d0bde35 100644 --- a/g/os/gspath/gspath.go +++ b/g/os/gspath/gspath.go @@ -10,6 +10,7 @@ package gspath import ( "errors" + "fmt" "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/os/gfile" "gitee.com/johng/gf/g/os/gfsnotify" @@ -32,46 +33,52 @@ func New () *SPath { } // 设置搜索路径,只保留当前设置项,其他搜索路径被清空 -func (sp *SPath) Set(path string) error { - r := gfile.RealPath(path) - if r == "" { - r = sp.Search(path) - if r == "" { - r = gfile.RealPath(gfile.Pwd() + gfile.Separator + path) +func (sp *SPath) Set(path string) (realpath string, err error) { + realpath = gfile.RealPath(path) + if realpath == "" { + realpath = sp.Search(path) + if realpath == "" { + realpath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path) } } - if r != "" && gfile.IsDir(r) { - r = strings.TrimRight(r, gfile.Separator) + if realpath == "" { + return realpath, errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) + } + if realpath != "" && gfile.IsDir(realpath) { + realpath = strings.TrimRight(realpath, gfile.Separator) sp.mu.Lock() - sp.paths = []string{r} + sp.paths = []string{realpath} sp.mu.Unlock() sp.cache.Clear() //glog.Debug("gspath.SetPath:", r) - return nil + return realpath, nil } //glog.Warning("gspath.SetPath failed:", path) - return errors.New("invalid path:" + path) + return realpath, errors.New("invalid path:" + path) } // 添加搜索路径 -func (sp *SPath) Add(path string) error { - r := gfile.RealPath(path) - if r == "" { - r = sp.Search(path) - if r == "" { - r = gfile.RealPath(gfile.Pwd() + gfile.Separator + path) +func (sp *SPath) Add(path string) (realpath string, err error) { + realpath = gfile.RealPath(path) + if realpath == "" { + realpath = sp.Search(path) + if realpath == "" { + realpath = gfile.RealPath(gfile.Pwd() + gfile.Separator + path) } } - if r != "" && gfile.IsDir(r) { - r = strings.TrimRight(r, gfile.Separator) + if realpath == "" { + return realpath, errors.New(fmt.Sprintf(`path "%s" does not exist`, path)) + } + if realpath != "" && gfile.IsDir(realpath) { + realpath = strings.TrimRight(realpath, gfile.Separator) sp.mu.Lock() - sp.paths = append(sp.paths, r) + sp.paths = append(sp.paths, realpath) sp.mu.Unlock() //glog.Debug("gspath.Add:", r) - return nil + return realpath, nil } //glog.Warning("gspath.Add failed:", path) - return errors.New("invalid path:" + path) + return realpath, errors.New("invalid path:" + path) } // 按照优先级搜索文件,返回搜索到的文件绝对路径,找不到该文件时,返回空字符串 diff --git a/g/os/gview/gview.go b/g/os/gview/gview.go index 7a16c80d6..011024b2d 100644 --- a/g/os/gview/gview.go +++ b/g/os/gview/gview.go @@ -9,6 +9,7 @@ package gview import ( "gitee.com/johng/gf/g/encoding/gurl" + "gitee.com/johng/gf/g/os/glog" "gitee.com/johng/gf/g/os/gtime" "gitee.com/johng/gf/g/util/gstr" "strings" @@ -70,14 +71,13 @@ func Get(path string) *View { // 生成一个视图对象 func New(path string) *View { - s := gspath.New() - s.Set(path) view := &View { - paths : s, + paths : gspath.New(), data : make(map[string]interface{}), funcmap : make(map[string]interface{}), delimiters : make([]string, 2), } + view.SetPath(path) view.SetDelimiters("{{", "}}") // 内置方法 view.BindFunc("text", view.funcText) @@ -98,12 +98,24 @@ func New(path string) *View { // 设置模板目录绝对路径 func (view *View) SetPath(path string) error { - return view.paths.Set(path) + if rp, err := view.paths.Set(path); err != nil { + glog.Error("gview.SetPath failed:", err.Error()) + return err + } else { + glog.Debug("gview.SetPath:", rp) + } + return nil } // 添加模板目录搜索路径 func (view *View) AddPath(path string) error { - return view.paths.Add(path) + if rp, err := view.paths.Add(path); err != nil { + glog.Error("gview.AddPath failed:", err.Error()) + return err + } else { + glog.Debug("gview.SetPath:", rp) + } + return nil } // 批量绑定模板变量,即调用之后每个线程都会生效,因此有并发安全控制 diff --git a/g/util/gregex/gregex.go b/g/util/gregex/gregex.go index 73d92ae88..c6c74ebbc 100644 --- a/g/util/gregex/gregex.go +++ b/g/util/gregex/gregex.go @@ -8,12 +8,12 @@ package gregex import ( + "gitee.com/johng/gf/g/container/gmap" "regexp" - "gitee.com/johng/gf/g/os/gcache" ) // 缓存对象,主要用于缓存底层regx对象 -var regxCache = gcache.New() +var regxCache = gmap.NewStringInterfaceMap(true) // 根据pattern生成对应的regexp正则对象 func getRegexp(pattern string) (*regexp.Regexp, error) { @@ -21,7 +21,7 @@ func getRegexp(pattern string) (*regexp.Regexp, error) { return v.(*regexp.Regexp), nil } if r, err := regexp.Compile(pattern); err == nil { - regxCache.Set(pattern, r, 0) + regxCache.Set(pattern, r) return r, nil } else { return nil, err diff --git a/geg/other/test2.go b/geg/other/test2.go index d51d46561..e2811e825 100644 --- a/geg/other/test2.go +++ b/geg/other/test2.go @@ -1,10 +1,20 @@ package main import ( - "fmt" - "gitee.com/johng/gf/g/os/gfile" + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/net/ghttp" ) + func main() { - fmt.Println(gfile.Dir("c:\111\222")) + s := g.Server() + s.Domain("www.a.com").BindHandler("/*", func(r *ghttp.Request) { + r.Response.ServeFile("/home/john/www1" + r.URL.Path) + }) + s.Domain("www.b.com").BindHandler("/*", func(r *ghttp.Request) { + r.Response.ServeFile("/home/john/www2" + r.URL.Path) + }) + s.SetIndexFolder(true) + s.SetPort(8080) + s.Run() } \ No newline at end of file From 4bbaf6db1bef9ddbfc85e2c65dbd5f3bfe6ec2fd Mon Sep 17 00:00:00 2001 From: john Date: Wed, 31 Oct 2018 09:14:52 +0800 Subject: [PATCH 2/9] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgconv.Struct=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E9=BB=98=E8=AE=A4=E8=A7=84=E5=88=99=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=8D=E5=8C=BA=E5=88=86=E5=A4=A7=E5=B0=8F=E5=86=99?= =?UTF-8?q?=E7=9A=84=E9=94=AE=E5=90=8D=E4=B8=8E=E5=B1=9E=E6=80=A7=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 1 - g/util/gconv/gconv_struct.go | 50 ++++++++++++++++++++++++--------- g/util/gstr/gstr.go | 10 +++++++ geg/util/gconv/gconv_struct1.go | 12 ++++---- geg/util/gconv/gconv_struct2.go | 35 +++++++++++------------ geg/util/gconv/gconv_struct3.go | 21 +++++++------- geg/util/gconv/gconv_struct4.go | 4 +-- geg/util/gconv/gconv_struct5.go | 14 +++------ geg/util/gconv/gconv_struct6.go | 38 +++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 62 deletions(-) create mode 100644 geg/util/gconv/gconv_struct6.go diff --git a/TODO b/TODO index 740646c93..ae76a2dcc 100644 --- a/TODO +++ b/TODO @@ -43,7 +43,6 @@ ghttp hook回调使用方式在注册路由比较多的时候,优先级可能 gform参考 https://gohouse.github.io/gorose/dist/index.html 进行改进 完善配置管理章节,说明默认的配置文件更改方式; 完善gform配置管理说明,g.DB/Database和gdb.New的区别; -改进gconv.Struct方法,支持不区分大小写的属性-键名匹配,便于开发者执行对象转换; diff --git a/g/util/gconv/gconv_struct.go b/g/util/gconv/gconv_struct.go index 2ed0e0819..24ad7c9c6 100644 --- a/g/util/gconv/gconv_struct.go +++ b/g/util/gconv/gconv_struct.go @@ -7,6 +7,7 @@ package gconv import ( + "gitee.com/johng/gf/g/container/gset" "gitee.com/johng/gf/g/util/gstr" "reflect" "gitee.com/johng/gf/third/github.com/fatih/structs" @@ -83,16 +84,38 @@ func Struct(params interface{}, objPointer interface{}, attrMapping...map[string } } // 最后按照默认规则进行匹配 + attrset := gset.NewStringSet(false) + elemtype := elem.Type() + for i := 0; i < elem.NumField(); i++ { + attrset.Add(elemtype.Field(i).Name) + } for mapk, mapv := range paramsMap { - name := gstr.UcFirst(mapk) - if _, ok := dmap[name]; ok { + name := "" + for _, v := range []string{gstr.UcFirst(mapk), gstr.ToLower(mapk), gstr.ToUpper(mapk)} { + if _, ok := dmap[v]; ok { + continue + } + if _, ok := tagmap[v]; ok { + continue + } + // 循环查找属性名称进行匹配 + attrset.Iterator(func(value string) bool { + if strings.EqualFold(value, v) { + name = value + return false + } + return true + }) + if name != "" { + break + } + } + // 如果没有匹配到属性名称,放弃 + if name == "" { continue } - // 后续tag逻辑中会处理的key(重复的键名)这里便不处理 - if _, ok := tagmap[mapk]; !ok { - if err := bindVarToStruct(elem, name, mapv); err != nil { - return err - } + if err := bindVarToStruct(elem, name, mapv); err != nil { + return err } } return nil @@ -120,7 +143,7 @@ func getTagMapOfStruct(objPointer interface{}) map[string]string { } // 将参数值绑定到对象指定名称的属性上 -func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { +func bindVarToStruct(elem reflect.Value, name string, value interface{}) (err error) { structFieldValue := elem.FieldByName(name) // 键名与对象属性匹配检测,map中如果有struct不存在的属性,那么不做处理,直接return if !structFieldValue.IsValid() { @@ -136,7 +159,7 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { defer func() { // 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换 if recover() != nil { - bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) + err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) } }() structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) @@ -144,7 +167,7 @@ func bindVarToStruct(elem reflect.Value, name string, value interface{}) error { } // 将参数值绑定到对象指定索引位置的属性上 -func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) error { +func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) (err error) { structFieldValue := elem.FieldByIndex([]int{index}) // 键名与对象属性匹配检测 if !structFieldValue.IsValid() { @@ -160,7 +183,7 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) er defer func() { // 如果转换失败,那么可能是类型不匹配造成(例如属性包含自定义类型),那么执行递归转换 if recover() != nil { - bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) + err = bindVarToStructIfDefaultConvertionFailed(structFieldValue, value) } }() structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) @@ -168,7 +191,7 @@ func bindVarToStructByIndex(elem reflect.Value, index int, value interface{}) er } // 当默认的基本类型转换失败时,通过recover判断后执行反射类型转换 -func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, value interface{}) { +func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, value interface{}) error { switch structFieldValue.Kind() { case reflect.Struct: Struct(value, structFieldValue) @@ -190,7 +213,8 @@ func bindVarToStructIfDefaultConvertionFailed(structFieldValue reflect.Value, va } structFieldValue.Set(a) default: - panic(errors.New(fmt.Sprintf(`cannot convert to type "%s"`, structFieldValue.Type().String()))) + return errors.New(fmt.Sprintf(`cannot convert to type "%s"`, structFieldValue.Type().String())) } + return nil } diff --git a/g/util/gstr/gstr.go b/g/util/gstr/gstr.go index eeb46a7da..dd788afe1 100644 --- a/g/util/gstr/gstr.go +++ b/g/util/gstr/gstr.go @@ -23,6 +23,16 @@ func ReplaceByMap(origin string, replaces map[string]string) string { return result } +// 字符串转换为小写 +func ToLower(s string) string { + return strings.ToLower(s) +} + +// 字符串转换为大写 +func ToUpper(s string) string { + return strings.ToUpper(s) +} + // 字符串首字母转换为大写 func UcFirst(s string) string { if len(s) == 0 { diff --git a/geg/util/gconv/gconv_struct1.go b/geg/util/gconv/gconv_struct1.go index 2e6a971e7..1b2906560 100644 --- a/geg/util/gconv/gconv_struct1.go +++ b/geg/util/gconv/gconv_struct1.go @@ -16,13 +16,13 @@ type User struct { func main() { user := (*User)(nil) - // 使用map直接映射绑定属性值到对象 + // 使用默认映射规则绑定属性值到对象 user = new(User) params1 := g.Map{ "uid" : 1, - "name" : "john", - "pass1" : "123", - "pass2" : "123", + "Name" : "john", + "PASS1" : "123", + "PASS2" : "456", } if err := gconv.Struct(params1, user); err == nil { fmt.Println(user) @@ -33,8 +33,8 @@ func main() { params2 := g.Map { "uid" : 2, "name" : "smith", - "password1" : "456", - "password2" : "456", + "password1" : "111", + "password2" : "222", } if err := gconv.Struct(params2, user); err == nil { fmt.Println(user) diff --git a/geg/util/gconv/gconv_struct2.go b/geg/util/gconv/gconv_struct2.go index 0b3bf6132..c9ad3a369 100644 --- a/geg/util/gconv/gconv_struct2.go +++ b/geg/util/gconv/gconv_struct2.go @@ -1,31 +1,28 @@ package main import ( - "gitee.com/johng/gf/g/util/gconv" - "gitee.com/johng/gf/g" "fmt" + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/util/gconv" ) -// 演示slice类型属性的赋值 + +// 使用默认映射规则绑定属性值到对象 func main() { type User struct { - Scores []int + Uid int + Name string + Pass1 string + Pass2 string } - - user := new(User) - scores := []interface{}{99, 100, 60, 140} - - // 通过map映射转换 - if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil { - fmt.Println(err) - } else { - g.Dump(user) + user := new(User) + params := g.Map { + "uid" : 1, + "Name" : "john", + "PASS1" : "123", + "PASS2" : "456", } - - // 通过变量映射转换,直接slice赋值 - if err := gconv.Struct(scores, user); err != nil { - fmt.Println(err) - } else { - g.Dump(user) + if err := gconv.Struct(params, user); err == nil { + fmt.Println(user) } } \ No newline at end of file diff --git a/geg/util/gconv/gconv_struct3.go b/geg/util/gconv/gconv_struct3.go index 797ce13db..0b3bf6132 100644 --- a/geg/util/gconv/gconv_struct3.go +++ b/geg/util/gconv/gconv_struct3.go @@ -6,24 +6,23 @@ import ( "fmt" ) +// 演示slice类型属性的赋值 func main() { - type Score struct { - Name string - Result int - } type User struct { - Scores Score + Scores []int } user := new(User) - scores := map[string]interface{}{ - "Scores" : map[string]interface{}{ - "Name" : "john", - "Result" : 100, - }, + scores := []interface{}{99, 100, 60, 140} + + // 通过map映射转换 + if err := gconv.Struct(g.Map{"Scores" : scores}, user); err != nil { + fmt.Println(err) + } else { + g.Dump(user) } - // 嵌套struct转换 + // 通过变量映射转换,直接slice赋值 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct4.go b/geg/util/gconv/gconv_struct4.go index 99dcb221b..797ce13db 100644 --- a/geg/util/gconv/gconv_struct4.go +++ b/geg/util/gconv/gconv_struct4.go @@ -12,7 +12,7 @@ func main() { Result int } type User struct { - Scores []Score + Scores Score } user := new(User) @@ -23,7 +23,7 @@ func main() { }, } - // 嵌套struct转换,属性为slice类型,数值为map类型 + // 嵌套struct转换 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct5.go b/geg/util/gconv/gconv_struct5.go index 5e31d47e7..99dcb221b 100644 --- a/geg/util/gconv/gconv_struct5.go +++ b/geg/util/gconv/gconv_struct5.go @@ -17,19 +17,13 @@ func main() { user := new(User) scores := map[string]interface{}{ - "Scores" : []interface{}{ - map[string]interface{}{ - "Name" : "john", - "Result" : 100, - }, - map[string]interface{}{ - "Name" : "smith", - "Result" : 60, - }, + "Scores" : map[string]interface{}{ + "Name" : "john", + "Result" : 100, }, } - // 嵌套struct转换,属性为slice类型,数值为slice map类型 + // 嵌套struct转换,属性为slice类型,数值为map类型 if err := gconv.Struct(scores, user); err != nil { fmt.Println(err) } else { diff --git a/geg/util/gconv/gconv_struct6.go b/geg/util/gconv/gconv_struct6.go new file mode 100644 index 000000000..5e31d47e7 --- /dev/null +++ b/geg/util/gconv/gconv_struct6.go @@ -0,0 +1,38 @@ +package main + +import ( + "gitee.com/johng/gf/g/util/gconv" + "gitee.com/johng/gf/g" + "fmt" +) + +func main() { + type Score struct { + Name string + Result int + } + type User struct { + Scores []Score + } + + user := new(User) + scores := map[string]interface{}{ + "Scores" : []interface{}{ + map[string]interface{}{ + "Name" : "john", + "Result" : 100, + }, + map[string]interface{}{ + "Name" : "smith", + "Result" : 60, + }, + }, + } + + // 嵌套struct转换,属性为slice类型,数值为slice map类型 + if err := gconv.Struct(scores, user); err != nil { + fmt.Println(err) + } else { + g.Dump(user) + } +} \ No newline at end of file From 6e4ef6d0b5cd49ca689453cd0eef51636237de14 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 31 Oct 2018 09:15:17 +0800 Subject: [PATCH 3/9] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgconv.Struct=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E9=BB=98=E8=AE=A4=E8=A7=84=E5=88=99=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E4=B8=8D=E5=8C=BA=E5=88=86=E5=A4=A7=E5=B0=8F=E5=86=99?= =?UTF-8?q?=E7=9A=84=E9=94=AE=E5=90=8D=E4=B8=8E=E5=B1=9E=E6=80=A7=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- geg/util/gconv/gconv_struct1.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geg/util/gconv/gconv_struct1.go b/geg/util/gconv/gconv_struct1.go index 1b2906560..5481c1599 100644 --- a/geg/util/gconv/gconv_struct1.go +++ b/geg/util/gconv/gconv_struct1.go @@ -22,7 +22,7 @@ func main() { "uid" : 1, "Name" : "john", "PASS1" : "123", - "PASS2" : "456", + "PaSs2" : "456", } if err := gconv.Struct(params1, user); err == nil { fmt.Println(user) From 293cf81cf10f9f79a4758fad211052aed689d2d8 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 31 Oct 2018 09:57:37 +0800 Subject: [PATCH 4/9] =?UTF-8?q?gconv=E5=A2=9E=E5=8A=A0=E5=9F=BA=E5=87=86?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/util/gconv/gconv_test.go | 137 +++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 g/util/gconv/gconv_test.go diff --git a/g/util/gconv/gconv_test.go b/g/util/gconv/gconv_test.go new file mode 100644 index 000000000..b740eb2ff --- /dev/null +++ b/g/util/gconv/gconv_test.go @@ -0,0 +1,137 @@ +// Copyright 2017-2018 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=".*" -benchmem + +package gconv + +import ( + "testing" +) + +var value = 123456789 + +func BenchmarkString(b *testing.B) { + for i := 0; i < b.N; i++ { + String(value) + } +} + +func BenchmarkInt(b *testing.B) { + for i := 0; i < b.N; i++ { + Int(value) + } +} + +func BenchmarkInt8(b *testing.B) { + for i := 0; i < b.N; i++ { + Int8(value) + } +} + +func BenchmarkInt16(b *testing.B) { + for i := 0; i < b.N; i++ { + Int16(value) + } +} + +func BenchmarkInt32(b *testing.B) { + for i := 0; i < b.N; i++ { + Int32(value) + } +} + +func BenchmarkInt64(b *testing.B) { + for i := 0; i < b.N; i++ { + Int(value) + } +} + +func BenchmarkUint(b *testing.B) { + for i := 0; i < b.N; i++ { + Uint(value) + } +} + +func BenchmarkUint8(b *testing.B) { + for i := 0; i < b.N; i++ { + Uint8(value) + } +} + +func BenchmarkUint16(b *testing.B) { + for i := 0; i < b.N; i++ { + Uint16(value) + } +} + +func BenchmarkUint32(b *testing.B) { + for i := 0; i < b.N; i++ { + Uint32(value) + } +} + +func BenchmarkUint64(b *testing.B) { + for i := 0; i < b.N; i++ { + Uint64(value) + } +} + +func BenchmarkFloat32(b *testing.B) { + for i := 0; i < b.N; i++ { + Float32(value) + } +} + +func BenchmarkFloat64(b *testing.B) { + for i := 0; i < b.N; i++ { + Float64(value) + } +} + + +func BenchmarkTime(b *testing.B) { + for i := 0; i < b.N; i++ { + Time(value) + } +} + +func BenchmarkTimeDuration(b *testing.B) { + for i := 0; i < b.N; i++ { + TimeDuration(value) + } +} + + +func BenchmarkBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + Bytes(value) + } +} + +func BenchmarkStrings(b *testing.B) { + for i := 0; i < b.N; i++ { + Strings(value) + } +} + +func BenchmarkInts(b *testing.B) { + for i := 0; i < b.N; i++ { + Ints(value) + } +} + +func BenchmarkFloats(b *testing.B) { + for i := 0; i < b.N; i++ { + Floats(value) + } +} + +func BenchmarkInterfaces(b *testing.B) { + for i := 0; i < b.N; i++ { + Interfaces(value) + } +} \ No newline at end of file From ee9362666e85c38365afc89709956ec4d7339663 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 31 Oct 2018 16:23:31 +0800 Subject: [PATCH 5/9] =?UTF-8?q?=E8=BF=98=E5=8E=9Fglog.GetBacktrace?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=89=93=E5=8D=B0=E5=BC=80=E5=A7=8B=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/os/glog/glog_logger.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/g/os/glog/glog_logger.go b/g/os/glog/glog_logger.go index 83bd7b051..fce9a5a18 100644 --- a/g/os/glog/glog_logger.go +++ b/g/os/glog/glog_logger.go @@ -246,8 +246,19 @@ func (l *Logger) GetBacktrace(skip...int) string { } backtrace := "" index := 1 + from := 0 + // 首先定位业务文件开始位置 + for i := 0; i < 10; i++ { + if _, cfile, _, ok := runtime.Caller(i); ok { + if !gregex.IsMatchString("/g/os/glog/glog.+$", cfile) { + from = i + break + } + } + } + // 从业务文件开始位置根据自定义的skip开始backtrace goroot := runtime.GOROOT() - for i := customSkip + l.btSkip.Val(); i < 10000; i++ { + for i := from + customSkip + l.btSkip.Val(); i < 10000; i++ { if _, cfile, cline, ok := runtime.Caller(i); ok && cfile != "" { // 不打印出go源码路径及glog包文件路径,日志打印必须从业务源码文件开始,且从glog包文件开始检索 if (goroot == "" || !gregex.IsMatchString("^" + goroot, cfile)) && !gregex.IsMatchString(``, cfile) { From 371ab48d7a82647e93ea3153e426cd1d85d42a0b Mon Sep 17 00:00:00 2001 From: john Date: Wed, 31 Oct 2018 16:57:13 +0800 Subject: [PATCH 6/9] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgtime.StrToTime=E5=AF=B9?= =?UTF-8?q?=E5=B8=B8=E7=94=A8=E6=97=B6=E9=97=B4=E6=A0=BC=E5=BC=8F=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/os/gtime/gtime.go | 3 ++- geg/os/gtime/gtime_regex.go | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/g/os/gtime/gtime.go b/g/os/gtime/gtime.go index 0b8647f8e..cc1f6d619 100644 --- a/g/os/gtime/gtime.go +++ b/g/os/gtime/gtime.go @@ -25,9 +25,10 @@ const ( // "2018-02-09 20:46:17.897", // "2018-02-09T20:46:17Z", // "2018-02-09 20:46:17", + // "2018/10/31 - 16:38:46" // "2018-02-09", // 日期连接符号支持'-'或者'/' - TIME_REAGEX_PATTERN = `(\d{2,4}[-/]\d{2}[-/]\d{2})[\sT]{0,1}(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)` + TIME_REAGEX_PATTERN = `(\d{2,4}[-/]\d{2}[-/]\d{2})[\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)` ) var ( diff --git a/geg/os/gtime/gtime_regex.go b/geg/os/gtime/gtime_regex.go index 4f4463a28..03f0d51fa 100644 --- a/geg/os/gtime/gtime_regex.go +++ b/geg/os/gtime/gtime_regex.go @@ -19,6 +19,7 @@ func main() { "2018-02-09 20:46:17.897", "2018-02-09T20:46:17Z", "2018-02-09 20:46:17", + "2018/10/31 - 16:38:46", "2018-02-09", "2017/12/14 04:51:34 +0805 LMT", "2018/02/09 12:00:15", From cdd3d507b881bfaa82fad7e26aeb4a54395245df Mon Sep 17 00:00:00 2001 From: John Date: Wed, 31 Oct 2018 22:39:58 +0800 Subject: [PATCH 7/9] =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E6=97=B6=E5=A2=9E=E5=8A=A0=E6=96=B9=E6=B3=95=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=9B=E6=A8=A1=E6=9D=BF=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0strlimit/hidestr/highlight/toupper/tolower/nl?= =?UTF-8?q?2br=E5=86=85=E7=BD=AE=E6=A8=A1=E6=9D=BF=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/net/ghttp/ghttp_server.go | 2 +- .../ghttp/ghttp_server_service_controller.go | 22 ++++++- g/net/ghttp/ghttp_server_service_object.go | 30 +++++++-- g/os/gview/gview.go | 49 +++++++++++---- g/util/gstr/gstr.go | 61 ++++++++++++++++++- geg/net/ghttp/server/controller/user.go | 9 ++- geg/net/ghttp/server/object/user.go | 31 ++++++++++ geg/os/gview/build_in_funcs/build_in_funcs.go | 7 +++ geg/util/gstr/gstr_hidestr.go | 11 ++++ 9 files changed, 199 insertions(+), 23 deletions(-) create mode 100644 geg/net/ghttp/server/object/user.go create mode 100644 geg/util/gstr/gstr_hidestr.go diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 2a4979588..954864822 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -276,7 +276,7 @@ func (s *Server) Start() error { // 打印展示路由表 func (s *Server) DumpRoutesMap() { - if s.config.DumpRouteMap { + if s.config.DumpRouteMap && len(s.routesMap) > 0 { // (等待一定时间后)当所有框架初始化信息打印完毕之后才打印路由表信息 gtime.SetTimeout(50*time.Millisecond, func() { glog.Header(false).Println(fmt.Sprintf("\n%s\n", s.GetRouteMap())) diff --git a/g/net/ghttp/ghttp_server_service_controller.go b/g/net/ghttp/ghttp_server_service_controller.go index 4455f4697..2580c7428 100644 --- a/g/net/ghttp/ghttp_server_service_controller.go +++ b/g/net/ghttp/ghttp_server_service_controller.go @@ -9,6 +9,7 @@ package ghttp import ( "errors" + "gitee.com/johng/gf/g/os/glog" "strings" "reflect" "fmt" @@ -42,6 +43,14 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e if mname == "Init" || mname == "Shut" || mname == "Exit" { continue } + if _, ok := v.Method(i).Interface().(func()); !ok { + if methodMap != nil { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) + glog.Warning(s) + return errors.New(s) + } + continue + } ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") if ctlName[0] == '*' { ctlName = fmt.Sprintf(`(%s)`, ctlName) @@ -82,9 +91,15 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string t := v.Type() sname := t.Elem().Name() mname := strings.TrimSpace(method) - if !v.MethodByName(mname).IsValid() { + fval := v.MethodByName(mname) + if !fval.IsValid() { return errors.New("invalid method name:" + mname) } + if _, ok := fval.Interface().(func()); !ok { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, fval.Type().String()) + glog.Warning(s) + return errors.New(s) + } pkgPath := t.Elem().PkgPath() pkgName := gfile.Basename(pkgPath) ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") @@ -119,6 +134,11 @@ func (s *Server)BindControllerRest(pattern string, c Controller) error { if _, ok := s.methodsMap[method]; !ok { continue } + if _, ok := v.Method(i).Interface().(func()); !ok { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) + glog.Warning(s) + return errors.New(s) + } pkgName := gfile.Basename(pkgPath) ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") if ctlName[0] == '*' { diff --git a/g/net/ghttp/ghttp_server_service_object.go b/g/net/ghttp/ghttp_server_service_object.go index 8603ab6f1..58e3cf246 100644 --- a/g/net/ghttp/ghttp_server_service_object.go +++ b/g/net/ghttp/ghttp_server_service_object.go @@ -9,6 +9,7 @@ package ghttp import ( "errors" + "gitee.com/johng/gf/g/os/glog" "strings" "reflect" "fmt" @@ -48,6 +49,15 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er if mname == "Init" || mname == "Shut" { continue } + faddr, ok := v.Method(i).Interface().(func(*Request)) + if !ok { + if methodMap != nil { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func(*Request))" is required`, v.Method(i).Type().String()) + glog.Warning(s) + return errors.New(s) + } + continue + } objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") if objName[0] == '*' { objName = fmt.Sprintf(`(%s)`, objName) @@ -58,7 +68,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", - faddr : v.Method(i).Interface().(func(*Request)), + faddr : faddr, finit : finit, fshut : fshut, } @@ -76,7 +86,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", - faddr : v.Method(i).Interface().(func(*Request)), + faddr : faddr, finit : finit, fshut : fshut, } @@ -97,6 +107,12 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string) if !fval.IsValid() { return errors.New("invalid method name:" + mname) } + faddr, ok := fval.Interface().(func(*Request)) + if !ok { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func(*Request)" is required`, fval.Type().String()) + glog.Warning(s) + return errors.New(s) + } finit := (func(*Request))(nil) fshut := (func(*Request))(nil) if v.MethodByName("Init").IsValid() { @@ -117,7 +133,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string) rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", - faddr : fval.Interface().(func(*Request)), + faddr : faddr, finit : finit, fshut : fshut, } @@ -146,6 +162,12 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) error { if _, ok := s.methodsMap[method]; !ok { continue } + faddr, ok := v.Method(i).Interface().(func(*Request)) + if !ok { + s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) + glog.Warning(s) + return errors.New(s) + } pkgName := gfile.Basename(pkgPath) objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") if objName[0] == '*' { @@ -157,7 +179,7 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) error { rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", - faddr : v.Method(i).Interface().(func(*Request)), + faddr : faddr, finit : finit, fshut : fshut, } diff --git a/g/os/gview/gview.go b/g/os/gview/gview.go index 011024b2d..76852c9cf 100644 --- a/g/os/gview/gview.go +++ b/g/os/gview/gview.go @@ -8,6 +8,7 @@ package gview import ( + "fmt" "gitee.com/johng/gf/g/encoding/gurl" "gitee.com/johng/gf/g/os/glog" "gitee.com/johng/gf/g/os/gtime" @@ -84,14 +85,18 @@ func New(path string) *View { view.BindFunc("html", view.funcHtmlEncode) view.BindFunc("htmlencode", view.funcHtmlEncode) view.BindFunc("htmldecode", view.funcHtmlDecode) - //view.BindFunc("htmlchars", view.funcHtmlChars) - //view.BindFunc("htmldechars", view.funcHtmlCharsDecode) view.BindFunc("url", view.funcUrlEncode) view.BindFunc("urlencode", view.funcUrlEncode) view.BindFunc("urldecode", view.funcUrlDecode) view.BindFunc("date", view.funcDate) view.BindFunc("substr", view.funcSubStr) + view.BindFunc("strlimit", view.funcStrLimit) view.BindFunc("compare", view.funcCompare) + view.BindFunc("hidestr", view.funcHideStr) + view.BindFunc("highlight", view.funcHighlight) + view.BindFunc("toupper", view.funcToUpper) + view.BindFunc("tolower", view.funcToLower) + view.BindFunc("nl2br", view.funcNl2Br) view.BindFunc("include", view.funcInclude) return view } @@ -256,16 +261,6 @@ func (view *View) funcHtmlDecode(html interface{}) string { return ghtml.EntitiesDecode(gconv.String(html)) } -// 模板内置方法:htmlchars -func (view *View) funcHtmlChars(html interface{}) string { - return ghtml.SpecialChars(gconv.String(html)) -} - -// 模板内置方法:htmlcharsdecode -func (view *View) funcHtmlCharsDecode(html interface{}) string { - return ghtml.SpecialCharsDecode(gconv.String(html)) -} - // 模板内置方法:url func (view *View) funcUrlEncode(url interface{}) string { return gurl.Encode(gconv.String(url)) @@ -295,4 +290,34 @@ func (view *View) funcSubStr(start, end int, str interface{}) string { return gstr.SubStr(gconv.String(str), start, end) } +// 模板内置方法:strlimit +func (view *View) funcStrLimit(length int, suffix string, str interface{}) string { + return gstr.StrLimit(gconv.String(str), length, suffix) +} + +// 模板内置方法:highlight +func (view *View) funcHighlight(key string, color string, str interface{}) string { + return gstr.Replace(gconv.String(str), key, fmt.Sprintf(`%s`, color, key)) +} + +// 模板内置方法:hidestr +func (view *View) funcHideStr(percent int, hide string, str interface{}) string { + return gstr.HideStr(gconv.String(str), percent, hide) +} + +// 模板内置方法:toupper +func (view *View) funcToUpper(str interface{}) string { + return gstr.ToUpper(gconv.String(str)) +} + +// 模板内置方法:toupper +func (view *View) funcToLower(str interface{}) string { + return gstr.ToLower(gconv.String(str)) +} + +// 模板内置方法:nl2br +func (view *View) funcNl2Br(str interface{}) string { + return gstr.Nl2Br(gconv.String(str)) +} + diff --git a/g/util/gstr/gstr.go b/g/util/gstr/gstr.go index dd788afe1..8decd74ba 100644 --- a/g/util/gstr/gstr.go +++ b/g/util/gstr/gstr.go @@ -7,11 +7,19 @@ // 字符串操作. package gstr -import "strings" +import ( + "bytes" + "math" + "strings" +) // 字符串替换 -func Replace(origin, search, replace string) string { - return strings.Replace(origin, search, replace, -1) +func Replace(origin, search, replace string, count...int) string { + n := -1 + if len(count) > 0 { + n = count[0] + } + return strings.Replace(origin, search, replace, n) } // 使用map进行字符串替换 @@ -120,4 +128,51 @@ func SubStr(str string, start int, length...int) (substr string) { } // 返回子串 return string(rs[start : end]) +} + +// 字符串长度截取限制,超过长度限制被截取并在字符串末尾追加指定的内容,支持中文 +func StrLimit(str string, length int, suffix...string) (string) { + rs := []rune(str) + if len(str) < length { + return str + } + addstr := "..." + if len(suffix) > 0 { + addstr = suffix[0] + } + return string(rs[0 : length]) + addstr +} + +// 按照百分比从字符串中间向两边隐藏字符(主要用于姓名、手机号、邮箱地址、身份证号等的隐藏),支持utf-8中文,支持email格式。 +func HideStr(str string, percent int, hide string) string { + array := strings.Split(str, "@") + if len(array) > 1 { + str = array[0] + } + rs := []rune(str) + length := len(rs) + mid := math.Floor(float64(length/2)) + hideLen := int(math.Floor(float64(length) * (float64(percent)/100))) + start := int(mid - math.Floor(float64(hideLen) / 2)) + hideStr := []rune("") + hideRune := []rune(hide) + for i := 0; i < int(hideLen); i++ { + hideStr = append(hideStr, hideRune...) + } + buffer := bytes.NewBuffer(nil) + buffer.WriteString(string(rs[0 : start])) + buffer.WriteString(string(hideStr)) + buffer.WriteString(string(rs[start + hideLen : ])) + if len(array) > 1 { + buffer.WriteString(array[1]) + } + return buffer.String() +} + +// 将\n\r替换为html中的
标签。 +func Nl2Br(str string) string { + str = Replace(str, "\r\n", "\n") + str = Replace(str, "\n\r", "\n") + str = Replace(str, "\n", "
") + return str } \ No newline at end of file diff --git a/geg/net/ghttp/server/controller/user.go b/geg/net/ghttp/server/controller/user.go index f0283ec90..50db001c9 100644 --- a/geg/net/ghttp/server/controller/user.go +++ b/geg/net/ghttp/server/controller/user.go @@ -1,8 +1,8 @@ package main import ( - "gitee.com/johng/gf/g/frame/gmvc" "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/frame/gmvc" ) type User struct { @@ -13,8 +13,13 @@ func (c *User) Index() { c.View.Display("index.html") } +// 不符合规范,不会被自动注册 +func (c *User) Test(value interface{}) { + c.View.Display("index.html") +} + func main() { - g.View().SetPath("C:/www/static") + //g.View().SetPath("C:/www/static") s := g.Server() s.BindController("/user", new(User)) s.SetPort(8199) diff --git a/geg/net/ghttp/server/object/user.go b/geg/net/ghttp/server/object/user.go new file mode 100644 index 000000000..cd39824c8 --- /dev/null +++ b/geg/net/ghttp/server/object/user.go @@ -0,0 +1,31 @@ +package main + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/net/ghttp" +) + +type User struct { + +} + +func (c *User) Index(r *ghttp.Request) { + r.Response.Write("Index") +} + +// 不符合规范,不会被注册 +func (c *User) Test(r *ghttp.Request, value interface{}) { + r.Response.Write("Test") +} + +func main() { + s := g.Server() + s.BindObjectMethod("/user", new(User), "Test") + s.SetPort(8199) + s.Run() +} + + + + + diff --git a/geg/os/gview/build_in_funcs/build_in_funcs.go b/geg/os/gview/build_in_funcs/build_in_funcs.go index 462b8d763..d39c683dd 100644 --- a/geg/os/gview/build_in_funcs/build_in_funcs.go +++ b/geg/os/gview/build_in_funcs/build_in_funcs.go @@ -20,6 +20,13 @@ func main() { {{compare 1 1}} {{"我是中国人" | substr 2 -1}} {{"我是中国人" | substr 2 2}} +{{"我是中国人" | strlimit 2 "..."}} +{{"热爱GF热爱生活" | hidestr 20 "*"}} +{{"热爱GF热爱生活" | hidestr 50 "*"}} +{{"热爱GF热爱生活" | highlight "GF" "red"}} +{{"gf" | toupper}} +{{"GF" | tolower}} +{{"Go\nFrame" | nl2br}} ` content, err := g.View().ParseContent(tplContent, nil) fmt.Println(err) diff --git a/geg/util/gstr/gstr_hidestr.go b/geg/util/gstr/gstr_hidestr.go new file mode 100644 index 000000000..3cc38d4f2 --- /dev/null +++ b/geg/util/gstr/gstr_hidestr.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + "gitee.com/johng/gf/g/util/gstr" +) + +func main() { + fmt.Println(gstr.HideStr("热爱GF热爱生活", 20, "*")) + fmt.Println(gstr.HideStr("热爱GF热爱生活", 50, "*")) +} From 35fa199c5ae20695f11cc751614e1be619d2a54d Mon Sep 17 00:00:00 2001 From: john Date: Thu, 1 Nov 2018 08:37:23 +0800 Subject: [PATCH 8/9] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=97=B6=E4=B8=8D=E7=AC=A6=E5=90=88=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AE=9A=E4=B9=89=E7=9A=84=E9=94=99=E8=AF=AF=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=96=B9=E5=BC=8F:=20glog.Warning->glog.Error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/net/ghttp/ghttp_server_service_controller.go | 6 +++--- g/net/ghttp/ghttp_server_service_object.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/g/net/ghttp/ghttp_server_service_controller.go b/g/net/ghttp/ghttp_server_service_controller.go index 2580c7428..e20fddb94 100644 --- a/g/net/ghttp/ghttp_server_service_controller.go +++ b/g/net/ghttp/ghttp_server_service_controller.go @@ -46,7 +46,7 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e if _, ok := v.Method(i).Interface().(func()); !ok { if methodMap != nil { s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } continue @@ -97,7 +97,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string } if _, ok := fval.Interface().(func()); !ok { s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, fval.Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } pkgPath := t.Elem().PkgPath() @@ -136,7 +136,7 @@ func (s *Server)BindControllerRest(pattern string, c Controller) error { } if _, ok := v.Method(i).Interface().(func()); !ok { s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } pkgName := gfile.Basename(pkgPath) diff --git a/g/net/ghttp/ghttp_server_service_object.go b/g/net/ghttp/ghttp_server_service_object.go index 58e3cf246..ef64df4a1 100644 --- a/g/net/ghttp/ghttp_server_service_object.go +++ b/g/net/ghttp/ghttp_server_service_object.go @@ -53,7 +53,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er if !ok { if methodMap != nil { s := fmt.Sprintf(`invalid medthod definition "%s", while "func(*Request))" is required`, v.Method(i).Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } continue @@ -110,7 +110,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string) faddr, ok := fval.Interface().(func(*Request)) if !ok { s := fmt.Sprintf(`invalid medthod definition "%s", while "func(*Request)" is required`, fval.Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } finit := (func(*Request))(nil) @@ -165,7 +165,7 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) error { faddr, ok := v.Method(i).Interface().(func(*Request)) if !ok { s := fmt.Sprintf(`invalid medthod definition "%s", while "func()" is required`, v.Method(i).Type().String()) - glog.Warning(s) + glog.Error(s) return errors.New(s) } pkgName := gfile.Basename(pkgPath) From 7a6dbf159ca7456412a73bbee320422fded452de Mon Sep 17 00:00:00 2001 From: john Date: Thu, 1 Nov 2018 08:44:06 +0800 Subject: [PATCH 9/9] README updates --- README.MD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.MD b/README.MD index f4c4c887b..4f1d1f23c 100644 --- a/README.MD +++ b/README.MD @@ -36,10 +36,10 @@ golang版本 >= 1.9.2 1. 提供了对基本数据类型的并发安全封装,提供了常用的数据结构容器; 1. 支持Go变量/Json/Xml/Yml/Toml任意数据格式之间的相互转换及创建; 1. 强大的数据库ORM,支持应用层级的集群管理、读写分离、负载均衡,查询缓存、方法及链式ORM操作; -1. 更多特点请查阅框架[手册](http://gf.johng.cn)和[源码](https://godoc.org/github.com/johng-cn/gf); +1. 更多特点请查阅框架[手册](https://gfer.me)和[源码](https://godoc.org/github.com/johng-cn/gf); # 文档 -GoFrame开发文档:[http://gf.johng.cn](http://gf.johng.cn) +GoFrame开发文档:[gfer.me](https://gfer.me) # 使用 @@ -178,4 +178,4 @@ if tx, err := db.Begin(); err == nil { ... -更多特性及示例请查看官方开发文档:[gf.johng.cn](http://gf.johng.cn) +更多特性及示例请查看官方开发文档:[gfer.me](https://gfer.me)