一. 首先,介绍下框架的主要功能:
将如下url:
1
/controller/function/arg1/arg2...
路由到对应的方法:
1
Controller.function(arg1,arg2,...)
二. 具体实现
将所有请求都集中到一个handler中做处理
1
2
3
4
5
func GetServeMux() *http.ServeMux {
var mServeMux http.ServeMux
mServeMux.HandleFunc("/", defaultHandler)
return &mServeMux
}
根据url格式,解析请求的uri
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
func defaultHandler(w http.ResponseWriter, req *http.Request) {
defer func() {
if err := recover(); err != nil {
//这里,主要是捕获调用函数参数不一致情况
common.PrintError(err)
io.WriteString(w, common.Error404())
}
}()
//获取请求uri
uri := req.RequestURI
fmt.Print(req.Method, " ", req.Host, " ", uri, " ",req.RemoteAddr, " " )
//若请求不带任何值, 则加上默认的controller(这个默认值是可以配置的)
if uri == "/" {
uri = "/" + config.GetConfig().DEFAULT_CONTROLLER
}
data := strings.Split(uri, "/")
//根据url格式,data[1]是路由的controller名称
//在routerMap中查找controller name( routeMap是手动配置的路由表 )
if v, ok := routeMap[strings.ToUpper(data[1])]; ok {
//匹配到,继续解析
parse(&v, data[2:], &w, req)
} else if len(data) == 2 {
//TODO 以后增加处理,如 /favicon.ico /sdsd.html 等等
common.PrintError("No router found")
io.WriteString(w, common.Error404())
} else {
common.PrintError("No router found")
io.WriteString(w, common.Error404())
}
}
parse方法中, 关键代码
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
func parse(cfg *controller.Cfg, data []string, w *http.ResponseWriter, req *http.Request) {
// cfg.Cb 就是对应的controller实例的指针
//考虑到并发, 要copy出一个实例
//这里用反射实现
b := reflect.New(reflect.ValueOf(cfg.Cb).Elem().Type()).Interface().(controller.Base)
......
//如果url格式没有方法名,默认加上index方法
if len(data) == 0 {
data = append(data, "index")
}
//将方法名转换成{首字母大写、其余小写}的形式
methodName := strings.ToUpper(string(data[0][0])) + strings.ToLower(string(data[0][1:]))
......
//利用反射调用方法
mMethod := reflect.ValueOf(b).MethodByName(methodName)
if mMethod.IsValid() {
var params []reflect.Value
if len(data) > 1 {
//设置方法的参数
//根据url格式,解析参数
params = make([]reflect.Value, len(data)-1)
for i := range params {
switch mMethod.Type().In(i).Name() {
case "int":
if v,err := strconv.Atoi(data[i+1]); err == nil {
params[i] = reflect.ValueOf(v)
} else {
common.PrintError("Arguments Type is not match!")
io.WriteString(*w, common.Error404())
return
}
default:
params[i] = reflect.ValueOf(data[i+1])
}
}
}
//最后,调用方法
mMethod.Call(params)
fmt.Println()
} else {
common.PrintError("Not found method in controller")
io.WriteString(*w, common.Error404())
}
}
项目的github地址: https://github.com/ejin66/GoEjin