1. Template 介绍
Go中提供了两种类型的template包:html/template 和 text/template 。前者用于前端项目,其中对一些特殊字符进行了安全转义操作,避免可能存在的安全问题。后者用于普通文件的渲染,比如 ansible 的清单文件或者k8s的yaml文件等。Template 模板使用语法如下:
- 模板文件后缀通常为 .tmpl 或者 .tpl,目的是方便区分。文件编码格式为 UTF-8
- 默认使用 {{ }} 标识变量或者关键字,可以人为修改
- 使用 . 标识传进来的数据,多个数据传递一般使用map方式,{{ .key }} 访问传递进来的数据中子字段
- 注释格式为
{{/* xxxx */}}
注释不能嵌套,但是可以多行。
Template 一般使用步骤如下:
- 定义一个模板文件
- 解析模板文件
- 渲染模板文件
2. Template基本语法
2.1. 数据传递
2.1.1. 常见传递的数据类型
在模板语法中, {{ . }}
表示传递个模板的变量,仅支持一个变量。变量常用类型有:字符串,map,结构体和结构体指针,结构体指针在渲染后,也是结构体的值。如下案例,编译的时候需要注意可执行文件的路径,因为代码的模板文件为相对路径。
// templates/data.tmpl
data: {{ . }}
import (
"fmt"
"html/template"
"net/http"
)
var tp *template.Template
func init() {
var err error
tp, err = template.ParseFiles("./templates/data.tmpl")
if err != nil {
fmt.Printf("template parse failed,err:%s\n", err.Error())
return
}
}
func f1(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, "Hello world!"); err != nil {
_, _ = fmt.Fprint(w, "template operate failed!")
return
}
}
func f2(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, map[string]interface{}{
"name": "ZhangSan",
"age": 18,
}); err != nil {
_, _ = fmt.Fprint(w, "template operate failed!")
return
}
}
func f3(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, struct {
name string
age int
}{
name: "LiSi",
age: 27,
}); err != nil {
_, _ = fmt.Fprint(w, "template operate failed!")
return
}
}
func f4(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, &struct {
name string
age int
}{
name: "WanWu",
age: 36,
}); err != nil {
_, _ = fmt.Fprint(w, "template operate failed!")
return
}
}
func main() {
http.HandleFunc("/f1", f1) // 数据为 字符串
http.HandleFunc("/f2", f2) // 数据为 map
http.HandleFunc("/f3", f3) // 数据为结构体
http.HandleFunc("/f4", f4) // 数据为结构体指针
err := http.ListenAndServe("127.0.0.1:8080", nil)
if err != nil {
fmt.Printf("start http server failed, err:%s\n", err.Error())
return
}
}
[root@duduniao go_learn]# curl 127.0.0.1:8080/f1
data: Hello world!
[root@duduniao go_learn]# curl 127.0.0.1:8080/f2
data: map[age:18 name:ZhangSan]
[root@duduniao go_learn]# curl 127.0.0.1:8080/f3
data: {LiSi 27}
[root@duduniao go_learn]# curl 127.0.0.1:8080/f4
data: {WanWu 36}
2.1.2. 传递多个数据
在Go的模板中, {{ . }}
表示传递给模板的值,仅支持一个。但需要传递多个值的时候,有来两种方案:传递map或者结构体,采用 {{ .fieldName }}
方式获取字段的值。结构体想要对外可见,必须首字母大写,map根据Key取值时,如果取不到字段则为空,结构体取不到则报错。
// templates/data.tmpl
name: {{ .Name }}
age: {{ .Age }}
import (
"fmt"
"html/template"
"net/http"
)
var tp *template.Template
func init() {
var err error
tp, err = template.ParseFiles("./templates/data.tmpl")
if err != nil {
fmt.Printf("template parse failed,err:%s\n", err.Error())
return
}
}
func f2(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, map[string]interface{}{
"Name": "ZhangSan",
"Age": 18,
}); err != nil {
_, _ = fmt.Fprint(w, fmt.Sprintf("template operate failed, err:%s", err.Error()))
return
}
}
func f3(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, struct {
Name string
Age int
}{
Name: "LiSi",
Age: 27,
}); err != nil {
_, _ = fmt.Fprint(w, fmt.Sprintf("template operate failed, err:%s", err.Error()))
return
}
}
func f4(w http.ResponseWriter, r *http.Request) {
if err := tp.Execute(w, &struct {
Name string
Age int
}{
Name: "WanWu",
Age: 36,
}); err != nil {
_, _ = fmt.Fprint(w, fmt.Sprintf("template operate failed, err:%s", err.Error()))
return
}
}
func main() {
//http.HandleFunc("/f1", f1) // 数据为 字符串
http.HandleFunc("/f2", f2) // 数据为 map
http.HandleFunc("/f3", f3) // 数据为结构体
http.HandleFunc("/f4", f4) // 数据为结构体指针
err := http.ListenAndServe("127.0.0.1:8080", nil)
if err != nil {
fmt.Printf("start http server failed, err:%s\n", err.Error())
return
}
}
[root@duduniao go_learn]# curl 127.0.0.1:8080/f2
name: ZhangSan
age: 18
[root@duduniao go_learn]# curl 127.0.0.1:8080/f3
name: LiSi
age: 27
[root@duduniao go_learn]# curl 127.0.0.1:8080/f4
name: WanWu
age: 36
2.2. 模板中自定义变量
使用 {{ $var := xxx }}
可以定义一个新的变量,引用的时候使用 {{ $var }}
,已经定义过的变量使用 {{ $var = xxx }}
。变量定义的所在行会产生空行,采用 {{-
或者 -}}
去除不必要的空行和空格。
{{- $var01 := . -}}
Name: {{ $var01.Name }}
Age: {{ $var01.Age }}
{{ $var01 = "name: 张三" -}}
{{ $var02 := "password: 123456" -}}
info: {{ $var01}} - {{$var02}}
[root@duduniao go_learn]# curl 127.0.0.1:8080
Name: 张三
Age: 18
info: name: 张三 - password: 123456
2.3. 条件判断
2.3.1. 条件判断常用函数
Golang 的Template将能输出数据的变量或者表达式称为 pipeline,if 条件判断有以下三种格式,和go语言基本一致,只需要注意格式。如果 pipeline 输出为该数据类型的零值则为 false。
{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
len 取pipeline的长度
eq 如果arg1 == arg2则返回真
ne 如果arg1 != arg2则返回真
lt 如果arg1 < arg2则返回真
le 如果arg1 <= arg2则返回真
gt 如果arg1 > arg2则返回真
ge 如果arg1 >= arg2则返回真
2.3.2. 条件判断案例
{{ if gt .Age 20 }}{{.Age }}gt than 20{{ else }}{{ .Aget }}le than 20{{ end }}
{{ if .Addr }}Addr:{{.Addr}}{{end}}
{{ if .Name }}Name:{{ .Name }}{{end}}
2.4. 遍历
使用 range
关键词可以实现对数组、切片、map和channel的遍历。遍历的过程中,如果需要取值则用 赋值的语句。
{{- range $k,$v := . -}}
{{- if eq $k "hobby" -}}
{{- range $i, $hobby := $v }}hobby: {{ $hobby }}{{ end }}
{{ else }}
{{ $k }} - {{ $v }}
{{- end }}
{{- end}}