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 {*RouterGrouprouter *routergorups []*RouterGrouphtmlTemplates *template.TemplatefuncMap       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 pointerengine *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 = middlewaresc.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 stringAge  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

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

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

相关文章

看懂lscpu的输出

文章目录 1. lscpu1.1 Architecture1.2 逻辑核心数1.3 缓存1.4 CPU型号1.5 NUMA架构1.5.1 CPU多核架构1.5.2 多CPU Socket架构 2. cat /proc/cpuinfo2.1 关键字段 1. lscpu 通过lscpu查看当前系统的CPU信息。 [hadoopserver3 ~]$ lscpuArchitecture: x86_64 …

「词令」2023年12月6日蚂蚁庄园今日问题答案是什么?支付宝蚂蚁庄园今日答案12.6

问题&#xff1a;千页豆腐的主要原料是豆腐吗&#xff1f; 选项&#xff1a;A、不是哦 B、当然是 答案&#xff1a;不是哦 解析&#xff1a;千页豆腐是素食新产品&#xff0c;以大豆分离蛋白和水为主要原料&#xff0c;食用植物油、淀粉等为辅料;添加或不添加稳定剂和凝固剂…

java--接口的其他细节

1.jdk8开始&#xff0c;接口新增了三种形式的方法 ①默认方法(实例方法)&#xff1a;使用用default修饰&#xff0c;默认会被加上public修饰。注意&#xff1a;只能使用接口的实现类对象调用 ②私有方法&#xff1a;必须用private修饰(jdk9开始才支持) ③类方法(静态方法)&a…

234 回文链表

解题思路&#xff1a; \qquad 由于链表的结构特点&#xff0c;访问链表中的元素的时间复杂度为O(n)。相比较而言&#xff0c;使用数组会方便很多&#xff0c;实现O(1)访问。 \qquad 所以这个题&#xff0c;可以先遍历一遍把数值存到数组中&#xff0c;再使用双指针判断是否是…

openlayers地图使用---跟随地图比例尺动态标绘大小的一种方式

openlayers地图使用—跟随地图比例尺动态标绘大小的一种方式 预期&#xff1a;随着地图比例尺放大缩小&#xff0c;地图上的标绘随着变化尺寸 结果图 页面元素 <script src"https://cdn.bootcdn.net/ajax/libs/openlayers/8.1.0/dist/ol.min.js"></script…

7_企业架构MySQL读写分离

企业架构MySQL读写分离 学习目标和内容 1、能够理解读写分离的目的 2、能够描述读写分离的常见实现方式 3、能够通过项目框架配置文件实现读写分离 4、能够通过中间件实现读写分离 一、背景描述及其方案设计 1、业务背景描述 时间&#xff1a;2014.6.-2015.9 发布产品类型&…

AntDesignBlazor示例——创建项目

本示例是AntDesign Blazor的入门示例&#xff0c;在学习的同时分享出来&#xff0c;以供新手参考。 示例代码仓库&#xff1a;https://gitee.com/known/AntDesignDemo 1. 开发环境 VS2022 17.8.2.NET8AntDesign 0.16.2 2. 学习目标 创建新项目安装AntDesign组件包及使用方…

不知道如何制作电商产品说明书?推荐一个很好的方法!

作为一名电商从业者&#xff0c;你可能会经常面临一个问题&#xff1a;如何制作一份详细且吸引人的产品说明书&#xff1f;这的确是一个棘手的问题&#xff0c;因为产品说明书不仅要准确地描述产品的特点和功能&#xff0c;还要能够吸引潜在客户的注意。 一、电商网站制作产品说…

基于轻量级模型GHoshNet开发构建眼球眼疾识别分析系统,构建全方位多层次参数对比分析实验

工作中经常会使用到轻量级的网络模型来进行开发&#xff0c;所以平时也会常常留意使用和记录&#xff0c;在前面的博文中有过很多相关的实践工作&#xff0c;感兴趣的话可以自行移步阅读即可。 《移动端轻量级模型开发谁更胜一筹&#xff0c;efficientnet、mobilenetv2、mobil…

06、pytest将多个测试放在一个类中

官方用例 # content of test_class.py # 实例1 class TestClass:def test_one(self):x "this"assert "h" in xdef test_two(self):x "hello"assert hasattr(x,"check")# content of test_class_demo.py # 每个测试都有唯一的类实例…

CopyOnWriteArrayList怎么用

什么是CopyOnWriteArrayListCopyOnWriteArrayList常用方法CopyOnWriteArrayList源码详解CopyOnWriteArrayList使用注意点CopyOnWriteArrayList存在的性能问题CopyOnWriteArrayList 使用实例基本应用实例并发应用实例 拓展写时复制 什么是CopyOnWriteArrayList CopyOnWriteArra…

企业网络安全守护者:EventLog Analyzer日志审计系统

在当今数字时代&#xff0c;企业网络不仅仅是业务运营的核心&#xff0c;也成为各种潜在威胁的目标。为了保障企业的网络安全&#xff0c;日志审计系统成为了不可或缺的一环。其中&#xff0c;ManageEngine的EventLog Analyzer作为一款强大而全面的日志管理与审计解决方案&…

【第三方】微信登录

目录 前言小程序登录步骤说明前端效果涉及到的接口登录凭证&#xff1a;wx.login获取用户信息&#xff1a;wx.getUserInfo 后端涉及到接口小程序登录 代码展示 微信扫码登录 前言 微信官方文档&#xff0c;需要对接哪个模块就从哪里进入。 由于本次我们需要的是小程序的登录。…

有趣的代码——有故事背景的程序设计3

这篇文章再和大家分享一些有“背景”的程序设计&#xff0c;希望能够让大家学到知识的同时&#xff0c;对编程学习更感兴趣&#xff0c;更能在这条路上坚定地走下去。 目录 1.幻方问题 2.用函数打印九九乘法表 3.鸡兔同笼问题 4.字数统计 5.简单选择排序 1.幻方问题 幻方又…

【无标题】什么是UL9540测试,UL9540:2023版本增加哪些测试项目

什么是UL9540测试&#xff0c;UL9540:2023版本增加哪些测试项目 UL 9540是美国安全实验室&#xff08;Underwriters Laboratories&#xff09;发布的标准&#xff0c;名称为"UL 9540: Energy Storage Systems and Equipment"&#xff0c;翻译为中文为"能量存储…

【JavaWeb】前端工程化(VUE3)

前端工程化&#xff08;VUE3&#xff09; 文章目录 前端工程化&#xff08;VUE3&#xff09;一、概述二、ECMA6Script2.1 es6的变量和模板字符串2.2 es6的解构表达式2.3 es6的箭头函数2.4 rest和spread2.5 es6的对象创建和拷贝2.6 es6的模块化处理 三、前端工程化环境搭建3.1 N…

数据分析师的学习之路-pandas篇(7)

继续接上篇&#xff0c;这次学习下透视表、线性回归还有根据条件上颜色。 3.9 透视表 在excel里也经常用到透视表来构建想要的列的组合来形成一个新的表&#xff0c;在pandas里也能做。 举例数据是这样的&#xff1a; 是各种类产品的订单数据&#xff0c;现在想做一个透视表&…

electron 应用图标修改

修改窗口图标 更换Electron应用程序的桌面图标 准备好你想要作为图标的图片文件&#xff0c;可以是PNG格式安装一个可以转换图片格式为ICO的工具&#xff0c;例如在线转换工具“在线转换icon图标工具”。将你的PNG图片文件上传并转换为ICO格式将转换得到的ICO文件放到你的El…

synxflow 安装环境

介绍&#xff1a; 该软件可以动态模拟洪水淹没&#xff0c;滑坡跳动和泥石流使用多个cuda支持的gpu。它还提供了一个用户友好但多功能的Python界面&#xff0c;可以完全集成到数据科学工作流程中&#xff0c;旨在简化和加速危害风险评估任务。 这个包我从网上找到的资源特别特…

GAN:WGAN-DIV

论文&#xff1a;https://arxiv.org/pdf/1712.01026.pdf 代码&#xff1a; 发表&#xff1a;2018 摘要 在计算机视觉的许多领域中&#xff0c;生成对抗性网络已经取得了巨大的成功&#xff0c;其中WGANs系列被认为是最先进的&#xff0c;主要是由于其理论贡献和竞争的定性表…