Gin 中许多类型都可以认为它是一个路由(IRoutes)类型,这包括了 RouterGroup、Engine等。并且 IRoutes 接口中定义的方法都会有一个 IRoutes 类型的返回值,使得 Gin Routers 可以支持链式调用,让代码更加简洁。
路由分组
RouterGroup 是一种路由组对象(Engine 继承自 RouterGroup,所以也可以认为是一个路由组)。通过 Group() 方法可以创建一个新的 RouterGroup。Group() 方法的定义如下:
func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
return &RouterGroup{
Handlers: group.combineHandlers(handlers),
basePath: group.calculateAbsolutePath(relativePath),
engine: group.engine,
}
}
relativePath:路由组的相对路径。与handle()方法 相同,relativePath同样需要使用group.calculateAbsolutePath()来计算出绝对路径。handlers:路由组的处理方法,一般是将其作为中间处理函数(中间件)来定义。
RouterGroup 类型的定义如下:
type RouterGroup struct {
Handlers HandlersChain
basePath string
engine *Engine
root bool
}
其中:
- 使用
root和engine字段来标记当前路由组是否为根路由,以及根路由的地址(Engine可以认为是当前 Gin 程序中所有路由组的根路由组); Handlers记录了当前路由组中所需要的一系列路由处理函数(其中也包括了它上层路由的处理函数);basePath指明了当前路由组的绝对路径。
路由组的使用方式如下所示:
// 创建路由组
user := r.Group("/user", middlewares.UserMiddleware)
{
user.GET("", func(context *gin.Context) {
context.String(http.StatusOK, "User get\n")
})
user.POST("", func(context *gin.Context) {
context.String(http.StatusOK, "User post\n")
})
user.PUT("", func(context *gin.Context) {
context.String(http.StatusOK, "User put\n")
})
user.DELETE("", func(context *gin.Context) {
context.String(http.StatusOK, "User delete\n")
})
}
对于任何一个 RouterGroup 来说,可以继续使用 Group() 方法创建路由,即使该 RouterGroup 也是由其它 RouterGroup 创建的。
Routers 包
一般在项目中,会专门创建一个 routers 包来存放项目中路由配置的相关代码。
将一系列相关的路由抽取为理由组后,可以专门为其在 routers 包下创建一个文件来存放这一系列路由的配置。例如可以将 user 路由中的内容配置在 user.go 中:
func UserRoutersInit(engin *gin.Engine) {
user := engin.Group("/user", middlewares.UserMiddleware)
user.GET("", func(context *gin.Context) {
context.String(http.StatusOK, "User get\n")
})
user.POST("", func(context *gin.Context) {
context.String(http.StatusOK, "User post\n")
})
user.PUT("", func(context *gin.Context) {
context.String(http.StatusOK, "User put\n")
})
user.DELETE("", func(context *gin.Context) {
context.String(http.StatusOK, "User delete\n")
})
// 相对路径传入空串,表示请求路径与路由组的路径相同
// 需要注意,不能使用 "/" 来表示 “当前请求路径与路由组的路径相同” 这一含义
}
在 routers 包中可以创建一个 routers.go 来配置根路由、设置全局中间件以及初始化其它路由:
func Router() (engine *gin.Engine) {
// 创建根路由
engine = gin.Default()
// 初始化其它子路由
UserRoutersInit(engine)
// ...
return
}
根路由的创建除了使用 gin.Default() 外,还可以使用 gin.New()。gin.Default() 默认使用了 gin.Logger() 和 gin.Recovery()。使用 gin.New() 来创建路由,需要自己手动配置 Logger 和 Recovery 中间件:
engine = gin.New()
engine.Use(gin.Logger(), gin.Recovery())
gin.Logger():日志。gin.Recovery():错误管理,它会recover()任何panic(),并且返回给客户端500响应码。
Controllers 包
除了路由,路由处理器也可以定义在专门的 controllers 包中。例如,user 路由,首先在 controllers 包中创建 user.go:
// userController 类型
type userController struct{}
// UserController 示例
// 通过内部类型,以及定义外部实例,模拟一个简单的单例模式
var UserController userController
func (userController) GetUser(ctx *gin.Context) {
context.String(http.StatusOK, "User get\n")
}
func (userController) AddUser(ctx *gin.Context) {
context.String(http.StatusOK, "User post\n")
}
func (userController) UpdateUser(ctx *gin.Context) {
context.String(http.StatusOK, "User put\n")
}
func (userController) DeleteUser(ctx *gin.Context) {
context.String(http.StatusOK, "User delete\n")
}
接着,修改 routers/user.go:
user.GET("", controllers.UserController.GetUser)
user.POST("", controllers.UserController.AddUser)
user.PUT("", controllers.UserController.UpdateUser)
user.DELETE("", controllers.UserController.DeleteUser)
评论