在我们开发定义路由的时候,可能会遇到很多部分重复的路由:
/admin/users
/admin/manager
/admin/photo
/admin/Gin
分组路由
类似以上示例,就是分好组的路由,分组的原因有很多,比如基于模块化,把同样模块的放在一起,比如基于版本,把相同版本的API放一起,便于使用。在有的框架中,分组路由也被称之为命名空间。
Gin
func main() {
r := gin.Default()
//V1版本的API
v1Group := r.Group("/v1")
v1Group.GET("/users", func(c *gin.Context) {
c.String(200, "/v1/users")
})
v1Group.GET("/products", func(c *gin.Context) {
c.String(200, "/v1/products")
})
//V2版本的API
v2Group := r.Group("/v2")
v2Group.GET("/users", func(c *gin.Context) {
c.String(200, "/v2/users")
})
v2Group.GET("/products", func(c *gin.Context) {
c.String(200, "/v2/products")
})
r.Run(":8080")
}
Groupr{}
v1Group := r.Group("/v1")
{
v1Group.GET("/users", func(c *gin.Context) {
c.String(200, "/v1/users")
})
v1Group.GET("/products", func(c *gin.Context) {
c.String(200, "/v1/products")
})
}
v2Group := r.Group("/v2")
{
v2Group.GET("/users", func(c *gin.Context) {
c.String(200, "/v2/users")
})
v2Group.GET("/products", func(c *gin.Context) {
c.String(200, "/v2/products")
})
}
路由中间件
Group
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup
...HandlerFunc
/admin
v1Group := r.Group("/v1", func(c *gin.Context) {
fmt.Println("/v1中间件")
})
/v1/users/v1/products/v1中间件
GroupHandlerFunc
分组路由嵌套
我们不光可以定义一个分组路由,还可以在这个分组路由中再添加一个分组路由,达到分组路由嵌套的目的,这种业务场景也不少,比如:
/v1/admin/users
/v1/admin/manager
/v1/admin/photo
adminGin
v1AdminGroup := v1Group.Group("/admin")
{
v1AdminGroup.GET("/users", func(c *gin.Context) {
c.String(200, "/v1/admin/users")
})
v1AdminGroup.GET("/manager", func(c *gin.Context) {
c.String(200, "/v1/admin/manager")
})
v1AdminGroup.GET("/photo", func(c *gin.Context) {
c.String(200, "/v1/admin/photo")
})
}
Group
原理解析
那么以前这种分组路由这么方便,实现会不会很复杂呢?我们来看看源代码,分析一下它的实现方式。
GET
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle("GET", relativePath, handlers)
}
relativePathGin
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
absolutePath := group.calculateAbsolutePath(relativePath)
handlers = group.combineHandlers(handlers)
group.engine.addRoute(httpMethod, absolutePath, handlers)
return group.returnObj()
}
absolutePath := group.calculateAbsolutePath(relativePath)group
calculateAbsolutePathGroup
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
return &RouterGroup{
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
engine: group.engine,
}
}
gin.Default()gin.EngineRouterGroupRouterGroup
Group*RouterGroupbasePathgroup.calculateAbsolutePath(relativePath)
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
return joinPaths(group.basePath, relativePath)
}
RouterGroupbasePathGroupRouterGroupbasePath
GroupRouterGroupbasePathRouterGroupbasePath
gin.Default()gin.EnginebasePath/
这是一种非常棒的代码实现方式,简单的代码,是强大的功能。
小结
分组路由的功能非常强大, 可以帮助我们进行版本的升级,模块的切分,而且它的代码实现又非常简单,这就是优秀的代码。通过分析,我们可以学到很多,也能提升很多,让自己的能力不知不觉的超越同行,同事。
精彩文章推荐
flysnow_org
扫码关注