2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-07-31 21:05:02 +08:00
|
|
|
|
//
|
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-07-31 21:05:02 +08:00
|
|
|
|
|
|
|
|
|
package ghttp
|
|
|
|
|
|
|
|
|
|
import (
|
2019-06-19 09:06:52 +08:00
|
|
|
|
"fmt"
|
2019-06-25 23:03:29 +08:00
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2019-07-29 21:01:19 +08:00
|
|
|
|
"github.com/gogf/gf/os/gfile"
|
|
|
|
|
"github.com/gogf/gf/text/gregex"
|
|
|
|
|
"github.com/gogf/gf/text/gstr"
|
2018-07-31 21:05:02 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面
|
2018-08-16 21:33:47 +08:00
|
|
|
|
// 第三个参数methods用以指定需要注册的方法,支持多个方法名称,多个方法以英文“,”号分隔,区分大小写
|
2019-12-04 10:03:03 +08:00
|
|
|
|
func (s *Server) BindObject(pattern string, object interface{}, method ...string) {
|
|
|
|
|
bindMethod := ""
|
|
|
|
|
if len(method) > 0 {
|
|
|
|
|
bindMethod = method[0]
|
|
|
|
|
}
|
|
|
|
|
s.doBindObject(pattern, object, bindMethod, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面,
|
|
|
|
|
// 第三个参数method仅支持一个方法注册,不支持多个,并且区分大小写。
|
|
|
|
|
func (s *Server) BindObjectMethod(pattern string, object interface{}, method string) {
|
|
|
|
|
s.doBindObjectMethod(pattern, object, method, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面,
|
|
|
|
|
// 需要注意对象方法的定义必须按照 ghttp.HandlerFunc 来定义
|
|
|
|
|
func (s *Server) BindObjectRest(pattern string, object interface{}) {
|
|
|
|
|
s.doBindObjectRest(pattern, object, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *Server) doBindObject(pattern string, object interface{}, method string, middleware []HandlerFunc) {
|
|
|
|
|
// Convert input method to map for convenience and high performance searching.
|
|
|
|
|
var methodMap map[string]bool
|
|
|
|
|
if len(method) > 0 {
|
|
|
|
|
methodMap = make(map[string]bool)
|
|
|
|
|
for _, v := range strings.Split(method, ",") {
|
|
|
|
|
methodMap[strings.TrimSpace(v)] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-25 23:03:29 +08:00
|
|
|
|
// 当pattern中的method为all时,去掉该method,以便于后续方法判断
|
|
|
|
|
domain, method, path, err := s.parsePattern(pattern)
|
|
|
|
|
if err != nil {
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Fatal(err)
|
2019-06-25 23:03:29 +08:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if strings.EqualFold(method, gDEFAULT_METHOD) {
|
|
|
|
|
pattern = s.serveHandlerKey("", path, domain)
|
|
|
|
|
}
|
2020-01-21 17:18:03 +08:00
|
|
|
|
m := make(map[string]*handlerItem)
|
2019-12-04 10:03:03 +08:00
|
|
|
|
v := reflect.ValueOf(object)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
t := v.Type()
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc := (func(*Request))(nil)
|
|
|
|
|
shutFunc := (func(*Request))(nil)
|
2019-12-18 19:37:07 +08:00
|
|
|
|
structName := t.Elem().Name()
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if v.MethodByName("Init").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
if v.MethodByName("Shut").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
pkgPath := t.Elem().PkgPath()
|
|
|
|
|
pkgName := gfile.Basename(pkgPath)
|
|
|
|
|
for i := 0; i < v.NumMethod(); i++ {
|
2019-12-18 19:37:07 +08:00
|
|
|
|
methodName := t.Method(i).Name
|
|
|
|
|
if methodMap != nil && !methodMap[methodName] {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-18 19:37:07 +08:00
|
|
|
|
if methodName == "Init" || methodName == "Shut" {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
|
|
|
|
if objName[0] == '*' {
|
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
|
}
|
2019-08-03 15:54:12 +08:00
|
|
|
|
itemFunc, ok := v.Method(i).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if !ok {
|
|
|
|
|
if len(methodMap) > 0 {
|
|
|
|
|
// 指定的方法名称注册,那么需要使用错误提示
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
|
2019-12-18 19:37:07 +08:00
|
|
|
|
pkgPath, objName, methodName, v.Method(i).Type().String())
|
2019-06-19 09:06:52 +08:00
|
|
|
|
} else {
|
|
|
|
|
// 否则只是Debug提示
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
|
2019-12-18 19:37:07 +08:00
|
|
|
|
pkgPath, objName, methodName, v.Method(i).Type().String())
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-18 19:37:07 +08:00
|
|
|
|
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, true)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
m[key] = &handlerItem{
|
2019-12-18 19:37:07 +08:00
|
|
|
|
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2019-12-04 10:03:03 +08:00
|
|
|
|
itemType: gHANDLER_TYPE_OBJECT,
|
|
|
|
|
itemFunc: itemFunc,
|
|
|
|
|
initFunc: initFunc,
|
|
|
|
|
shutFunc: shutFunc,
|
|
|
|
|
middleware: middleware,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
// 如果方法中带有Index方法,那么额外自动增加一个路由规则匹配主URI。
|
|
|
|
|
// 注意,当pattern带有内置变量时,不会自动加该路由。
|
2019-12-18 19:37:07 +08:00
|
|
|
|
if strings.EqualFold(methodName, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
|
2019-08-30 20:29:12 +08:00
|
|
|
|
p := gstr.PosRI(key, "/index")
|
2019-06-19 09:06:52 +08:00
|
|
|
|
k := key[0:p] + key[p+6:]
|
|
|
|
|
if len(k) == 0 || k[0] == '@' {
|
|
|
|
|
k = "/" + k
|
|
|
|
|
}
|
|
|
|
|
m[k] = &handlerItem{
|
2019-12-18 19:37:07 +08:00
|
|
|
|
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2019-12-04 10:03:03 +08:00
|
|
|
|
itemType: gHANDLER_TYPE_OBJECT,
|
|
|
|
|
itemFunc: itemFunc,
|
|
|
|
|
initFunc: initFunc,
|
|
|
|
|
shutFunc: shutFunc,
|
|
|
|
|
middleware: middleware,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.bindHandlerByMap(m)
|
2018-07-31 21:05:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-06 15:21:00 +08:00
|
|
|
|
// 绑定对象到URI请求处理中,会自动识别方法名称,并附加到对应的URI地址后面,
|
|
|
|
|
// 第三个参数method仅支持一个方法注册,不支持多个,并且区分大小写。
|
2019-12-04 10:03:03 +08:00
|
|
|
|
func (s *Server) doBindObjectMethod(pattern string, object interface{}, method string, middleware []HandlerFunc) {
|
2020-01-21 17:18:03 +08:00
|
|
|
|
m := make(map[string]*handlerItem)
|
2019-12-04 10:03:03 +08:00
|
|
|
|
v := reflect.ValueOf(object)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
t := v.Type()
|
2019-12-18 19:37:07 +08:00
|
|
|
|
structName := t.Elem().Name()
|
|
|
|
|
methodName := strings.TrimSpace(method)
|
|
|
|
|
methodValue := v.MethodByName(methodName)
|
|
|
|
|
if !methodValue.IsValid() {
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Fatal("invalid method name: " + methodName)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return
|
|
|
|
|
}
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc := (func(*Request))(nil)
|
|
|
|
|
shutFunc := (func(*Request))(nil)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if v.MethodByName("Init").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
if v.MethodByName("Shut").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
pkgPath := t.Elem().PkgPath()
|
|
|
|
|
pkgName := gfile.Basename(pkgPath)
|
|
|
|
|
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
|
|
|
|
if objName[0] == '*' {
|
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
|
}
|
2019-12-18 19:37:07 +08:00
|
|
|
|
itemFunc, ok := methodValue.Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if !ok {
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
|
2019-12-18 19:37:07 +08:00
|
|
|
|
pkgPath, objName, methodName, methodValue.Type().String())
|
2019-06-19 09:06:52 +08:00
|
|
|
|
return
|
|
|
|
|
}
|
2019-12-18 19:37:07 +08:00
|
|
|
|
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, false)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
m[key] = &handlerItem{
|
2019-12-18 19:37:07 +08:00
|
|
|
|
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2019-12-04 10:03:03 +08:00
|
|
|
|
itemType: gHANDLER_TYPE_OBJECT,
|
|
|
|
|
itemFunc: itemFunc,
|
|
|
|
|
initFunc: initFunc,
|
|
|
|
|
shutFunc: shutFunc,
|
|
|
|
|
middleware: middleware,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
2018-08-16 21:33:47 +08:00
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
|
s.bindHandlerByMap(m)
|
2018-07-31 21:05:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 10:03:03 +08:00
|
|
|
|
func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware []HandlerFunc) {
|
2020-01-21 17:18:03 +08:00
|
|
|
|
m := make(map[string]*handlerItem)
|
2019-12-04 10:03:03 +08:00
|
|
|
|
v := reflect.ValueOf(object)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
t := v.Type()
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc := (func(*Request))(nil)
|
|
|
|
|
shutFunc := (func(*Request))(nil)
|
2019-12-18 19:37:07 +08:00
|
|
|
|
structName := t.Elem().Name()
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if v.MethodByName("Init").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
if v.MethodByName("Shut").IsValid() {
|
2019-08-03 15:54:12 +08:00
|
|
|
|
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
pkgPath := t.Elem().PkgPath()
|
|
|
|
|
for i := 0; i < v.NumMethod(); i++ {
|
2019-12-18 19:37:07 +08:00
|
|
|
|
methodName := t.Method(i).Name
|
|
|
|
|
if _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
pkgName := gfile.Basename(pkgPath)
|
|
|
|
|
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
|
|
|
|
if objName[0] == '*' {
|
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
|
}
|
2019-08-03 15:54:12 +08:00
|
|
|
|
itemFunc, ok := v.Method(i).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if !ok {
|
2020-01-21 15:42:08 +08:00
|
|
|
|
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
|
2019-12-18 19:37:07 +08:00
|
|
|
|
pkgPath, objName, methodName, v.Method(i).Type().String())
|
2019-06-19 09:06:52 +08:00
|
|
|
|
continue
|
|
|
|
|
}
|
2019-12-18 19:37:07 +08:00
|
|
|
|
key := s.mergeBuildInNameToPattern(methodName+":"+pattern, structName, methodName, false)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
m[key] = &handlerItem{
|
2019-12-18 19:37:07 +08:00
|
|
|
|
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2019-12-04 10:03:03 +08:00
|
|
|
|
itemType: gHANDLER_TYPE_OBJECT,
|
|
|
|
|
itemFunc: itemFunc,
|
|
|
|
|
initFunc: initFunc,
|
|
|
|
|
shutFunc: shutFunc,
|
|
|
|
|
middleware: middleware,
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s.bindHandlerByMap(m)
|
|
|
|
|
}
|