反射reflect实现自定义路由

一、背景

在使用websocket功能的时候要实现根据不同的请求url,执行不同的方法。怎么样能简单一点呢?

解决办法

  1. 实际上golnag的 自带路由处理方式。只不过每次都要在里面处理,一个路由定义一个handleFunc方法,如果方法多了确实挺麻烦,每次都要添加
go http.HandleFunc("/", onMessage)

2.实用参数判断基根据每次url的不同来返回对应的结构体然后执行他的对应的方法,这个其实是简单的工厂模式。缺点就是如果该结构提的方法很多的话,调用的参数判断结构就很多哦而且很杂。
在这里插入图片描述
3.使用反射(reflect)实现,其实现思路是先将所有的结构体存在一个map类型里key则为结构体名字,值则为每个结构体实例。
然后比如请求url参数为 Message/GetUser ,首先分割结构体名字 message从而找到对应的结构体。最后通过MethodByName 找到对应的GetUser方法,然后 执行就可以。本方法实际上有个缺点就是需要还需要手动维护 存结构体的map,但是比之前简单多了一点,具体看代码。

package routers

import (
	"reflect"
	"strings"
	"xfy_whotalk_socket/model"
	"xfy_whotalk_socket/runtime"
	"xfy_whotalk_socket/server"
	"xfy_whotalk_socket/server/message"
	"xfy_whotalk_socket/server/user"
)

var regStruct map[string]interface{}

func init() {
	// 初始化服务map(必须要)
	regStruct = make(map[string]interface{})
	regStruct["User"] = user.NewUserServer()
	regStruct["Message"] = message.NewMessageServer()
}

// @Title GetRouter
// @Description 系统路由
// @Param   method  model.ReceiveMessage   消息类型
// @return code int8
// @return res string

func GetRouter(method model.ReceiveMessage) (code int16, res string) {
	server := server.NewBaseServer()
	methods := strings.Split(method.Method, "/")
	if len(methods) != 2 {
		go server.SendToId(method.Client, method.FromId, 10003, "api参数有误", method.Method, "", 0)
		return
	}
	serverName := methods[0]
	methodName := methods[1]
	if _, ok := regStruct[serverName]; !ok {
		// 不存在
		go server.SendToId(method.Client, method.FromId, 10004, "url not found", method.Method, "", 0)
		return
	}

	code, res = execute(serverName, methodName, method)
	if code > 0 {
		go server.SendToId(method.Client, method.FromId, 10004, res, method.Method, "", 0)
	}
	return
}

// @Title execute
// @Description 通过反射调用对象的操作方法
// @Param   ruleClassName  string   服务名
// @Param   methodName  methodName   方法名
// @Param   message  model.ReceiveMessage   消息结构
// @return code int8
// @return res string

func execute(ruleClassName string, methodName string, message model.ReceiveMessage) (code int16, res string) {
	t := reflect.TypeOf(regStruct[ruleClassName])
	value := reflect.ValueOf(regStruct[ruleClassName])
	if _, ok := t.MethodByName(methodName); !ok {
		return 1, "no method"
	}

	// 所有方法need args 必须要
	args := []reflect.Value{reflect.ValueOf(message)}
	response := value.MethodByName(methodName).Call(args)

	for i := range response {
		if i == 0 {
			x := response[i].Int()
			code = int16(x)
		}
		if i == 1 {
			res = response[i].String()
		}
	}
	runtime.Info.Println("execute--->:", response, code, res)
	return
}

其中有点一需要注意的是,在使用reflect 的 call来执行每个结构体方法的时候,如果有参数必须带上参数 正如上面的例子一样。

// 所有方法need args 必须要
args := []reflect.Value{reflect.ValueOf(message)}
reflect.ValueOf().MethodByName(methodName).Call(args)

反射执行的结果是那个方法的返回结果是一个该方法的执行结果。
在这里插入图片描述
反射就是动态获取对象的类型,和动态执行他的方法。 比如接口,被赋予各种值以后是没法直接确认他的类型和属性的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值