如何将我的资源拆分为多个文件

时间:2017-11-04 21:18:33

标签: go

我试图在golang上写一个restful api。对于http路由器我使用gin-gonic,与我使用gorm的数据库进行交互。     包主要

import (
    "fmt"

    "github.com/gin-gonic/gin"
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/postgres"
)

var db *gorm.DB

type Person struct {
    ID        uint   `json:"id"`
    FirstName string `json:"firstname"`
    LastName  string `json:"lastname"`
}

func main() {
    // NOTE: See we’re using = to assign the global var
    // instead of := which would assign it only in this function
    db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
    if err != nil {
        fmt.Println(err)
    }
    defer db.Close()
    db.AutoMigrate(&Person{})
    r := gin.Default()
    r.GET("/people/", GetPeople)
    r.GET("/people/:id", GetPerson)
    r.POST("/people", CreatePerson)
    r.Run(":8080")
}
func CreatePerson(c *gin.Context) {
    var person Person
    c.BindJSON(&person)
    db.Create(&person)
    c.JSON(200, person)
}
func GetPerson(c *gin.Context) {
    id := c.Params.ByName("id")
    var person Person
    if err := db.Where("id = ?", id).First(&person).Error; err != nil {
        c.AbortWithStatus(404)
        fmt.Println(err)
    } else {
        c.JSON(200, person)
    }
}
func GetPeople(c *gin.Context) {
    var people []Person
    if err := db.Find(&people).Error; err != nil {
        c.AbortWithStatus(404)
        fmt.Println(err)
    } else {
        c.JSON(200, people)
    }
}

如何将代码拆分为多个文件,以便单独的资源位于单独的文件中?如何在另一个文件中使用路由器和数据库?

更新

使用这样的结构:

.
└── app
    ├── users.go
    ├── products.go
    └── main.go

我有两个问题:

  1. db == nil products.gousers.go
  2. 在不同文件中重新声明函数(getcreate ...),这可以通过函数声明中的前缀来解决,例如CreateUserCreateProduct等。但它可能会通过将代码放入另一个包来解决这个问题
  3. main.go

    package main
    
    import (
        "fmt"
    
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/postgres"
    )
    
    var (
        db *gorm.DB
        r  *gin.Engine
    )
    
    func init() {
        db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password="))
        if err != nil {
            fmt.Println(err)
        }
        defer db.Close()
    
        r = gin.Default()
    }
    
    func main() {
        r.Run(":8080")
    }
    

    products.go

    package main
    
    import (
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
    )
    
    type Product struct {
        gorm.Model
        Code  string
        Price uint
    }
    
    func init() {
        db.AutoMigrate(&Product{}) // db -> nil
    
        r.GET("/products", get)
    }
    
    func get(c *gin.Context) {
        var product Product
        db.First(&product, 1)
    
        c.JSON(200, gin.H{
            "product": product,
        })
    }
    

    users.go

    package main
    
    import (
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
    )
    
    type User struct {
        gorm.Model
        Name string
    }
    
    func init() {
        db.AutoMigrate(&User{}) // db -> nil
    
        r.GET("/users", get)
    }
    
    // ./users.go:19: get redeclared in this block
    // previous declaration at ./products.go:20    
    func get(c *gin.Context) {
        var user User
        db.First(&user, 1)
    
        c.JSON(200, gin.H{
            "user": user,
        })
    }
    

1 个答案:

答案 0 :(得分:1)

由于您的db var是在包级别定义的,因此它基本上是该包的全局变量,可以在该包中的任何文件中引用。

例如,在这样的项目中:

.
└── app
    ├── a.go
    ├── b.go
    ├── c.go
    └── main.go

如果在软件包级别的main.go中定义了db,如示例所示,则文件a.go,b.go和c.go中的代码可以使用db。< / p>

它也是另一种方式,a.go,b.go和c.go中定义的任何资源处理程序都可以在main.go中引用。这意味着在每个文件中你可以定义一个带路由器,gin路由器的功能,并设置相应的处理程序,然后在main.go的主要功能中调用那些在路由器中传递的函数{{1 }}

更新

首先,您在init函数内部调用r,这意味着在init返回后,您的defer db.Close()将被关闭,这绝对不是您想要的。在main中使用db很好,因为当你的应用程序终止时,main会终止,那时关闭数据库是有意义的,但是当init终止你的应用程序甚至没有正确启动时,主要是刚刚执行而你仍需要你的defer db.Close()

如果你想在每个文件中使用db函数来执行特定于该文件的初始化,你必须确保这些初始化函数所依赖的,在执行之前初始化

在您的示例中,所有初始化函数都依赖于initdb,因此您需要确保这两个函数不是r。我不完全确定在Go中,执行的顺序是单个包中的多个init函数,但我确切知道在初始化函数执行之前初始化了包级别变量表达式。

所以你可以做的是使用函数调用初始化两个包级变量,如下所示:

nil

至于你的第二个问题,在Go package main import ( "fmt" "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/postgres" ) var ( db = func() *gorm.DB { db, err := gorm.Open("postgres", fmt.Sprintf("host=localhost sslmode=disable user=postgres password=")) if err != nil { // if you can't open a db connection you should stop the app, // no point in continuing if you can't do anything useful. panic(err) } return db }() // <- call the anon function to get the db. r = gin.Default() ) func main() { // you can call defer db.Close() here but you don't really need to // because after main exists, that is, your app terminates, db // will be closed automatically. r.Run(":8080") } 中是一个特殊情况,我的意思是你可以在一个包中有多个init函数,甚至在一个文件中。您声明的任何其他标识符都不是这样。

这意味着在包内,并在包级别声明,您只能有一个init标识符,一个db标识符,只有一个get标识符,等等。使用suffiex例如User或包getUser完全取决于您。

请注意,您可以重新声明另一个范围内的标识符 ,假设您在包级别有user.Get,然后在同一个pacakge中声明的函数可以在里面它自己的范围声明了一个像type User struct { ...这样的变量,尽管它可能不是最好的想法。

有关详细信息,请参阅: Package initialization

更新2

如果要将代码拆分为多个包,只需将文件放入单独的文件夹中,并确保文件顶部的var User = "whatever"声明具有正确的包名称。

以下是一个例子:

package

现在您的└── app/ ├── main.go ├── product/ │   ├── product.go │   └── product_test.go └── user/ ├── user.go └── user_test.go 代码看起来像这样。

app/user/user.go

你的package user import ( "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" ) var db *gorm.DB type User struct { gorm.Model Name string } // custom and exported Init function, this will not be called automatically // by the go runtime like the special `init` function and therefore must be called // manually by the package that imports this one. func Init(gormdb *gorm.DB, r *gin.Engine) { db = gormdb // set package global db.AutoMigrate(&User{}) r.GET("/users", get) } func get(c *gin.Context) { var user User db.First(&user, 1) c.JSON(200, gin.H{ "user": user, }) } ...

app/product/product.go

您的入口点为package product import ( "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" ) var db *gorm.DB type Product struct { gorm.Model Code string Price uint } // custom and exported Init function, this will not be called automatically // by the go runtime like the special `init` function and therefore must be called // manually by the package that imports this one. func Init(gormdb *gorm.DB, r *gin.Engine) { db = gormdb // set package global db.AutoMigrate(&Product{}) r.GET("/products", get) } func get(c *gin.Context) { var product Product db.First(&product, 1) c.JSON(200, gin.H{ "product": product, }) } ...

app/main.go