数据格式渲染

JSON数据渲染

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. type Login struct{
  6. User string `form:"username" json:"username" xml:"username" uri:"username" binding:"required"`
  7. Password string `form:"password" json:"password" xml:"password" uri:"password" binding:"required"`
  8. }
  9. func main(){
  10. // 1、创建路由
  11. g := gin.Default()
  12. // 2、绑定路由规则
  13. g.GET("/json", func(context *gin.Context) {
  14. // (1)、自己拼接数据
  15. context.JSON(200,gin.H{
  16. "status": 200,
  17. "data": "joker",
  18. })
  19. })
  20. g.GET("/structJson", func(context *gin.Context) {
  21. var res struct{
  22. name string
  23. age int
  24. }
  25. res.name="joker"
  26. res.age=20
  27. context.JSON(200,res)
  28. })
  29. g.Run(":8000")
  30. }

XML数据渲染

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. type Login struct{
  6. User string `form:"username" json:"username" xml:"username" uri:"username" binding:"required"`
  7. Password string `form:"password" json:"password" xml:"password" uri:"password" binding:"required"`
  8. }
  9. func main(){
  10. // 1、创建路由
  11. g := gin.Default()
  12. // 2、绑定路由规则
  13. g.GET("/xml", func(context *gin.Context) {
  14. // (1)、自己拼接数据
  15. context.XML(200,gin.H{
  16. "status": 200,
  17. "data": "joker",
  18. })
  19. })
  20. g.GET("/structXML", func(context *gin.Context) {
  21. var res struct{
  22. name string
  23. age int
  24. }
  25. res.name="joker"
  26. res.age=20
  27. context.XML(200,res)
  28. })
  29. g.Run(":8000")
  30. }

YAML数据渲染

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. type Login struct{
  6. User string `form:"username" json:"username" xml:"username" uri:"username" binding:"required"`
  7. Password string `form:"password" json:"password" xml:"password" uri:"password" binding:"required"`
  8. }
  9. func main(){
  10. // 1、创建路由
  11. g := gin.Default()
  12. // 2、绑定路由规则
  13. g.GET("/yaml", func(context *gin.Context) {
  14. // (1)、自己拼接数据
  15. context.YAML(200,gin.H{
  16. "status": 200,
  17. "data": "joker",
  18. })
  19. })
  20. g.Run(":8000")
  21. }

protobuf渲染

protobuf是谷歌开发的高性能读取写入方式。

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/gin-gonic/gin/testdata/protoexample"
  5. "net/http"
  6. )
  7. type Login struct{
  8. User string `form:"username" json:"username" xml:"username" uri:"username" binding:"required"`
  9. Password string `form:"password" json:"password" xml:"password" uri:"password" binding:"required"`
  10. }
  11. func main(){
  12. // 1、创建路由
  13. g := gin.Default()
  14. // 2、绑定路由规则
  15. g.GET("/someProtoBuf", func(c *gin.Context) {
  16. reps := []int64{int64(1), int64(2)}
  17. label := "test"
  18. // protobuf 的具体定义写在 testdata/protoexample 文件中。
  19. data := &protoexample.Test{
  20. Label: &label,
  21. Reps: reps,
  22. }
  23. // 请注意,数据在响应中变为二进制数据
  24. // 将输出被 protoexample.Test protobuf 序列化了的数据
  25. c.ProtoBuf(http.StatusOK, data)
  26. })
  27. g.Run(":8000")
  28. }

HTML渲染

模板文件统一放到templates目录下,下面可以再根据不同的业务分不同的目录,比如studentteacher等。
如下:
image.png

然后编辑index.html

  1. {{define "student/index.html"}}
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>{{.title}}</title>
  9. </head>
  10. <body>
  11. {{.msg}}
  12. </body>
  13. </html>
  14. {{end}}

在Gin中使用LoadHTMLGlob()或者LoadHTMLFiles()方法进行HTML模板渲染。

  • LoadHTMLGlob:加载路径
  • LoadHTMLFiles:加载文件
  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. type Login struct{
  6. User string `form:"username" json:"username" xml:"username" uri:"username" binding:"required"`
  7. Password string `form:"password" json:"password" xml:"password" uri:"password" binding:"required"`
  8. }
  9. func main(){
  10. // 1、创建路由
  11. g := gin.Default()
  12. // 2、加载HTML文件
  13. g.LoadHTMLGlob("templates/**/*")
  14. // 3、绑定路由规则
  15. g.GET("/student/index", func(context *gin.Context) {
  16. // 渲染html返回
  17. context.HTML(200,"student/index.html",gin.H{
  18. "title": "学生页面",
  19. "msg": "学生主页......",
  20. })
  21. })
  22. g.GET("/teacher/index", func(context *gin.Context) {
  23. context.HTML(200,"teacher/index.html",gin.H{
  24. "title":"教师页面",
  25. "msg":"教师主页......",
  26. })
  27. })
  28. g.Run(":8000")
  29. }

