Dawn's Blogs

分享技术 记录成长

0%

从零实现一个Web框架 (4) 分组

在本节,最终的代码目录结构如下:

1
2
3
4
5
6
7
8
dain/
|--context.go
|--dain.go
|--router.go
|--trie.go
|--go.mod
main.go
go.mod

实现目标

可以对路由进行分组,每一组内的路由都可以有相似用途,也对分组定义中间件。

main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"DawnGin/dain"
"net/http"
)

func main() {
e := dain.New()

// 分组路由
v1 := e.Group("/v1")
{
v1.Get("/video/:name", func(c *dain.Context) {
videoName := c.Param("name")
c.String(http.StatusOK, "Hello, this is v1 group, video name = %v, path = %v", videoName, c.Path)
})
}

e.Run(":9000")
}

分组控制

dain/dain.go

结构体

我们需要通过前缀来区分分组路由,同时还需要记录当前分组的上一层、应用于当前分组的中间件以及最顶层的 Engine

1
2
3
4
5
6
7
// RouterGroup 分组路由
type RouterGroup struct {
prefix string // 当前分组的公共前缀
parent *RouterGroup // 记录当前分组的上一层
middleware []HandlerFunc // 记录中间件
engine *Engine // 记录所属的 Engine
}

可以将 Engine 作为最顶层的分组,也就是说 Engine 具有 RouterGroup 的所有能力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type Engine struct {
// 路由器
router *router
// 继承 RouterGroup,把根也看作是一个分组
*RouterGroup
// 记录所有的路由分组
groups []*RouterGroup
}

// New 返回一个 Engine 指针
func New() *Engine {
engine := &Engine{router: NewRouter()}
engine.RouterGroup = &RouterGroup{engine: engine}
engine.groups = []*RouterGroup{engine.RouterGroup}

return engine
}

添加分组

通过 Group 函数可以添加分组:

1
2
3
4
5
6
7
8
9
10
func (group *RouterGroup) Group(prefix string) *RouterGroup {
engine := group.engine
newGroup := &RouterGroup{
prefix: group.prefix + prefix,
parent: group,
engine: engine,
}
engine.groups = append(engine.groups, newGroup) // 在 Engine 中保存新的分组
return newGroup
}

注册路由

因为分组也可以注册路由,所以将 Engine 的路由注册方法更改为 RouterGroup 的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// addRouter 实现路由注册功能
func (group *RouterGroup) addRouter(method, pattern string, handler HandlerFunc) {
pattern = group.prefix + pattern
group.engine.router.addRouter(method, pattern, handler)
}

// Get 路由注册 GET 请求方式
func (group *RouterGroup) Get(pattern string, handler HandlerFunc) {
group.addRouter("GET", pattern, handler)
}

// Post 路由注册 POST 请求方式
func (group *RouterGroup) Post(pattern string, handler HandlerFunc) {
group.addRouter("POST", pattern, handler)
}