个人技术分享

在使用gin框架进行开发的时候,我们可以通过自定义gin.Context来实现和增强gin框架,方法也很简单,关键就2个步骤, 1是继承gin.Context, 2是在路由的时候对函数入参类型进行转换,下面为具体的方法:

1. 自定义一个结构体,然后以匿名的方式继承*gin.Context

package ginx

import (
	"github.com/gin-gonic/gin"
)

// 自定义一个本地结构体,然后以匿名方式继承*gin.Context
// @author: tekintian <tekintian@gmail.com>
type XContext struct {
	*gin.Context // 匿名继承 *gin.Context
}

上面为自定义的结构体 XContext里面以匿名方式继承了 *gin.Context, 这样我们就可以在本地将我们需要增强的功能绑定到XContext对象上了,在使用的时候我们可以通过我们自定义的结构体访问gin.Context中的所有可内容,同时也可以访问我们自定义的方法。  

这里有一个小知识点就是结构体匿名继承的访问方式有2种,1是通过继承对象访问,2是通过继承对象.被继承结构体名称访问(匿名继承的结构体默认会有一个名称即结构体的名称)

在我们自定义的XContext上面绑定我们自己的方法示例:

获取get或者post的查询参数

package ginx

import (
	"github.com/gin-gonic/gin"
)

// 自定义一个本地结构体,然后以匿名方式继承*gin.Context
// @author: tekintian <tekintian@gmail.com>
type XContext struct {
	*gin.Context // 匿名继承 *gin.Context
}

// 获取string类型的查询参数 支持GET POST  如果key不存在则返回默认值defaultVal
func (c *XContext) QueryStr(key string, defaultVal ...string) string {
	var defVal string
	if len(defaultVal) > 0 {
		defVal = defaultVal[0]
	}
	v, ok := c.GetQuery(key)
	if !ok {
		v, ok = c.GetPostForm(key)
	}
	if ok {
		return v
	}
	return defVal
}

2. 使用闭包将自定义XContext转换为 *gin.Context

*gin.Context 的使用都是在路由对应的handlerFunc里面, 我们只需要将我们自定义的context放到路由handlerFunc里面即可, gin默认的路由handlerFunc定义是这样的  type HandlerFunc func(*Context)  , 我们自定义的XContext的handlerFunc的入参就会是这样 func(c  *XContext) ,  

XHandlerFunc 函数的作用就是初始化我们自定义的对象XContext和转换为gin路由需要的HandlerFunc 

package ginx

import (
	"github.com/gin-gonic/gin"
)

// XHandlerFunc闭包函数, 实现gin.Context到自定义 XContext 的转换。
func XHandlerFunc(handler func(c *XContext)) func(ctx *gin.Context) {
	// 闭包函数
	return func(c *gin.Context) {
		// 这里的Context是匿名继承的结构体的默认名称(结构体本身的名称),
		// 如果XContext中没有其他字段,这个也可以写成 &XContext{c}
		handler(&XContext{Context: c})
	}
}

3. 使用自定义gin.Context (XContext)示例

使用就比较简单了,就是在路由定义的时候使用即可。

package main

import (
	"fmt"
	"gotms/global/ginx"

	"github.com/gin-gonic/gin"
)

// 注意这里的 入参c是我们自定义的XContext
func hello(c *ginx.XContext) {
	name:=c.QueryStr("name","Tekin") // 使用我们自定义的XContext中的方法
	c.JSON(200, gin.H{
		"msg": fmt.Sprintf("Hello %v", name),
	})
}

func main() {
	r := gin.Default()
	// 注意这里的路由对应的handlerFunc需要使用我们的闭包函数进行初始化和转换
	r.GET("/hello", ginx.XHandlerFunc(hello))

	r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

总结:

gin.Context是gin框架中最重要的一个对象,这个里面包含了所有gin框架http服务的内容,我们通过自定义一个结构体以匿名方式继承gin.Context 这样即可不修改gin框架,又可以实现自己想要的功能, 这种方式可以应用在其他任何的第三方库或者框架里面,这里的关键就是自定义对象的初始化和转换,掌握了这个方法可极大的提升我们的开发效率。