improve router group for duplicated router registering for package ghttp.Server

This commit is contained in:
John
2020-03-17 14:48:52 +08:00
parent 2b46e765c4
commit f3d859159d
12 changed files with 370 additions and 158 deletions

View File

@ -462,39 +462,3 @@ func Test_IsNil(t *testing.T) {
gtest.Assert(j.IsNil(), true)
})
}
func Test_ToStructDeep(t *testing.T) {
gtest.Case(t, func() {
type Item struct {
Title string `json:"title"`
Key string `json:"key"`
}
type M struct {
Id string `json:"id"`
Me map[string]interface{} `json:"me"`
Txt string `json:"txt"`
Items []*Item `json:"items"`
}
txt := `{
"id":"88888",
"me":{"name":"mikey","day":"20009"},
"txt":"hello",
"items":null
}`
j, err := gjson.LoadContent(txt)
gtest.Assert(err, nil)
gtest.Assert(j.GetString("me.name"), "mikey")
gtest.Assert(j.GetString("items"), "")
gtest.Assert(j.GetBool("items"), false)
gtest.Assert(j.GetArray("items"), nil)
m := new(M)
err = j.ToStructDeep(m)
gtest.Assert(err, nil)
gtest.AssertNE(m.Me, nil)
gtest.Assert(m.Me["day"], "20009")
gtest.Assert(m.Items, nil)
})
}

View File

@ -0,0 +1,132 @@
// Copyright 2017 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 gjson_test
import (
"github.com/gogf/gf/encoding/gjson"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/test/gtest"
"testing"
)
func Test_ToStruct1(t *testing.T) {
gtest.Case(t, func() {
type BaseInfoItem struct {
IdCardNumber string `db:"id_card_number" json:"idCardNumber" field:"id_card_number"`
IsHouseholder bool `db:"is_householder" json:"isHouseholder" field:"is_householder"`
HouseholderRelation string `db:"householder_relation" json:"householderRelation" field:"householder_relation"`
UserName string `db:"user_name" json:"userName" field:"user_name"`
UserSex string `db:"user_sex" json:"userSex" field:"user_sex"`
UserAge int `db:"user_age" json:"userAge" field:"user_age"`
UserNation string `db:"user_nation" json:"userNation" field:"user_nation"`
}
type UserCollectionAddReq struct {
BaseInfo []BaseInfoItem `db:"_" json:"baseInfo" field:"_"`
}
jsonContent := `{
"baseInfo": [{
"idCardNumber": "520101199412141111",
"isHouseholder": true,
"householderRelation": "户主",
"userName": "李四",
"userSex": "男",
"userAge": 32,
"userNation": "苗族",
"userPhone": "13084183323",
"liveAddress": {},
"occupationInfo": [{
"occupationType": "经商",
"occupationBusinessInfo": [{
"occupationClass": "制造业",
"businessLicenseNumber": "32020000012300",
"businessName": "土灶柴火鸡",
"spouseName": "",
"spouseIdCardNumber": "",
"businessLicensePhotoId": 125,
"businessPlace": "租赁房产",
"hasGoodsInsurance": true,
"businessScopeStr": "柴火鸡;烧烤",
"businessAddress": {},
"businessPerformAbility": {
"businessType": "服务业",
"businessLife": 5,
"salesRevenue": 8000,
"familyEquity": 6000
}
}],
"occupationWorkInfo": {
"occupationClass": "",
"companyName": "",
"companyType": "",
"workYearNum": 0,
"spouseName": "",
"spouseIdCardNumber": "",
"spousePhone": "",
"spouseEducation": "",
"spouseCompanyName": "",
"workLevel": "",
"workAddress": {},
"workPerformAbility": {
"familyAnnualIncome": 0,
"familyEquity": 0,
"workCooperationState": "",
"workMoneyCooperationState": ""
}
},
"occupationAgricultureInfo": []
}],
"assetsInfo": [],
"expenditureInfo": [],
"incomeInfo": [],
"liabilityInfo": []
}]
}`
data := new(UserCollectionAddReq)
j, err := gjson.LoadJson(jsonContent)
gtest.Assert(err, nil)
err = j.ToStruct(data)
gtest.Assert(err, nil)
g.Dump(data)
})
}
func Test_ToStructDeep(t *testing.T) {
gtest.Case(t, func() {
type Item struct {
Title string `json:"title"`
Key string `json:"key"`
}
type M struct {
Id string `json:"id"`
Me map[string]interface{} `json:"me"`
Txt string `json:"txt"`
Items []*Item `json:"items"`
}
txt := `{
"id":"88888",
"me":{"name":"mikey","day":"20009"},
"txt":"hello",
"items":null
}`
j, err := gjson.LoadContent(txt)
gtest.Assert(err, nil)
gtest.Assert(j.GetString("me.name"), "mikey")
gtest.Assert(j.GetString("items"), "")
gtest.Assert(j.GetBool("items"), false)
gtest.Assert(j.GetArray("items"), nil)
m := new(M)
err = j.ToStructDeep(m)
gtest.Assert(err, nil)
gtest.AssertNE(m.Me, nil)
gtest.Assert(m.Me["day"], "20009")
gtest.Assert(m.Items, nil)
})
}

