Gin框架官方文档详解03:HTML渲染

news2024/10/21 15:34:49

官方文档:https://gin-gonic.com/zh-cn/docs/
注:强烈建议没用过Gin的读者先阅读第一节:第一个Gin应用。

目录

    • 一、简单渲染
    • 二、使用不同目录下名称相同的模板
    • 三、自定义模板渲染器
    • 四、自定义分隔符
    • 五、自定义模板函数
    • 六、总结

一、简单渲染

以"03HTML渲染"为根目录,创建如下目录结构:

├─demo01
│  │  main.go
│  └─templates
│          index.html
├─demo02
│  │  main.go
│  └─templates
│      ├─posts
│      │      index.html
│      └─users
│              index.html
├─demo03
│      file1.html
│      file2.html
│      main.go
├─demo04
│  │  main.go
│  └─templates
│          index.html
└─demo05
    │  main.go
    └─templates
            raw.html

进入到demo01,填充代码:
main.go

package main

import (
	"net/http" // 导入 HTTP 状态码和服务功能

	"github.com/gin-gonic/gin" // 导入 Gin 框架
)

func main() {
	router := gin.Default() // 创建一个默认的 Gin 路由器,带有默认的中间件(如日志和恢复)

	// 加载所有位于 /templates 目录下的 HTML 文件,支持通配符(如 *.html)
	router.LoadHTMLGlob("templates/*")
	// 使用 LoadHTMLFiles 可以加载指定的多个文件
	// router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")

	// 设置一个 GET 路由,当用户访问 /index 时,返回 HTML 页面
	router.GET("/index", func(c *gin.Context) {
		// 使用 HTML 渲染函数,HTTP 状态码 200 (http.StatusOK),
		// 渲染 "index.html" 文件,并传递数据(键值对形式)供模板使用
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "Main website", // 传递 "title" 变量到模板
		})
	})

	// 运行应用程序,并监听在端口 8080 上
	router.Run(":8080")
}

index.html

<html>
<h1>
    {{ .title }} <!-- 这里是模板占位符,将被渲染时替换为 title 变量的值 -->
</h1>

</html>

LoadHTMLGlob():用于加载模板文件的函数。LoadHTMLGlob("../templates/*") 表示加载 …/templates 目录下的所有 HTML 文件。它支持通配符,常用于一次性加载多个模板。
LoadHTMLFiles():和 LoadHTMLGlob() 类似,但它不使用通配符,而是明确列出要加载的模板文件。可以根据需要使用该函数加载特定的模板文件。
c.HTML(http.StatusOK, "index.html", gin.H{"title": "Main website"}):渲染 index.html 模板,并将 title 变量传递给模板,值为 “Main website”。在模板文件中,{{ .title }} 会被渲染为传递进来的 title 值。
注意:Gin 的模板引擎支持多种文件扩展名,常见的 .html 文件扩展名并不是必须的,比如你可以将模板文件命名为 .tmpl,模板引擎同样能够识别和渲染这些文件。但个人建议仍使用.html,因为IDE都能对.html提供代码高亮和补全。
效果
在这里插入图片描述

二、使用不同目录下名称相同的模板

进入到demo02,填充代码:
main.go

package main

import (
	"net/http" // 导入 HTTP 状态码和服务功能

	"github.com/gin-gonic/gin" // 导入 Gin 框架
)

func main() {
	router := gin.Default() // 创建一个默认的 Gin 路由器,带有默认中间件(如日志和恢复)

	// 加载 templates 目录下所有子目录的所有模板文件
	router.LoadHTMLGlob("templates/**/*")

	// 定义一个 GET 路由,处理 /posts/index
	router.GET("/posts/index", func(c *gin.Context) {
		// 渲染 posts/index.html 模板,并传递数据
		c.HTML(http.StatusOK, "posts/index.html", gin.H{
			"title": "Posts", // 传递标题
		})
	})

	// 定义另一个 GET 路由,处理 /users/index
	router.GET("/users/index", func(c *gin.Context) {
		// 渲染 users/index.html 模板,并传递数据
		c.HTML(http.StatusOK, "users/index.html", gin.H{
			"title": "Users", // 传递标题
		})
	})

	// 启动 HTTP 服务器,监听 8080 端口
	router.Run(":8080")
}

posts/index.html

{{ define "posts/index.html" }} <!-- 定义一个名为 "posts/index.html" 的模板块 -->
<html>
<h1>
    {{ .title }} <!-- 这里会被传递进来的标题替换 -->
</h1>
<p>Using posts/index.html</p> <!-- 说明当前使用的是哪个模板 -->

</html>
{{ end }} <!-- 结束模板块定义 -->

users/index.html

