Gin框架
数据绑定
简单来说,,就是根据Body数据类型,将数据赋值到指定的结构体变量中 (类似于序列化和反序列化) 。
Must bind
- ⽅法:Bind , BindJSON , BindXML , BindQuery , BindYAML
- 如果存在绑定错误,则⽤c终⽌请求,使⽤ c.AbortWithError (400) .SetType (ErrorTypeBind) 即可。如果想更好地控制⾏为,可以考虑使⽤ShouldBind等效⽅法.
Should bind
- 方法:ShouldBind , ShouldBindJSON , ShouldBindXML , ShouldBindQuery , ShouldBindYAXML
- ⾏为:这些⽅法使⽤ShouldBindWith。如果存在绑定错误,则返回错误.
例子:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Login struct {
User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"`
}
func main() {
router := gin.Default()
// binding JSON
// Example for binding JSON ({"user": "ls", "password": "123456"})
router.POST("/loginJSON", func(c *gin.Context) {
var data Login
// 其实就是将request中ContentType 类型去动态解析
// 如果是mustBind,类型必须一样
if err := c.ShouldBind(&data); err != nil {
//c.String(http.StatusOK, "error")
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if data.User != "ls" || data.Password != "123456" {
c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
return
}
c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
})
router.Run(":8080")
}
模板
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
// 加载文件夹下全部的模板
router.LoadHTMLGlob("templates/**/*")
// 加载个别模板
// router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
// 定义路由
router.GET("/index", func(c *gin.Context) {
//根据完整⽂件名渲染模板,并传递参数
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
})
})
// 定义路由
router.GET("/shop/index", func(c *gin.Context) {
//根据完整⽂件名渲染模板,并传递参数
c.HTML(http.StatusOK, "/shop/index.tmpl", gin.H{
"title": "shop website",
})
})
router.Run(":8080")
}
模板继承
- 模板继承
- ⽂件响应
- 重定向(http重定向)
package main
import (
"github.com/gin-contrib/multitemplate"
"github.com/gin-gonic/gin"
"net/http"
"path/filepath"
)
// 装载模板
func loadTemplates(templatesDir string) multitemplate.Renderer {
r := multitemplate.NewRenderer()
// 加载布局,用于被继承
layouts, err := filepath.Glob(templatesDir + "/layouts/*.html")
if err != nil {
panic(err.Error())
}
// 加载模板,继承layouts
includes, err := filepath.Glob(templatesDir + "/includes/*.html")
if err != nil {
panic(err.Error())
}
// 为layouts/和includes/⽬录⽣成 templates map
for _, include := range includes {
layoutCopy := make([]string, len(layouts))
copy(layoutCopy, layouts)
files := append(layoutCopy, include)
r.AddFromFiles(filepath.Base(include), files...)
}
return r
}
// 模板继承练习
func main() {
r := gin.Default()
r.HTMLRender = loadTemplates("./templates")
// 路径映射,之后,模板文件中,可以使用/xx/zjl.jpg来访问
//r.Static("xx", "./images")
// http服务器,把文件暴露出来,点击即可下载
r.StaticFS("/showDir", http.Dir("."))
r.GET("/base/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", gin.H{
"content": "/base/index",
})
})
r.GET("/base/home", func(c *gin.Context) {
c.HTML(http.StatusOK, "home.html", gin.H{
"content": "/base.home",
})
})
// 重定向,get请求后,转到别的网站
r.GET("/redirect", func(c *gin.Context) {
// ⽀持内部和外部的重定向
c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com/")
//c.Redirect(http.StatusMovedPermanently, "/base/home")
})
r.Run(":8080")
}
同步异步
goroutine 机制可以⽅便地实现异步处理。当在中间件或处理程序中启动新的Goroutines时,你不应该在原始上下⽂使⽤它,你必须使⽤只读的副本。
package main
import (
"github.com/gin-gonic/gin"
"log"
"time"
)
func main() {
r := gin.Default()
// 1. 异步
r.GET("/long_async", func(c *gin.Context) {
// goroutine 中只能使⽤只读的上下⽂ c.Copy()
cCp := c.Copy()
go func() {
time.Sleep(5 * time.Second)
// 注意使⽤只读上下⽂
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
})
// 2. 同步
r.GET("/long_sync", func(c *gin.Context) {
time.Sleep(5 * time.Second)
// 注意可以使⽤原始上下⽂
log.Println("Done! in path " + c.Request.URL.Path)
})
r.Run(":8080")
}