如何使用Gin web框架将参数传递给Golang中的路由器处理程序?

如何使用Gin web框架将参数传递给Golang中的路由器处理程序?,go,go-gin,Go,Go Gin,我正在使用Gin,用Golang构建一个简单的restfuljsonapi 路线的设置如下所示: func testRouteHandler(c *gin.Context) { // do smth } func main() { router := gin.Default() router.GET("/test", testRouteHandler) router.Run(":8080") } 我的问题是如何将参数传递给testRouteHandler函数?

我正在使用Gin,用Golang构建一个简单的restfuljsonapi

路线的设置如下所示:

func testRouteHandler(c *gin.Context) {
    // do smth
}

func main() {
    router := gin.Default()
    router.GET("/test", testRouteHandler)
    router.Run(":8080")
}
我的问题是如何将参数传递给testRouteHandler函数?例如,公共数据库连接可能是希望在路由之间重用的连接

将其放入全局变量中的最佳方法是什么?或者Go中是否有某种方法将额外的变量传递给testRouteHandler函数?Go中是否有函数的可选参数


另外,我刚刚开始学习围棋,所以可能有一些明显的东西我没有:)

使用我在评论上发布的链接,我创建了一个简单的例子

package main

import (
    "log"

    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/mattn/go-sqlite3"
)

// ApiMiddleware will add the db connection to the context
func ApiMiddleware(db gorm.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Set("databaseConn", db)
        c.Next()
    }
}

func main() {
    r := gin.New()

    // In this example, I'll open the db connection here...
    // In your code you would probably do it somewhere else
    db, err := gorm.Open("sqlite3", "./example.db")
    if err != nil {
        log.Fatal(err)
    }

    r.Use(ApiMiddleware(db))

    r.GET("/api", func(c *gin.Context) {
        // Don't forget type assertion when getting the connection from context.
        dbConn, ok := c.MustGet("databaseConn").(gorm.DB)
        if !ok {
            // handle error here...
        }

        // do your thing here...
    })

    r.Run(":8080")
}
这只是一个简单的POC。但我相信这是一个开始。
希望能有所帮助。

