Files
gf/g/net/ghttp/ghttp_server_router_group.go

223 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2018 gf Author(https://github.com/gogf/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://github.com/gogf/gf.
// 分组路由管理.
package ghttp
import (
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/util/gconv"
"reflect"
"strings"
)
// 分组路由对象
type RouterGroup struct {
server *Server // Server
domain *Domain // Domain
prefix string // URI前缀
}
// 分组路由批量绑定项
type GroupItem = []interface{}
// 获取分组路由对象
func (s *Server) Group(prefix...string) *RouterGroup {
group := &RouterGroup{
server : s,
}
if len(prefix) > 0 {
group.prefix = prefix[0]
}
return group
}
// 获取分组路由对象
func (d *Domain) Group(prefix...string) *RouterGroup {
if len(prefix) > 0 {
return &RouterGroup{
domain : d,
prefix : prefix[0],
}
}
return &RouterGroup{}
}
// 执行分组路由批量绑定
func (g *RouterGroup) Bind(items []GroupItem) {
for _, item := range items {
if len(item) < 3 {
glog.Fatalfln("invalid router item: %s", item)
}
if strings.EqualFold(gconv.String(item[0]), "REST") {
g.bind("REST", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2])
} else {
if len(item) > 3 {
g.bind("HANDLER", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2], item[3])
} else {
g.bind("HANDLER", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2])
}
}
}
}
// 绑定所有的HTTP Method请求方式
func (g *RouterGroup) ALL(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", gDEFAULT_METHOD + ":" + pattern, object, params...)
}
// 绑定常用方法: GET/PUT/POST/DELETE
func (g *RouterGroup) COMMON(pattern string, object interface{}, params...interface{}) {
g.GET(pattern, object, params...)
g.PUT(pattern, object, params...)
g.POST(pattern, object, params...)
g.DELETE(pattern, object, params...)
}
func (g *RouterGroup) GET(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "GET:" + pattern, object, params...)
}
func (g *RouterGroup) PUT(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "PUT:" + pattern, object, params...)
}
func (g *RouterGroup) POST(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "POST:" + pattern, object, params...)
}
func (g *RouterGroup) DELETE(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "DELETE:" + pattern, object, params...)
}
func (g *RouterGroup) PATCH(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "PATCH:" + pattern, object, params...)
}
func (g *RouterGroup) HEAD(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "HEAD:" + pattern, object, params...)
}
func (g *RouterGroup) CONNECT(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "CONNECT:" + pattern, object, params...)
}
func (g *RouterGroup) OPTIONS(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "OPTIONS:" + pattern, object, params...)
}
func (g *RouterGroup) TRACE(pattern string, object interface{}, params...interface{}) {
g.bind("HANDLER", "TRACE:" + pattern, object, params...)
}
// REST路由注册
func (g *RouterGroup) REST(pattern string, object interface{}) {
g.bind("REST", pattern, object)
}
// 执行路由绑定
func (g *RouterGroup) bind(bindType string, pattern string, object interface{}, params...interface{}) {
// 注册路由处理
if len(g.prefix) > 0 {
domain, method, path, err := g.server.parsePattern(pattern)
if err != nil {
glog.Fatalfln("invalid pattern: %s", pattern)
}
if bindType == "HANDLER" {
pattern = g.server.serveHandlerKey(method, g.prefix + "/" + strings.TrimLeft(path, "/"), domain)
} else {
pattern = g.prefix + "/" + strings.TrimLeft(path, "/")
}
}
methods := gconv.Strings(params)
// 判断是否事件回调注册
if _, ok := object.(HandlerFunc); ok && len(methods) > 0 {
bindType = "HOOK"
}
switch bindType {
case "HANDLER":
if h, ok := object.(HandlerFunc); ok {
if g.server != nil {
g.server.BindHandler(pattern, h)
} else {
g.domain.BindHandler(pattern, h)
}
} else if g.isController(object) {
if len(methods) > 0 {
if g.server != nil {
g.server.BindControllerMethod(pattern, object.(Controller), methods[0])
} else {
g.domain.BindControllerMethod(pattern, object.(Controller), methods[0])
}
} else {
if g.server != nil {
g.server.BindController(pattern, object.(Controller))
} else {
g.domain.BindController(pattern, object.(Controller))
}
}
} else {
if len(methods) > 0 {
if g.server != nil {
g.server.BindObjectMethod(pattern, object, methods[0])
} else {
g.domain.BindObjectMethod(pattern, object, methods[0])
}
} else {
if g.server != nil {
g.server.BindObject(pattern, object)
} else {
g.domain.BindObject(pattern, object)
}
}
}
case "REST":
if g.isController(object) {
if g.server != nil {
g.server.BindControllerRest(pattern, object.(Controller))
} else {
g.domain.BindControllerRest(pattern, object.(Controller))
}
} else {
if g.server != nil {
g.server.BindObjectRest(pattern, object)
} else {
g.domain.BindObjectRest(pattern, object)
}
}
case "HOOK":
if h, ok := object.(HandlerFunc); ok {
if g.server != nil {
g.server.BindHookHandler(pattern, methods[0], h)
} else {
g.domain.BindHookHandler(pattern, methods[0], h)
}
} else {
glog.Fatalfln("invalid hook handler for pattern:%s", pattern)
}
}
}
// 判断给定对象是否控制器对象:
// 控制器必须包含以下公开的属性对象Request/Response/Server/Cookie/Session/View.
func (g *RouterGroup) isController(value interface{}) bool {
// 首先判断是否满足控制器接口定义
if _, ok := value.(Controller); !ok {
return false
}
// 其次检查控制器的必需属性
v := reflect.ValueOf(value)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.FieldByName("Request").IsValid() && v.FieldByName("Response").IsValid() &&
v.FieldByName("Server").IsValid() && v.FieldByName("Cookie").IsValid() &&
v.FieldByName("Session").IsValid() && v.FieldByName("View").IsValid() {
return true
}
return false
}