github.com/zhongdalu/gf@v1.0.0/g/net/ghttp/ghttp_server_service_object.go (about) 1 // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 // 服务注册. 7 8 package ghttp 9 10 import ( 11 "fmt" 12 "reflect" 13 "strings" 14 15 "github.com/zhongdalu/gf/g/os/gfile" 16 "github.com/zhongdalu/gf/g/os/glog" 17 "github.com/zhongdalu/gf/g/text/gregex" 18 "github.com/zhongdalu/gf/g/text/gstr" 19 ) 20 21 // 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面 22 // 第三个参数methods用以指定需要注册的方法,支持多个方法名称,多个方法以英文“,”号分隔,区分大小写 23 func (s *Server) BindObject(pattern string, obj interface{}, methods ...string) { 24 // 当pattern中的method为all时,去掉该method,以便于后续方法判断 25 domain, method, path, err := s.parsePattern(pattern) 26 if err != nil { 27 glog.Error(err) 28 return 29 } 30 if strings.EqualFold(method, gDEFAULT_METHOD) { 31 pattern = s.serveHandlerKey("", path, domain) 32 } 33 34 methodMap := (map[string]bool)(nil) 35 if len(methods) > 0 { 36 methodMap = make(map[string]bool) 37 for _, v := range strings.Split(methods[0], ",") { 38 methodMap[strings.TrimSpace(v)] = true 39 } 40 } 41 m := make(handlerMap) 42 v := reflect.ValueOf(obj) 43 t := v.Type() 44 sname := t.Elem().Name() 45 finit := (func(*Request))(nil) 46 fshut := (func(*Request))(nil) 47 if v.MethodByName("Init").IsValid() { 48 finit = v.MethodByName("Init").Interface().(func(*Request)) 49 } 50 if v.MethodByName("Shut").IsValid() { 51 fshut = v.MethodByName("Shut").Interface().(func(*Request)) 52 } 53 pkgPath := t.Elem().PkgPath() 54 pkgName := gfile.Basename(pkgPath) 55 for i := 0; i < v.NumMethod(); i++ { 56 mname := t.Method(i).Name 57 if methodMap != nil && !methodMap[mname] { 58 continue 59 } 60 if mname == "Init" || mname == "Shut" { 61 continue 62 } 63 objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") 64 if objName[0] == '*' { 65 objName = fmt.Sprintf(`(%s)`, objName) 66 } 67 faddr, ok := v.Method(i).Interface().(func(*Request)) 68 if !ok { 69 if len(methodMap) > 0 { 70 // 指定的方法名称注册,那么需要使用错误提示 71 glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`, 72 pkgPath, objName, mname, v.Method(i).Type().String()) 73 } else { 74 // 否则只是Debug提示 75 glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`, 76 pkgPath, objName, mname, v.Method(i).Type().String()) 77 } 78 continue 79 } 80 key := s.mergeBuildInNameToPattern(pattern, sname, mname, true) 81 m[key] = &handlerItem{ 82 name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname), 83 rtype: gROUTE_REGISTER_OBJECT, 84 ctype: nil, 85 fname: "", 86 faddr: faddr, 87 finit: finit, 88 fshut: fshut, 89 } 90 // 如果方法中带有Index方法,那么额外自动增加一个路由规则匹配主URI。 91 // 注意,当pattern带有内置变量时,不会自动加该路由。 92 if strings.EqualFold(mname, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) { 93 p := gstr.PosR(key, "/index") 94 k := key[0:p] + key[p+6:] 95 if len(k) == 0 || k[0] == '@' { 96 k = "/" + k 97 } 98 m[k] = &handlerItem{ 99 name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname), 100 rtype: gROUTE_REGISTER_OBJECT, 101 ctype: nil, 102 fname: "", 103 faddr: faddr, 104 finit: finit, 105 fshut: fshut, 106 } 107 } 108 } 109 s.bindHandlerByMap(m) 110 } 111 112 // 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面, 113 // 第三个参数method仅支持一个方法注册,不支持多个,并且区分大小写。 114 func (s *Server) BindObjectMethod(pattern string, obj interface{}, method string) { 115 m := make(handlerMap) 116 v := reflect.ValueOf(obj) 117 t := v.Type() 118 sname := t.Elem().Name() 119 mname := strings.TrimSpace(method) 120 fval := v.MethodByName(mname) 121 if !fval.IsValid() { 122 glog.Error("invalid method name:" + mname) 123 return 124 } 125 finit := (func(*Request))(nil) 126 fshut := (func(*Request))(nil) 127 if v.MethodByName("Init").IsValid() { 128 finit = v.MethodByName("Init").Interface().(func(*Request)) 129 } 130 if v.MethodByName("Shut").IsValid() { 131 fshut = v.MethodByName("Shut").Interface().(func(*Request)) 132 } 133 pkgPath := t.Elem().PkgPath() 134 pkgName := gfile.Basename(pkgPath) 135 objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") 136 if objName[0] == '*' { 137 objName = fmt.Sprintf(`(%s)`, objName) 138 } 139 faddr, ok := fval.Interface().(func(*Request)) 140 if !ok { 141 glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`, 142 pkgPath, objName, mname, fval.Type().String()) 143 return 144 } 145 key := s.mergeBuildInNameToPattern(pattern, sname, mname, false) 146 m[key] = &handlerItem{ 147 name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname), 148 rtype: gROUTE_REGISTER_OBJECT, 149 ctype: nil, 150 fname: "", 151 faddr: faddr, 152 finit: finit, 153 fshut: fshut, 154 } 155 156 s.bindHandlerByMap(m) 157 } 158 159 // 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面, 160 // 需要注意对象方法的定义必须按照 ghttp.HandlerFunc 来定义 161 func (s *Server) BindObjectRest(pattern string, obj interface{}) { 162 m := make(handlerMap) 163 v := reflect.ValueOf(obj) 164 t := v.Type() 165 sname := t.Elem().Name() 166 finit := (func(*Request))(nil) 167 fshut := (func(*Request))(nil) 168 if v.MethodByName("Init").IsValid() { 169 finit = v.MethodByName("Init").Interface().(func(*Request)) 170 } 171 if v.MethodByName("Shut").IsValid() { 172 fshut = v.MethodByName("Shut").Interface().(func(*Request)) 173 } 174 pkgPath := t.Elem().PkgPath() 175 for i := 0; i < v.NumMethod(); i++ { 176 mname := t.Method(i).Name 177 method := strings.ToUpper(mname) 178 if _, ok := methodsMap[method]; !ok { 179 continue 180 } 181 pkgName := gfile.Basename(pkgPath) 182 objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "") 183 if objName[0] == '*' { 184 objName = fmt.Sprintf(`(%s)`, objName) 185 } 186 faddr, ok := v.Method(i).Interface().(func(*Request)) 187 if !ok { 188 glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`, 189 pkgPath, objName, mname, v.Method(i).Type().String()) 190 continue 191 } 192 key := s.mergeBuildInNameToPattern(mname+":"+pattern, sname, mname, false) 193 m[key] = &handlerItem{ 194 name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname), 195 rtype: gROUTE_REGISTER_OBJECT, 196 ctype: nil, 197 fname: "", 198 faddr: faddr, 199 finit: finit, 200 fshut: fshut, 201 } 202 } 203 s.bindHandlerByMap(m) 204 }