douzhuang6321
2015-12-02 15:13
浏览 297
已采纳

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

I'm using Gin, https://gin-gonic.github.io/gin/, to build a simple RESTful JSON API with Golang.

The routes are setup with something like this:

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

func main() {
    router := gin.Default()
    router.GET("/test", testRouteHandler)
    router.Run(":8080")
}

My question is how can I pass down an argument to the testRouteHandler function? For example a common database connection could be something that one wants to reuse among routes.

Is the best way to have this in a global variable? Or is there some way in Go to pass along an extra variable to the testRouteHandler function? Are there optional arguments for functions in Go?

PS. I'm just getting started in learning Go, so could be something obvious that I'm missing :)

图片转代码服务由CSDN问答提供 功能建议

我正在使用Gin,https://gin-gonic.github.io/gin/ ,以使用Golang构建简单的RESTful JSON API。

通过类似以下方式设置路由

  func testRouteHandler(c * gin.Context){
 //做smth 
} 
 
func main(){
 router:= gin。  Default()
 router.GET(“ / test”,testRouteHandler)
 router.Run(“:8080”)
} 
   
 
 

我的问题是 如何将参数传递给testRouteHandler函数? 例如,常见的数据库连接可能是要在路由之间重用的某种东西。

将其存储在全局变量中的最佳方法是吗? 还是Go中有某种方法可以将额外的变量传递给testRouteHandler函数? Go中的函数有可选参数吗?

PS。 我刚刚开始学习Go,所以可能很明显我想念的东西:)

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

4条回答 默认 最新

  • douchao9899 2015-12-02 21:11
    已采纳

    Using the link i posted on comments, I have created a simple example.

    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")
    }
    

    This is just a simple POC. But i believe it's a start. Hope it helps.

    打赏 评论
  • douhan4812 2015-12-03 02:20

    I would avoid stuffing 'application scoped' dependencies (e.g. a DB connection pool) into a request context. Your two 'easiest' options are:

    1. Make it a global. This is OK for smaller projects, and *sql.DB is thread-safe.
    2. Pass it explicitly in a closure so that the return type satisfies gin.HandlerFunc

    e.g.

    // SomeHandler returns a `func(*gin.Context)` to satisfy Gin's router methods
    // db could turn into an 'Env' struct that encapsulates all of your
    // app dependencies - e.g. DB, logger, env vars, etc.
    func SomeHandler(db *sql.DB) gin.HandlerFunc {
        fn := func(c *gin.Context) {
            // Your handler code goes in here - e.g.
            rows, err := db.Query(...)
    
            c.String(200, results)
        }
    
        return gin.HandlerFunc(fn)
    }
    
    func main() {
        db, err := sql.Open(...)
        // handle the error
    
        router := gin.Default()
        router.GET("/test", SomeHandler(db))
        router.Run(":8080")
    }
    
    打赏 评论
  • douzun4443 2016-02-27 15:13

    Alright, I have given you a simple example. It should work. You can extend it as per your need

    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")
    }
    

    Now you will have to call your handler as below http://localhost:8080/test/1/myname

    打赏 评论
  • duancuan6466 2017-04-27 01:29

    Late to the party, so far here is my proposal. Incapsulate methods into the object with private/public vars in it:

    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")
    }
    
    打赏 评论

相关推荐 更多相似问题