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





拒绝白嫖从一键三连开始!

原创不易,未经允许,请勿转载。

博客主页:https://xiaojujiang.blog.csdn.net/

以上是关于Gin利用Go的反射原理进行路由注册的主要内容,如果未能解决你的问题,请参考以下文章

Gin利用Go的反射原理进行路由注册

Gin利用Go的反射原理进行路由注册

go的web框架-gin

Go实战 | 电商平台 用户注册

Go的web框架——Gin初识

go-gin-api 路由中间件 - 日志记录