在Gin等Web框架中,路由是组织应用程序的核心部分之一。在应用程序变得越来越大时,将所有的路由都放在主文件中会使代码变得难以维护和扩展。因此,将路由抽离出来,使代码更加模块化和组织化,有以下几个好处:
提高代码可维护性:将路由单独提取出来,可以减少主文件的复杂性,降低代码的耦合性。这使得代码更容易维护和修改,也更容易进行单元测试。
提高代码可扩展性:将路由抽离出来,可以更容易地添加新的路由和处理函数,而无需修改主文件。这样,当应用程序变得更大时,可以更容易地扩展和维护。
提高代码可读性:将路由从主文件中分离出来,可以更容易地理解应用程序的结构和逻辑。这使得代码更易于阅读和理解,从而更容易协作和维护。
代码复用:将路由抽离出来,可以使不同的模块和包共享相同的路由。这样,可以减少冗余代码,提高代码复用性。
因此,将路由抽离出来是一种良好的编程实践,可以提高代码的可维护性、可扩展性、可读性和复用性。
那么怎么在Gin框架中,可以将路由(routers)抽离出来,以便更好地组织和管理应用程序。
具体的抽离方法如下:
创建一个名为"routers"的包(package)。
在该包中,创建一个名为"router.go"的文件,用于定义路由。
在该文件中,导入(import)"github.com/gin-gonic/gin"库。
定义一个名为"SetupRouter"的函数,用于设置路由。
在"SetupRouter"函数中,创建一个名为"router"的Gin引擎(engine)。
定义路由和处理函数,例如:
func SetupRouter() *gin.Engine {
router := gin.Default()
router.GET("/hello", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello World!",
})
})
return router
}
在main函数中,调用"SetupRouter"函数,并将返回的Gin引擎启动:
func main() {
r := SetupRouter()
r.Run(":8080")
}
最后,在其他文件中,导入"routers"包,并使用"SetupRouter"函数设置路由。
这样,就可以将路由和处理函数从主文件中抽离出来,更好地组织和管理应用程序。
另外补充说明一下,还可以类似这样抽离路由:
在main.go 文件中,把之前的路由跳转post和get请求进行一步分组,并且给予单独的文件夹存放,类似于这样:
r.GET("/admin/index", func(ctx *gin.Context) {
new := &Article{
Title: "admin/index",
Content: "这是一个首页后台管理",
}
ctx.HTML(http.StatusOK, "admin/index.html", gin.H{
"title": "后台首页",
"news": new,
})
})
r.GET("/admin/edit", func(ctx *gin.Context) {
new := &Article{
Title: "admin/index",
Content: "这是一个首页后台管理",
}
ctx.HTML(http.StatusOK, "admin/index.html", gin.H{
"title": "后台首页",
"news": new,
})
})
// 这里对这两个路由请求 get请求进行分组
loginRouters := r.Group("/login")
{
loginRouters.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login",
})
})
loginRouters.GET("/edit", func(c *gin.Context) {
c.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login/edit",
})
})
}
这里补充一下,一个概念 router.Group()这个方法是?
在 Gin 框架中,使用 router.Group()
可以创建一个路由组,用于将一组相关的路由分组管理。抽离路由组有以下几个好处:
-
代码复用性:将具有相同路径前缀的路由分组管理,可以避免重复定义相同的前缀,提高代码复用性。
-
代码可读性:通过分组管理路由,可以使代码更具有可读性,更容易理解和维护。
-
可扩展性:当需要添加新的路由时,只需要在相应的路由组中添加即可,而不需要修改主文件中的代码,提高了代码的可扩展性。
-
中间件管理:路由组可以使用中间件,将一组路由的共同中间件分组管理,方便管理和维护。
-
可配置性:通过路由组,可以对不同的路由分别进行配置,例如设置路由组级别的中间件、路由组级别的错误处理函数等。
因此,抽离 router.Group()
可以提高代码的复用性、可读性、可扩展性、可配置性和中间件管理能力,使代码更加模块化和组织化。
同时,我们这里使用 router.Group()来
抽离路由后,为了方便后面的控制器【controller】方法做准备;
这里抽离成功后状态路由应该是,根目录下有一个routers目录,并且下面有多个路由分组后的单个路由文件;类似于 loginRouters.go 这样的文件。那么,这些文件内部优势怎么样子的呢?接下来就是代码部分:
package routers
import (
"net/http"
"github.com/gin-gonic/gin"
)
func LoginRoutersinit(r *gin.Engine) {
loginRouters := r.Group("/login")
{
loginRouters.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login",
})
})
loginRouters.GET("/edit", func(c *gin.Context) {
c.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login/edit",
})
})
}
}
以上,就是路由分组后,各自管理自己的路有分组,并且抽离出单独的文件了。
最后一一步就是今天的最终任务,控制器controller的抽离。首先,我们为什么要有控制器,它又是一个什么东西?为啥一定要写控制器?这样的诸如此类的问题,去接着看……
在Gin框架中,将控制器(Controller)从路由处理函数中抽离出来,是一种常见的编程实践。以下是抽离控制器的几个好处:
-
分离业务逻辑和路由:将路由处理函数与业务逻辑分离开来,可以使代码更加模块化和组织化。这样,可以更好地管理和维护代码,并且使代码更容易理解和扩展。
-
提高代码复用性:将控制器从路由处理函数中抽离出来,可以使控制器代码更加通用和可复用。这样,可以避免在不同的路由处理函数中重复编写相同的代码,提高代码复用性。
-
提高代码可读性:将控制器从路由处理函数中抽离出来,可以使代码更加清晰、易于理解和维护。这样,可以更好地遵循“单一职责原则”,使代码更加模块化和组织化。
-
方便测试:将控制器从路由处理函数中抽离出来,可以使控制器更容易测试。这样,可以分别测试控制器和路由处理函数,提高代码的可测试性。
因此,将控制器从路由处理函数中抽离出来是一种良好的编程实践,可以提高代码的模块化、组织化、可复用性、可读性和可测试性。
代码演示部分同上代码演化的:
package routers
import (
"github.com/gin-gonic/gin"
"****/controllers/login"
)
func LoginRoutersinit(r *gin.Engine) {
loginRouters := r.Group("/login")
{
loginRouters.GET("/", login.LoginControllers{}.Index)
loginRouters.GET("/edit", login.LoginControllers{}.Edit)
}
}
// 这里就对路由中函数处理,进行了抽离 放到了对应的控制器包内"****/controllers/login" 这个包就是控制器部分。
对应的controller控制器的login包package login 内部的代码演示部分:
package login
import (
"net/http"
"github.com/gin-gonic/gin"
)
type LoginControllers struct {
}
func (con LoginControllers) Index(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login-controller",
})
}
func (con LoginControllers) Edit(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login/edit-controller",
})
}
以上就是 对控制器 loginControllers.go 文件的具体代码,并且,可以看出,如何从路由分组阶段,演化成 有控制器进行更细化的分类处理,路由中的函数处理方法抽离。
同时,这也缺少了一部分,关于函数是可以继承的,那么对应的控制器文件下,同一个包内是否可以通用呢,答案是……
具体的代码描述一下情况
logincontrollers.go文件
package login
import (
"net/http"
"github.com/gin-gonic/gin"
)
// 控制器继承, 和结构体 一样。
type LoginControllers struct {
BaseControllers
}
func (con LoginControllers) Index(ctx *gin.Context) {
con.success(ctx)
}
basecontrollers.go 文件
package login
import (
"net/http"
"github.com/gin-gonic/gin"
)
type BaseControllers struct {
}
// 控制器继承, 和结构体 一样。
func (con BaseControllers) success(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "default/login.html", gin.H{
"title": "login-controller--成功",
})
}
这里是不是有点不一样或者说是一样的问题呢?
细心的人就可以看出来,这里控制器的继承 basecontroller.go文件的package 包的名字和 loginconttrollers.go文件的包名一致。
这是为了继承而搞的,如果说,不是一个包如何继承呢?这个问题,需要继续往下学习。
当然,这里如果很难理解,你可以回过头看看基础篇的,结构体继承,同样的道理。