Gee教程6.模板(HTML Template)

这一章节的内容是介绍 Web 框架如何支持服务端渲染的场景

  • 实现静态资源服务(Static Resource)。
  • 支持HTML模板渲染。

这一章节很多内容是基于net/http库的,该库已经实现了很多静态文件和HMML模板的相关功能的了。

 静态文件

网页的三剑客,JavaScript、CSS 和 HTML。要做到服务端渲染,第一步便是要支持 JS、CSS 等静态文件。

http.FileServer

为了方便使用像JavaScript、CSS和图像这样的静态资源,net/http内置了http文件服务器http.FileServer。

func main() {
	fs := http.FileServer(http.Dir("./static"))
	http.Handle("/assets/", http.StripPrefix("/assets/", fs))
	http.ListenAndServe("localhost:10000", nil)
}

我们使用了内置的http.FileServer,并将其指向url路径。为了使文件服务器正常工作,它需要知道从哪里提供文件。第二行代码就是告知静态文件是在路径./static。http.FileServer() 方法返回的是 fileHandler 实例,而 fileHandler 结构体实现了 Handler 接口的方法 ServeHTTP()

一旦我们的文件服务器就位,我们只需要将一个url路径指向它,就像我们对动态请求所做的一样。需要注意的一点是:为了正确地提供文件,我们需要去掉url路径的一部分。通常这是我们文件所在目录的名称。这是第三行代码http.StripPrefix的操作。

比如当前静态文件是在./static路径中,该路径有文件gee.js。

而用户访问localhost:10000/assets/gee.js。这时服务器就会把/assets/gee.js变成/gee.js,那就是访问./static/gee.js。这是正确的,而不是去访问./static/assers/gee.js。

静态文件Web服务器

找到文件后,如何返回这一步,net/http库已经实现了。因此,该web 框架要做的,仅仅是解析请求的地址,映射到服务器上文件的真实地址,交给http.FileServer处理就好了。

来看看使用方式

r := gee.New()
r.Static("/assets", "/usr/static")    //"/usr/static"是静态文件的存放路径
// 或相对路径 r.Static("/assets", "./static")
r.Run(":10000")

 r.Static就相当于r.GET。用户访问localhost:10000/assets/js/gee.js,最终会返回/usr/static/js/gee.js

代码实现HTML 模板渲染

// 静态文件服务器
func (group *RouterGroup) Static(relativePath string, root string) {
	handler := group.createStaticHandler(relativePath, http.Dir(root))
	urlPath := path.Join(relativePath, "/*filepath")
	group.GET(urlPath, handler)
}

func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
	absolutePath := path.Join(group.prefix, relativePath)
	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))

	return func(c *Context) {
		file := c.Param("filepath")
		if _, err := fs.Open(file); err != nil {
			c.Status(http.StatusNotFound)
			return
		}
		fileServer.ServeHTTP(c.Wrtier, c.Req)
	}
}

 HTML 模板渲染

 Go语言内置了text/templatehtml/template2个模板标准库,其中html/template为 HTML 提供了较为完整的支持。包括普通变量渲染、列表渲染、对象渲染等。该web框架的模板渲染直接使用了html/template提供的能力。

html/template库

这里需要简单介绍下html/template库的函数使用,该流程主要是

构建模板对象New()-->解析数据Parse()-->应用Execute()

新建一个模板

使用func(*Template) New(name string) *Template新建一个模板,并指定模板的名称。

比如:tpl := template.New("test")

文件模板解析:ParseFiles和ParseGlob

ParseFiles接受一个字符串,字符串的内容是一个模板文件的路径(绝对路径or相对路径)。
ParseGlob也差不多,是用正则的方式匹配多个文件。

假设一个目录里有a.txt b.txt c.txt的话,用ParseFiles需要写3行对应3个文件,如果有一百个文件呢?
而用ParseGlob只要写成template.ParseGlob("*.txt") 即可

模板的输出,ExecuteTemplate和Execute

模板下有多套模板,其中有一套模板是当前模板
可以使用Name的方式查看当前模板

err = tmpl.ExecuteTemplate(os.Stdout, "a.html", sweaters)  //指定模板名,这次为a.html
err = tmpl.Execute(os.Stdout, sweaters)  //模板名省略,打印的是当前模板

 添加模板函数

 模板文件中支持函数操作,我们可以使用func (t *Template) Funcs(funcMap FuncMap) *Template方法给模板添加函数。

函数Must,初始化简便

Must函数用于包装返回(*Template, error)的函数/方法调用。它会自动在有err的时候panic,无错的时候只返回其中的*Template,一般用于变量初始化。这在赋值给变量的时候非常简便。

比如:var t = template.Must(template.New("name").Parse("html"))

模板功能添加入框架

了解了上面的函数使用,之后,就可以在web框架中添加template功能。

type Engine struct {
	*RouterGroup
	router *router
	gorups []*RouterGroup

	htmlTemplates *template.Template
	funcMap       template.FuncMap
}

func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
	engine.funcMap = funcMap
}