我会避免将“应用程序范围”依赖项(例如数据库连接池)塞进请求上下文中。您的两个“最简单”选项是:

  • 让它成为一个全球性的组织。这对于较小的项目来说是可以的,
    *sql.DB
    是线程安全的
  • 在闭包中显式传递它,以便返回类型满足
  • e、 g


    好的,我给你举了一个简单的例子。它应该会起作用。您可以根据需要扩展它

    func main() {
        router := gin.Default()
        router.GET("/test/:id/:name", testRouteHandler)
        router.Run(":8080")
    }
    
    func testRouteHandler(c *gin.Context) {
        id := c.Params.ByName("id")
        name := c.Params.ByName("name")
    }
    
    现在,您必须按如下方式调用处理程序
    晚会迟到了,到目前为止,这是我的建议。将方法装入包含私有/公共变量的对象中:

    package main
    
    import (
        "log"
    
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/mattn/go-sqlite3"
    )
    
    type HandlerA struct {
        Db gorm.DB
    }
    
    func (this *HandlerA) Get(c *gin.Context) {
    
        log.Info("[%#f]", this.Db)
        // do your thing here...
    }
    
    func main() {
        r := gin.New()
    
        // Init, should be separate, but it's ok for this sample:
        db, err := gorm.Open("sqlite3", "./example.db")
        if err != nil {
            log.Fatal(err)
        }
    
        Obj := new(HandlerA)
        Obj.Db = db // Or init inside Object
    
        r := gin.New()
    
        Group := r.Group("api/v1/")
        {
            Group.GET("/storage", Obj.Get)
        }
    
        r.Run(":8080")
    }
    

    我喜欢wildneuro的示例,但会使用一行程序来设置处理程序

    package main
    
    import (
        "log"
    
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/mattn/go-sqlite3"
    )
    
    type HandlerA struct {
        Db gorm.DB
    }
    
    func (this *HandlerA) Get(c *gin.Context) {
    
        log.Info("[%#f]", this.Db)
        // do your thing here...
    }
    
    func main() {
        r := gin.New()
    
        // Init, should be separate, but it's ok for this sample:
        db, err := gorm.Open("sqlite3", "./example.db")
        if err != nil {
            log.Fatal(err)
        }
     
        r := gin.New()
    
        Group := r.Group("api/v1/")
        {
            Group.GET("/storage", (&HandlerA{Db: db}).Get)
        }
    
        r.Run(":8080")
    }
    

    让我试着详细解释一下,这样你就不会感到困惑了

  • 根据传入路由,您需要调用控制器函数。假设您的入站路线为
    /books
    ,控制器为
    BooksController
  • 您的
    BooksController
    将尝试从数据库中获取书籍并返回响应
  • 现在,您希望在
    BooksController
    中有一个处理程序,以便访问数据库

    我会这样做。假设您使用的是dynamoDB,aws sdk提供了
    *dynamoDB.dynamoDB
    。根据您的数据库,更改此变量

  • 创建一个结构,如下所示
  • 在main函数中,获取数据库连接信息。假设您已经有了一个函数
    initDatabaseConnection
    ,它将处理程序返回给db,如下所示
  • db:=initDatabaseConnection()
    ->返回
    *dynamodb.dynamodb

  • db
    设置为结构变量
  • 使用接收方处理程序调用gin请求方法,如下所示
  • 如您所见,gin处理程序是一个控制器方法,它将您的结构实例作为接收器

  • 现在,使用
    serviceConnection
    struct receiver创建一个控制器方法

  • 正如您在这里看到的,您可以访问所有的
    serviceConnection
    struct变量,并且可以在控制器中使用它们。

    我认为您正在寻找HTTP中间件这是一个很好的起点,正如@MIkCode所说,中间件是一个不错的选择。。。看看杜松子酒的定制中间产品。这应该是推荐的答案。不幸的是,在使用
    Use
    Group
    ()等方法时,我在让这个闭包模式与Gin框架很好地配合时遇到了多个问题,我建议使用
    Set
    Get
    方法,直到Gin设计得更好。我很少提倡更糟糕的设计,但最好在方法上保持一致并利用框架。很好的模式,但是Gin还没有。如何在chi框架中实现同样的“将db连接添加到上下文”呢?不幸的是,这是最好的答案。这并不理想,因为
    Set
    Get
    创建了一个依赖项,其中闭包模式可以简单地将参数从中间件传递到封闭的路由。然而,Gin并不自然地使用闭包模式,因此一些方法,如
    使用
    变得复杂。
    package main
    
    import (
        "log"
    
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/mattn/go-sqlite3"
    )
    
    type HandlerA struct {
        Db gorm.DB
    }
    
    func (this *HandlerA) Get(c *gin.Context) {
    
        log.Info("[%#f]", this.Db)
        // do your thing here...
    }
    
    func main() {
        r := gin.New()
    
        // Init, should be separate, but it's ok for this sample:
        db, err := gorm.Open("sqlite3", "./example.db")
        if err != nil {
            log.Fatal(err)
        }
     
        r := gin.New()
    
        Group := r.Group("api/v1/")
        {
            Group.GET("/storage", (&HandlerA{Db: db}).Get)
        }
    
        r.Run(":8080")
    }
    
    type serviceConnection struct {
        db *dynamoDB.DynamoDB
        // You can have all services declared here 
        // which you want to use it in your controller
    }
    
    conn := new(serviceConnection)
    conn.db = db
    
    r := gin.Default()
    r.GET("/books", conn.BooksController)
    
    func (conn *serviceConnection) BooksController(c *gin.Context) {
        books := getBooks(conn.db)
    }