官方文档地址(中文):https://gin-gonic.com/zh-cn/docs/
注:本教程采用工作区机制,所以一个项目下载了Gin框架,其余项目就无需重复下载,想了解的读者可阅读第一节:Gin操作指南:开山篇。
本节演示HTML渲染,包括简单渲染,使用不同目录下名称相同的模板,自定义模板渲染器,自定义模板函数,注意多模板渲染官方没有直接介绍,只是给出了参考链接,自定义分隔符比较简单,有兴趣的读者可自行学习这些。在开始之前,我们需要在”01数据渲染“目录下打开命令行,执行如下命令来创建子目录:
mkdir HTML渲染
cd到该目录,创建4个目录:
mkdir demo01 demo02 demo03 demo04
目录
- 一、简单渲染
- 二、使用不同目录下名称相同的模板
- 三、自定义模板渲染器
- 四、自定义模板函数
一、简单渲染
cd到demo01,创建如下目录结构:
│ main.go
└─templates
index.html
main.go:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 创建默认的 Gin 路由器
router := gin.Default()
// 使用 LoadHTMLGlob 加载 templates 目录下的所有 HTML 模板文件
// 这里使用通配符 "*" 匹配所有文件
router.LoadHTMLGlob("templates/*")
// 另一种方式是使用 LoadHTMLFiles 加载具体的模板文件
// 它可以单独列出需要加载的模板文件
// router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
// 定义一个 GET 路由,当用户访问 /index 时触发此处理函数
router.GET("/index", func(c *gin.Context) {
// 使用 c.HTML() 方法渲染 HTML 页面
// 第一个参数 http.StatusOK 表示 HTTP 状态码 200,表示请求成功
// 第二个参数是要渲染的模板文件名 "index.html"
// 第三个参数是传递给模板的数据,通过 gin.H 创建键值对
c.HTML(http.StatusOK, "index.html", gin.H{
"title": "Main website", // 这里将传递一个名为 "title" 的数据,其值为 "Main website"
})
})
// 启动 Gin 服务器,监听在 0.0.0.0:8080
// 这会让服务器在本地 8080 端口上等待并响应请求
router.Run(":8080")
}
注意:官方文档用的是.tmpl,但**.html和.tmpl的效果是一样的**,而且IDE对html提供代码高亮和补全,所以推荐用.html。
index.html:
<html>
<h1>
{{ .title }} <!-- 这里是 Go 模板语法,表示将模板中传递的 "title" 数据渲染到此处 -->
</h1>
</html>
效果:
二、使用不同目录下名称相同的模板
cd到demo02,创建如下目录结构:
│ main.go
└─templates
├─posts
│ index.html
└─users
index.html
main.go:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// 创建默认的 Gin 路由器
router := gin.Default()
// 使用 LoadHTMLGlob 加载 templates 目录下的所有 HTML 模板文件
// 使用 "**/*" 通配符表示递归加载所有子目录下的模板文件
router.LoadHTMLGlob("templates/**/*")
// 定义一个 GET 路由,当用户访问 /posts/index 时触发此处理函数
router.GET("/posts/index", func(c *gin.Context) {
// 使用 c.HTML() 方法渲染 "posts/index.html" 模板
// 第一个参数 http.StatusOK 表示 HTTP 状态码 200,表示请求成功
// 第二个参数是要渲染的模板文件名 "posts/index.html"
// 第三个参数是传递给模板的数据,通过 gin.H 创建键值对
c.HTML(http.StatusOK, "posts/index.html", gin.H{
"title": "Posts", // 这里将传递一个名为 "title" 的数据,其值为 "Posts"
})
})
// 定义另一个 GET 路由,当用户访问 /users/index 时触发此处理函数
router.GET("/users/index", func(c *gin.Context) {
// 使用 c.HTML() 方法渲染 "users/index.html" 模板
// 第一个参数 http.StatusOK 表示 HTTP 状态码 200,表示请求成功
// 第二个参数是要渲染的模板文件名 "users/index.html"
// 第三个参数是传递给模板的数据,通过 gin.H 创建键值对
c.HTML(http.StatusOK, "users/index.html", gin.H{
"title": "Users", // 这里将传递一个名为 "title" 的数据,其值为 "Users"
})
})
// 启动 Gin 服务器,监听在 0.0.0.0:8080
// 这会让服务器在本地 8080 端口上等待并响应请求
router.Run(":8080")
}
posts/index.html
{{ define "posts/index.html" }} <!-- 定义一个名为 "posts/index.html" 的模板 -->
<html>
<h1>
{{ .title }} <!-- 这里是 Go 模板语法,表示将模板中传递的 "title" 数据渲染到此处 -->
</h1>
<p>Using posts/index.html</p> <!-- 显示此页面的来源 -->
</html>
{{ end }} <!-- 结束模板定义 -->
users/index.html
{{ define "users/index.html" }} <!-- 定义一个名为 "users/index.html" 的模板 -->
<html>
<h1>
{{ .title }} <!-- 这里是 Go 模板语法,表示将模板中传递的 "title" 数据渲染到此处 -->
</h1>
<p>Using users/index.html</p> <!-- 显示此页面的来源 -->
</html>
{{ end }} <!-- 结束模板定义 -->
效果只展示一个,另一个同理:
三、自定义模板渲染器
注意这里官方示例是不全的,请读者按本文的步骤实验。
cd到demo03,创建main.go,file1.html,file2.html,填充代码:
main.go
package main
import (
"html/template" // 导入 Go 的 html/template 包,用于处理 HTML 模板
"net/http"
"github.com/gin-gonic/gin" // 导入 Gin 框架
)
func main() {
// 创建默认的 Gin 路由器
router := gin.Default()
// 使用 template.Must() 方法来解析指定的 HTML 模板文件
html := template.Must(template.ParseFiles("file1.html", "file2.html"))
// 设置 HTML 模板
router.SetHTMLTemplate(html)
// 定义路由以访问 file1.html
router.GET("/file1", func(c *gin.Context) {
c.HTML(http.StatusOK, "file1.html", nil)
})
// 定义路由以访问 file2.html
router.GET("/file2", func(c *gin.Context) {
c.HTML(http.StatusOK, "file2.html", nil)
})
// 启动 Gin 服务器,监听在 0.0.0.0:8080
router.Run(":8080")
}
file1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File 1</title>
</head>
<body>
<h1>This is file 1</h1>
<p>Welcome to the first HTML file.</p>
</body>
</html>
file2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File 2</title>
</head>
<body>
<h1>This is file 2</h1>
<p>Welcome to the second HTML file.</p>
</body>
</html>
效果,另一个同理:
四、自定义模板函数
cd到demo04,创建main.go,raw.html,填充代码:
package main
import (
"fmt"
"html/template" // 引入 html/template 包用于模板渲染
"net/http" // 引入 net/http 包用于 HTTP 相关功能
"time" // 引入 time 包用于处理时间
"github.com/gin-gonic/gin" // 引入 Gin 框架
)
// formatAsDate 是一个自定义函数,接受一个 time.Time 类型的参数
// 返回格式化为 "年/月/日" 的字符串形式
func formatAsDate(t time.Time) string {
// 获取年份、月份和日期
year, month, day := t.Date()
// 使用 fmt.Sprintf 格式化字符串,返回格式为 "YYYY/MM/DD"
return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}
func main() {
// 创建一个默认的 Gin 路由实例
router := gin.Default()
// 自定义模板的分隔符,改变默认的 {{ 和 }} 分隔符
// 将其设置为 {[{ 和 }]},以避免与 JavaScript 的冲突
router.Delims("{[{", "}]}")
// 设置模板函数映射,允许在模板中使用自定义函数
// 将 formatAsDate 函数添加到模板函数映射中
router.SetFuncMap(template.FuncMap{
"formatAsDate": formatAsDate, // 注册格式化函数
})
// 加载指定路径下的 HTML 模板文件
// 在此示例中,加载的模板文件是 "raw.tmpl"
router.LoadHTMLFiles("raw.html")
// 定义处理 GET 请求的路由,访问 /raw 时触发该处理函数
router.GET("/raw", func(c *gin.Context) {
// 渲染 HTML 模板,并传递当前时间作为数据
// map[string]interface{} 用于传递数据给模板
c.HTML(http.StatusOK, "raw.html", map[string]interface{}{
// 设置 "now" 字段为特定的时间(2017年7月1日)
"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
})
})
// 启动 HTTP 服务器,监听在 8080 端口
// 该服务器将在接收到请求时调用上面定义的路由
router.Run(":8080")
}
raw.html
Date: {[{.now | formatAsDate}]}
效果: