[beego]NSRouter参数提议

2024-07-19 267 views
8

这是一个 route的示例:

web.NSRouter("/",&controllers.AppController{},"get:list")

在开发中,如果我想找到 get:list的方法,我需要先 进入 AppController这个文件,然后检索 list, 如果最后 get:list 这个地方传参是方法而不是 字符串的话,,在编写代码时,在 ide 中点一下就能跳到目标方法

回答

9

我尝试使用 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)

4
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。而且你的参数本身传的是有问题的。

5

哈喽,我一开始就注意到了 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"))
}
2

了解,其实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>
1

@flycash @jianzhiyao

8

@hhstu 我大概理解你的意思。我是想说,这个更改并不是一个很简单的修改。我觉得这是一个很有意思的建议,因为我在日常DEBUG的时候,我也觉得这种找到方法的过程实在过于繁琐。

@changsongl 的我看过之后,还是不能达到想要的希望,我觉得,可能类似于:

Route(/xxx, POST, controller.XXXX)

会达到你所期望的效果。

我觉得是可以考虑提供一个RouterXXX的方法来支持。这会使开发体验很好,毕竟字符串的话,写错名字也是常有的事情。

@jianzhiyao @AllenX2018 你们觉得如何呢?

4

赞同,我这边修改下方法的receiver。如果有需要添加这个功能的话,可以把这个指派给我哈,希望可以多参与下BEEGO。

4

这里我记得 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 ...