这是一个 route的示例:
web.NSRouter("/",&controllers.AppController{},"get:list")
在开发中,如果我想找到 get:list的方法,我需要先 进入 AppController这个文件,然后检索 list, 如果最后 get:list 这个地方传参是方法而不是 字符串的话,,在编写代码时,在 ide 中点一下就能跳到目标方法
这是一个 route的示例:
web.NSRouter("/",&controllers.AppController{},"get:list")
在开发中,如果我想找到 get:list的方法,我需要先 进入 AppController这个文件,然后检索 list, 如果最后 get:list 这个地方传参是方法而不是 字符串的话,,在编写代码时,在 ide 中点一下就能跳到目标方法
我尝试使用 NsGet 去解决,,NsGet的参数不合适
web.NSGet("/ping", controllers.BaseController.Ping)
import "github.com/beego/beego/v2/server/web"
type BaseController struct {
web.Controller
}
func (this *BaseController) Ping(){
this.Data["json"] = "pong"
this.ServeJSON()
this.StopRun()
}
编译失败
routes\route.go:9:47: invalid method expression controllers.BaseController.Ping (needs pointer receiver: (*controllers.BaseController).Ping)
type BaseController struct {
web.Controller
}
func (b *BaseController) Ping(ctx *context.Context) {
ctx.Output.Body([]byte("pong"))
}
b := &game.BaseController{}
ns := web.NewNamespace("/v1",
web.NSGet("/ping", b.Ping),
)
web.AddNamespace(ns)
// http://127.0.0.1:8080/v1/ping
// pong
// 这个代码有效
// NSGet call Namespace Get
func NSGet(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Get(rootpath, f)
}
}
// FilterFunc defines a filter function which is invoked before the controller handler is executed.
type FilterFunc func(ctx *context.Context)
你需要看一下NSGet的方法签名,第二参数需要传 FilterFunc。而且你的参数本身传的是有问题的。
哈喽,我一开始就注意到了 NSGet需要传递 FilterFunc,上边的示例 描述的是我希望传递的方式。但感觉NSget的 FilterFunc 类型的参数普适性有些差 :
例如一下代码中 baseController中已经有了 context,Ping里 context参数就有些多余 @changsongl
type BaseController struct {
web.Controller
}
func (b *BaseController) Ping(ctx *context.Context) {
ctx.Output.Body([]byte("pong"))
}
了解,其实beego还提供了AutoRouter的方式。不过从这个方法来看,也不能满足你指定特定的method和方法。
用户首先需要把需要路由的控制器注册到自动路由中:
web.AutoRouter(&controllers.ObjectController{})
那么 beego 就会通过反射获取该结构体中所有的实现方法,你就可以通过如下的方式访问到对应的方法中:
/object/login 调用 ObjectController 中的 Login 方法
/object/logout 调用 ObjectController 中的 Logout 方法
从我的观点来看,因为你的方法调用传入的是一个方法,因此必须要确保这个方法的调用方应该已经实现了ControllerInterface。因此验证起来会有点麻烦,我有尝试去实现你想达到的效果,下面的代码应该是可行的。但是我不确定是否为一个好的着手点。其实BEEGO已经实现了很多路由配置的方式。
package main
import (
"errors"
"fmt"
"reflect"
)
type ControllerInterface interface {
}
type MyController struct {
}
func (s *MyController) Ping() {
fmt.Println("Pong")
}
func main() {
fmt.Println(GetRoute((*MyController).Ping))
}
func GetRoute(f interface{}) error {
funcType := reflect.TypeOf(f)
if funcType.Kind() != reflect.Func {
return errors.New("not a function")
}
// 检查是否只有一个参数
if numIn := funcType.NumIn(); numIn != 1 {
return errors.New("invalid number of param in")
}
// 获得这个方法的调用方,检查是否实现 ControllerInterface
firstParamValue := reflect.New(funcType.In(0))
_, ok := firstParamValue.Elem().Interface().(ControllerInterface)
if !ok {
return errors.New("not implemented ControllerInterface")
}
// 可以调用方法,或者把这个方法存储起来。
reflect.ValueOf(f).Call([]reflect.Value{firstParamValue.Elem()})
return nil
}
// console
Pong
<nil>
@flycash @jianzhiyao
@hhstu 我大概理解你的意思。我是想说,这个更改并不是一个很简单的修改。我觉得这是一个很有意思的建议,因为我在日常DEBUG的时候,我也觉得这种找到方法的过程实在过于繁琐。
@changsongl 的我看过之后,还是不能达到想要的希望,我觉得,可能类似于:
Route(/xxx, POST, controller.XXXX)
会达到你所期望的效果。
我觉得是可以考虑提供一个RouterXXX的方法来支持。这会使开发体验很好,毕竟字符串的话,写错名字也是常有的事情。
@jianzhiyao @AllenX2018 你们觉得如何呢?
赞同,我这边修改下方法的receiver。如果有需要添加这个功能的话,可以把这个指派给我哈,希望可以多参与下BEEGO。
这里我记得 NS有NSGet之类的方法,但是web.Route就是没有。我的建议是,我们新增加一个非常通用的方法:
func Route("/path_to_xxx", method, ctrt.xxxxMethod, ... Opts) {}
在这个基础上,提供一些简单的封装,例如:
func Get("/xxxx", ctrl.XXXMethod) {
Route("/xxxx", "GET", ctrl.XXXMethod)
}
func Post ...