/
controller.go
370 lines (334 loc) · 11.6 KB
/
controller.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
package eudore
import (
"fmt"
"reflect"
"sort"
"strings"
)
/*
Controller defines the controller interface.
The default AutoRoute controller implements the following functions:
The controller method maps the route method path.
Controller construction error delivery.
Custom controller function mapping relationship.
Custom controller routing group and routing parameters.
Controller routing combination, get the routing method of the combined controller.
Controller method composition, using the calling method controlled by the composition.
Controller 定义控制器接口。
默认AutoRoute控制器实现下列功能:
控制器方法映射路由方法路径。
控制器构造错误传递(NewControllerError)。
自定义控制器函数映射关系(实现'func ControllerRoute() map[string]string)')。
自定义控制器路由组和路由参数(实现'func ControllerParam(pkg, name, method string) string')。
控制器路由组合,获得被组合控制器的路由方法。
控制器方法组合,使用被组合控制的的调用方法。
*/
type Controller interface {
Inject(Controller, Router) error
}
type controllerGroup interface {
ControllerGroup(string) string
}
// controllerRoute 定义获得路由和方法映射的接口。
type controllerRoute interface {
ControllerRoute() map[string]string
}
// controllerParam 定义获得一个路由参数的接口,转入pkg、controllername、methodname获得需要添加的路由参数。
type controllerParam interface {
ControllerParam(string, string, string) string
}
// The ControllerAutoRoute implements the routing mapping controller
// to register the corresponding router method according to the method.
//
// ControllerAutoRoute 实现路由映射控制器根据方法注册对应的路由器方法。
type ControllerAutoRoute struct{}
type controllerError struct {
Controller
Error error
}
// NewControllerError function returns a controller error, and the corresponding error is returned when the controller Inject.
//
// NewControllerError 函数返回一个控制器错误,在控制器Inject时返回对应的错误。
func NewControllerError(ctl Controller, err error) Controller {
return &controllerError{
Controller: ctl,
Error: err,
}
}
// The Inject method returns a controller error when injecting routing rules.
//
// Inject 方法在注入路由规则时返回控制器错误。
func (ctl controllerError) Inject(Controller, Router) error {
return ctl.Error
}
func (ctl controllerError) Unwrap() Controller {
return ctl.Controller
}
// Inject method implements the method of injecting the controller into the router,
// and the ControllerAutoRoute controller calls the ControllerInjectAutoRoute method to inject.
//
// Inject 方法实现控制器注入到路由器的方法,ControllerAutoRoute控制器调用ControllerInjectAutoRoute方法注入。
func (ctl ControllerAutoRoute) Inject(controller Controller, router Router) error {
return ControllerInjectAutoRoute(controller, router)
}
// ControllerInjectAutoRoute function generates routing rules based on the controller rules,
// and the usage method is converted into a processing function to support routers.
//
// Routing group: If the'ControllerGroup(string) string' method is implemented,
// the routing group is returned; if the routing parameter ParamControllerGroup is included,
// it is used; otherwise, the controller name is used to turn the path.
//
// Routing path: Convert the method with the request method as the prefix to the routing method and path,
// and then use the map[method]path returned by the'ControllerRoute() map[string]string' method to overwrite the routing path.
//
// Method conversion rules: The method prefix must be a valid request method (within DefaultRouterAllMethod),
// the remaining path is converted to a path, ByName is converted to variable matching/:name,
// and the last By of the method path is converted to /*;
// The return path of ControllerRoute is'-' and the method is ignored. The first character is”,
// which means it is a path append parameter.
//
// Routing parameters: If you implement the'ControllerParam(string, string, string) string' method to return routing parameters,
// otherwise use "controllername=%s.%s controllermethod=%s".
//
// Controller combination: If the controller combines other objects,
// only the methods of the object whose name suffix is Controller are reserved,
// and other methods with embedded properties will be ignored.
//
// ControllerInjectAutoRoute 函数基于控制器规则生成路由规则,使用方法转换成处理函数支持路由器。
//
// 路由组: 如果实现'ControllerGroup(string) string'方法返回路由组;
// 如果包含路由参数ParamControllerGroup则使用;否则使用控制器名称驼峰转路径。
//
// 路由路径: 将请求方法为前缀的方法转换成路由方法和路径,
// 然后使用'ControllerRoute() map[string]string'方法返回的map[method]path覆盖路由路径。
//
// 方法转换规则: 方法前缀必须是有效的请求方法(DefaultRouterAllMethod之内),
// 剩余路径驼峰转路径,ByName转换成变量匹配/:name,方法路径最后一个By转换成/*;
// ControllerRoute返回路径为'-'则忽略方法,第一个字符为' '表示为路径追加参数。
//
// 路由参数: 如果实现'ControllerParam(string, string, string) string'方法返回路由参数,
// 否则使用"controllername=%s.%s controllermethod=%s"。
//
// 控制器组合: 如果控制器组合了其他对象,仅保留名称后缀为Controller的对象的方法,其他嵌入属性的方法将被忽略。
func ControllerInjectAutoRoute(controller Controller, router Router) error {
iType := reflect.TypeOf(controller)
v := reflect.ValueOf(controller)
// 添加控制器组。
cname := getControllerName(v)
cpkg := reflect.Indirect(v).Type().PkgPath()
router = router.Group(getContrllerRouterGroup(controller, cname, router))
// 获取路由参数函数
pfn := defaultRouteParam
p, ok := controller.(controllerParam)
if ok {
pfn = p.ControllerParam
}
// 路由器注册控制器方法
names, paths := getSortMapValue(getControllerRoutes(controller))
for i, name := range names {
m, ok := iType.MethodByName(name)
if !ok || paths[i] == "-" {
continue
}
h := v.Method(m.Index).Interface()
SetHandlerAliasName(h, fmt.Sprintf("%s.%s.%s", cpkg, cname, name))
method := getMethodByName(name)
if method == "" {
method = MethodAny
}
err := router.AddHandler(method, paths[i]+" "+pfn(cpkg, cname, name), h)
if err != nil {
return err
}
}
return nil
}
func getContrllerRouterGroup(controller Controller, name string, router Router) (group string) {
ctl, ok := controller.(controllerGroup)
switch {
case ok:
group = ctl.ControllerGroup(name)
case router.Params().Get(ParamControllerGroup) != "":
group = router.Params().Get(ParamControllerGroup)
router.Params().Del(ParamControllerGroup)
case strings.HasSuffix(name, "Controller"):
buf := make([]rune, 0, len(name)*2)
for _, b := range name[:len(name)-10] {
if 64 < b && b < 91 {
buf = append(buf, '/', b+0x20)
} else {
buf = append(buf, b)
}
}
group = string(buf)
}
if group != "" && group[0] != '/' {
return "/" + group
}
return group
}
// defaultRouteParam 函数定义默认的控制器参数,可以通过实现controllerParam来覆盖该函数。
func defaultRouteParam(pkg, name, method string) string {
return fmt.Sprintf("controller=%s.%s controllermethod=%s", pkg, name, method)
}
func getSortMapValue(data map[string]string) ([]string, []string) {
keys := make([]string, 0, len(data))
vals := make([]string, len(data))
for key := range data {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool {
vi, vj := getRoutePath(data[keys[i]]), getRoutePath(data[keys[j]])
if vi == vj {
return keys[i] < keys[j]
}
return vi < vj
})
for i, key := range keys {
vals[i] = data[key]
}
return keys, vals
}
// getControllerRoutes 函数获得一个控制器类型注入的全部名称和路由路径的映射。
func getControllerRoutes(controller Controller) map[string]string {
routes := getContrllerAllowMethos(reflect.ValueOf(controller))
for name := range routes {
if getMethodByName(name) != "" {
routes[name] = getRouteByName(name)
} else {
delete(routes, name)
}
}
// 如果控制器实现ControllerRoute接口,加载额外路由。
controllerRoute, isRoute := controller.(controllerRoute)
if isRoute {
for name, path := range controllerRoute.ControllerRoute() {
if len(path) > 0 && path[0] == ' ' {
// ControllerRoute获得的路径是空格开头,表示为路由参数。
routes[name] += path
} else {
routes[name] = path
}
}
}
return routes
}
func getContrllerAllowMethos(v reflect.Value) map[string]string {
names := make(map[string]string)
for _, name := range getContrllerAllMethos(v) {
names[name] = ""
}
v = reflect.Indirect(v)
iType := v.Type()
if v.Kind() == reflect.Struct {
// 删除嵌入非控制器方法
for i := 0; i < v.NumField(); i++ {
if iType.Field(i).Anonymous {
if !strings.HasSuffix(getControllerName(v.Field(i)), "Controller") {
for _, name := range getContrllerAllMethos(v.Field(i)) {
delete(names, name)
}
}
}
}
// 追加嵌入控制器方法
for i := 0; i < iType.NumField(); i++ {
if iType.Field(i).Anonymous {
if strings.HasSuffix(getControllerName(v.Field(i)), "Controller") {
for _, name := range getContrllerAllMethos(v.Field(i)) {
names[name] = ""
}
}
}
}
}
return names
}
// getContrllerAllMethos 函数获得一共类型包含指针类型的全部方法名称。
func getContrllerAllMethos(v reflect.Value) []string {
iType := v.Type()
if iType.Kind() != reflect.Ptr {
iType = reflect.New(iType).Type()
}
names := make([]string, iType.NumMethod())
for i := 0; i < iType.NumMethod(); i++ {
names[i] = iType.Method(i).Name
}
return names
}
func getControllerName(v reflect.Value) string {
if v.Kind() == reflect.Ptr && v.IsNil() {
v = reflect.New(v.Type().Elem())
}
name := reflect.Indirect(v).Type().Name()
// 泛型名称
pos := strings.IndexByte(name, '[')
if pos != -1 {
name = name[:pos]
}
return name
}
// getRouteByName 函数使用函数名称生成路由路径。
func getRouteByName(name string) string {
names := splitTitleName(name)
if getMethodByName(names[0]) != "" {
names = names[1:]
}
name = ""
for i := 0; i < len(names); i++ {
if names[i] == "By" {
i++
if i == len(names) {
name += "/*"
} else {
name = name + "/:" + names[i]
}
} else {
name = name + "/" + names[i]
}
}
return strings.ToLower(name)
}
func getMethodByName(name string) string {
name = strings.ToUpper(getFirstUp(name))
if name == "ANY" {
return MethodAny
}
for _, method := range DefaultRouterAllMethod {
if method == name {
return name
}
}
return ""
}
func getFirstUp(name string) string {
for i, c := range name {
if 0x40 < c && c < 0x5B && i != 0 {
return name[:i]
}
}
return name
}
// splitTitleName 方法基于路径首字符大写切割。
func splitTitleName(str string) []string {
var body []byte
for i := range str {
switch {
case i != 0 && byteIn(str[i], 0x40) && byteIn(str[i-1], 0x60):
body = append(body, ' ')
body = append(body, str[i])
case i != 0 && i != len(str)-1 && byteIn(str[i], 0x40) &&
byteIn(str[i-1], 0x40) && byteIn(str[i+1], 0x60):
body = append(body, ' ')
body = append(body, str[i])
case byteIn(str[i], 0x40) && i != 0:
body = append(body, str[i]+0x20)
default:
body = append(body, str[i])
}
}
return strings.Split(string(body), " ")
}
func byteIn(b byte, r byte) bool {
return r < b && b < r+0x1B
}