golang gin-gonic 和在包中拆分文件

Posted

技术标签:

【中文标题】golang gin-gonic 和在包中拆分文件【英文标题】:golang gin-gonic and splitting files in package 【发布时间】:2017-07-01 17:35:12 【问题描述】:

我还是个新手,我正在尝试学习,我正在使用 gin-gonic 服务器设置应用程序。 我设法让它与主包中的所有内容一起工作,我想更好地组织它与包中相关的所有 apirest(我管理)并按文件拆分每个组 CRUD。

所以在init函数内包的“main”文件中,我定义了:

Router := gin.New()
Router.Use(gin.Logger())
Router.Use(gin.Recovery())

虽然我可以在包的其他文件中这样使用它:

v1 := Router.Group("/api/v1/todos")
v1.Use(AuthRequired())

    v1.POST("/", CreateTodo)
    v1.GET("/", FetchAllTodo)
    v1.GET("/:id", FetchSingleTodo)
    v1.PUT("/:id", UpdateTodo)
    v1.DELETE("/:id", DeleteTodo)

packagename.Router.Group

但没有一个工作,我得到:

未定义:Router.Group 中的路由器

史蒂芬 PS:我确实为包设置了一个子文件夹,如果它在一个文件中,我可以去构建它。


我虽然解决方案是将 Router 变量声明为 *gin.Engine,但是当它编译正常时,我在 Router.Group 调用上遇到了一个恐慌错误

让我再贴一些代码:

maincode.go:

package main

import (
    "fmt"
    "./apirest"
    "github.com/braintree/manners"
)

func main()
    fmt.Printf("hello world.\n")
    //router.Run()
    manners.ListenAndServe(":8080", apirest.Router)

然后我将 apirest 包分成 2 个文件:

apirest.go(我做了手动清理,也许我错过了导入):

package apirest

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/braintree/manners"
    "os"
    "os/signal"
)

//Router pour gérer l'api
var Router *gin.Engine

/*
    MAIN FUNCTION
*/
func init() 

    Router := gin.New()
    Router.Use(gin.Logger())
    Router.Use(gin.Recovery())

    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt)
    go func()
        for sig := range c 
            // sig is a ^C, handle it
            fmt.Printf("ctl+c catched "+sig.String())
            manners.Close()
        
    ()

    LoadMonitor()


然后是处理所有声明的 todoCRUD.go 文件,todoCRUD.go 和 apirest.go 在同一个子文件夹 apirest 中(并且可以编译):

package apirest

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "gopkg.in/validator.v2"
    "github.com/jinzhu/gorm"
    "strconv"
    "net/http"
    "time"
)

//Todo definition d'un element todo
type Todo struct 
    gorm.Model
    CreatedAt   time.Time
    UpdatedAt   time.Time
    OwnerID     int    `json:"ownerid"  validate:"nonzero"`
    URL         string `json:"url"`


//TransformedTodo version pour le retour d'api sans certaines infos
type TransformedTodo struct 
    ID          uint   `json:"id"`
    CreatedAt   time.Time
    UpdatedAt   time.Time
    OwnerID     uint   `json:"ownerid"`
    URL         string `json:"url"`   


//LoadTodo permet de lancer le mappage todos
func LoadTodo()
    v1 := Router.Group("/api/v1/todos")
    
        v1.POST("/", CreateTodo)
        v1.GET("/", FetchAllTodo)
        v1.GET("/:id", FetchSingleTodo)
        v1.PUT("/:id", UpdateTodo)
        v1.DELETE("/:id", DeleteTodo)
    


//CreateTodo génération d'un todo
func CreateTodo(c *gin.Context) 

    owner, _ := strconv.Atoi(c.PostForm("ownerid"))
    todo := Todo
        OwnerID: owner,
        URL: c.PostForm("url"),
    ;
    v := validator.NewValidator()
    if errs := v.Validate(todo); errs!=nil 
        errors := errs.(validator.ErrorMap)
        var errOuts []string
        for f, e := range errors 
            errOuts = append(errOuts, fmt.Sprintf("\t - %s (%v)\n", f, e))
        
        //c.JSON(500, gin.H"Error": errs.Error())
        c.JSON(500, gin.H"Erreur sur le(s) champ(s) : ": errOuts)
     else 

        db, _ := Database()
        defer db.Close()
        db.Save(&todo)

        c.JSON(http.StatusCreated, gin.H"status" : http.StatusCreated, "message" : "Todo item created successfully!", "resourceId": todo.ID)
    


