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语言那样可以通过注解来辅助请求方法。
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访问即可得到结果
至此,一个抽象出来的封装自动路由就搭建好了,路由的注册、初始化已经封装好,简单调用即可,我们只需要集中精力写好控制层逻辑,就能更加高效的完成业务代码了。