七天从零实现Web框架Gee - 4

今天的任务是实现路由分组控制

关于分组控制

        这里的分组是指对可以进行相似处理的路由进行分组,是否分为一个组通常是以前缀进行区分,例如 /admin 为一个分组,那么 /admin/a 和 /admin/b 就是该分组下的子分组。如果没有分组控制,那么就需要对这两个不同的路由分别进行控制,会增加不必要的工作,也会增加路由控制的难度和复杂度。

        此外,分组支持嵌套,父分组的功能应该可以作用到子分组上,例如 /admin分组应该包含顶层分组 / 的相关处理。

数据结构

  • 分组需要通过前缀来对分组进行区分,所以包含 string 类型的 prefix
  • 分组之间要支持分组嵌套也就是需要知道当前分组的父辈,因此包含指向当前分组父亲分组的 RouterGroup 指针 parent
  • 分组对象需要有访问Router路由对象的能力,因此在其中包含指向 Engine(整个框架所有资源由Engine统一协调) 的指针 engine
  • 最后对已有的 Engine 对象进一步抽象,将其作为最顶层的分组,拥有RouterGroup的所有处理能力

最终 Engine 和 RouterGroup 的构造函数如下:

type (
	RouterGroup struct {             // 分组结构体
		prefix      string           // 分组对应的前缀
		parent      *RouterGroup     // 当前分组的父亲分组(支持分组嵌套)
		engine      *Engine          // 所有分组共享同一个 Engine 实例(帮助group访问router)
	}
 
	Engine struct {         // 实现 ServeHTTP的接口
		*RouterGroup        // 内嵌结构体,实现简单的继承,Engine可以继承RouterGroup的相关方法
		router        *router
		groups        []*RouterGroup     // 存放所有分组
	}
)

RouterGroup相关方法

修改与路由相关的各个函数,交由 RouterGroup 对象实现

  • Engine 的构造函数,完成各个属性的初始化
func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}
  • 通过 Group 构造新的子 Group(但是新的子 Group 与当前 Group 共用同一个 engine)
func (group *RouterGroup) Group(prefix string) *RouterGroup {
	engine := group.engine
	newGroup := &RouterGroup{
		prefix: group.prefix + prefix, // 分组前缀为父分组的前缀+当前的前缀
		parent: group,
		engine: engine, // 与父分组公用同一个 engine
	}
	engine.groups = append(engine.groups, newGroup)
	return newGroup
}
  • 通过 RouterGroup 实现之前 Engine 对应的相关路由函数

Engine中含内嵌结构体RouterGroup,继承了其所有属性和方法,所以我们既可以像之前一样通过engine添加路由,也可以通过routergroup添加路由。

func (group *RouterGroup) addRoute(method string, comp string, handler HandlerFunc) {
	pattern := group.prefix + comp
	log.Printf("Route %4s - %s", method, pattern)
	group.engine.router.addRoute(method, pattern, handler)
}
 
// ---添加GET请求
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}
 
// ---添加POST请求
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}

修改main.go中代码

func main() {
	r := gee.New()
	r.GET("/", func(c *gee.Context) {
		c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
	})
	v1 := r.Group("v1")
	{
		v1.GET("/", func(c *gee.Context) {
			c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
		})

		v1.GET("/hello", func(c *gee.Context) {
			// expect /hello?name=geektutu
			c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
		})
	}

	v2 := r.Group("/v2")
	{
		v2.GET("/hello/:name", func(c *gee.Context) {
			// expect /hello/geektutu
			c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
		})
		v2.POST("/login", func(c *gee.Context) {
			c.JSON(http.StatusOK, gee.H{
				"username": c.PostForm("username"),
				"password": c.PostForm("password"),
			})
		})

	}

	r.Run(":8090")
}

猜你喜欢

转载自blog.csdn.net/qq_47431008/article/details/130668485