func (engine *Engine) LoadHTMLGlob(path string) {
	engine.htmlTemplates = template.Must(template.New("").Funcs(engine.funcMap).ParseGlob(path))
}

首先为 Engine 添加了 *template.Template 和 template.FuncMap对象,前者将所有的模板加载进内存,后者是所有的自定义模板渲染函数。

另外,也给用户分别提供了设置自定义渲染函数funcMap和加载模板LoadHTMLGlob的方法。

注意:从这也看出来,要先使用SetFuncMap方法,才能使用LoadHTMLGlob

接下来,对原来的 (*Context).HTML()方法做了些小修改,使之支持根据模板文件名选择模板进行渲染。

type Context struct {
    // ...
	// engine pointer
	engine *Engine    //新添加的,为了HTMl方法中能访问到engine.htmlTemplates
}

// func (c *Context) HTML(code int, html string) {
func (c *Context) HTML(code int, name string, data any) {
	c.SetHeader("Content-Type", "text/html")
	c.Status(code)
	if err := c.engine.htmlTemplates.ExecuteTemplate(c.Wrtier, name, data); err != nil {
		c.Fail(500, err.Error())
	}

	//以前的做法
	// c.SetHeader("Content-Type", "text/html")
	// c.Status(code)
	// c.Wrtier.Write([]byte(html))
}

在Context.HTML方法中要想能使用到templates,那么就需要能访问到Engine。那我们在 Context 中添加了成员变量 engine *Engine,这样就能够通过 Context 访问 Engine 中的 HTML 模板。实例化 Context 时,还需要给 c.engine 赋值。

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    .............................
	c := newContext(w, req)
	c.midHandlers = middlewares
	c.engine = engine       //给 c.engine 赋值 
	engine.router.handle(c)
}

测试

 该文件目录结构

代码

<!-- templates/custom_func.tmpl -->
<html>
<body>
    <p>hello, {{.title}}</p>
    <p>Date: {{.now | FormatAsDate}}</p>
</body>
</html>
type student struct {
	Name string
	Age  int8
}

func FormatAsDate(t time.Time) string {
	year, month, day := t.Date()
	return fmt.Sprintf("%d-%02d-%02d", year, month, day)
    //return fmt.Sprintf("%d-%02d-%d", year, month, day)
}

func main() {
	r := gee.New()
	r.Use(gee.Logger())
    //设置自定义渲染函数funcMap,custom_func.tmpl文件中的FormatAsDate格式就是FormatAsDate函数返回的格式
	r.SetFuncMap(template.FuncMap{
		"FormatAsDate": FormatAsDate,
	})
	r.LoadHTMLGlob("templates/*")
	r.Static("/assets", "./static")

	stu1 := &student{Name: "Geektutu", Age: 20}
	stu2 := &student{Name: "Jack", Age: 22}
	r.GET("/", func(c *gee.Context) {
		c.HTML(http.StatusOK, "css.tmpl", nil)
	})
	r.GET("/students", func(c *gee.Context) {
		c.HTML(http.StatusOK, "arr.tmpl", gee.H{
			"title":  "gee",
			"stuArr": [2]*student{stu1, stu2},
		})
	})

	r.GET("/date", func(c *gee.Context) {
		c.HTML(http.StatusOK, "custom_func.tmpl", gee.H{
			"title": "gee",
			"now":   time.Date(2023, 12, 5, 0, 0, 0, 0, time.UTC),
		})
	})

	r.Run("localhost:10000")
}

完整代码:https://github.com/liwook/Go-projects/tree/main/gee-web/6-template

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

28、pytest实战:获取多用户鉴权

前提 测试过程中有用户体系&#xff0c;例如包括管理员、商家、用户角色&#xff0c;不同测试用例需要使用不同角色来操作&#xff0c;操作权限根据用户的鉴权来判断实现。 技能点 建立全局变量文件&#xff0c;保存账号相关信息获取鉴权信息变为module级别fixture&#xff…

mac批量修改图片格式

1. 当前窗口在word文档&#xff0c;选择工具-》宏-》点击宏 2. 弹出弹框&#xff0c;起个宏名1&#xff0c;点击2添加一个宏。 输入以下代码&#xff1a; Sub 图片格式统一()图片格式统一 宏Dim iDim Height, WeightHeight 200 改成自己的高度Weight 350 改成自己的宽度On E…

基于Java swing 学生选课成绩管理系统

Java swing 学生选课成绩管理系统 在SQL Server下建库、建表、建约束、建视图、建触发器、建角色、建用户等&#xff0c;并录入必要的数据。 编程实现至少3个模块 登录模块&#xff1a;输入用户名、密码&#xff0c;选择身份&#xff08;通过检索出数据库里现有的用户身份&…

分类预测 | Matlab实现OOA-CNN-SVM鱼鹰算法优化卷积支持向量机分类预测

分类预测 | Matlab实现OOA-CNN-SVM鱼鹰算法优化卷积支持向量机分类预测 目录 分类预测 | Matlab实现OOA-CNN-SVM鱼鹰算法优化卷积支持向量机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现OOA-CNN-SVM鱼鹰算法优化卷积支持向量机分类预测&#xff0…

