golang web学习随便记6-模板引擎

这篇具有很好参考价值的文章主要介绍了golang web学习随便记6-模板引擎。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

模板浅尝

文件型模板

以下代码是几乎最简单的一个模板,{{ . }} 表示执行模板时将嵌入的数据

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Go Web 编程</title>
</head>

<body>
    {{ . }}
</body>

</html>

程序也足够简单,就是解析模板文件得到模板对象,执行模板输出结果

package main

import (
	"html/template"
	"net/http"
)

func process(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	t.Execute(w, "Golang编程就是简单")
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8088",
	}
	http.HandleFunc("/process", process)
	server.ListenAndServe()
}

运行结果为

golang web学习随便记6-模板引擎

字符串模板

模板可以是模板文件,也可以是字符串,在上述代码中添加一个处理器函数

// ...........................
func process2(w http.ResponseWriter, r *http.Request) {
	strtpl := `
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Go Web 编程</title>
</head>

<body>
    {{ . }}
</body>

</html>
`
	t := template.New("strtpl.html")
	t, _ = t.Parse(strtpl)
	t.Execute(w, "字符串模板也简单")
}

// .......................
	http.HandleFunc("/process2", process2)
// .......................

其实,对于文件模板,也是可以先New一个模板实例,然后用实例的ParseFiles方法解析模板文件。直接template.ParseFiles相当于生成了以文件名为模板名的模板实例。ParseFiles方法接受的参数是可变个数的,所以,实际应用中是一堆模板相互嵌套时,会把参数先放在一个数组,然后调用ParseFiles时将数组打散传入。模板中有多个文件时,必须有一个“主模板”,如果执行模板时没有指定“主模板”(调用的是Execute方法),那么第一个将作为“主模板”。指定主模板时(调用的是ExecuteTemplate方法),如果模板是未命名的,那么就用模板文件名作为模板名。模板解析过程中可能产生错误,用 template.Must(...) 包裹模板解析函数的调用过程是一种“偷懒”的错误处理模式,这种模式下,发生错误时将产生panic。

golang web学习随便记1-快速入门_sjg20010414的博客-CSDN博客   中有基本的模板嵌套情况。

条件动作

下面我们来看模板中的动作。先来看条件动作:模板文件tpl.html

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>模板动作</title>
</head>

<body>
    {{ if . }}
    数字大于5!
    {{ else }}
    数字为5或小于5!
    {{ end }}
    <hr>
</body>

</html>
package main

import (
	"html/template"
	"math/rand"
	"net/http"
	"time"
)

func actionif(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	rand.Seed(time.Now().Unix())
	t.Execute(w, rand.Intn(10) > 5)
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8088",
	}
	http.HandleFunc("/actionif", actionif)
	server.ListenAndServe()
}

运行并从浏览器访问,得到的结果可能是2种之一:

golang web学习随便记6-模板引擎golang web学习随便记6-模板引擎

迭代动作

然后来看迭代动作 :需要注意的是,迭代动作range,有可选的(fallback)选项 else,即没有数据时显示点什么。如果没有该选项,要处理无数据提示会麻烦很多。


<body>
    <ul>
        {{ range . }}
        <li>{{ . }}</li>
        {{ else }}
        <li>当前无数据</li>
        {{ end }}
    </ul>
</body>
package main

import (
	"html/template"
	"net/http"
)

func actionrange(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	daysOfWeek := []string{"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"}
	t.Execute(w, daysOfWeek)
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8088",
	}
	http.HandleFunc("/actionrange", actionrange)
	server.ListenAndServe()
}

 显示结果为:

golang web学习随便记6-模板引擎

前面代码中,{{ . }} 的值都是golang代码执行模板时提供的确定值,但模板也提供了设置动作with,可以在指定区域内使用模板内设定的其他值。with也包含else选项,即with设定值为空时应该显示的信息。

<body>
    <div>最难的语言是 {{ . }}</div>
    <div>
        {{ with "C++" }}
        最难的语言是 {{ . }}
        {{ else }}
        最难的语言还是 {{ . }}
        {{ end }}
    </div>
    <div>最难的语言又是 {{ . }} </div>
</body>
package main

import (
	"html/template"
	"net/http"
)

func actionwith(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	t.Execute(w, "Rust")
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8088",
	}
	http.HandleFunc("/actionwith", actionwith)
	server.ListenAndServe()
}

输出结果为:(第二个图是把html模板中的C++去掉,刷新后得到的,不用重启服务器)

golang web学习随便记6-模板引擎golang web学习随便记6-模板引擎

包含动作

golang模板是可以嵌套的,使用包含动作 template 嵌入已命名的模板,可以模块式构建模板。

下面的代码,解析了模板t1.html和t2.html,t1.html中嵌入了t2.html