{{ define "users/index.html" }} <!-- 定义一个名为 "users/index.html" 的模板块 -->
<html>
<h1>
    {{ .title }} <!-- 这里会被传递进来的标题替换 -->
</h1>
<p>Using users/index.html</p> <!-- 说明当前使用的是哪个模板 -->

</html>
{{ end }} <!-- 结束模板块定义 -->

模板定义:每个模板都使用 {{ define "模板名称" }}{{ end }} 包裹,定义了一个可重用的模板块。在渲染时,通过指定模板的完整名称来选择要渲染的具体模板。
使得在不同目录中存在同名模板时(比如这里都有index.html),可以准确指定使用哪个模板。当然,使用LoadHTMLFiles()可以不用定义模板块,也能达到相同的效果,就是要指定具体文件路径而已。相对来说,LoadHTMLGlob()使用更方便,不管templates下有多少个模板,调用语句都是一样的。
效果
在这里插入图片描述

三、自定义模板渲染器

进入到demo03,填充代码:
main.go

package main

import (
	"html/template" // 导入 HTML 模板包
	"net/http"

	"github.com/gin-gonic/gin" // 导入 Gin 框架
)

func main() {
	router := gin.Default()

	// 加载 file1.html 和 file2.html 模板文件
	html := template.Must(template.ParseFiles("file1.html", "file2.html"))
	// 设置自定义的 HTML 模板渲染器
	router.SetHTMLTemplate(html)

	// 定义一个路由,当用户访问 /file1 时,返回 file1.html 页面
	router.GET("/file1", func(c *gin.Context) {
		c.HTML(http.StatusOK, "file1.html", gin.H{
			"title": "Hello, World", // 传递 "title" 变量到模板
		})
	})

	// 定义另一个路由,当用户访问 /file2 时,返回 file2.html 页面
	router.GET("/file2", func(c *gin.Context) {
		c.HTML(http.StatusOK, "file2.html", gin.H{
			"title": "Hello, World", // 传递 "title" 变量到模板
		})
	})

	// 启动 Gin 服务器,监听在 8080 端口
	router.Run(":8080")
}

file1.html

<!DOCTYPE html>
<html>

<head>
    <title>{{ .title }} - File 1</title>
</head>

<body>
    <h1>{{ .title }} from File 1</h1>
    <p>This content is rendered from file1.html.</p>
</body>

</html>

file2.html

<!DOCTYPE html>
<html>

<head>
    <title>{{ .title }} - File 2</title>
</head>

<body>
    <h1>{{ .title }} from File 2</h1>
    <p>This content is rendered from file2.html.</p>
</body>

</html>

效果
在这里插入图片描述

到目前为止,我们已经学了三种模板加载方法:
1.定义模板名,用LoadHTMLGlob()
2.不定义模板名,用LoadHTMLFiles()
3.不用模板目录,用template.Must()
在真实开发中,团队和项目的性质通常会影响选择的方式。常见的倾向包括:
中大型项目:往往会选择 1,因为它能保持项目结构的整洁,并且方便管理多个模板。
小型项目:可能会倾向于 2,因为它提供了更大的灵活性和可控性。
原型开发或快速迭代:通常会选择 3,以便于快速验证和调整。

四、自定义分隔符

进入到demo04,填充代码:
main.go

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	// 设置自定义的分隔符
	r.Delims("{[{", "}]}")

	// 加载指定路径下的 HTML 模板
	r.LoadHTMLGlob("templates/*")

	// 定义一个路由,当用户访问 /index 时,返回 index.html 页面
	r.GET("/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", gin.H{
			"title": "Custom Delimiter Example", // 传递 "title" 变量到模板
		})
	})

	// 启动 Gin 服务器,监听在 8080 端口
	r.Run(":8080")
}

index.html

<!DOCTYPE html>
<html>

<head>
    <title>{[{ .title }]}</title>
</head>

<body>
    <h1>{[{ .title }]}</h1>
    <p>Welcome to the page with custom delimiters!</p>
</body>

</html>

效果
在这里插入图片描述

五、自定义模板函数

进入到demo05,填充代码:
main.go

package main

