GoLang-Gin框架之自动路由封装

Gin框架参考资料

GoLang之统一框架_云焰的博客-CSDN博客

Gin框架的入门及介绍,参看上述资料。

引言

        Gin框架封装了基础框架,给开发人员带来了很多方便,但是具体项目中,如果只使用Gin框架原生的来开发,还是有些单薄,如Gin的路由,写法比较冗长,如果开发项目,代码量过多,冗余重复代码比较多,看起来逻辑不够清晰,我们经过一些封装可能就比较简单清晰,我们就可以专注于业务逻辑的实现来编码了。

        我们先来看一下,gin框架路由的基础调用:

package main

import "github.com/gin-gonic/gin"
func main() {
	r := gin.Default()
	// http://127.0.0.1:8080/index
	r.GET("/index", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"code": "ok",
		})
	})
	// 默认端口是 8080
	r.Run()
}

我们来看一下上述路由调用,

1)首先调用gin的Default函数返回值r为gin.Engine类型,是gin框架的引擎的初始化。

2)调用http的GET方法获取响应,我们看到GET方法包含2个参数,1个是访问路径“/index”,另一个是Gin框架的HandlerFunc方法,我们直接通过闭包函数调用func(c *gin.Context) {...},返回响应内容c.JSON...这个先不用细说了。

我们项目中一般通过MVC结构来调用,路由就是在控制层,主要有3个要素:httpMethod方法(如GET)、访问路径(如/index)、处理请求(如func(c *gin.Context) {...})。如果我们都通过上述的结构来编码,主要在处理请求中写入逻辑,每次都这样写,可能业务量多的话,这样写会有很多冗余的代码,基于此,我们进行一些优化处理。

源码总体目录结构

根目录为exam1

 controller---控制层,主要包含控制层的类

route---路由层,主要包含路由的类

main.go--程序主入口

路由层

package route

import (
	"fmt"
	"reflect"
	"github.com/gin-gonic/gin"
	"strings"
)
//路由结构体
type Route struct {
	path string //url路径
	httpMethod string //http方法 get post
	Method reflect.Value //方法路由
	Args   []reflect.Type //参数类型
}
//路由集合
var Routes =[]Route{}
func InitRouter() *gin.Engine  {
	//初始化路由
	r := gin.Default()
	//绑定基本路由,访问路径:/User/List
	Bind(r)
	return r
}

//注册控制器
func Register(controller interface{}) bool{
	ctrlName:=reflect.TypeOf(controller).String()
	fmt.Println("ctrlName=",ctrlName)
	module := ctrlName
	if strings.Contains(ctrlName, ".") {
		module = ctrlName[strings.Index(ctrlName, ".") + 1:]
	}
	fmt.Println("module=",module)
	v := reflect.ValueOf(controller)
	//遍历方法
	for i:= 0; i < v.NumMethod(); i++ {
		method := v.Method(i)
		action := v.Type().Method(i).Name
		path := "/"+module+"/"+action
		//遍历参数
		params := make([]reflect.Type, 0, v.NumMethod())
		httpMethod :="POST";
		if( strings.Contains(action,"_get") ){
			httpMethod = "GET"
		}
		for j := 0; j < method.Type().NumIn(); j++ {
			params = append(params, method.Type().In(j))
			fmt.Println("params-name=",method.Type().In(j))
		}
		fmt.Println("params=",params)
		fmt.Println("action=",action)
		//if Routes[module] == nil {
		//	Routes[module] = make(map[string]Route)
		//}
		//Routes[module][action] = Route{method,params}
		route := Route{ path:path, Method:method,Args:params,httpMethod:httpMethod}
		Routes =append(Routes,route)
	}
	fmt.Println("Routes=",Routes)
	return true
}
//绑定路由 m是方法GET POST等
//绑定基本路由
func Bind(e *gin.Engine) {
	//pathInit()
	for _, route := range Routes {
		//e.POST(path, match(path))
		if(route.httpMethod=="GET"){
			e.GET(route.path,match(route.path,route))
		}
		if(route.httpMethod=="POST"){
			e.POST(route.path,match(route.path,route))
		}

	}
}
//根据path匹配对应的方法
func match(path string,route Route) gin.HandlerFunc {
	return func(c *gin.Context) {
		fields := strings.Split(path, "/")
		fmt.Println("fields,len(fields)=",fields,len(fields))
		if len(fields) < 3 {
			return
		}

		if len(Routes)>0 {
			arguments := make([]reflect.Value, 1)
			arguments[0] = reflect.ValueOf(c) // *gin.Context
			//reflect.ValueOf(method).Method(0).Call(arguments)
			route.Method.Call(arguments)
		}
	}
}

路由类,主要包含路由结构体(url路径、httpMethod方法等属性) 、路由集合(包含将应用中所有路由收集在一起的结构,全局引用)、

路由的工具方法Register(注册)、Bind(绑定)、match(匹配路径),此处是利用反射机制,将控制层对象名、方法名通过反射得到,作为url路径,这样就可以不再声明路由路径,通过代码就可以看出路由的访问路径,此处是借鉴php语言的Thinkphp6框架的多路由复用模块,所以很多语言优势可以互相参照,取长补短。其中方法Pages_get带_get对应GET方法,这里是一种理想化的编写规范,由于golang没有像JAVA语言那样可以通过注解来辅助请求方法。后续控制层会调用上述工具方法。

控制层

package controller

import (
	"frame/routes/00/exam1/route"
	"github.com/gin-gonic/gin"
	"net/http"
)

//这里每个controller执行init方法都要注册自动路由
func init() {
	route.Register(&User{})
}
type User struct {

}

//控制器的方法 分页查询
func (api *User) Pages_get(c *gin.Context){ //,httpMethod string
	//api.httpMethod="GET"
	users := []int{1,2,3}
	c.JSON(http.StatusOK, gin.H{
		"code": 1,
		"msg": "ok",
		"data": users,
	})

}
func (api *User) AddUser(c *gin.Context){ //,httpMethod string
	//api.httpMethod="GET"
	users := []int{2,3,6}
	c.JSON(http.StatusOK, gin.H{
		"code": 1,
		"msg": "ok",
		"data": users,
	})

}

控制层主要包含声明的控制器方法主要控制逻辑,在方法体中增加相关业务逻辑即可,控制器集中了所有业务控制逻辑看起来也比较清晰。其中init方法是通过调用route类的注册方法将通过反射处理,把自己类的方法注册为路由,统一调用。这里user可以作为模块名。访问路径规则是

/模块名/方法名

 其中方法Pages_get带_get对应GET方法,这里是一种理想化的编写规范,由于golang没有像JAVA语言那样可以通过注解来辅助请求方法。

main.go入口

package main

import (
	_ "frame/routes/00/exam1/controller"
	"frame/routes/00/exam1/route"
)

func main() {
	//加载路由
	r := route.InitRouter()
	r.Run()//":8000"

}

 入口层就比较简单了,其中_ "frame/routes/00/exam1/controller",要自动调用controller中的init方法初始化,将路由注册到路由集合中。

启动服务器

运行main.go  ,即可启动服务器,如下图

$ go run main.go

 我们看到服务器启动后,自动加载路由(见红色标识框)

我们通过浏览器或postmain访问即可得到结果

 至此,一个抽象出来的封装自动路由就搭建好了,路由的注册、初始化已经封装好,简单调用即可,我们只需要集中精力写好控制层逻辑,就能更加高效的完成业务代码了。

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云焰

你的鼓励是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值