1. 各种数据格式的响应
- json、结构体、XML、YAML类似于java的properties、ProtoBuf
package mainimport ("github.com/gin-gonic/gin""github.com/gin-gonic/gin/testdata/protoexample"
)// 多种响应方式
func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 1.jsonr.GET("/someJSON", func(c *gin.Context) {c.JSON(200, gin.H{"message": "someJSON", "status": 200})})// 2. 结构体响应r.GET("/someStruct", func(c *gin.Context) {var msg struct {Name stringMessage stringNumber int}msg.Name = "root"msg.Message = "message"msg.Number = 123c.JSON(200, msg)})// 3.XMLr.GET("/someXML", func(c *gin.Context) {c.XML(200, gin.H{"message": "abc"})})// 4.YAML响应r.GET("/someYAML", func(c *gin.Context) {c.YAML(200, gin.H{"name": "zhangsan"})})// 5.protobuf格式,谷歌开发的高效存储读取的工具// 数组?切片?如果自己构建一个传输格式,应该是什么格式?r.GET("/someProtoBuf", func(c *gin.Context) {reps := []int64{int64(1), int64(2)}// 定义数据label := "label"// 传protobuf格式数据data := &protoexample.Test{Label: &label,Reps: reps,}c.ProtoBuf(200, data)})r.Run(":8000")
}
2. HTML模板渲染
- gin支持加载HTML模板, 然后根据模板参数进行配置并返回相应的数据,本质上就是字符串替换
- LoadHTMLGlob()方法可以加载模板文件
package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.LoadHTMLGlob("tem/*")r.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "index.html", gin.H{"title": "我是测试", "ce": "123456"})})r.Run()
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>{{.title}}</title>
</head><body>fgkjdskjdsh{{.ce}}</body>
</html>
目录结构:
- 如果你的目录结构是下面的情况
代码如下:
package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.LoadHTMLGlob("tem/**/*")r.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "user/index.html", gin.H{"title": "我是测试", "address": "www.5lmh.com"})})r.Run()
}
{{ define "user/index.html" }}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>{{.title}}</title>
</head><body>fgkjdskjdsh{{.address}}</body>
</html>
{{ end }}
- 如果你想进行头尾分离就是下面这种写法了:
package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.LoadHTMLGlob("tem/**/*")r.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "user/index.html", gin.H{"title": "我是测试", "address": "www.5lmh.com"})})r.Run()
}
user/index.html
文件代码:
{{ define "user/index.html" }}
{{template "public/header" .}}fgkjdskjdsh{{.address}}
{{template "public/footer" .}}
{{ end }}
public/header.html
文件代码:
{{define "public/header"}}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>{{.title}}</title>
</head><body>{{end}}
public/footer.html
文件代码:
{{define "public/footer"}}
</body>
</html>
{{ end }}
- 如果你需要引入静态文件需要定义一个静态文件目录
r.Static("/assets", "./assets")
3. 重定向
package mainimport ("net/http""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("/index", func(c *gin.Context) {c.Redirect(http.StatusMovedPermanently, "http://www.5lmh.com")})r.Run()
}
4. 同步异步
- goroutine机制可以方便地实现异步处理
- 另外,在启动新的goroutine时,不应该使用原始上下文,必须使用它的只读副本
package mainimport ("log""time""github.com/gin-gonic/gin"
)func main() {// 1.创建路由// 默认使用了2个中间件Logger(), Recovery()r := gin.Default()// 1.异步r.GET("/long_async", func(c *gin.Context) {// 需要搞一个副本copyContext := c.Copy()// 异步处理go func() {time.Sleep(3 * time.Second)log.Println("异步执行:" + copyContext.Request.URL.Path)}()})// 2.同步r.GET("/long_sync", func(c *gin.Context) {time.Sleep(3 * time.Second)log.Println("同步执行:" + c.Request.URL.Path)})r.Run(":8000")
}
5.自定义模板函数
定义一个不转义相应内容的safe
模板函数如下:
func main() {router := gin.Default()router.SetFuncMap(template.FuncMap{"safe": func(str string) template.HTML{return template.HTML(str)},})router.LoadHTMLFiles("./index.tmpl")router.GET("/index", func(c *gin.Context) {c.HTML(http.StatusOK, "index.tmpl", "<a href='https://liwenzhou.com'>李文周的博客</a>")})router.Run(":8080")
}
在index.tmpl
中使用定义好的safe
模板函数:
<!DOCTYPE html>
<html lang="zh-CN">
<head><title>修改模板引擎的标识符</title>
</head>
<body>
<div>{{ . | safe }}</div>
</body>
</html>
6.静态文件处理
当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用gin.Static
方法即可。
func main() {r := gin.Default()r.Static("/static", "./static")r.LoadHTMLGlob("templates/**/*")// ...r.Run(":8080")
}
7.使用模板继承
Gin框架默认都是使用单模板,如果需要使用block template
功能,可以通过"github.com/gin-contrib/multitemplate"
库实现,具体示例如下:
首先,假设我们项目目录下的templates文件夹下有以下模板文件,其中home.tmpl
和index.tmpl
继承了base.tmpl
:
templates
├── includes
│ ├── home.tmpl
│ └── index.tmpl
├── layouts
│ └── base.tmpl
└── scripts.tmpl
然后我们定义一个loadTemplates
函数如下:
func loadTemplates(templatesDir string) multitemplate.Renderer {r := multitemplate.NewRenderer()layouts, err := filepath.Glob(templatesDir + "/layouts/*.tmpl")if err != nil {panic(err.Error())}includes, err := filepath.Glob(templatesDir + "/includes/*.tmpl")if err != nil {panic(err.Error())}// 为layouts/和includes/目录生成 templates mapfor _, include := range includes {layoutCopy := make([]string, len(layouts))copy(layoutCopy, layouts)files := append(layoutCopy, include)r.AddFromFiles(filepath.Base(include), files...)}return r
}
我们在main
函数中
func indexFunc(c *gin.Context){c.HTML(http.StatusOK, "index.tmpl", nil)
}func homeFunc(c *gin.Context){c.HTML(http.StatusOK, "home.tmpl", nil)
}func main(){r := gin.Default()r.HTMLRender = loadTemplates("./templates")r.GET("/index", indexFunc)r.GET("/home", homeFunc)r.Run()
}