从零实现gin day04 路由分组

95 阅读2分钟

前言

上一章我们实现了动态路由的匹配.这一章我们要实现路由的分组.一般来说/user/info /user/add /user/update 这些路由都属于/user组,我们可以通过统一的前缀来给路由添加分组.

上一章的bug修复

  • bug fix:将return n改为了return child,只有匹配到了这个part的节点才返回,而不是返回整体的n
func (n *node) matchChild(part string) *node {  
    for _, child := range n.child {  
        if child.part == part || n.isWild {  
            return child  
        }  
    }  
    return nil  
}

路由分组实现

结构体的设计与修改

  • 路由分组的设计
    • prefix是分组的前缀
    • 所有的路由都属于同一个engine实例
    • parent是分组的父分组
  • Engine的修改
    • RouterGroup 抽象Engine为最顶层,拥有RouterGroup的能力
    • Engine 拥有所有的已添加RouterGroup
type RouterGroup struct {  
    prefix string 
    engine *Engine  
    parent *RouterGroup  
}
type Engine struct {  
    *RouterGroup  
    router *Router  
    groups []*RouterGroup  
}

改造router

现在RouterGroup接管了整个的路由,那么RouterGroup应该具备以下能力

  • 路由分组能力 Group
  • 添加路由能力 AddRouter GET POST
func (g *RouterGroup) Group(prefix string) *RouterGroup {  
    engine := g.engine  
    routerGroup := &RouterGroup{  
        prefix: g.prefix + prefix,  
        engine: engine,  
        parent: g,  
    }  
    engine.groups = append(engine.groups, routerGroup)  
    return routerGroup  
}  
  
//分组添加路由  
func (g *RouterGroup) AddRouter(method string, path string, handle HandleFunc) {  
    patten := g.prefix + path  
    g.engine.router.AddRouter(method, patten, handle)  
}
func (g *RouterGroup) POST(path string, handle HandleFunc) {  
    g.AddRouter("POST", path, handle)  
}  
func (g *RouterGroup) GET(path string, handle HandleFunc) {  
    g.AddRouter("GET", path, handle)  
}

改造engine

engine具备RouterGroup的能力,并且将新增的RouterGroup添加到groups中

func newEngine() *Engine {  
    engine := &Engine{router: newRouter()}  
    engine.RouterGroup = &RouterGroup{engine: engine}  
    engine.groups = append(engine.groups, engine.RouterGroup)  
    return engine  
}

测试

user := e.Group("/user")  
{  
    user.GET("/info", func(ctx *Context) {  
        ctx.HTML(200, "用户信息")  
    })  
    v1 := user.Group("/v1")  
    {  
        v1.GET("/info", func(ctx *Context) {  
            ctx.HTML(http.StatusOK, "v1 版本用户信息")  
            })  
        }  
        user.POST("/save", func(ctx *Context) {  
            ctx.JSON(http.StatusOK, H{  
            "username": "ziyu",  
            "age": 18,  
            })  
        })  
    }
GET http://localhost:7999/user/info

HTTP/1.1 200 OK
Date: Mon, 16 Oct 2023 06:56:02 GMT
Content-Length: 12
Content-Type: text/plain; charset=utf-8

用户信息
GET http://localhost:7999/user/v1/info

HTTP/1.1 200 OK
Date: Mon, 16 Oct 2023 06:57:10 GMT
Content-Length: 21
Content-Type: text/plain; charset=utf-8

v1 版本用户信息

总结

本章完成了路由的分组.总体逻辑较为简单