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

时间:2015-12-02 15:13:09

标签: go go-gin

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

路线设置如下:

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

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

我的问题是如何将参数传递给testRouteHandler函数?例如,一个公共数据库连接可能是想要在路由中重用的东西。

这是在全局变量中使用它的最佳方法吗?或者Go中有一些方法可以将额外的变量传递给testRouteHandler函数吗? Go中的函数是否有可选参数?

PS。我刚刚开始学习Go,所以可能是我缺少的明显事物:)

6 个答案:

答案 0 :(得分:15)

我会避免将“应用程序作用域”依赖项(例如数据库连接池)填充到请求上下文中。你最简单的两个选择是:

  1. 让它成为全球性的。对于较小的项目,这是可以的,*sql.DB是线程安全的。
  2. 在闭包中显式传递,以便返回类型满足gin.HandlerFunc
  3. 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")
    }
    

答案 1 :(得分:14)

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

$scope.userDidAttemptToSubmitDateTime = function userDidAttemptToSubmitDateTimeFn(){
  //Given that your date and time live in $scope.
  var validationObject = $scope.isValidOfficeDateTimeSubmission($scope.dateVarBoundFromInputInHTML, $scope.timeVarBoundFromInputInHTML); 

  //Now use the properties in your validationObject to do whatever the heck you want to show the user

 if (validationObject.errors.length) {
   $scope.showErrorsToUserWithArbitraryErrorStringArray(validationObject.errors);
 } else {
   $scope.showSuccessfulSelectionMessageWithPotentialCallbackIfYouWantedTo(callBackFn);
 }
}

这只是一个简单的POC。但我相信这是一个开始。 希望它有所帮助。

答案 2 :(得分:1)

到了晚会,到目前为止这是我的建议。将方法封装到具有私有/公共变量的对象中:

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

答案 3 :(得分:1)

我喜欢 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")
}

答案 4 :(得分:0)

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

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

现在您必须按以下方式调用您的处理程序 http://localhost:8080/test/1/myname

答案 5 :(得分:0)

让我试着详细解释一下,以免您感到困惑。

  1. 根据传入路由,您需要调用控制器函数。假设您的传入路由是 /books,而您的控制器是 BooksController
  2. 您的 BooksController 将尝试从数据库中获取图书并返回响应。

现在,您希望将其作为 BooksController 中的处理程序,以便您可以访问数据库。

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

  1. 创建一个结构如下。
type serviceConnection struct {
    db *dynamoDB.DynamoDB
    // You can have all services declared here 
    // which you want to use it in your controller
}
  1. 在您的主函数中,获取数据库连接信息。假设您已经有一个函数 initDatabaseConnection,它向 db 返回一个处理程序,如下所示。

db := initDatabaseConnection() -> 返回 *dynamodb.DynamoDB

  1. db 设置为结构变量。
conn := new(serviceConnection)
conn.db = db
  1. 使用接收器处理程序调用 gin 请求方法,如下所示。
r := gin.Default()
r.GET("/books", conn.BooksController)

如您所见,gin 处理程序是一个控制器方法,它将您的结构实例作为接收器。

  1. 现在,使用 serviceConnection struct receiver 创建控制器方法。
func (conn *serviceConnection) BooksController(c *gin.Context) {
    books := getBooks(conn.db)
}

正如您在此处看到的,您可以访问所有 serviceConnection 结构变量,并且可以在您的控制器中使用它们。