// .....................

func actionInclude(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("t1.html", "t2.html")
	if err != nil {
		fmt.Println(err)
	}
	t.Execute(w, "Rust")
}

// ..................................................
	http.HandleFunc("/actioninclude", actionInclude)
// ..................................................
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Golang模板</title>
</head>

<body>
    <div>这是 t1.html 上部</div>
    <div>t1.html中 点. 的值为 {{ . }}</div>
    <hr>
    {{ template "t2.html" }}
    <hr>
    <div>这是 t1.html 下部</div>
</body>

</html>
<div style="background-color: yellow;">
    这是 t2.html <br>
    t2.html中 点. 的值为 {{ . }}
</div>

运行后,结果如下

golang web学习随便记6-模板引擎

我们可以发现,执行模板时,值传入到了主模板t1.html中,t2.html没有获得值,即模板嵌套时,传入的值不会自动传入到嵌入模板中。如果我们希望传给t1.html的值也能传给t2.html,需要对传值进行“接力” ,方法是嵌入模板时在模板名称后添加参数,最简单的传. 就会把母模板的参数传给子模板:

    {{ template "t2.html" . }}

按上述代码修改t1.html,不必重启服务器,刷新后显示结果变成了

golang web学习随便记6-模板引擎

参数、变量、管道

模板中的参数,指的是模板中的一个值,它可能是布尔值、整数、字符串等字面量 ,也可能是结构体、结构体中一个字段、数组中一个键。参数还可能是变量、只返回一个值(或同时返回一个错误)的方法或者函数。参数还有一种情形就是一个.,即处理器传递给模板引擎的数据。

在模板的动作中,可以设置变量(用$开头),例如: $v = value,  range  $k, $v := .

模板中的管道可以把参数串联起来,例如: {{ 3.1415926  |  printf  "%.2f" }} 就是浮点参数输出作为函数参数输入实现对结果的格式化。

printf 是Go模板引擎内置的函数,让模板引擎强大的是,不仅可以使用内置的函数,还可以用户自定义函数。实现自定义函数的步骤是:创建名为 FuncMap 的映射,映射的键是模板中用的函数名,映射的值则是 Golang实现中的函数名;将 FuncMap 与模板绑定。需要注意,定义的函数只能返回一个值,或者一个值+一个错误。

下面的例子是一个日期格式化函数应用的例子:

// ................................

func formatDate(t time.Time) string {
	format := "2006年01月02日"
	return t.Format(format)
}

func actionfunc(w http.ResponseWriter, r *http.Request) {
	funcMap := template.FuncMap{ // 定义映射
		"chndate": formatDate,
	}
	t := template.New("tpl.html").Funcs(funcMap) // 绑定映射到模板
	t, _ = t.ParseFiles("tpl.html")
	t.Execute(w, time.Now())
}

// ..............................................
	http.HandleFunc("/actionfunc", actionfunc)
// ..............................................

<body>
    <div>日期是(管道方式) {{ . | chndate }}</div>
    <div>日期是(参数方式) {{ chndate . }}</div>
</body>

使用函数时,我们既可以使用管道方式传递参数(多个函数时可以连续处理),也可以参数方式传递参数(适合单个函数使用)。显示结果是

golang web学习随便记6-模板引擎

上下文感知、转义、防XSS攻击

Golang模板引擎是具有上下文感知特性的,即可以根据内容在文档中所处的位置(不同的“身份”)进行不同的呈现,其中最明显的是对内容进行合适的转义。

<body>
    <div>{{ . }}</div>
    <div><a href="/{{ . }}">路径</a></div>
    <div><a href="/?q={{ . }}">查询</a></div>
    <div><a onclick="fn('{{ . }}')">点击</a></div>
</body>
// .........................
func contextAware(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	content := `我想知道:<i>这段文本会怎样?</i>`
	t.Execute(w, content)
}

// ....................................................
	http.HandleFunc("/context-aware", contextAware)
// ....................................................

用curl命令能准确看出返回结果,浏览器开发工具不能看出HTML转义。显示结果如下(只贴了部分):

sjg@sjg-PC:~$ curl -i 127.0.0.1:8088/context-aware
.................
<body>
    <div>我想知道:&lt;i&gt;这段文本会怎样?&lt;/i&gt;</div>
    <div><a href="/%e6%88%91%e6%83%b3%e7%9f%a5%e9%81%93%ef%bc%9a%3ci%3e%e8%bf%99%e6%ae%b5%e6%96%87%e6%9c%ac%e4%bc%9a%e6%80%8e%e6%a0%b7%ef%bc%9f%3c/i%3e">路径</a></div>
    <div><a href="/?q=%e6%88%91%e6%83%b3%e7%9f%a5%e9%81%93%ef%bc%9a%3ci%3e%e8%bf%99%e6%ae%b5%e6%96%87%e6%9c%ac%e4%bc%9a%e6%80%8e%e6%a0%b7%ef%bc%9f%3c%2fi%3e">查询</a></div>
    <div><a onclick="fn('我想知道:\u003ci\u003e这段文本会怎样?\u003c\/i\u003e')">点击</a></div>