//FetchAllTodo récupération de tous les todos
func FetchAllTodo(c *gin.Context) 
    var todos []Todo
    var _todos []TransformedTodo

    db, _ := Database()
    defer db.Close()
    db.Find(&todos)

    if (len(todos) <= 0) 
        c.JSON(http.StatusNotFound, gin.H"status" : http.StatusNotFound, "message" : "No todo found!")
        return
    

    //transforms the todos for building a good response,
    //je peux choisir des champs a ne pas display
    for _, item := range todos 
        status := false
        if (item.Status == 1) 
            status = true
         else 
            status = false
        
        _todos = append(_todos, TransformedTodoID: item.ID, URL:item.URL)
    
    c.JSON(http.StatusOK, gin.H"status" : http.StatusOK, "data" : _todos)


//FetchSingleTodo Récupération d'un seul todo en fonction de son id
func FetchSingleTodo(c *gin.Context) 
    var todo Todo
    todoID := c.Param("id")

    db, _ := Database()
    defer db.Close()
    db.First(&todo, todoID)

    if (todo.ID == 0) 
        c.JSON(http.StatusNotFound, gin.H"status" : http.StatusNotFound, "message" : "No todo found!")
        return
    

    _todo := TransformedTodoID: todo.ID, URL:todo.URL
    c.JSON(http.StatusOK, gin.H"status" : http.StatusOK, "data" : _todo)


//UpdateTodo Mise à jour d'un todo
func UpdateTodo(c *gin.Context) 
    var todo Todo
    todoID := c.Param("id")
    db, _ := Database()
    defer db.Close()
    db.First(&todo, todoID)

    if (todo.ID == 0) 
        c.JSON(http.StatusNotFound, gin.H"status" : http.StatusNotFound, "message" : "No todo found!")
        return
    

    db.Model(&todo).Update("title", c.PostForm("title"))
    db.Model(&todo).Update("completed", c.PostForm("completed"))
    c.JSON(http.StatusOK, gin.H"status" : http.StatusOK, "message" : "Todo updated successfully!")



//DeleteTodo Suppression d'un todo
func DeleteTodo(c *gin.Context) 
    var todo Todo
    todoID := c.Param("id")
    db, _ := Database()
    defer db.Close()
    db.First(&todo, todoID)

    if (todo.ID == 0) 
        c.JSON(http.StatusNotFound, gin.H"status" : http.StatusNotFound, "message" : "No todo found!")
        return
    

    db.Delete(&todo)
    c.JSON(http.StatusOK, gin.H"status" : http.StatusOK, "message" : "Todo deleted successfully!")

想法是为每个实体处理一个 xxxxCRUD.go 文件,但将整个文件夹放在同一个包中。

确切的错误是:

PS D:\www\developpement> 运行 .\maincode.go [GIN-debug] [WARNING] 在“调试”模式下运行。在生产中切换到“发布”模式。 - 使用环境:导出 GIN_MODE=release - 使用代码:gin.SetMode(gin.ReleaseMode)

恐慌:运行时错误:无效的内存地址或零指针 取消引用 [信号 0xc0000005 代码=0x0 addr=0x0 pc=0x46cc0f]

goroutine 1 [运行]: 恐慌(0x831880, 0xc04200a080) C:/Go/src/runtime/panic.go:500 +0x1af /D/www/developpement/apirest.LoadTodo() D:/www/developpement/apirest/todoCRUD.go:33 +0x2f [Router.Group] /D/www/developpement/apirest.init.1() D:/www/developpement/apirest/apirest.go:73 +0x220 [LoadTodo()] /D/www/developpement/apirest.init() D:/www/developpement/apirest/todoCRUD.go:190 +0x80 [最后一行] main.init() D:/www/developpement/maincode.go:13 +0x3a [manners.ListenAndServe(":8080", apirest.Router)] 退出状态2

希望对理解有所帮助!

感谢您的宝贵时间和帮助!

史蒂芬

【问题讨论】:

你能提供你的非工作源吗? (根据您的解释,一切似乎都井井有条) 【参考方案1】:

我确实设法通过在 LoadTodo 函数中“发送”路由器来使其工作:

在 apirest.go 中:

LoadTodo(Router)

在 todoCRUD.go 中:

func LoadTodo(r *gin.Engine)

它工作正常......我希望我没有在代码中带来错误失败......

史蒂芬

【讨论】:

以上是关于golang gin-gonic 和在包中拆分文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Golang 和 MongoDB 中将路由拆分为单独的包

使用 Autotools 在包中添加 .c 文件而不编译它们

Sencha app watch 包含在包中的 scss 文件

如何使用静态库传输资源文件(如何将资源包装在包中)?

golang中自定义包

在包中定义类