View File

@ -8,9 +8,7 @@ package gmvc
import "github.com/gogf/gf/database/gdb"
// M is alias for Model,
// just for short write purpose.
type M = Model
// Model is alias for *gdb.Model.
type Model = *gdb.Model
type (
M = Model // M is alias for Model, just for short write purpose.
Model = *gdb.Model // Model is alias for *gdb.Model.
)

View File

@ -89,6 +89,7 @@ type (
ctrlInfo *handlerController // Controller information for reflect usage.
hookName string // Hook type name.
router *Router // Router object.
source string // Source file path:line when registering.
}
// handlerParsedItem is the item parsed from URL.Path.
@ -105,7 +106,7 @@ type (
// registeredRouteItem stores the information of the router and is used for route map.
registeredRouteItem struct {
file string // Source file path and its line number.
source string // Source file path and its line number.
handler *handlerItem // Handler object.
}

View File

@ -12,121 +12,148 @@ import (
// 域名管理器对象
type Domain struct {
s *Server // 所属Server
m map[string]bool // 多域名
server *Server // 所属Server
domains map[string]struct{} // 多域名
}
// 生成一个域名对象, 参数 domains 支持给定多个域名。
func (s *Server) Domain(domains string) *Domain {
d := &Domain{
s: s,
m: make(map[string]bool),
server: s,
domains: make(map[string]struct{}),
}
for _, v := range strings.Split(domains, ",") {
d.m[strings.TrimSpace(v)] = true
d.domains[strings.TrimSpace(v)] = struct{}{}
}
return d
}
func (d *Domain) BindHandler(pattern string, handler HandlerFunc) {
for domain, _ := range d.m {
d.s.BindHandler(pattern+"@"+domain, handler)
for domain, _ := range d.domains {
d.server.BindHandler(pattern+"@"+domain, handler)
}
}
func (d *Domain) doBindHandler(pattern string, handler HandlerFunc, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindHandler(pattern+"@"+domain, handler, middleware)
func (d *Domain) doBindHandler(
pattern string, handler HandlerFunc,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindHandler(pattern+"@"+domain, handler, middleware, source)
}
}
func (d *Domain) BindObject(pattern string, obj interface{}, methods ...string) {
for domain, _ := range d.m {
d.s.BindObject(pattern+"@"+domain, obj, methods...)
for domain, _ := range d.domains {
d.server.BindObject(pattern+"@"+domain, obj, methods...)
}
}
func (d *Domain) doBindObject(pattern string, obj interface{}, methods string, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindObject(pattern+"@"+domain, obj, methods, middleware)
func (d *Domain) doBindObject(
pattern string, obj interface{}, methods string,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindObject(pattern+"@"+domain, obj, methods, middleware, source)
}
}
func (d *Domain) BindObjectMethod(pattern string, obj interface{}, method string) {
for domain, _ := range d.m {
d.s.BindObjectMethod(pattern+"@"+domain, obj, method)
for domain, _ := range d.domains {
d.server.BindObjectMethod(pattern+"@"+domain, obj, method)
}
}
func (d *Domain) doBindObjectMethod(pattern string, obj interface{}, method string, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindObjectMethod(pattern+"@"+domain, obj, method, middleware)
func (d *Domain) doBindObjectMethod(
pattern string, obj interface{}, method string,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindObjectMethod(pattern+"@"+domain, obj, method, middleware, source)
}
}
func (d *Domain) BindObjectRest(pattern string, obj interface{}) {
for domain, _ := range d.m {
d.s.BindObjectRest(pattern+"@"+domain, obj)
for domain, _ := range d.domains {
d.server.BindObjectRest(pattern+"@"+domain, obj)
}
}
func (d *Domain) doBindObjectRest(pattern string, obj interface{}, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindObjectRest(pattern+"@"+domain, obj, middleware)
func (d *Domain) doBindObjectRest(
pattern string, obj interface{},
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindObjectRest(pattern+"@"+domain, obj, middleware, source)
}
}
func (d *Domain) BindController(pattern string, c Controller, methods ...string) {
for domain, _ := range d.m {
d.s.BindController(pattern+"@"+domain, c, methods...)
for domain, _ := range d.domains {
d.server.BindController(pattern+"@"+domain, c, methods...)
}
}
func (d *Domain) doBindController(pattern string, c Controller, methods string, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindController(pattern+"@"+domain, c, methods, middleware)
func (d *Domain) doBindController(
pattern string, c Controller, methods string,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindController(pattern+"@"+domain, c, methods, middleware, source)
}
}
func (d *Domain) BindControllerMethod(pattern string, c Controller, method string) {
for domain, _ := range d.m {
d.s.BindControllerMethod(pattern+"@"+domain, c, method)
for domain, _ := range d.domains {
d.server.BindControllerMethod(pattern+"@"+domain, c, method)
}
}
func (d *Domain) doBindControllerMethod(pattern string, c Controller, method string, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindControllerMethod(pattern+"@"+domain, c, method, middleware)
func (d *Domain) doBindControllerMethod(
pattern string, c Controller, method string,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindControllerMethod(pattern+"@"+domain, c, method, middleware, source)
}
}
func (d *Domain) BindControllerRest(pattern string, c Controller) {
for domain, _ := range d.m {
d.s.BindControllerRest(pattern+"@"+domain, c)
for domain, _ := range d.domains {
d.server.BindControllerRest(pattern+"@"+domain, c)
}
}
func (d *Domain) doBindControllerRest(pattern string, c Controller, middleware []HandlerFunc) {
for domain, _ := range d.m {
d.s.doBindControllerRest(pattern+"@"+domain, c, middleware)
func (d *Domain) doBindControllerRest(
pattern string, c Controller,
middleware []HandlerFunc, source string,
) {
for domain, _ := range d.domains {
d.server.doBindControllerRest(pattern+"@"+domain, c, middleware, source)
}
}
func (d *Domain) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
for domain, _ := range d.m {
d.s.BindHookHandler(pattern+"@"+domain, hook, handler)
for domain, _ := range d.domains {
d.server.BindHookHandler(pattern+"@"+domain, hook, handler)
}
}
func (d *Domain) doBindHookHandler(pattern string, hook string, handler HandlerFunc, source string) {
for domain, _ := range d.domains {
d.server.doBindHookHandler(pattern+"@"+domain, hook, handler, source)
}
}
func (d *Domain) BindHookHandlerByMap(pattern string, hookmap map[string]HandlerFunc) {
for domain, _ := range d.m {
d.s.BindHookHandlerByMap(pattern+"@"+domain, hookmap)
for domain, _ := range d.domains {
d.server.BindHookHandlerByMap(pattern+"@"+domain, hookmap)
}
}
func (d *Domain) BindStatusHandler(status int, handler HandlerFunc) {
for domain, _ := range d.m {
d.s.setStatusHandler(d.s.statusHandlerKey(status, domain), handler)
for domain, _ := range d.domains {
d.server.setStatusHandler(d.server.statusHandlerKey(status, domain), handler)
}
}
@ -137,14 +164,14 @@ func (d *Domain) BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {
}
func (d *Domain) BindMiddleware(pattern string, handlers ...HandlerFunc) {
for domain, _ := range d.m {
d.s.BindMiddleware(pattern+"@"+domain, handlers...)
for domain, _ := range d.domains {
d.server.BindMiddleware(pattern+"@"+domain, handlers...)
}
}
func (d *Domain) BindMiddlewareDefault(handlers ...HandlerFunc) {
for domain, _ := range d.m {
d.s.BindMiddleware(gDEFAULT_MIDDLEWARE_PATTERN+"@"+domain, handlers...)
for domain, _ := range d.domains {
d.server.BindMiddleware(gDEFAULT_MIDDLEWARE_PATTERN+"@"+domain, handlers...)
}
}

View File

@ -67,6 +67,10 @@ func (s *Server) parsePattern(pattern string) (domain, method, path string, err
// is the well designed router storage structure for router searching when the request is under serving.
func (s *Server) setHandler(pattern string, handler *handlerItem) {
handler.itemId = handlerIdGenerator.Add(1)
if handler.source == "" {
_, file, line := gdebug.CallerWithFilter(gFILTER_KEY)
handler.source = fmt.Sprintf(`%s:%d`, file, line)
}
domain, method, uri, err := s.parsePattern(pattern)
if err != nil {
s.Logger().Fatal("invalid pattern:", pattern, err)
@ -83,7 +87,10 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) {
switch handler.itemType {
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
if item, ok := s.routesMap[routerKey]; ok {
s.Logger().Fatalf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
s.Logger().Fatalf(
`duplicated route registry "%s" at %s , already registered at %s`,
pattern, handler.source, item[0].source,
)
return
}
}
@ -184,9 +191,9 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) {
if _, ok := s.routesMap[routerKey]; !ok {
s.routesMap[routerKey] = make([]registeredRouteItem, 0)
}
_, file, line := gdebug.CallerWithFilter(gFILTER_KEY)
routeItem := registeredRouteItem{
file: fmt.Sprintf(`%s:%d`, file, line),
source: handler.source,
handler: handler,
}
switch handler.itemType {

View File

@ -7,6 +7,8 @@
package ghttp
import (
"fmt"
"github.com/gogf/gf/debug/gdebug"
"reflect"
"strings"
@ -36,6 +38,7 @@ type (
pattern string
object interface{} // Can be handler, controller or object.
params []interface{} // Extra parameters for route registering depending on the type.
source string // // Handler is register at certain source file path:line.
}
)
@ -53,10 +56,10 @@ func (s *Server) handlePreBindItems() {
if item.group.server != nil && item.group.server != s {
continue
}
if item.group.domain != nil && item.group.domain.s != s {
if item.group.domain != nil && item.group.domain.server != s {
continue
}
item.group.doBind(item.bindType, item.pattern, item.object, item.params...)
item.group.doBindRoutersToServer(item)
}
preBindItems = preBindItems[:0]
}
@ -147,9 +150,9 @@ func (g *RouterGroup) Bind(items []GroupItem) *RouterGroup {
bindType := gstr.ToUpper(gconv.String(item[0]))
switch bindType {
case "REST":
group.preBind("REST", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
group.preBindToLocalArray("REST", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
case "MIDDLEWARE":
group.preBind("MIDDLEWARE", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
group.preBindToLocalArray("MIDDLEWARE", gconv.String(item[0])+":"+gconv.String(item[1]), item[2])
default:
if strings.EqualFold(bindType, "ALL") {
bindType = ""
@ -157,9 +160,9 @@ func (g *RouterGroup) Bind(items []GroupItem) *RouterGroup {
bindType += ":"
}
if len(item) > 3 {
group.preBind("HANDLER", bindType+gconv.String(item[1]), item[2], item[3])
group.preBindToLocalArray("HANDLER", bindType+gconv.String(item[1]), item[2], item[3])
} else {
group.preBind("HANDLER", bindType+gconv.String(item[1]), item[2])
group.preBindToLocalArray("HANDLER", bindType+gconv.String(item[1]), item[2])
}
}
}
@ -168,62 +171,62 @@ func (g *RouterGroup) Bind(items []GroupItem) *RouterGroup {
// ALL registers a http handler to given route pattern and all http methods.
func (g *RouterGroup) ALL(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", gDEFAULT_METHOD+":"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", gDEFAULT_METHOD+":"+pattern, object, params...)
}
// GET registers a http handler to given route pattern and http method: GET.
func (g *RouterGroup) GET(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "GET:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "GET:"+pattern, object, params...)
}
// PUT registers a http handler to given route pattern and http method: PUT.
func (g *RouterGroup) PUT(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "PUT:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "PUT:"+pattern, object, params...)
}
// POST registers a http handler to given route pattern and http method: POST.
func (g *RouterGroup) POST(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "POST:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "POST:"+pattern, object, params...)
}
// DELETE registers a http handler to given route pattern and http method: DELETE.
func (g *RouterGroup) DELETE(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "DELETE:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "DELETE:"+pattern, object, params...)
}
// PATCH registers a http handler to given route pattern and http method: PATCH.
func (g *RouterGroup) PATCH(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "PATCH:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "PATCH:"+pattern, object, params...)
}
// HEAD registers a http handler to given route pattern and http method: HEAD.
func (g *RouterGroup) HEAD(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "HEAD:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "HEAD:"+pattern, object, params...)
}
// CONNECT registers a http handler to given route pattern and http method: CONNECT.
func (g *RouterGroup) CONNECT(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "CONNECT:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "CONNECT:"+pattern, object, params...)
}
// OPTIONS registers a http handler to given route pattern and http method: OPTIONS.
func (g *RouterGroup) OPTIONS(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "OPTIONS:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "OPTIONS:"+pattern, object, params...)
}
// TRACE registers a http handler to given route pattern and http method: TRACE.
func (g *RouterGroup) TRACE(pattern string, object interface{}, params ...interface{}) *RouterGroup {
return g.Clone().preBind("HANDLER", "TRACE:"+pattern, object, params...)
return g.Clone().preBindToLocalArray("HANDLER", "TRACE:"+pattern, object, params...)
}
// REST registers a http handler to given route pattern according to REST rule.
func (g *RouterGroup) REST(pattern string, object interface{}) *RouterGroup {
return g.Clone().preBind("REST", pattern, object)
return g.Clone().preBindToLocalArray("REST", pattern, object)
}
// Hook registers a hook to given route pattern.
func (g *RouterGroup) Hook(pattern string, hook string, handler HandlerFunc) *RouterGroup {
return g.Clone().preBind("HANDLER", pattern, handler, hook)
return g.Clone().preBindToLocalArray("HANDLER", pattern, handler, hook)
}
// Middleware binds one or more middleware to the router group.
@ -232,14 +235,16 @@ func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {
return g
}
// preBind adds the route registering parameters to internal variable array for lazily registering feature.
func (g *RouterGroup) preBind(bindType string, pattern string, object interface{}, params ...interface{}) *RouterGroup {
// preBindToLocalArray adds the route registering parameters to internal variable array for lazily registering feature.
func (g *RouterGroup) preBindToLocalArray(bindType string, pattern string, object interface{}, params ...interface{}) *RouterGroup {
_, file, line := gdebug.CallerWithFilter(gFILTER_KEY)
preBindItems = append(preBindItems, preBindItem{
group: g,
bindType: bindType,
pattern: pattern,
object: object,
params: params,
source: fmt.Sprintf(`%s:%d`, file, line),
})
return g
}
@ -255,8 +260,15 @@ func (g *RouterGroup) getPrefix() string {
return prefix
}
// doBind does really registering for the group.
func (g *RouterGroup) doBind(bindType string, pattern string, object interface{}, params ...interface{}) *RouterGroup {
// doBindRoutersToServer does really registering for the group.
func (g *RouterGroup) doBindRoutersToServer(item preBindItem) *RouterGroup {
var (
bindType = item.bindType
pattern = item.pattern
object = item.object
params = item.params
source = item.source
)
prefix := g.getPrefix()
// Route check.
if len(prefix) > 0 {
@ -271,7 +283,9 @@ func (g *RouterGroup) doBind(bindType string, pattern string, object interface{}
if bindType == "REST" {
pattern = prefix + "/" + strings.TrimLeft(path, "/")
} else {
pattern = g.server.serveHandlerKey(method, prefix+"/"+strings.TrimLeft(path, "/"), domain)
pattern = g.server.serveHandlerKey(
method, prefix+"/"+strings.TrimLeft(path, "/"), domain,
)
}
}
// Filter repeated char '/'.
@ -286,78 +300,102 @@ func (g *RouterGroup) doBind(bindType string, pattern string, object interface{}
case "HANDLER":
if h, ok := object.(HandlerFunc); ok {
if g.server != nil {
g.server.doBindHandler(pattern, h, g.middleware)
g.server.doBindHandler(pattern, h, g.middleware, source)
} else {
g.domain.doBindHandler(pattern, h, g.middleware)
g.domain.doBindHandler(pattern, h, g.middleware, source)
}
} else if g.isController(object) {
if len(extras) > 0 {
if g.server != nil {
if gstr.Contains(extras[0], ",") {
g.server.doBindController(pattern, object.(Controller), extras[0], g.middleware)
g.server.doBindController(
pattern, object.(Controller), extras[0], g.middleware, source,
)
} else {
g.server.doBindControllerMethod(pattern, object.(Controller), extras[0], g.middleware)
g.server.doBindControllerMethod(
pattern, object.(Controller), extras[0], g.middleware, source,
)
}
} else {
if gstr.Contains(extras[0], ",") {
g.domain.doBindController(pattern, object.(Controller), extras[0], g.middleware)
g.domain.doBindController(
pattern, object.(Controller), extras[0], g.middleware, source,
)
} else {
g.domain.doBindControllerMethod(pattern, object.(Controller), extras[0], g.middleware)
g.domain.doBindControllerMethod(
pattern, object.(Controller), extras[0], g.middleware, source,
)
}
}
} else {
if g.server != nil {
g.server.doBindController(pattern, object.(Controller), "", g.middleware)
g.server.doBindController(
pattern, object.(Controller), "", g.middleware, source,
)
} else {
g.domain.doBindController(pattern, object.(Controller), "", g.middleware)
g.domain.doBindController(
pattern, object.(Controller), "", g.middleware, source,
)
}
}
} else {
if len(extras) > 0 {
if g.server != nil {
if gstr.Contains(extras[0], ",") {
g.server.doBindObject(pattern, object, extras[0], g.middleware)
g.server.doBindObject(
pattern, object, extras[0], g.middleware, source,
)
} else {
g.server.doBindObjectMethod(pattern, object, extras[0], g.middleware)
g.server.doBindObjectMethod(
pattern, object, extras[0], g.middleware, source,
)
}
} else {
if gstr.Contains(extras[0], ",") {
g.domain.doBindObject(pattern, object, extras[0], g.middleware)
g.domain.doBindObject(
pattern, object, extras[0], g.middleware, source,
)
} else {
g.domain.doBindObjectMethod(pattern, object, extras[0], g.middleware)
g.domain.doBindObjectMethod(
pattern, object, extras[0], g.middleware, source,
)
}
}
} else {
if g.server != nil {
g.server.doBindObject(pattern, object, "", g.middleware)
g.server.doBindObject(pattern, object, "", g.middleware, source)
} else {
g.domain.doBindObject(pattern, object, "", g.middleware)
g.domain.doBindObject(pattern, object, "", g.middleware, source)
}
}
}
case "REST":
if g.isController(object) {
if g.server != nil {
g.server.doBindControllerRest(pattern, object.(Controller), g.middleware)
g.server.doBindControllerRest(
pattern, object.(Controller), g.middleware, source,
)
} else {
g.domain.doBindControllerRest(pattern, object.(Controller), g.middleware)
g.domain.doBindControllerRest(
pattern, object.(Controller), g.middleware, source,
)
}
} else {
if g.server != nil {
g.server.doBindObjectRest(pattern, object, g.middleware)
g.server.doBindObjectRest(pattern, object, g.middleware, source)
} else {
g.domain.doBindObjectRest(pattern, object, g.middleware)
g.domain.doBindObjectRest(pattern, object, g.middleware, source)
}
}
case "HOOK":
if h, ok := object.(HandlerFunc); ok {
if g.server != nil {
g.server.BindHookHandler(pattern, extras[0], h)
g.server.doBindHookHandler(pattern, extras[0], h, source)
} else {
g.domain.BindHookHandler(pattern, extras[0], h)
g.domain.doBindHookHandler(pattern, extras[0], h, source)
}
} else {
g.server.Logger().Fatalf("invalid hook handler for pattern:%s", pattern)
g.server.Logger().Fatalf("invalid hook handler for pattern: %s", pattern)
}
}
return g

View File

@ -13,11 +13,16 @@ import (
// 绑定指定的hook回调函数, pattern参数同BindHandler支持命名路由hook参数的值由ghttp server设定参数不区分大小写
func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
s.doBindHookHandler(pattern, hook, handler, "")
}
func (s *Server) doBindHookHandler(pattern string, hook string, handler HandlerFunc, source string) {
s.setHandler(pattern, &handlerItem{
itemType: gHANDLER_TYPE_HOOK,
itemName: gdebug.FuncPath(handler),
itemFunc: handler,
hookName: hook,
source: source,
})
}

View File

@ -24,12 +24,12 @@ func (s *Server) BindController(pattern string, controller Controller, method ..
if len(method) > 0 {
bindMethod = method[0]
}
s.doBindController(pattern, controller, bindMethod, nil)
s.doBindController(pattern, controller, bindMethod, nil, "")
}
// 绑定路由到指定的方法执行, 第三个参数method仅支持一个方法注册不支持多个并且区分大小写。
func (s *Server) BindControllerMethod(pattern string, controller Controller, method string) {
s.doBindControllerMethod(pattern, controller, method, nil)
s.doBindControllerMethod(pattern, controller, method, nil, "")
}
// 绑定控制器(RESTFul)控制器需要实现gmvc.Controller接口
@ -37,10 +37,13 @@ func (s *Server) BindControllerMethod(pattern string, controller Controller, met
// 因此只会绑定HTTP Method对应的方法其他方法不会自动注册绑定
// 这种方式绑定的控制器每一次请求都会初始化一个新的控制器对象进行处理,对应不同的请求会话
func (s *Server) BindControllerRest(pattern string, controller Controller) {
s.doBindControllerRest(pattern, controller, nil)
s.doBindControllerRest(pattern, controller, nil, "")
}
func (s *Server) doBindController(pattern string, controller Controller, method string, middleware []HandlerFunc) {
func (s *Server) doBindController(
pattern string, controller Controller, method string,
middleware []HandlerFunc, source string,
) {
// Convert input method to map for convenience and high performance searching.
var methodMap map[string]bool
if len(method) > 0 {
@ -98,6 +101,7 @@ func (s *Server) doBindController(pattern string, controller Controller, method
reflect: v.Elem().Type(),
},
middleware: middleware,
source: source,
}
// 如果方法中带有Index方法那么额外自动增加一个路由规则匹配主URI
// 例如: pattern为/user, 那么会同时注册/user及/user/index
@ -117,13 +121,20 @@ func (s *Server) doBindController(pattern string, controller Controller, method
reflect: v.Elem().Type(),
},
middleware: middleware,
source: source,
}
}
}
s.bindHandlerByMap(m)
}
func (s *Server) doBindControllerMethod(pattern string, controller Controller, method string, middleware []HandlerFunc) {
func (s *Server) doBindControllerMethod(
pattern string,
controller Controller,
method string,
middleware []HandlerFunc,
source string,
) {
m := make(map[string]*handlerItem)
v := reflect.ValueOf(controller)
t := v.Type()
@ -141,8 +152,10 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := methodValue.Interface().(func()); !ok {
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, methodValue.Type().String())
s.Logger().Errorf(
`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, methodValue.Type().String(),
)
return
}
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, false)
@ -154,11 +167,15 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
reflect: v.Elem().Type(),
},
middleware: middleware,
source: source,
}
s.bindHandlerByMap(m)
}
func (s *Server) doBindControllerRest(pattern string, controller Controller, middleware []HandlerFunc) {
func (s *Server) doBindControllerRest(
pattern string, controller Controller,
middleware []HandlerFunc, source string,
) {
// 遍历控制器获取方法列表并构造成uri
m := make(map[string]*handlerItem)
v := reflect.ValueOf(controller)
@ -177,8 +194,10 @@ func (s *Server) doBindControllerRest(pattern string, controller Controller, mid
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := v.Method(i).Interface().(func()); !ok {
s.Logger().Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, v.Method(i).Type().String())
s.Logger().Errorf(
`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, methodName, v.Method(i).Type().String(),
)
return
}
key := s.mergeBuildInNameToPattern(methodName+":"+pattern, structName, methodName, false)
@ -190,6 +209,7 @@ func (s *Server) doBindControllerRest(pattern string, controller Controller, mid
reflect: v.Elem().Type(),
},
middleware: middleware,
source: source,
}
}
s.bindHandlerByMap(m)

View File

@ -16,18 +16,22 @@ import (
// 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑
func (s *Server) BindHandler(pattern string, handler HandlerFunc) {
s.doBindHandler(pattern, handler, nil)
s.doBindHandler(pattern, handler, nil, "")
}
// 绑定URI到操作函数/方法
// pattern的格式形如/user/list, put:/user, delete:/user, post:/user@johng.cn
// 支持RESTful的请求格式具体业务逻辑由绑定的处理方法来执行
func (s *Server) doBindHandler(pattern string, handler HandlerFunc, middleware []HandlerFunc) {
func (s *Server) doBindHandler(
pattern string, handler HandlerFunc,
middleware []HandlerFunc, source string,
) {
s.setHandler(pattern, &handlerItem{
itemName: gdebug.FuncPath(handler),
itemType: gHANDLER_TYPE_HANDLER,
itemFunc: handler,
middleware: middleware,
source: source,
})
}

View File

@ -23,22 +23,25 @@ func (s *Server) BindObject(pattern string, object interface{}, method ...string
if len(method) > 0 {
bindMethod = method[0]
}
s.doBindObject(pattern, object, bindMethod, nil)
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)
s.doBindObjectMethod(pattern, object, method, nil, "")
}
// 绑定对象到URI请求处理中会自动识别方法名称并附加到对应的URI地址后面,
// 需要注意对象方法的定义必须按照 ghttp.HandlerFunc 来定义
func (s *Server) BindObjectRest(pattern string, object interface{}) {
s.doBindObjectRest(pattern, object, nil)
s.doBindObjectRest(pattern, object, nil, "")
}
func (s *Server) doBindObject(pattern string, object interface{}, method string, middleware []HandlerFunc) {
func (s *Server) doBindObject(
pattern string, object interface{}, method string,
middleware []HandlerFunc, source string,
) {
// Convert input method to map for convenience and high performance searching purpose.
var methodMap map[string]bool
if len(method) > 0 {
@ -107,6 +110,7 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
initFunc: initFunc,
shutFunc: shutFunc,
middleware: middleware,
source: source,
}
// 如果方法中带有Index方法那么额外自动增加一个路由规则匹配主URI。
// 注意当pattern带有内置变量时不会自动加该路由。
@ -123,6 +127,7 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
initFunc: initFunc,
shutFunc: shutFunc,
middleware: middleware,
source: source,
}
}
}
@ -131,7 +136,10 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
// 绑定对象到URI请求处理中会自动识别方法名称并附加到对应的URI地址后面
// 第三个参数method仅支持一个方法注册不支持多个并且区分大小写。
func (s *Server) doBindObjectMethod(pattern string, object interface{}, method string, middleware []HandlerFunc) {
func (s *Server) doBindObjectMethod(
pattern string, object interface{}, method string,
middleware []HandlerFunc, source string,
) {
m := make(map[string]*handlerItem)
v := reflect.ValueOf(object)
t := v.Type()
@ -170,12 +178,16 @@ func (s *Server) doBindObjectMethod(pattern string, object interface{}, method s
initFunc: initFunc,
shutFunc: shutFunc,
middleware: middleware,
source: source,
}
s.bindHandlerByMap(m)
}
func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware []HandlerFunc) {
func (s *Server) doBindObjectRest(
pattern string, object interface{},
middleware []HandlerFunc, source string,
) {
m := make(map[string]*handlerItem)
v := reflect.ValueOf(object)
t := v.Type()
@ -213,6 +225,7 @@ func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware
initFunc: initFunc,
shutFunc: shutFunc,
middleware: middleware,
source: source,
}
}
s.bindHandlerByMap(m)

View File

@ -40,6 +40,7 @@ func Test_Middleware_CORS(t *testing.T) {
resp, err := client.Get("/api.v2/user/list")
gtest.Assert(err, nil)
gtest.Assert(len(resp.Header["Access-Control-Allow-Headers"]), 0)
gtest.Assert(resp.StatusCode, 404)
resp.Close()
// POST request matches the route and CORS middleware.
@ -61,6 +62,7 @@ func Test_Middleware_CORS(t *testing.T) {
gtest.Assert(err, nil)
gtest.Assert(len(resp.Header["Access-Control-Allow-Headers"]), 0)
gtest.Assert(resp.ReadAllString(), "Not Found")
gtest.Assert(resp.StatusCode, 404)
resp.Close()
})
// OPTIONS POST
@ -71,6 +73,7 @@ func Test_Middleware_CORS(t *testing.T) {
resp, err := client.Options("/api.v2/user/list")
gtest.Assert(err, nil)
gtest.Assert(len(resp.Header["Access-Control-Allow-Headers"]), 1)
gtest.Assert(resp.StatusCode, 200)
resp.Close()
})
}