GO七天开发挑战:7天实现Web框架-Gee(day 4 分组控制Group)

 学习资料来自:GitHub - geektutu/7days-golang: 7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列icon-default.png?t=M85Bhttps://github.com/geektutu/7days-golang

Go语言动手写Web框架 - Gee第四天 分组控制Group | 极客兔兔 (geektutu.com)icon-default.png?t=M85Bhttps://geektutu.com/post/gee-day4.html 

Day4 分组控制Group

关于分组控制

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

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

 组对象 Group

        1. 数据结构

        分组需要通过前缀来对分组进行区分,所以包含 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     // 存放所有分组
	}
)

         2. 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添加路由。

        根据不同的请求类型,调用 addRoute 实现相关路由的添加注册。

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)
}

         3. 运行测试

        分别实现以下几个路由的注册

        1)构造新的 Engine对象,直接通过 engine 注册添加路由:

r := gee.New()
r.GET("/index", func(c *gee.Context) {
    c.HTML(http.StatusOK, "

Index Page

") })

        2) 构造分组v1,通过 routergroup 注册添加路由

v1 := r.Group("/v1")
{
	v1.GET("/", func(c *gee.Context) {
		c.HTML(http.StatusOK, "

Hello Gee

") }) 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) }) }

        3) 构造分组v2,通过 routergroup 注册添加路由

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"),
		})
	})

}

使用curl命令简单测试,结果如下: 

GO七天开发挑战:7天实现Web框架-Gee(day 4 分组控制Group)_第1张图片

你可能感兴趣的:(七天开发挑战,Go,golang)