-
Notifications
You must be signed in to change notification settings - Fork 6
/
router_map.go
128 lines (110 loc) · 3.42 KB
/
router_map.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package hfw
import (
"fmt"
"reflect"
"strings"
logger "github.com/hsyan2008/go-logger"
"github.com/hsyan2008/hfw/encoding"
)
type instance struct {
reflectVal reflect.Value
controllerName string
//方法名字
methodName string
}
const (
NotFound = "NotFound"
)
var (
routeMap = make(map[string]*instance)
routeMapMethod = make(map[string]*instance)
routeMapRegister = make(map[string]string)
defaultInstance *instance
)
//controller如果有下划线,可以直接在注册的时候指定
//action的下划线,可以自动处理
func findInstanceByPath(httpCtx *HTTPContext) (instance *instance, action string) {
var ok bool
defer func() {
httpCtx.Controller = instance.controllerName
httpCtx.Action = action
}()
var inputPath string
if httpCtx.Path == "" {
inputPath = httpCtx.Request.URL.Path
} else {
inputPath = httpCtx.Path
}
//假设url上没有action
controllerPath := completeURL(inputPath)
httpCtx.Action = Config.Route.DefaultAction
httpCtx.Path = fmt.Sprintf("%s/%s", controllerPath, httpCtx.Action)
if instance, ok = routeMapMethod[httpCtx.Path+"for"+httpCtx.Request.Method]; ok {
return instance, instance.methodName
}
if instance, ok = routeMap[httpCtx.Path]; ok {
return instance, instance.methodName
}
//假设url上最后一段是action
tmp := strings.Split(controllerPath, "/")
controllerPath = strings.Join(tmp[:len(tmp)-1], "/")
httpCtx.Action = tmp[len(tmp)-1]
httpCtx.Path = fmt.Sprintf("%s/%s", controllerPath, httpCtx.Action)
if instance, ok = routeMapMethod[httpCtx.Path+"for"+httpCtx.Request.Method]; ok {
return instance, instance.methodName
}
if instance, ok = routeMap[httpCtx.Path]; ok {
return instance, instance.methodName
}
httpCtx.Action = strings.ToLower(NotFound)
//defaultInstance可能是nil,但Router已有判断
return defaultInstance, NotFound
}
func completeURL(url string) string {
//去掉前缀并把url补全为2段
trimURL := strings.Trim(strings.ToLower(url), "/")
if trimURL == "" {
trimURL = Config.Route.DefaultController
}
return trimURL
}
//actions包含小写和下划线两种格式的方法名,已去重
func getActionsAndMethod(funcName string) (actions []string, method string, isMethod bool) {
if len(funcName) == 0 {
return
}
action := funcName
tmp := strings.Split(funcName, "For")
tmpLen := len(tmp)
if tmpLen > 1 {
method = tmp[tmpLen-1]
switch method {
case "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT":
isMethod = true
action = strings.TrimSuffix(funcName, fmt.Sprintf("For%s", method))
default:
method = ""
}
}
actions = append(actions, strings.ToLower(action))
snakeAction := encoding.Snake(action)
if actions[0] != snakeAction {
actions = append(actions, snakeAction)
}
return
}
//修改httpCtx.Path后重新寻找执行action
func DispatchRoute(httpCtx *HTTPContext) {
//这里httpCtx的Controller和Action是传过来的c和m,在findInstanceByPath会修改成正确的
httpCtx.Path = fmt.Sprintf("C:%s M:%s", httpCtx.Controller, httpCtx.Action)
instance, action := findInstanceByPath(httpCtx)
logger.Debugf("Dispatch %s -> Call: %s/%s", httpCtx.Path, httpCtx.Controller, httpCtx.Action)
reflectVal := instance.reflectVal
//初始化httpCtx
initValue := []reflect.Value{
reflect.ValueOf(httpCtx),
}
reflectVal.MethodByName("Before").Call(initValue)
defer reflectVal.MethodByName("After").Call(initValue)
reflectVal.MethodByName(action).Call(initValue)
}