Golang | http注解路由
Http服务器
Golang有一个很强大的官方http库了,使用上很方便。也有一些很强大的三方http框架, 比如gin,beego等等。 自以为,框架在提供便利,提升开发效率的同时,也限制了我们的想象力。 相对beego而言我更喜欢gin这样的简单高效框架,给我们提供了一些基础设施。剩下的有什么功能需要自己写进去就好了。
在开发过程中,我需要有个注解路由的功能,也就是不用手动的把路由和对应的函数一个一个手写进行绑定,百度无果后,发现gin没有提供这样的功能。于是有了下文。
gin的注解路由
gin是没有注解路由功能的,但是使用golang的reflect
包,加一点代码就能实现,代码如下
golang
package net
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"reflect"
"strings"
)
type HttpServer struct {
version string
port []string
Handler interface{}
}
func Pong (c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
func NewHttpServer(version string, port ...string) *HttpServer {
return &HttpServer{version: version, port: port}
}
func (h *HttpServer)HandlerFuncObj(tvl, obj reflect.Value) gin.HandlerFunc {
return func(c *gin.Context) {
v := tvl.Call([]reflect.Value{obj, reflect.ValueOf(c)})
if len(v) != 2 {
c.JSON(http.StatusNotFound, gin.H{"code": -100, "data": ""})
return
}
c.JSON(http.StatusOK, gin.H{"code": v[0].Interface(), "data": v[1].Interface()})
}
}
func GetRoutePath(objName, objFunc string) string {
return strings.ToLower(objName + "/" + objFunc)
}
func (h *HttpServer) BindHandler(handler interface{}) {
h.Handler = handler
}
func (h *HttpServer) Start() error {
//gin初始化
r := gin.Default()
r.GET("/ping", Pong)
typ := reflect.TypeOf(h.Handler)
val := reflect.ValueOf(h.Handler)
//t := reflect.Indirect(val).Type()
//objectName := t.Name()
numOfMethod := val.NumMethod()
for i := 0; i < numOfMethod; i++ {
method := typ.Method(i)
r.GET(GetRoutePath(h.version, method.Name), h.HandlerFuncObj(method.Func, val))
}
return r.Run(h.port...) // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
主要逻辑在 h.Start()
上
- h.Handler 是从外部绑定过来的Handler,也就是逻辑处理的Handler
- typ := reflect.TypeOf(h.Handler) 反射Handler类型
- val := reflect.ValueOf(h.Handler) 反射Handler的reflect.Value
- val.NumMethod(): 获取Handler的函数个数
- for i := 0; i < numOfMethod; i++ {}: 遍历获得函数, method := typ.Method(i)
- 根据 版本号+函数名 得到路由,用函数h.HandlerFuncObj(method.Func, val)得到 gin.HandlerFunc
- 把路由
ip:port/version/methodName
绑定到medhod.Func
上。
主要函数HandlerFuncObj()
, 把需要绑定的函数转化为gin.HandlerFunc
func (h *HttpServer)HandlerFuncObj(tvl, obj reflect.Value) gin.HandlerFunc {
return func(c *gin.Context) {
v := tvl.Call([]reflect.Value{obj, reflect.ValueOf(c)})
if len(v) != 2 {
c.JSON(http.StatusNotFound, gin.H{"code": -100, "data": ""})
return
}
c.JSON(http.StatusOK, gin.H{"code": v[0].Interface(), "data": v[1].Interface()})
}
}
tvl reflect.Value
: 实际上是method.Func
,obj reflect.Value
: 实际上是reflect.ValueOf(h.Handler)
reflect.Call用法: 函数用于使用输入参数in调用函数v;
func (v Value) Call(in []Value) []Value
使用Http服务器
声明一个结构体 HttpAction struct
, 成员函数名字的小写就是路由,函数就是路由对应逻辑处理的地方。
golang
package main
import (
"github.com/gin-gonic/gin"
)
type HttpAction struct {
}
func (h *HttpAction) PrintA(c *gin.Context) (int, interface{}) {
return 0, "I'm A"
}
func (h *HttpAction) PrintB(c *gin.Context) (int, interface{}) {
return 0, "I'm B"
}
func main() {
web := NewHttpServer("v1")
web.BindHandler(&HttpAction{})
web.Start()
}
- 逻辑处理只用写在HttpAction的成员函数中
- 不用一个一个手动的把路由和函数进行绑定。
至此,一个结合gin框架的注解路由就写好了。
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2022/03/http/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接