import (
	"fmt"
	"html/template"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

// 自定义函数:将时间格式化为指定格式
func formatAsDate(t time.Time) string {
	year, month, day := t.Date()
	return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}

func main() {
	router := gin.Default()
	router.Delims("{[{", "}]}") // 设置自定义分隔符

	// 注册自定义函数
	router.SetFuncMap(template.FuncMap{
		"formatAsDate": formatAsDate, // 将 formatAsDate 函数注册为模板函数
	})

	// 加载 HTML 模板文件
	router.LoadHTMLFiles("templates/raw.html")

	// 定义路由,当用户访问 /raw 时,返回 raw.html 模板
	router.GET("/raw", func(c *gin.Context) {
		c.HTML(http.StatusOK, "raw.html", map[string]interface{}{
			"now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), // 传递当前时间到模板
		})
	})

	// 启动 Gin 服务器,监听在 8080 端口
	router.Run(":8080")
}

raw.html

Date: {[{.now | formatAsDate}]}

注意
1.FuncMap()中的key和value可以不同。
2.html中调用的函数名是FuncMap()中的key,不是value!也就是说,value的值可以随便取,不影响html调用。
3.SetFuncMap必须在 LoadHTMLFiles之前调用!
效果
在这里插入图片描述

六、总结

在使用 Gin 框架进行 HTML 渲染时,可以通过 LoadHTMLGlob() 或 LoadHTMLFiles() 方法加载模板文件。LoadHTMLGlob() 支持使用通配符,适合批量加载多个模板,而 LoadHTMLFiles() 允许精确加载特定的模板文件。通过在模板中定义结构,可以避免不同目录中同名模板的冲突,确保在渲染时通过完整名称来选择正确的模板。自定义模板渲染器和函数映射(使用 SetFuncMap)可以扩展模板功能,如格式化日期。使用自定义分隔符可改变模板中变量的标识符。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2213849.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数通--5

一、链路聚合 背景&#xff1a;带宽不够&#xff0c;加线&#xff0c;但是stp判断是环路&#xff0c;阻塞&#xff0c;等于没加线。通过链路聚合解决&#xff08;如果我把千兆换成万兆&#xff0c;老子有钱任性的话&#xff0c;没得说&#xff09; 现在我要的不是备份而是带宽…

电能表预付费系统-标准传输规范(STS)(4)

5.4 TokenCarrier 到 MeterApplicationProcess 的数据流 The flow of data from the TokenCarrier to the MeterApplicationProcess is shown in Figure 4.此数据流见图 4。 图 4 TokenCarrier 到 MeterApplicationProcess 的数据 The token entry process from the TokenCarr…

抢单超卖? 并发问题解决思路

1. 问题介绍 在用户抢单或者商品售卖的过程中&#xff0c;正常情况下是一人一件&#xff0c;但是当网络流量剧增时多个用户同时抢到一个商品应该如何分配&#xff1f;假设这样一个场景A商品库存是100个&#xff0c;但是秒杀的过程中&#xff0c;一共卖出去500个A商品。对于卖家…

AXI GPIO按键控制——ZYNQ学习笔记4

一、AXI GPIO接口简介 是什么&#xff1f;是PL部分的一个IP软核&#xff0c;实现通用输入输出接口的功能&#xff0c;并通过AXI协议实现与处理系统通信&#xff0c;方便控制与拓展GPIO接口。 AXI GPIO IP 核为 AXI 接口提供了一个通用的输入/输出接口。 与 PS 端的 GPIO 不同&…

【YOLO系列】YOLO11原理和深入解析——待完善

文章目录 前言一、主要新增特性二、主要改进2.1 C3K2网络结构2.2 C2PSA网络结构2.3 Head部分 三、对比与性能优势四、X-AnyLabeling4.1 目标检测&#xff1a;4.2 实例分割&#xff1a;4.3 图像分类&#xff1a;4.4 姿态估计&#xff1a;4.5 旋转目标检测&#xff1a; 五、总结 …

Vue+Vant实现7天日历展示,并在切换日期时实时变换

效果图&#xff1a; 主要使用 moment.js 插件完成 HTML部分 <div class"day-content"><div class"day-content-t"><div>{{ monthVal }}</div><div click"onCalendar()">更多>></div></div><…

HTTP vs WebSocket

本文将对比介绍HTTP 和 WebSocket &#xff01; 相关文章&#xff1a; 1.HTTP 详解 2.WebSocket 详解 一、HTTP&#xff1a;请求/响应的主流协议 HTTP&#xff08;超文本传输协议&#xff09;是用于发送和接收网页数据的标准协议。它最早于1991年由Tim Berners-Lee提出来&…

【C++】二叉搜索树的概念与实现

目录 二叉搜索树 概念 key类型 概念 代码实现 key_value类型 概念 代码实现 二叉搜索树 概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树: 左子树的值默认小于根节点&#xff0c;右子树的值默认大于根节点 。 ⼆…

具备技术三:通用类型any实现

一、背景 一个连接必须拥有请求接收与解析的上下文。 上下文的结构不能固定&#xff0c;因为服务器支持的协议很多&#xff0c;不同协议有不同的上下文结构&#xff0c;所以必须拥有一个容器保存不同的类型结构数据。 二、设计思路 目标&#xff1a;一个容器保存各种不同数…

opencv学习:CascadeClassifier和detectMultiScale算法进行人脸识别

CascadeClassifier CascadeClassifier 是 OpenCV 提供的一个用于对象检测的类&#xff0c;它基于Haar特征和AdaBoost算法。它能够识别图像中的特定对象&#xff0c;比如人脸、眼睛、微笑等。CascadeClassifier 需要一个预训练的XML分类器文件&#xff0c;该文件包含了用于检测…

SHA1算法学习

SHA-1&#xff08;安全哈希算法1&#xff09;是一种加密哈希函数&#xff0c;它接受一个输入并生成一个160位&#xff08;20字节&#xff09;的哈希值&#xff0c;通常表示为一个40位的十六进制数。 SHA1的特点 输入与输出&#xff1a;SHA-1可以接受几乎任意大小的输入&#…

21世纪20年代最伟大的情侣:泰勒斯威夫特和特拉维斯凯尔西每张照片都在秀恩爱

在时代的长河中&#xff0c;每一代都毫无例外地拥有属于自己的 it couple&#xff08;当红情侣&#xff09;&#xff0c;他们成为了那个特定时期大众瞩目的焦点和津津乐道的话题。 千禧年间&#xff0c;确实涌现出了诸多令人瞩目的情侣组合。就像汤姆克鲁斯和凯蒂霍尔姆斯&…

【H2O2|全栈】更多关于HTML(2)HTML5新增内容

目录 HTML5新特性 前言 准备工作 语义化标签 概念 新内容 案例 多媒体标签 音频标签audio 视频标签 video 新增部分input表单属性 预告和回顾 后话 HTML5新特性 前言 本系列博客是对入门专栏的HTML知识的补充&#xff0c;并伴随一些补充案例。 这一期主要介绍H…

从源码上剖析AQS的方方面面(超详细版)

AQS在 ReentrantLock 的使用方式&#xff08;非公平锁&#xff09; 我们之前学习过 ReentrantLock 非公平锁与公平锁的区别在于&#xff0c;非公平锁不会强行按照任务等待队列去等待任务&#xff0c;而是在获取锁的时候先去尝试使用 CAS 改变一下 State&#xff0c;如果改变成…

架构设计笔记-18-安全架构设计理论与实践

知识要点 常见的安全威胁&#xff1a; 信息泄露&#xff1a;信息被泄露或透露给某个非授权的实体。破坏信息的完整性&#xff1a;数据被非授权地进行增删、修改或破坏而受到损失。拒绝服务&#xff1a;对信息或其他资源的合法访问被无条件地阻止。攻击者向服务器发送大量垃圾…

多选框的单选操作 Element ui

文章目录 样式预览Q&#xff1a;为什么要这么做&#xff1f;实现原理探索路程 样式预览 Q&#xff1a;为什么要这么做&#xff1f; 单选框的样式不够好看单选框因为框架等原因&#xff0c;无法取消选择 实现原理 判断多选框绑定的 value&#xff0c;如果长度为2&#xff0c;那…

实缴新玩法:公司注册资金与知识产权的完美结合

在当今商业环境中&#xff0c;公司注册资金的实缴方式不断创新和发展。其中&#xff0c;将公司注册资金与知识产权相结合&#xff0c;成为了一种引人注目的新玩法。 以往&#xff0c;公司注册资金的实缴往往依赖于货币资金的注入。然而&#xff0c;随着知识经济的崛起&#xf…

中文学术期刊(普刊)-全学科

文章目录 一、征稿简介二、重要信息三、服务简述四、投稿须知五、联系咨询 一、征稿简介 二、重要信息 期刊官网&#xff1a;https://ais.cn/u/3eEJNv 三、服务简述 中国知网是最负盛名的中文数据图书馆&#xff0c;收录来自自然科学、社会科学的优质学术期刊&#xff1b;维…

Redis哨兵TILT模式问题解决方案

Redis sentinel的TILT影响范围 Redis版本影响范围&#xff1a;5、6、7版本 部署方式为k8s部署&#xff0c;都会受到影响&#xff0c;裸金属部署没有问题 当redis哨兵集群进入TILT模式后&#xff0c;业务无法正常连接到redis集群&#xff0c;无法正常使用redis集群。 TILT 模式&…

你用过最好用的AI工具有哪些?探寻用户心中的最爱与最佳

随着人工智能技术的飞速发展&#xff0c;AI 工具如雨后春笋般涌现&#xff0c;广泛应用于各个领域。在 10 月 8 日至 10 月 27 日这段时间里&#xff0c;我们深入探讨了人们在使用 AI 工具时的偏好和体验&#xff0c;旨在揭示那些最受用户喜爱以及被认为最好用的 AI 工具&#…