智能优化算法应用:基于闪电连接过程算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于闪电连接过程算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于闪电连接过程算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.闪电连接过程算法4.实验参数设定5.算…

开始使用高性能、低延迟的对象存储服务 Amazon S3 Express One Zone

全新的对象存储服务 Amazon S3 Express One Zone 旨在提供比 Amazon S3 Standard 高出10倍的性能&#xff0c;同时每秒可处理数十万个请求&#xff0c;并且延迟始终保持在个位数毫秒级&#xff0c;因此非常适合存储最常访问的数据和要求最苛刻的应用程序。将对象存储和复制到单…

【链表Linked List】力扣-24 两两交换链表中的节点

目录 题目描述 解题过程 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;he…

⭐ Unity里 用OpenCv 插件 将图片生成Gcode

现在遇到一个需求&#xff0c;用Unity里用图片生成Gcode 告知硬件让它去画出来 翻阅了一些资料&#xff0c;最后决定用OpenCV去做 下图左侧是生成的Gcode文件 右侧是要画的图片 话不多说直接上代码 using System.IO; using UnityEngine; using OpenCVForUnity.CoreModule; …

第十五届蓝桥杯模拟赛B组(第二期)C++

前言&#xff1a; 第一次做蓝桥模拟赛的博客记录&#xff0c;可能有很多不足的地方&#xff0c;现在将第十五届蓝桥杯模拟赛B组&#xff08;第二期&#xff09;的题目与代码与大家进行分享&#xff0c;我是用C做的&#xff0c;有好几道算法题当时自己做的也是一脸懵&#xff0c…

财报解读:立足海外音视频直播战场,欢聚的BIGO盾牌还需加强?

如今&#xff0c;音视频社交平台出海早已不是新鲜事&#xff0c;随着时间推移&#xff0c;一批“坚定全球化不动摇”的企业也实现突围&#xff0c;站在出海舞台中心。 若提到中国企业出海范本&#xff0c;欢聚集团定是绕不开的存在。作为最早一批出海的中国互联网企业&#xf…

CS144(2023 Spring)Lab 0:networking warmup(环境搭建 webget bytestream)

文章目录 前言其他笔记相关链接 1. Set up GNU/Linux on your computer2. Networking by hand3. Writing a network program using an OS stream socket3.1 Linux配置3.2 C规范3.3 Writing webget3.3.1 实现3.3.2 测试 4. An in-memory reliable byte stream4.1 思路分析4.2 代…

记录 | vscode设置自动换行

右上菜单栏 -> 查看 -> 打开自动换行 或者还有种方式&#xff0c;如下&#xff0c; 左下角小齿轮&#xff0c;点击设置 然后输入 Editor: Word Wrap &#xff0c;把开关打开为 on

扩散模型实战(十四):扩散模型生成音频

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xff…

使用 Go Modules 管理依赖:简明教程

一、GoLang 中包的介绍和定义 包&#xff08;package&#xff09;是多个 Go 源码的集合&#xff0c;是一种高级的代码复用方案Go 语言为我们提供了很多内置包&#xff0c;如 fmt、strconv、strings、sort、errors、times、encoding/json、os、io 等Golang 中的包可以分为三种&…

C# WPF上位机开发(图形显示软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在实际应用中&#xff0c;有一种情况就是&#xff0c;我们需要经常对数据进行图形化显示&#xff0c;这样会比较直观一点。比如经济统计里面的同比…

宝塔部署appache部署ssl证书无法访问443端口

原因&#xff1a; 不是部署方法错误&#xff0c;而是操作不当&#xff0c;原来一开始为了测试我去修改了appache默配置路径下的httpd-ssl.donf&#xff0c;此文件一般 在appche/conf/extra/目录下&#xff08;版本不同目录可能有所区别&#xff09;。 导致问题&#xff1a; 在…

【数据结构和算法】到达首都的最少油耗

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 三、代码 四、复杂度分析 前言 这是力扣的2477题&#xff0c;难度为中等&#xff0c;解题方案有很多种&…

用友NC Cloud FileParserServlet反序列化RCE漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,实现企业的数字化转型和业务流程优化。 0x02 漏洞概述 用友 NC Cloud FileParserServlet接口存在反序列化代码执行漏…

Amazon CodeWhisperer 正式可用, 并面向个人开发者免费开放

文章作者&#xff1a;深度-围观 北京——2023年4月18日&#xff0c;亚马逊云科技宣布&#xff0c;实时 AI 编程助手 Amazon CodeWhisperer 正式可用&#xff0c;同时推出的还有供所有开发人员免费使用的个人版&#xff08;CodeWhisperer Individual&#xff09;。CodeWhisperer…

微服务1 springcloud学习笔记P1-P40

b微服务技术栈_哔哩哔哩_bilibili 文档资料: 链接&#xff1a;https://pan.baidu.com/s/1P_Ag1BYiPaF52EI19A0YRw?pwdd03r 提取码&#xff1a;d03r 一 了解微服务技术 二 Eureka (1) Eureka配置 (2) 注册user-service (3) 总结 Ribbon 负载均衡 (1) 流程 三 nacos配置管理…