当前位置: 首页 > news >正文

【Gee】Day4:分组控制

Day4:分组控制

今天的任务是:

  • 实现路由分组控制(Route Group Control),代码约 50 行。
    请添加图片描述

分组的意义

分组控制(Group Control)是 Web 框架应提供的基础功能之一。分组指的是路由的分组,如果没有路由分组,我们需要针对每一个路由进行控制。但在真实的业务场景下,往往某一组路由需要相似的处理。例如:

  • /post开头的路由匿名可访问;
  • /admin开头的路由需要鉴权;
  • /api开头的路由是 RESTful 接口,可以对接第三方平台,需要三方平台鉴权。

大部分情况下的路由分组是以相同的前缀来区分的。因此,今天我们要实现的分组控制也是以前缀来区分的,并且支持分组嵌套。例如/post是一个分组,而/post/a/post/b是该分组的子分组。作用在/post分组上的中间件,也都会作用在子分组,子分组还应该支持自己特有的中间件。

中间件可以给框架提供无限的拓展能力,应用在分组上,可以使得分组控制的收益更加明显,而不是共享相同的路由前缀这么简单。例如 /admin 分组可以应用鉴权中间件;/分组应用日志中间件(/是最顶层的分组)。

分组嵌套

一个 Group 对象需要具备哪些属性呢?首先是前缀 prefix,比如//api。要支持分组嵌套,必须知道当前分组的父亲(parent)是谁。按照我们最初的分析,中间件是应用在分组上的,所以我们还应该存储应用在分组上的中间件(middlewares)。在之前,我们应用(*Engine).addRoute()来映射所有的路由规则和 Handler。如果 Group 对象需要直接映射路由规则的话,比如我们想在使用框架时,按照如下方式调用:

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

那么 Group 对象还需要具有访问 Router 的能力。为了方便,我们可以在 Group 种保存一个指向 Engine 的指针,整个框架所有的资源都是由 Engine 统一协调的,可以通过 Engine 间接地访问各种接口。

最终,Group 的定义如下:

// in gee/gee.go

type RouterGroup struct {
	prefix      string
	middlewares []HandlerFunc // support middleware
	parent      *RouterGroup  // support nesting
	engine      *Engine       // all groups share an Engine instance
}

我们可以进一步地抽象,将 Engine 作为顶层的分组,也就是 Engine 具有 RouterGroup 的所有能力:

type Engine struct {
	*RouterGroup // embed a RouterGroup pointer
	router       *router
	groups       []*RouterGroup
}

至此,我们可以将所有与路由相关的函数,都交给RouterGroup来处理了。

func New() *Engine {
	engine := &Engine{router: newRouter()}
	engine.RouterGroup = &RouterGroup{engine: engine}
	engine.groups = []*RouterGroup{engine.RouterGroup}
	return engine
}

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

// addRoute combines method and pattern together and then add method-pattern and handler to map
func (group *RouterGroup) addRoute(method, comp string, handler HandlerFunc) {
	pattern := group.prefix + comp
	log.Printf("Route %4s - %s", method, pattern)
	group.engine.router.addRoute(method, pattern, handler)
}

// GET defines the method to add GET request
func (group *RouterGroup) GET(pattern string, handler HandlerFunc) {
	group.addRoute("GET", pattern, handler)
}

// POST defines the method to add POST request
func (group *RouterGroup) POST(pattern string, handler HandlerFunc) {
	group.addRoute("POST", pattern, handler)
}

仔细观察 addRoute 函数,它调用 group.engine.router.addRoute 来实现了路由的映射。由于Engine某种意义上继承了RouterGroup的所有属性和方法,因为(*Engine).engine是指向自己的。这样实现,我们既可以像原来一样添加路由,也可以通过分组添加路由。

Demo

测试框架的 Demo 如下:

package main

import (
	"gee/gee"
	"net/http"
)

func main() {
	r := gee.New()
	r.GET("/index", func(c *gee.Context) {
		c.HTML(http.StatusOK, "<h1>Index Page</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(":9999")
}

相关文章:

  • MySQL日志undo log、redo log和binlog详解
  • EasyRTC:基于WebRTC与P2P技术,开启智能硬件音视频交互的全新时代
  • Grok 使用指南
  • StarRocks FE leader节点CPU使用率周期性的忽高忽低问题分析
  • 【mysql间隙锁何时出现及锁定范围】
  • vue项目接入谷歌登录
  • 【深度学习】Pytorch项目实战-基于协同过滤实现物品推荐系统
  • Redis存在线程安全吗?为什么?
  • 2025蓝桥杯JAVA编程题练习Day5
  • deepseek本地部署以及搭建知识库
  • C++(17):为optional类型构造对象
  • 有序任务规划的局限性
  • 深度学习基础--ResNet网络的讲解,ResNet50的复现(pytorch)以及用复现的ResNet50做鸟类图像分类
  • 【目标检测】【PANet】Path Aggregation Network for Instance Segmentation
  • 深入浅出:理解闭包在JavaScript中的应用
  • Promptic:Python 中的 LLM 应用开发利器
  • 什么是接口自动化测试?接口自动化测试的目的是什么?
  • JEEWMS cgFormBuildController.do 方法mobileForm存在SQL注入
  • python pandas下载
  • ADCP处理软件CODAS安装 (conda方法安装)
  • 广州美容网站建设/重庆seo网站运营
  • 网站建设厦门/百度官方优化指南
  • 新准则中公司网站建设费用计入什么科目/搜索引擎大全全搜网
  • 文化传媒有限公司网站建设/seo多久可以学会
  • 网站收录需要多久/网络推广产品公司
  • 编程软件推荐/seo百度发包工具