github.com/zhongdalu/gf@v1.0.0/g/net/ghttp/ghttp_server_service_handler.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  	"bytes"
    12  	"github.com/zhongdalu/gf/g/os/glog"
    13  	"github.com/zhongdalu/gf/g/text/gstr"
    14  	"reflect"
    15  	"runtime"
    16  	"strings"
    17  )
    18  
    19  // 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑
    20  func (s *Server) BindHandler(pattern string, handler HandlerFunc) {
    21  	s.bindHandlerItem(pattern, &handlerItem{
    22  		name:  runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
    23  		rtype: gROUTE_REGISTER_HANDLER,
    24  		ctype: nil,
    25  		fname: "",
    26  		faddr: handler,
    27  	})
    28  }
    29  
    30  // 绑定URI到操作函数/方法
    31  // pattern的格式形如:/user/list, put:/user, delete:/user, post:/user@johng.cn
    32  // 支持RESTful的请求格式,具体业务逻辑由绑定的处理方法来执行
    33  func (s *Server) bindHandlerItem(pattern string, item *handlerItem) {
    34  	if s.Status() == SERVER_STATUS_RUNNING {
    35  		glog.Error("server handlers cannot be changed while running")
    36  		return
    37  	}
    38  	s.setHandler(pattern, item)
    39  }
    40  
    41  // 通过映射数组绑定URI到操作函数/方法
    42  func (s *Server) bindHandlerByMap(m handlerMap) {
    43  	for p, h := range m {
    44  		s.bindHandlerItem(p, h)
    45  	}
    46  }
    47  
    48  // 将内置的名称按照设定的规则合并到pattern中,内置名称按照{.xxx}规则命名。
    49  // 规则1:pattern中的URI包含{.struct}关键字,则替换该关键字为结构体名称;
    50  // 规则2:pattern中的URI包含{.method}关键字,则替换该关键字为方法名称;
    51  // 规则2:如果不满足规则1,那么直接将防发明附加到pattern中的URI后面;
    52  func (s *Server) mergeBuildInNameToPattern(pattern string, structName, methodName string, allowAppend bool) string {
    53  	structName = s.nameToUrlPart(structName)
    54  	methodName = s.nameToUrlPart(methodName)
    55  	pattern = strings.Replace(pattern, "{.struct}", structName, -1)
    56  	if strings.Index(pattern, "{.method}") != -1 {
    57  		return strings.Replace(pattern, "{.method}", methodName, -1)
    58  	}
    59  	// 不允许将方法名称append到路由末尾
    60  	if !allowAppend {
    61  		return pattern
    62  	}
    63  	// 检测域名后缀
    64  	array := strings.Split(pattern, "@")
    65  	// 分离URI(其实可能包含HTTP Method)
    66  	uri := array[0]
    67  	uri = strings.TrimRight(uri, "/") + "/" + methodName
    68  	// 加上指定域名后缀
    69  	if len(array) > 1 {
    70  		return uri + "@" + array[1]
    71  	}
    72  	return uri
    73  }
    74  
    75  // 将给定的名称转换为URL规范格式。
    76  // 规则0: 全部转换为小写,方法名中间存在大写字母,转换为小写URI地址以“-”号链接每个单词;
    77  // 规则1: 不处理名称,以原有名称构建成URI
    78  // 规则2: 仅转为小写,单词间不使用连接符号
    79  // 规则3: 采用驼峰命名方式
    80  func (s *Server) nameToUrlPart(name string) string {
    81  	switch s.config.NameToUriType {
    82  	case NAME_TO_URI_TYPE_FULLNAME:
    83  		return name
    84  
    85  	case NAME_TO_URI_TYPE_ALLLOWER:
    86  		return strings.ToLower(name)
    87  
    88  	case NAME_TO_URI_TYPE_CAMEL:
    89  		part := bytes.NewBuffer(nil)
    90  		if gstr.IsLetterUpper(name[0]) {
    91  			part.WriteByte(name[0] + 32)
    92  		} else {
    93  			part.WriteByte(name[0])
    94  		}
    95  		part.WriteString(name[1:])
    96  		return part.String()
    97  
    98  	case NAME_TO_URI_TYPE_DEFAULT:
    99  		fallthrough
   100  	default:
   101  		part := bytes.NewBuffer(nil)
   102  		for i := 0; i < len(name); i++ {
   103  			if i > 0 && gstr.IsLetterUpper(name[i]) {
   104  				part.WriteByte('-')
   105  			}
   106  			if gstr.IsLetterUpper(name[i]) {
   107  				part.WriteByte(name[i] + 32)
   108  			} else {
   109  				part.WriteByte(name[i])
   110  			}
   111  		}
   112  		return part.String()
   113  	}
   114  }