Go语言中的模板引擎

/ go / 没有评论 / 1545浏览

Go语言中的模板引擎

1 概述

处理响应主体时,最常见的方式就是发送处理好的 HTML 代码,由于需要将数据嵌入到 HTML 中,那么模板引擎(template engine)就是最好的选择。

Go语言中,提供了 html/template 包,实现模板引擎的相关功能。快速使用示例:

main.go

package main

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

func main() {
  // 设置 处理函数
  http.HandleFunc("/", TestAction)
  //// 开启监听(监听浏览器请求)
  log.Fatal(http.ListenAndServe(":8084", nil))
}

func TestAction(w http.ResponseWriter, r *http.Request) {
  // 解析模板
  t, _ := template.ParseFiles("template/index.html")
  // 设置模板数据
  data := map[string]interface{}{
    "User": "小韩说课",
    "List": []string{"Go", "Python", "PHP", "JavaScript"},
  }
  // 渲染模板,发送响应
  t.Execute(w, data)
}

template/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>小韩说课</title>
</head>
<body>

Hello, {{ .User }}
<br>

你熟悉的技术:
<ul>
{{ range .List }}
    <li>{{.}}</li>
{{end}}
</ul>

</body>
</html>

执行结果: img

以上代码就完了模板引擎的基本使用,包括解析模板,渲染数据,响应结果操作。接下来详细说明。

2 解析模板

函数 template.ParseFiles(filenames ...string) (*Template, error) 可以解析模板文件,并得到模板对象。参数为模板文件。同时会以模板文件的文件名(不包含后缀名)作为模板的名字。

还可以使用 template.New("name").Parse(src string) 来创建模板对象,并完成解析模板内容。

3 应用数据并发送响应

函数 func (t *Template) Execute(wr io.Writer, data interface{}) error 将 data 应用到解析好的模板上,并将输出写入 wr。如果执行时出现错误,会停止执行,但有可能已经写入wr部分数据。

data 数据可以接受任意类型,最常见的类型为:map[string]interface{},通过不同的下标来区分部分的分配数据。在模板中使用 .User.List 来访问分配数据中的 User 和 List。

Go语言中使模板引擎的语法

1 模板界定符

{{ }}

是默认的模板界定符。用于在 HTML 模板文件中界定模板语法。例如:

Hello, {{ .User }}
<br>
你熟悉的技术:
<ul>
{{ range .List }}
    <li>{{.}}</li>
{{end}}
</ul>

若需要使用自定义的界定符,使用 func (t *Template) Delims(left, right string) *Template 方法进行定义。后续的解析会识别新定义的界定符。

2 数据

分配到模板中的数据使用 . 点可以访问。点会随着所处的上下文变化而变化,例如上面的例子,在 range 内就表示所遍历的每个数据,而在 range 外,就表示分配到模板中的数据整体。

解析数据时,默认会被 HTML 实体编码,防止 XSS 攻击。若需要原样输出,需要将数据转换为 template.HTML 类型,例如:

t.Execute(w, `<script>alert("Hack")</script>`)
// 解析结果: &lt;script&gt;alert(&#34;Hack&#34;)&lt;/script&gt;

t.Execute(w, template.HTML(`<script>alert("Hack")</script>`))
// 解析结果: <script>alert("Hack")</script>

甚至在不同的 HTML 语法上下文中,会有不同的编码方式,例如:

假设 . 的值为 Hank's 博客:

a href="{{.}}" 中,会进行 URL 编码,结果为:Hank%27s%20%e5%8d%9a%e5%ae%a2
a title="{{.}}" 中,会进行 ASCII 实体编码,结果为:Hank&#39;s 博客

3 调用函数

{{FuncName1 "参数值1" "参数值2"}}

函数支持模板函数,和全局函数。预定义的全局函数为:

4 管道

可以在变量后使用 | (管道符),将其值作为参数传递给函数,并得到函数的返回值。管道可以连续使用,演示为:

// . 为 `Hank's 博客`
{{.|urlquery}}
// Hank%27s+%E5%8D%9A%E5%AE%A2

5 条件分支

{{if pipeline}} T1 {{ else if pipeline}} T2 {{else}} T3 {{end}}

若 pipeline 的值不为 empty,条件匹配,执行相应分支。

empty 空值为:false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典。

6 循环遍历

{{range pipeline}} T1 {{else}} T0 {{end}}
或
{{range $index, $element := pipeline}} T1 {{end}}

遍历数组、切片、字典或者通道的每一个成员元素并执行 T1。 若 pipeline 为空,执行 T0。else 分支可以省略。 empty 空值为:false、0、任意nil指针或者nil接口,任意长度为0的数组、切片、字典。

若需要同时获取下标和值,需要使用变量赋值语法。

7 解析子模板

{{template "name" pipeline}}

解析名为 name 的模板,提供给模板的参数为 pipeline。

8 定义模板变量

{{$variable := pipeline}} 

9 注释

{{/* a comment */}}