</body>
..................

明显的一点是,html标记<i> ,在 html 内容中 < 和 >  转义成了 &lt; 和 &gt; ,在 href 属性值中(无论是路径中还是查询参数中)这两个符号和中文被 URL编码,在 onclick 事件对应的 JavaScript代码中,两个符号被 Unicode 编码。

下面的代码可以验证golang模板引擎防XSS的效果:(form.html、tpl.html、main.go)

<body>
    <form action="/process" method="post">
        评论:<input name="comment" type="text">
        <hr>
        <button id="submit">提交</button>
    </form>
</body>
<body>
    <div>{{ . }}</div>
</body>
// .................................
func process(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("tpl.html")
	t.Execute(w, r.FormValue("comment")) // 读取表单数据合并到模板
}

func form(w http.ResponseWriter, r *http.Request) {
	t, _ := template.ParseFiles("form.html")
	t.Execute(w, nil) // 显示表单
}

// ........................................
	http.HandleFunc("/process", process)
	http.HandleFunc("/form", form)
// ........................................

运行并用浏览器访问 http://127.0.0.1:8088/form,在表单中输入 <script>alert('啊哈');</script> 并提交,可以发现浏览器“原样”输出了“JS代码”,并不会触发执行。

golang web学习随便记6-模板引擎

 有时候,我们的确想要允许用户输入HTML代码或者JavaScript代码,并在显示时执行,我们可以“命令”Go不要转义:把不想转义的内容作为参数传递给 template.HTML(..) 函数

前面代码修改一句

	t.Execute(w, template.HTML(r.FormValue("comment"))) // 读取表单数据合并到模板

重新运行并重新在表单中输入<script>alert('啊哈');</script> 并提交,可以发现浏览器(我是在Linux Edge 111.0.1661.54 64位上测试的)弹出了模态对话框。

嵌套模板的做法,其实在 golang web学习随便记1-快速入门_sjg20010414的博客-CSDN博客   中已经有例子,这里不再赘述。指的注意的是,在嵌套模板时,通常使用 define  action 定义动作给模板命名,然后用命名的模板名进行引用。而且,用定义动作可以实现在一个文件中定义多个不同名字的模板(define动作有end来结束块),也可以在不同的文件中定义同名的模板(例如,给网站提供不同的布局,根据不同情况可以选择不同布局,而布局模板名可以都叫layout)。命名了模板,就可以在 t.ExecuteTemplate(..) 函数的第二个参数中指定“主模板”。

block块动作

最后来了解一下block action块动作:它的引入是为了解决模板引用中,子模板不存在时,希望有个默认显示的问题。block动作允许用户定义一个模板,并且立即被应用作为缺省时模板。

// ..........................................................
func actionBlock(w http.ResponseWriter, r *http.Request) {
	rand.Seed(time.Now().Unix())
	var t *template.Template
	if rand.Intn(10) > 5 {
		t, _ = template.ParseFiles("layout.html", "red.html")
	} else {
		t, _ = template.ParseFiles("layout.html")
	}
	t.ExecuteTemplate(w, "layout", "最好语言:")
}

// ...................................................
	http.HandleFunc("/actionblock", actionBlock)
// ...................................................

上面的代码中,t 可能解析了 layout.html 和 red.html 两个模板文件,也可能只解析了前者,然后传递的参数为字符串“最好语言:”。两个模板文件分别如下

{{ define "layout" }}
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Golang模板</title>
</head>

<body>
    {{ block "content" . }}
    <h1 style="color: blue;">{{ . }}其实地球人都知道,PHP是最好的语言</h1>
    {{ end }}
</body>

</html>
{{ end }}
{{ define "content" }}
<h1 style="color: red;">{{ . }}Rust是最好的语言</h1>
{{ end }}

在 layout.html 中,用 block 动作引入模板 content,当模板 content 存在时(已经在 t 中被解析),就用解析了的 red.html 的信息,而如果模板 content 不存在,block 内部定义的内容就会充当缺省模板。运行后,连续访问 http://localhost:8088/actionblock, 显示结果会在以下两种结果中随机切换

golang web学习随便记6-模板引擎

golang web学习随便记6-模板引擎文章来源地址https://www.toymoban.com/news/detail-447391.html

