Gin利用Go的反射原理进行路由注册
Posted jiangxiaoju
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gin利用Go的反射原理进行路由注册相关的知识,希望对你有一定的参考价值。
原创不易,未经允许,请勿转载。
文章目录
系统:windows10
go版本:1.13.15
一、Gin如何进行路由注册?
gin
框架进行路由注册方法很简单,如下代码所示(这里就不多介绍gin
的使用方法了)
package main
import (
"github.com/gin-gonic/gin"
)
func main()
r := gin.Default()
r.GET("/", func(c *gin.Context)
c.JSON(200, gin.H"msg": "hello world")
)
r.Run(":8080")
像上面这中这种写法,很显然当注册的路由多了以后,都堆积到了main方法里面,这样是很不容易进行维护的,并且代码的可读性也会降低。所以我们需要多这代码进行一下重构
创建一个文件夹,名为controller
,放置进行逻辑处理的函数。在这个目录下创建一个文件,名为hello.go
,里面的代码如下
package controller
import (
"github.com/gin-gonic/gin"
)
type HelloController struct
func (hello HelloController) Hello(c *gin.Context)
c.JSON(200, gin.H"msg": "Hello World")
创建一个文件夹,名为route
,这里面存放路由注册相关的代码。在这个目录下创建一个文件,名为router.go
,里面的代码如下
package route
import (
"gin-demo/controller"
"github.com/gin-gonic/gin"
)
func Init(e *gin.Engine)
hello := controller.HelloController
e.GET("/hello", hello.Hello)
我们在main里面可以这么调用。
package main
import (
"gin-demo/route"
"github.com/gin-gonic/gin"
)
func main()
r := gin.Default()
route.Init(r)
r.Run(":8080")
这样,我们可以做到把路由注册和处理请求的代码给解耦分离。
但是这么写的话,还是会存在一个问题,如果每次需要增加新的路由映射的时候,在controller包下添加好新的方法后,还需要再router.go
里面去注册,这样就显得很麻烦。但代码多了以后,可能会出现方法写好了,但是忘了绑定相应的路由这种情况。
并且这么写的时候,路由的Path和方法是分离的,时间久了很容易忘掉某个方法对应的路由Path是什么,尤其是一些参数是绑定在Path上面的,例如这种:/:user/:password
。
二、利用Go的反射简化路由注册
上述的路由注册方式简单来说就是存在这两个问题:一、不直观,路由的Path和方法实现的位置相分离,不利于一些代码的编写。二、改动量大,没增加一个新的方法,得修改多处代码。
针对这两个问题,我们可以利用Go的反射来对上面的代码进行一些修改。
在HelloController
结构体中增加一个变量,类型是*gin.RouterGroup
。然后在HelloController
结构体中的方法里面,调用group
进行路由注册。并向外提供一个构造方法,需要传入一个gin.RouterGroup
类型的参数。
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
)
type HelloController struct
group *gin.RouterGroup
func (hello HelloController) Hello()
hello.group.GET("/hello", func(c *gin.Context)
c.JSON(200, gin.H"msg": "Hello World")
)
func (hello HelloController) SayHello()
hello.group.GET("/sayHello", func(c *gin.Context)
name := c.DefaultQuery("name", "")
c.JSON(200, gin.H"msg": fmt.Sprintf("hello %s", name))
)
func NewHelloController(g *gin.RouterGroup) HelloController
return HelloControllergroup: g
controller
里面的代码改造完后,接下去利用反射的原理,获取HelloController
结构体下的所有方法,然后去调用这些方法即可。
核心代码如下:
传入一个HelloController
的实例,因为可能会有多种controller
,所以这里参数用interface
来接受。通过反射获取变量的类型, 然后获取方法的数量(所有方法名应该大写开头,否则这里将无法被获取到)
func RegisterController(controller interface)
val := reflect.ValueOf(controller)
numOfMethod := val.NumMethod()
for i := 0; i < numOfMethod; i++
val.Method(i).Call(nil)
完整的router.go
代码如下
package route
import (
"gin-demo/controller"
"reflect"
"github.com/gin-gonic/gin"
)
func RegisterController(controller interface)
val := reflect.ValueOf(controller)
numOfMethod := val.NumMethod()
for i := 0; i < numOfMethod; i++
val.Method(i).Call(nil)
func Init(e *gin.Engine)
defaultGroup := e.Group("")
helloController := controller.NewHelloController(defaultGroup)
RegisterController(helloController)
在main方法中进行调用
package main
import (
"gin-demo/route"
"github.com/gin-gonic/gin"
)
func main()
r := gin.Default()
route.Init(r)
r.Run(":8080")
这样,当我们修改Controller里面的方法时,就不需要再去修改router.go
中的代码了。而且这样代码可读性也更高了。
上述代码运行结构如下
PS D:\\GolandProjects\\gin-demo> go run "d:\\GolandProjects\\gin-demo\\main.go"
[GIN-debug] [WARNING] Now Gin requires Go 1.13+.
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /hello --> gin-demo/controller.HelloController.Hello.func1 (3 handlers)
[GIN-debug] GET /sayHello --> gin-demo/controller.HelloController.SayHello.func1 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :8080
拒绝白嫖从一键三连开始!
原创不易,未经允许,请勿转载。
以上是关于Gin利用Go的反射原理进行路由注册的主要内容,如果未能解决你的问题,请参考以下文章