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  }