mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.
**Type alias migration to `any`:**
* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)
**Generated code and templates:**
* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
**Container and utility updates:**
* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)
These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
435 lines
12 KiB
Go
435 lines
12 KiB
Go
// Copyright GoFrame Author(https://goframe.org). 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 (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/gogf/gf/v2/debug/gdebug"
|
|
"github.com/gogf/gf/v2/internal/consts"
|
|
"github.com/gogf/gf/v2/internal/reflection"
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
)
|
|
|
|
type (
|
|
// RouterGroup is a group wrapping multiple routes and middleware.
|
|
RouterGroup struct {
|
|
parent *RouterGroup // Parent group.
|
|
server *Server // Server.
|
|
domain *Domain // Domain.
|
|
prefix string // Prefix for sub-route.
|
|
middleware []HandlerFunc // Middleware array.
|
|
}
|
|
|
|
// preBindItem is item for lazy registering feature of router group. preBindItem is not really registered
|
|
// to server when route function of the group called but is lazily registered when server starts.
|
|
preBindItem struct {
|
|
group *RouterGroup
|
|
bindType string
|
|
pattern string
|
|
object any // Can be handler, controller or object.
|
|
params []any // Extra parameters for route registering depending on the type.
|
|
source string // Handler is a register at a certain source file path: line.
|
|
bound bool // Is this item bound to server?
|
|
}
|
|
)
|
|
|
|
const (
|
|
groupBindTypeHandler = "HANDLER"
|
|
groupBindTypeRest = "REST"
|
|
groupBindTypeHook = "HOOK"
|
|
groupBindTypeMiddleware = "MIDDLEWARE"
|
|
)
|
|
|
|
var (
|
|
preBindItems = make([]*preBindItem, 0, 64)
|
|
)
|
|
|
|
// handlePreBindItems is called when server starts, which does really route registering to the server.
|
|
func (s *Server) handlePreBindItems(ctx context.Context) {
|
|
if len(preBindItems) == 0 {
|
|
return
|
|
}
|
|
for _, item := range preBindItems {
|
|
if item.bound {
|
|
continue
|
|
}
|
|
// Handle the items of current server.
|
|
if item.group.server != nil && item.group.server != s {
|
|
continue
|
|
}
|
|
if item.group.domain != nil && item.group.domain.server != s {
|
|
continue
|
|
}
|
|
item.group.doBindRoutersToServer(ctx, item)
|
|
item.bound = true
|
|
}
|
|
}
|
|
|
|
// Group creates and returns a RouterGroup object.
|
|
func (s *Server) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
|
|
if len(prefix) > 0 && prefix[0] != '/' {
|
|
prefix = "/" + prefix
|
|
}
|
|
if prefix == "/" {
|
|
prefix = ""
|
|
}
|
|
group := &RouterGroup{
|
|
server: s,
|
|
prefix: prefix,
|
|
}
|
|
if len(groups) > 0 {
|
|
for _, v := range groups {
|
|
v(group)
|
|
}
|
|
}
|
|
return group
|
|
}
|
|
|
|
// Group creates and returns a RouterGroup object, which is bound to a specified domain.
|
|
func (d *Domain) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
|
|
if len(prefix) > 0 && prefix[0] != '/' {
|
|
prefix = "/" + prefix
|
|
}
|
|
if prefix == "/" {
|
|
prefix = ""
|
|
}
|
|
routerGroup := &RouterGroup{
|
|
domain: d,
|
|
server: d.server,
|
|
prefix: prefix,
|
|
}
|
|
if len(groups) > 0 {
|
|
for _, nestedGroup := range groups {
|
|
nestedGroup(routerGroup)
|
|
}
|
|
}
|
|
return routerGroup
|
|
}
|
|
|
|
// Group creates and returns a subgroup of the current router group.
|
|
func (g *RouterGroup) Group(prefix string, groups ...func(group *RouterGroup)) *RouterGroup {
|
|
if prefix == "/" {
|
|
prefix = ""
|
|
}
|
|
group := &RouterGroup{
|
|
parent: g,
|
|
server: g.server,
|
|
domain: g.domain,
|
|
prefix: prefix,
|
|
}
|
|
if len(g.middleware) > 0 {
|
|
group.middleware = make([]HandlerFunc, len(g.middleware))
|
|
copy(group.middleware, g.middleware)
|
|
}
|
|
if len(groups) > 0 {
|
|
for _, v := range groups {
|
|
v(group)
|
|
}
|
|
}
|
|
return group
|
|
}
|
|
|
|
// Clone returns a new router group which is a clone of the current group.
|
|
func (g *RouterGroup) Clone() *RouterGroup {
|
|
newGroup := &RouterGroup{
|
|
parent: g.parent,
|
|
server: g.server,
|
|
domain: g.domain,
|
|
prefix: g.prefix,
|
|
middleware: make([]HandlerFunc, len(g.middleware)),
|
|
}
|
|
copy(newGroup.middleware, g.middleware)
|
|
return newGroup
|
|
}
|
|
|
|
// Bind does batch route registering feature for a router group.
|
|
func (g *RouterGroup) Bind(handlerOrObject ...any) *RouterGroup {
|
|
var (
|
|
ctx = context.TODO()
|
|
group = g.Clone()
|
|
)
|
|
for _, v := range handlerOrObject {
|
|
var (
|
|
item = v
|
|
originValueAndKind = reflection.OriginValueAndKind(item)
|
|
)
|
|
|
|
switch originValueAndKind.OriginKind {
|
|
case reflect.Func, reflect.Struct:
|
|
group = group.preBindToLocalArray(
|
|
groupBindTypeHandler,
|
|
"/",
|
|
item,
|
|
)
|
|
|
|
default:
|
|
g.server.Logger().Fatalf(
|
|
ctx, "invalid bind parameter type: %v, should be route function or struct object",
|
|
originValueAndKind.InputValue.Type(),
|
|
)
|
|
}
|
|
}
|
|
return group
|
|
}
|
|
|
|
// ALL register an http handler to give the route pattern and all http methods.
|
|
func (g *RouterGroup) ALL(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(
|
|
groupBindTypeHandler,
|
|
defaultMethod+":"+pattern,
|
|
object,
|
|
params...,
|
|
)
|
|
}
|
|
|
|
// ALLMap registers http handlers for http methods using map.
|
|
func (g *RouterGroup) ALLMap(m map[string]any) {
|
|
for pattern, object := range m {
|
|
g.ALL(pattern, object)
|
|
}
|
|
}
|
|
|
|
// Map registers http handlers for http methods using map.
|
|
func (g *RouterGroup) Map(m map[string]any) {
|
|
for pattern, object := range m {
|
|
g.preBindToLocalArray(groupBindTypeHandler, pattern, object)
|
|
}
|
|
}
|
|
|
|
// GET registers an http handler to give the route pattern and the http method: GET.
|
|
func (g *RouterGroup) GET(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "GET:"+pattern, object, params...)
|
|
}
|
|
|
|
// PUT registers an http handler to give the route pattern and the http method: PUT.
|
|
func (g *RouterGroup) PUT(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "PUT:"+pattern, object, params...)
|
|
}
|
|
|
|
// POST registers an http handler to give the route pattern and the http method: POST.
|
|
func (g *RouterGroup) POST(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "POST:"+pattern, object, params...)
|
|
}
|
|
|
|
// DELETE registers an http handler to give the route pattern and the http method: DELETE.
|
|
func (g *RouterGroup) DELETE(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "DELETE:"+pattern, object, params...)
|
|
}
|
|
|
|
// PATCH registers an http handler to give the route pattern and the http method: PATCH.
|
|
func (g *RouterGroup) PATCH(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "PATCH:"+pattern, object, params...)
|
|
}
|
|
|
|
// HEAD registers an http handler to give the route pattern and the http method: HEAD.
|
|
func (g *RouterGroup) HEAD(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "HEAD:"+pattern, object, params...)
|
|
}
|
|
|
|
// CONNECT registers an http handler to give the route pattern and the http method: CONNECT.
|
|
func (g *RouterGroup) CONNECT(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "CONNECT:"+pattern, object, params...)
|
|
}
|
|
|
|
// OPTIONS register an http handler to give the route pattern and the http method: OPTIONS.
|
|
func (g *RouterGroup) OPTIONS(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "OPTIONS:"+pattern, object, params...)
|
|
}
|
|
|
|
// TRACE registers an http handler to give the route pattern and the http method: TRACE.
|
|
func (g *RouterGroup) TRACE(pattern string, object any, params ...any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, "TRACE:"+pattern, object, params...)
|
|
}
|
|
|
|
// REST registers an http handler to give the route pattern according to REST rule.
|
|
func (g *RouterGroup) REST(pattern string, object any) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeRest, pattern, object)
|
|
}
|
|
|
|
// Hook registers a hook to given route pattern.
|
|
func (g *RouterGroup) Hook(pattern string, hook HookName, handler HandlerFunc) *RouterGroup {
|
|
return g.Clone().preBindToLocalArray(groupBindTypeHandler, pattern, handler, hook)
|
|
}
|
|
|
|
// Middleware binds one or more middleware to the router group.
|
|
func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {
|
|
g.middleware = append(g.middleware, handlers...)
|
|
return g
|
|
}
|
|
|
|
// preBindToLocalArray adds the route registering parameters to an internal variable array for lazily registering feature.
|
|
func (g *RouterGroup) preBindToLocalArray(bindType string, pattern string, object any, params ...any) *RouterGroup {
|
|
_, file, line := gdebug.CallerWithFilter([]string{consts.StackFilterKeyForGoFrame})
|
|
preBindItems = append(preBindItems, &preBindItem{
|
|
group: g,
|
|
bindType: bindType,
|
|
pattern: pattern,
|
|
object: object,
|
|
params: params,
|
|
source: fmt.Sprintf(`%s:%d`, file, line),
|
|
})
|
|
return g
|
|
}
|
|
|
|
// getPrefix returns the route prefix of the group, which recursively retrieves its parent's prefix.
|
|
func (g *RouterGroup) getPrefix() string {
|
|
prefix := g.prefix
|
|
parent := g.parent
|
|
for parent != nil {
|
|
prefix = parent.prefix + prefix
|
|
parent = parent.parent
|
|
}
|
|
return prefix
|
|
}
|
|
|
|
// doBindRoutersToServer does really register for the group.
|
|
func (g *RouterGroup) doBindRoutersToServer(ctx context.Context, 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 {
|
|
domain, method, path, err := g.server.parsePattern(pattern)
|
|
if err != nil {
|
|
g.server.Logger().Fatalf(ctx, "invalid route pattern: %s", pattern)
|
|
}
|
|
// If there is already a domain, unset the domain field in the pattern.
|
|
if g.domain != nil {
|
|
domain = ""
|
|
}
|
|
if bindType == groupBindTypeRest {
|
|
pattern = path
|
|
} else {
|
|
pattern = g.server.serveHandlerKey(
|
|
method, path, domain,
|
|
)
|
|
}
|
|
}
|
|
// Filter repeated char '/'.
|
|
pattern = gstr.Replace(pattern, "//", "/")
|
|
|
|
// Convert params to a string array.
|
|
extras := gconv.Strings(params)
|
|
|
|
// Check whether it's a hook handler.
|
|
if _, ok := object.(HandlerFunc); ok && len(extras) > 0 {
|
|
bindType = groupBindTypeHook
|
|
}
|
|
switch bindType {
|
|
case groupBindTypeHandler:
|
|
if reflect.ValueOf(object).Kind() == reflect.Func {
|
|
funcInfo, err := g.server.checkAndCreateFuncInfo(object, "", "", "")
|
|
if err != nil {
|
|
g.server.Logger().Fatal(ctx, err.Error())
|
|
return g
|
|
}
|
|
in := doBindHandlerInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
FuncInfo: funcInfo,
|
|
Middleware: g.middleware,
|
|
Source: source,
|
|
}
|
|
if g.domain != nil {
|
|
g.domain.doBindHandler(ctx, in)
|
|
} else {
|
|
g.server.doBindHandler(ctx, in)
|
|
}
|
|
} else {
|
|
if len(extras) > 0 {
|
|
if gstr.Contains(extras[0], ",") {
|
|
in := doBindObjectInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
Object: object,
|
|
Method: extras[0],
|
|
Middleware: g.middleware,
|
|
Source: source,
|
|
}
|
|
if g.domain != nil {
|
|
g.domain.doBindObject(ctx, in)
|
|
} else {
|
|
g.server.doBindObject(ctx, in)
|
|
}
|
|
} else {
|
|
in := doBindObjectMethodInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
Object: object,
|
|
Method: extras[0],
|
|
Middleware: g.middleware,
|
|
Source: source,
|
|
}
|
|
if g.domain != nil {
|
|
g.domain.doBindObjectMethod(ctx, in)
|
|
} else {
|
|
g.server.doBindObjectMethod(ctx, in)
|
|
}
|
|
}
|
|
} else {
|
|
in := doBindObjectInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
Object: object,
|
|
Method: "",
|
|
Middleware: g.middleware,
|
|
Source: source,
|
|
}
|
|
// Finally, it treats the `object` as the Object registering type.
|
|
if g.domain != nil {
|
|
g.domain.doBindObject(ctx, in)
|
|
} else {
|
|
g.server.doBindObject(ctx, in)
|
|
}
|
|
}
|
|
}
|
|
|
|
case groupBindTypeRest:
|
|
in := doBindObjectInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
Object: object,
|
|
Method: "",
|
|
Middleware: g.middleware,
|
|
Source: source,
|
|
}
|
|
if g.domain != nil {
|
|
g.domain.doBindObjectRest(ctx, in)
|
|
} else {
|
|
g.server.doBindObjectRest(ctx, in)
|
|
}
|
|
|
|
case groupBindTypeHook:
|
|
if handler, ok := object.(HandlerFunc); ok {
|
|
in := doBindHookHandlerInput{
|
|
Prefix: prefix,
|
|
Pattern: pattern,
|
|
HookName: HookName(extras[0]),
|
|
Handler: handler,
|
|
Source: source,
|
|
}
|
|
if g.domain != nil {
|
|
g.domain.doBindHookHandler(ctx, in)
|
|
} else {
|
|
g.server.doBindHookHandler(ctx, in)
|
|
}
|
|
} else {
|
|
g.server.Logger().Fatalf(ctx, "invalid hook handler for pattern: %s", pattern)
|
|
}
|
|
}
|
|
return g
|
|
}
|