html/template包实现了数据驱动的模板,用于生成可对抗代码注入的安全HTML输出。它提供了和text/template包相同的接口,Go语言中输出HTML的场景都应使用text/template包。

模板

在基于MVC的Web架构中,我们通常需要在后端渲染一些数据到HTML文件中,从而实现动态的网页效果。

模板示例

通过将模板应用于一个数据结构(即该数据结构作为模板的参数)来执行,来获得输出。模板中的注释引用数据接口的元素(一般如结构体的字段或者字典的键)来控制执行过程和获取需要呈现的值。模板执行时会遍历结构并将指针表示为’.‘(称之为”dot”)指向运行过程中数据结构的当前位置的值。

用作模板的输入文本必须是utf-8编码的文本。”Action”—数据运算和控制单位—由”{{“和”}}“界定;在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行,但注释可以有换行。

HTML文件代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello</title>
</head>
<body>
<p>Hello {{.}}</p>
</body>
</html>

我们的HTTP server端代码如下:

// main.go

func sayHello(w http.ResponseWriter, r *http.Request) {
// 解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./hello.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 利用给定数据渲染模板,并将结果写入w
tmpl.Execute(w, "沙河小王子")
}
func main() {
http.HandleFunc("/", sayHello)
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println("HTTP server failed,err:", err)
return
}
}

模板语法

{{.}}

模板语法都包含在{{}}中间,其中{{.}}中的点表示当前对象。

当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段。例如:

// main.go

type UserInfo struct {
Name string
Gender string
Age int
} func sayHello(w http.ResponseWriter, r *http.Request) {
// 解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./hello.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
// 利用给定数据渲染模板,并将结果写入w
user := UserInfo{
Name: "小王子",
Gender: "男",
Age: 18,
}
tmpl.Execute(w, user)
}

HTML文件代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello</title>
</head>
<body>
<p>Hello {{.Name}}</p>
<p>性别:{{.Gender}}</p>
<p>年龄:{{.Name}}</p>
</body>
</html>

同理,当我们传入的变量是map时,也可以在模板文件中通过.根据key来取值。

注释

{{/* a comment */}}
注释,执行时会忽略。可以多行。注释不能嵌套,并且必须紧贴分界符始止。

pipeline

pipeline是指产生数据的操作。比如{{.}}{{.Name}}等。Go的模板语法中支持使用管道符号|链接多个命令,用法和unix下的管道类似:|前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置。

注意:并不是只有使用了|才是pipeline。Go的模板语法中,pipeline的概念是传递数据,只要能产生数据的,都是pipeline

变量

Action里可以初始化一个变量来捕获管道的执行结果。初始化语法如下:

$variable := pipeline

其中$variable是变量的名字。声明变量的action不会产生任何输出。

条件判断

Go模板语法中的条件判断有以下几种:

{{if pipeline}} T1 {{end}}

{{if pipeline}} T1 {{else}} T0 {{end}}

{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}

range

Go的模板语法中使用range关键字进行遍历,有以下两种写法,其中pipeline的值必须是数组、切片、字典或者通道。

{{range pipeline}} T1 {{end}}
如果pipeline的值其长度为0,不会有任何输出 {{range pipeline}} T1 {{else}} T0 {{end}}
如果pipeline的值其长度为0,则会执行T0。

with

{{with pipeline}} T1 {{end}}
如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。 {{with pipeline}} T1 {{else}} T0 {{end}}
如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。

预定义函数

执行模板时,函数从两个函数字典中查找:首先是模板函数字典,然后是全局函数字典。一般不在模板内定义函数,而是使用Funcs方法添加函数到模板里。

预定义的全局函数如下:

and
函数返回它的第一个empty参数或者最后一个参数;
就是说"and x y"等价于"if x then y else x";所有参数都会执行;
or
返回第一个非empty参数或者最后一个参数;
亦即"or x y"等价于"if x then x else y";所有参数都会执行;
not
返回它的单个参数的布尔值的否定
len
返回它的参数的整数类型长度
index
执行结果为第一个参数以剩下的参数为索引/键指向的值;
如"index x 1 2 3"返回x[1][2][3]的值;每个被索引的主体必须是数组、切片或者字典。
print
即fmt.Sprint
printf
即fmt.Sprintf
println
即fmt.Sprintln
html
返回其参数文本表示的HTML逸码等价表示。
urlquery
返回其参数文本表示的可嵌入URL查询的逸码等价表示。
js
返回其参数文本表示的JavaScript逸码等价表示。
call
执行结果是调用第一个参数的返回值,该参数必须是函数类型,其余参数作为调用该函数的参数;
如"call .X.Y 1 2"等价于go语言里的dot.X.Y(1, 2);
其中Y是函数类型的字段或者字典的值,或者其他类似情况;
call的第一个参数的执行结果必须是函数类型的值(和预定义函数如print明显不同);
该函数类型值必须有1到2个返回值,如果有2个则后一个必须是error接口类型;
如果有2个返回值的方法返回的error非nil,模板执行会中断并返回给调用模板执行者该错误;

比较函数

布尔函数会将任何类型的零值视为假,其余视为真。

下面是定义为函数的二元比较运算的集合:

eq      如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真

为了简化多参数相等检测,eq(只有eq)可以接受2个或更多个参数,它会将第一个参数和其余参数依次比较,返回下式的结果:

{{eq arg1 arg2 arg3}}

比较函数只适用于基本类型(或重定义的基本类型,如”type Celsius float32”)。但是,整数和浮点数不能互相比较。

自定义函数

Go的模板支持自定义函数。

func sayHello(w http.ResponseWriter, r *http.Request) {
htmlByte, err := ioutil.ReadFile("./hello.html")
if err != nil {
fmt.Println("read html failed, err:", err)
return
}
// 自定义一个夸人的模板函数
kua := func(arg string) (string, error) {
return arg + "真帅", nil
}
// 采用链式操作在Parse之前调用Funcs添加自定义的kua函数
tmpl, err := template.New("hello").Funcs(template.FuncMap{"kua": kua}).Parse(string(htmlByte))
if err != nil {
fmt.Println("create template failed, err:", err)
return
} user := UserInfo{
Name: "小王子",
Gender: "男",
Age: 18,
}
// 使用user渲染模板,并将结果写入w
tmpl.Execute(w, user)
}

我们可以在模板文件hello.html中使用我们自定义的kua函数了。

{{kua .Name}}

嵌套template

我们可以在template中嵌套其他的template。这个template可以是单独的文件,也可以是通过define定义的template。

举个例子: t.html文件内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>tmpl test</title>
</head>
<body> <h1>测试嵌套template语法</h1>
<hr>
{{template "ul.html"}}
<hr>
{{template "ol.html"}}
</body>
</html> {{ define "ol.html"}}
<h1>这是ol.html</h1>
<ol>
<li>吃饭</li>
<li>睡觉</li>
<li>打豆豆</li>
</ol>
{{end}}

ul.html文件内容如下:

<ul>
<li>注释</li>
<li>日志</li>
<li>测试</li>
</ul>

我们注册一个templDemo路由处理函数.

http.HandleFunc("/tmpl", tmplDemo)

tmplDemo函数的具体内容如下:

func tmplDemo(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("./t.html", "./ul.html")
if err != nil {
fmt.Println("create template failed, err:", err)
return
}
user := UserInfo{
Name: "小王子",
Gender: "男",
Age: 18,
}
tmpl.Execute(w, user)
}