到了这里,关于golang web学习随便记6-模板引擎的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Golang个人web框架开发-学习流程

    github地址:ameamezhou/golang-web-frame 后续还将继续学习更新 设置免密登录 ssh-keygen 一路回车就OK 上面有告诉你密钥生成地址 红框为需要上传的公钥 首先明确目标– 我们学习开发web框架的目的是 : 在日常的web开发中,我们经常要使用到web框架, python 就有很多好用的框架,比如

    2024年01月19日
    浏览(38)
  • Golang学习+深入(十一)-文件

    目录 一、概述 1、文件 1.1、打开文件和关闭文件 1.2、读文件 1.3、写文件 1.4、判断文件是否存在 1.5、拷贝文件 文件: 文件是数据源(保存数据的地方) 的一种,比如word文档,txt文件,excel文件...都是文件。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保存

    2023年04月14日
    浏览(59)
  • 【Python】Web学习笔记_flask(7)——Jinja2模板(1)

    Jinja2是基于python的模板引擎,功能类似于PHP的amarty、J2ee的Freemarker和velocity,完全支持Unicode,并具有集成的沙箱执行环境,Jinja2使用的事BSD协议,允许使用者修改和重新发布代码,也允许使用或在BSD代码上开发商业软件发布和销售。 渲染模板: 执行关键代码: 执行结果:  

    2024年02月11日
    浏览(45)
  • 90套Axure原型模板源文件Rp高保真ui产品经理app web 网站案例模板(Axure9制作)

    素材信息名称:90+套Axure原型图设计源文件 格式:RP格式(Axure软件) 产品经理全套文档模板Axure8可以打开8、7版本制作 Axure9可以全部打开9、8、7版本制作 点此下载全部资源 后面还有很多 ——网站 阿里云网站.rp车辆违章处理.rp城市介绍网站.rp城市旅游网站.rp城市网站.rp城市

    2024年02月11日
    浏览(54)
  • web前端之若依项目窗口大小改变或侧边栏伸缩时echarts图表自适应、封装执行文件和模板文件、展开、折叠、ApacheECharts、KeepAlive、RouterView、deactivated

    如需完整代码请WX私聊: MJ682517 没有任何套路,直接发代码 在 vue 项目中,窗口大小不变(排除window的resize监听),侧边菜单栏折叠展开,导致右边内容区域宽度变化, echarts 图表不会自适应。常规解决办法的是使用window.addEventListener(“resize”)来监听窗口变化,但当前窗口大小并

    2024年02月01日
    浏览(47)
  • 【JavaEE基础学习打卡07】JDBC之应用分层设计浅尝!

    📜 本系列教程适用于JavaWeb初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。 🚀 文中白话居多,尽量以小白视角呈现,帮助大家快速入门。 🎅 我是 蜗牛老师 ,之前网名是 Ongoing蜗牛 ,人如其名,干啥都慢,所以

    2024年02月09日
    浏览(38)
  • 提示学习soft prompt浅尝,启发了p-tuing

    在高质量标注数据稀缺的工业界来说,少样本学习或者零样本学习的方法特别受欢迎,后面出现过一些少样本和零样本的方法,例如 对比学习和prompt 等,主流prompt的工作分为 离散型 和连续型模板。离散型主要还是 插入bert特殊的token 为主,连续型则是 插入数字token 。 离散

    2024年02月09日
    浏览(39)
  • Mojo:为Web应用程序提供了完整的框架,包括路由、模板、插件、Websocket、HTTP客户端、HTTP服务器、配置文件管理等功能

            Mojo是一种高级的、动态的Perl Web应用程序框架,它可以用来开发Web应用程序,定位于速度、简单和可扩展性。Mojo的设计理念是简洁、灵活、易用和高效,它为Web应用程序提供了完整的框架,包括路由、模板、插件、Websocket、HTTP客户端、HTTP服务器、配置文件管理等

    2024年02月09日
    浏览(73)
  • 【Golang系统开发】搜索引擎(2) 压缩词典

    这篇文章我们就给出一系列的数据结构,使得词典能达到越来越高的压缩比。当然,和倒排索引记录表的大小相比,词典只占据了非常小的空间。那么为什么要对词典进行压缩呢? 这是因为决定信息检索系统的查询响应时间的一个重要因素就是磁盘的访问次数,而如果有部分

    2024年02月12日
    浏览(29)
  • 【Golang系统开发】搜索引擎(3) 压缩倒排索引表

    假设我们的数据集中有 800000 篇文章,每篇文章有 200 词条,每个词条有6个字符,倒排记录数目是 1 亿。那么如果我们倒排索引表中单单记录文档id,不记录文档内的频率和偏移信息。 那么 文档id 的长度就必须是 l o g 2 800000 = 20 b i t log_2800000=20 bit l o g 2 ​ 800000 = 20 bi t (文档

    2024年02月12日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包