gin - skynocover/Wiki-for-GoLang GitHub Wiki

Gin

基本操作

//產生一個引擎 帶有logger及Recovery
router := gin.Default()

//載入html
router.LoadHTMLGlob("views/*")
router.StaticFS("/views", http.Dir("/views/assets"))

// 静态文件服务  可以hot fix不用重啟程式
router.Static("/resource", "resource") //載入整個目錄
router.StaticFile("main.css", "./views/assets/css/main.css") //載入單個文件

//註冊路由
//抓取index的網址並顯示serch.html的靜態網頁
router.GET("/index", func(c *gin.Context) {
    //根据完整文件名渲染模板,并传递参数
    c.HTML(http.StatusOK, "serch.html", gin.H{
    "title": "Main website",
    })
})

//執行
router.Run(":8080") //localhost:8080

路由的操作

GET

重新定向

router.GET("/redirect", func(c *gin.Context) {
    //支持内部和外部的重定向
    c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
})

路由的分組及handler的使用

v := router.Group("/test") //可以對入口進行分組,網址變成localhost:8080/test/index.html
{
    v.GET("/index.html", handler.IndexHandler) //藉由handler來處理
    v.GET("/mypage.html", uploadHandler)       //藉由handler來處理
    v.GET("/login", func(c *gin.Context) { //不藉由handler處理
    c.String(http.StatusOK, "v1 login")
})
}

// handler
func uploadHandler(c *gin.Context) { //建立handler(controller)
    c.HTML(http.StatusOK, "mypage.html", gin.H{
    "Title": "測試頁面", //在html內要有 <title>{{ .Title }}</title> 才會正確顯示
    })
}

//v2 := router.Group("/v2", middleware1) 在group中使用中間件

使用middleware

注册一个路由,使用了 middleware1,middleware2 两个中间件

router.GET("/someGet", middleware1, middleware2, handler2)
func middleware1(c *gin.Context) {
    log.Println("exec middleware1")
    // 执行该中间件之后的逻辑
    c.Next()
}

func middleware2(c *gin.Context) {
    log.Println("arrive at middleware2")
    // 执行该中间件之前,先跳到流程的下一个方法
    c.Next()
    // 流程中的其他逻辑已经执行完了才會回來這裡
    log.Println("exec middleware2")
    //你可以写一些逻辑代码
}
func handler2(c *gin.Context) {
    log.Println("exec handler")
}
2019/12/15 11:24:55 exec middleware1
2019/12/15 11:24:55 arrive at middleware2
2019/12/15 11:24:55 exec handler
2019/12/15 11:24:55 exec middleware2

參數抓取

//第1種
router.GET("/user/:name/*action", func(c *gin.Context) { //*會把/也抓出來
    name := c.Param("name")
    action := c.Param("action")
    message := name + " is " + action
    c.String(http.StatusOK, message)
})
//第2種
router.GET("/welcome", func(c *gin.Context) { //預設值
    firstname := c.DefaultQuery("firstname", "Guest")
    lastname := c.Query("lastname")
    c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
    // http://localhost:8080/welcome?firstname=eircu&lastname=wewe
    // Hello eircu wewe
    // http://localhost:8080/welcome?firstname/&lastname=wewe
    // Hello Guest wewe
    // http://localhost:8080/welcome?firstname=&lastname=wewe
    // Hello  wewe
})

POST

先將login的目錄顯示出來

router.GET("/login", func(c *gin.Context) {
    c.HTML(http.StatusOK, "login.html", gin.H{
            "title": "Main website",
    })
})

html內部需要導引至POST的網址

 <form action="http://127.0.0.1:8080/form_post"

之後用post把參數撈出來

router.POST("/form_post", func(c *gin.Context) {
    message := c.PostForm("message")
    nick := c.DefaultPostForm("nick", "anonymous") //有默認參數
    /*
    c.JSON(http.StatusOK, gin.H{
        "status": gin.H{
        "status_code": http.StatusOK,
        "status":      "ok",
    },
    "message": message,
    "nick":    nick,
    })
    */
//{"message":"","nick":"skycover","status":{"status":"ok","status_code":200}}

    c.JSON(200, gin.H{
        "status":  "posted",
        "message": message,
        "nick":    nick,
    })
    //{"message":"newmw","nick":"skycover","status":"posted"}

    type1 := c.DefaultPostForm("type", "alert") //可设置默认值
    username := c.PostForm("username")
    password := c.PostForm("password")
    //hobbys := c.PostFormMap("hobby")
    //hobbys := c.QueryArray("hobby")
    hobbys := c.PostFormArray("hobby")
    c.String(http.StatusOK, fmt.Sprintf("type is %s, username is %s, password is %s,hobby is %v", type1, username, password, hobbys))
    /*
    {"message":"newmwwa","nick":"skycover","status":"posted"}
    type is alert, username is ericwu, password is aaaa,hobby is [game money]
    */
})

數據處理

數據格式化

type Person2 struct {
    Name     string    `form:"name"`
    Address  string    `form:"address"`
    Birthday time.Time `form:"birthday" time_format:"2006-01-02" time_utc:"1"`
}
//http://localhost:8080/testing2?name=eric&address=here&birthday=2016-01-01
router.GET("/testing2", func(c *gin.Context) {
    var person Person2// 绑定到 person
    if c.ShouldBind(&person) == nil { //使用shouldbind 會依序使用JSON或XML,之后才是Form進行匹配
    //也可以直接指定c.ShouldBindQuery
        log.Println(person.Name)
        log.Println(person.Address)
        log.Println(person.Birthday)
    }
})

數據驗證

只要在數據綁定的結構上加上binding即可 binding:"required" 表必要參數,若無則會返回error

type Login struct {
    User     string `form:"user" json:"user" binding:"required"`
    Password string `form:"password" json:"password" binding:"required"`
}

使用Form驗證

// user=manu&password=123
 router.GET("/loginForm", func(c *gin.Context) {
        var form Login
        // 验证数据并绑定
        if err := c.ShouldBind(&form); err == nil {
            if form.User == "manu" && form.Password == "123" {
                c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
            } else {
                c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            }
        } else {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        }
    })

JSON

router.POST("/loginJSON", func(c *gin.Context) {
        var json Login
        // 验证数据并绑定
        if err := c.ShouldBindJSON(&json); err == nil {
            if json.User == "manu" && json.Password == "123" {
                c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
            } else {
                c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            }
        } else {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        }
})
⚠️ **GitHub.com Fallback** ⚠️