go语言标准库之http/template的更多相关文章

  1. 附录二 C语言标准库

    上章回顾 数组和指针相同与不同 通过指针访问数组和通过数组访问指针 指针在什么时候可以加减运算 函数指针的申明和调用 函数数组和数组函数 git@github.com:Kevin-Dfg/Data-S ...

  2. Go语言标准库_输入/输出

    Go语言标准库_输入/输出 转载节选自<Go语言标准库> Reader 接口 type Reader interface { Read(p []byte) (n int, err erro ...

  3. GO语言标准库—命令行参数解析FLAG

    flag包是Go语言标准库提供用来解析命令行参数的包,使得开发命令行工具更为简单 常用方法 1.flag.Usage 输出使用方法,如linux下ls -h的帮助输出 2.flag.Type(参数名, ...

  4. Go语言标准库之JSON编解码

    Go语言标准库之JSON编解码 基本的类型 Go语言中的数据类型和JSON的数据类型的关系 bool -> JSON boolean float64 -> JSON numbers str ...

  5. Go语言标准库之time

    Go语言标准库之time 时间的格式化和解析 格式化 Format Go语言和其他语言的时间格式化的方式不同,Go语言格式化的方式更直观,其他的语言一般是yyyy-mm-dd package main ...

  6. C语言标准库之setjmp

    协程的介绍 协程(coroutine),意思就是“协作的例程”(co-operative routines),最早由Melvin Conway在1963年提出并实现.跟主流程序语言中的线程不一样,线程 ...

  7. C语言标准库 qsort bsearch 源码实现

    C语言是简洁的强大的,当然也有很多坑.C语言也是有点业界良心的,至少它实现了2个最最常用的算法:快速排序和二分查找. 我们知道,对于C语言标准库 qsort和 bsearch: a. 它是“泛型”的, ...

  8. Go语言标准库flag基本使用

    文章引用自   Go语言标准库flag基本使用 os.Args 如果你只是简单的想要获取命令行参数,可以像下面的代码示例一样使用os.Args来获取命令行参数. package main import ...

  9. Go语言标准库log介绍

    Go语言标准库log介绍 无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志一直都是非常重要的一个环节,我们也应该养成在程序中记录日志的好习惯. log Go语言内置的log包实现了简单的日志服 ...

随机推荐

  1. Mysql主从同步配置方案(Centos7)

    最近在做项目高可用时,需要使用数据同步.由于只有双节点,且采用主主同步可能存在循环同步的风险,故综合考虑采用Mysql主从同步(Master-Slave同步). 可能没有接触过Mysql数据同步时,可 ...

  2. Python——最美丽的编程语言

    之前总听别人说Python有多厉害,有多好,我是不以为然的.但是当我开始接触Python的时候,我就知道它被誉为最美编程语言不是没有道理的.简短的代码,清晰明了的逻辑,方便快捷的编程工具让它注定会大放 ...

  3. 面向对象程序设计(Java) 第2周学习指导及要求

    面向对象程序设计(Java)第2周学习指导及要求 (2019.9.3-2019.9.9)   学习目标 适应老师教学方式,能按照自主学习要求完成本周理论知识学习: 掌握Java Application ...

  4. Storm 系列(六)—— Storm 项目三种打包方式对比分析

    一.简介 在将 Storm Topology 提交到服务器集群运行时,需要先将项目进行打包.本文主要对比分析各种打包方式,并将打包过程中需要注意的事项进行说明.主要打包方式有以下三种: 第一种:不加任 ...

  5. 一道算法问题:一幢 200 层的大楼,给你两个鸡蛋. 如果在第 n 层扔下鸡蛋,鸡蛋不碎,那么从前 n-1 层扔鸡蛋都不碎. 这两只鸡蛋一模一样,不碎的话可以扔无数次. 已知鸡蛋在0层扔不会碎. 提出一个策略, 要保证能测出鸡蛋恰好会碎的楼层, 并使此策略在最坏情况下所扔次数最少.

    今晚要参加网易的笔试,所以一直在刷题,刷到这个题的时候觉得自己的思路很模糊,就去网上百度了一下,找到一个大神给的解决方案: 如下: (http://ppwwyyxx.com/2013/Problem- ...

  6. Mybatis打印SQL

    配置mybatis日志级别,打印SQL 1.方案一:配置日志级别 logging.level.org.springboot.demo.mapper=debug 其中org.springboot.dem ...

  7. Java 创建/识别条形码、二维码

    条形码(Barcode)是将宽度不等的多个黑条和空白,按照一定的编码规则排列,用以表达一组信息的图形标识符.常用于标示物品的生产国.制造厂家.商品名称.生产日期.图书分类号.邮件起止地点.类别.日期等 ...

  8. App 冷启动与热启动及启动白屏优化

    介绍一下 app 冷启动和热启动方式来实现 app 秒开的效果.那么,先来看看什么叫冷启动和热启动. 冷启动:指 app 被后台杀死后,在这个状态打开 app,这种启动方式叫做冷启动. 热启动:指 a ...

  9. java教程系列一:什么是Java语言?

    海上生明月,天涯共此时. Java是一种通用的计算机编程语言,它具有卓越的通用性.高效性.平台移植性和安全性.它旨在让应用程序开发人员"write once, run anywhere&qu ...

  10. thinkphp6.0 composer 安装 web-token/jwt-framework 常见出错原因分析及解决方法

    composer require web-token/jwt-framework 安装JWT出现错误提示 - web-token/jwt-framework v2.0.1 requires ext-g ...