image.png
image.png

自定义模板函数

定义一个不转义相应内容的safe模板函数如下:

  1. func main() {
  2. router := gin.Default()
  3. router.SetFuncMap(template.FuncMap{
  4. "safe": func(str string) template.HTML{
  5. return template.HTML(str)
  6. },
  7. })
  8. router.LoadHTMLFiles("./index.tmpl")
  9. router.GET("/index", func(c *gin.Context) {
  10. c.HTML(http.StatusOK, "index.tmpl", "<a href='https://www.baidu.com'>百度</a>")
  11. })
  12. router.Run(":8080")
  13. }

index.tmpl中使用定义好的safe模板函数:

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <title>修改模板引擎的标识符</title>
  5. </head>
  6. <body>
  7. <div>{{ . | safe }}</div>
  8. </body>
  9. </html>

静态文件处理

当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用gin.Static方法即可。

  1. func main() {
  2. r := gin.Default()
  3. r.Static("/static", "./static")
  4. r.LoadHTMLGlob("templates/**/*")
  5. // ...
  6. r.Run(":8080")
  7. }

多级目录

  1. func main() {
  2. r := gin.Default()
  3. r.Static("/static", "./static")
  4. # 二级目录
  5. r.LoadHTMLGlob("templates/**/*")
  6. # 三级目录
  7. r.LoadHTMLGlob("templates/**/**/*")
  8. // ...
  9. r.Run(":8080")
  10. }

渲染的时候需要:

  1. c.HTML(http.StatusOK, "index/index.tmpl", nil)

并且在index.tmpl中还需要:

  1. {{ define "index/index.templ" }}
  2. <!DOCTYPE html>
  3. <html lang="zh-CN">
  4. <head>
  5. <title>修改模板引擎的标识符</title>
  6. </head>
  7. <body>
  8. <div>{{ . | safe }}</div>
  9. </body>
  10. </html>
  11. {{ end }}

使用模板继承

Gin框架默认都是使用单模板,如果需要使用block template功能,可以通过"github.com/gin-contrib/multitemplate"库实现,具体示例如下:
首先,假设我们项目目录下的templates文件夹下有以下模板文件,其中home.tmplindex.tmpl继承了base.tmpl

  1. templates
  2. ├── includes
  3. │ ├── home.tmpl
  4. │ └── index.tmpl
  5. ├── layouts
  6. │ └── base.tmpl
  7. └── scripts.tmpl

然后我们定义一个loadTemplates函数如下:

  1. func loadTemplates(templatesDir string) multitemplate.Renderer {
  2. r := multitemplate.NewRenderer()
  3. layouts, err := filepath.Glob(templatesDir + "/layouts/*.tmpl")
  4. if err != nil {
  5. panic(err.Error())
  6. }
  7. includes, err := filepath.Glob(templatesDir + "/includes/*.tmpl")
  8. if err != nil {
  9. panic(err.Error())
  10. }
  11. // 为layouts/和includes/目录生成 templates map
  12. for _, include := range includes {
  13. layoutCopy := make([]string, len(layouts))
  14. copy(layoutCopy, layouts)
  15. files := append(layoutCopy, include)
  16. r.AddFromFiles(filepath.Base(include), files...)
  17. }
  18. return r
  19. }

我们在main函数中

  1. func indexFunc(c *gin.Context){
  2. c.HTML(http.StatusOK, "index.tmpl", nil)
  3. }
  4. func homeFunc(c *gin.Context){
  5. c.HTML(http.StatusOK, "home.tmpl", nil)
  6. }
  7. func main(){
  8. r := gin.Default()
  9. r.HTMLRender = loadTemplates("./templates")
  10. r.GET("/index", indexFunc)
  11. r.GET("/home", homeFunc)
  12. r.Run()
  13. }

文件路径处理

关于模板文件和静态文件的路径,我们需要根据公司/项目的要求进行设置。可以使用下面的函数获取当前执行程序的路径。

  1. func getCurrentPath() string {
  2. if ex, err := os.Executable(); err == nil {
  3. return filepath.Dir(ex)
  4. }
  5. return "./"
  6. }