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)
评论