html/template包实现了数据驱动的模板,用于生成可防止代码注入的安全的HTML内容。它提供了和 text/template包相同的接口,Go语言中输出HTML的场景都应使用html/template这个包。
html/template会自动帮你转义掉有风险的代码,避免xss攻击
模板需要注意的
模板文件
{{/*定义模板*/}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hello</title>
</head>
<body>
<p>hello {{ . }}</p>
</body>
</html>
go服务端
package main
import (
"net/http"
"text/template"
)
func hello(w http.ResponseWriter, r *http.Request) {
//打开模板
t, err := template.ParseFiles("template/hello.tmpl")
if err != nil {
return
}
//渲染模板
name := "hello"
err := t.Execute(w, name)
if err != nil {
return
}
}
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":9090", nil)
if err != nil {
return
}
}
map作为参数传入,直接使用参数访问
服务端
m1 := map[string]interface{}{
"name": "ll",
"gender": "female",
"age": 0,
}
模板文件
<p>hello {{ .name }}</p>
<p>hello {{ .age }}</p>
<p>hello {{ .gender }}</p>
结构体传入
名称必须是要大写才能被外界访问到
type User struct {
Name string
Gender string
Age int
}
u1 := User{
Name: "ll",
Gender: "female",
Age: 0,
}
模板文件
<p>hello {{ .Name }}</p>
<p>hello {{ .Age }}</p>
<p>hello {{ .Gender }}</p>
想要一次传入多个参数,可以使用map来进行传入
u1 := User{
Name: "struct_para",
Gender: "female",
Age: 0,
}
m1 := map[string]interface{}{
"name": "map_para",
"gender": "female",
"age": 0,
}
err = t.Execute(w, map[string]interface{}{
"struct": u1,
"map_itf": m1,
})
模板文件
<p>hello {{ .struct.Name }}</p>
<p>hello {{ .map_itf.name }}</p>
变量
{{$v := 114}}
{{$}}
移除空格
移除左右的空格
{{- .name -}}
条件判断
{{ $v1 := 114 }}
{{if $v1}}
{{$v1}}
{{else}}
Nothing
{{end}}
预定义函数
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。
这个函数在html/template中不可用。
urlquery
以适合嵌入到网址查询中的形式返回其参数的文本表示的转义值。
这个函数在html/template中不可用。
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则返回真
循环
{{range $idx,$hobby := .hobby}}
<p>{{$idx}} - {{$hobby}}</p>
{{else}}
empty
{{end}}
with共同前缀
类似 var . = .struct
{{with .struct}}
<p>hello {{ .Name }}</p>
<p>hello {{ .Age }}</p>
<p>hello {{ .Gender }}</p>
{{end}}
自定义函数
len := func(str string) (int, error) {
return len(str), nil
}
//渲染模板
//name := "hello"
t.Funcs(template.FuncMap{"len": len})
自定义函数用法
<p>hello {{ len .struct.Name }}</p>
模板嵌套
主模板
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hello</title>
</head>
<body>
{{template "a.tmpl"}}
{{template "b.tmpl"}}
</body>
</html>
{{/*内部嵌套*/}}
{{define "a.tmpl"}}
<a>
<li>test_a_tmpl</li>
</a>
{{end}}
外部嵌套
b.tmpl
<b>
<li>test_b_tmpl</li>
</b>
服务端
package main
import (
"html/template"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
//先导入主文件 然后再导入嵌套文件
t, err := template.ParseFiles("template/hello.tmpl", "template/b.tmpl")
if err != nil {
return
}
t.Execute(w, nil)
}
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":9090", nil)
if err != nil {
return
}
}
block模板继承
利用根模板进行组合
根模板
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{{ . }}</title>
<style>
*{
margin: 0;
}
.nav{
height: 50px;
width: 100%;
position: fixed;
top: 0;
background-color: yellow;
}
.main{
margin-top: 50px;
}
.context{
width: 20%;
height: 100%;
position: fixed;
left: 0;
background-color: blue;
}
.center {
text-align: center;
}
</style>
</head>
<body>
<div class="nav"></div>
<div class="main">
<div class="menu"></div>
<div class="context center">
{{block "content" .}}{{end}}
</div>
</div>
</body>
</html>
继承模板
{{template "base.tmpl"}}
{{/*此处定义的模板要和上面的相同*/}}
{{define "content"}}
<h1>home_page</h1>
{{end}}
服务端
先根模板后继承模板
func home2(w http.ResponseWriter, r *http.Request) {
t, err := template.ParseFiles("template/base.tmpl", "template/test_home.tmpl")
if err != nil {
return
}
t.Execute(w, "home")
}
自定义标识符
防止和其他语言发生冲突
在解析模板的时候来定义
func test(w http.ResponseWriter, r *http.Request) {
t,err := template.New("test.tmpl").
Delims("{[", "]}").
ParseFiles("template/test.tmpl")
if err != nil{
return
}
t.Execute(w,nil)
}
这样标识符就成了 {[ name ]}了
使用gin框架的template模板
package main
import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)
func main() {
r := gin.Default()
//静态文件 解析前添加路径
r.Static("/name", "statics")
//自定义函数 解析前添加
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})
//模板解析 ** -> 所有文件夹 * -> 所有文件
r.LoadHTMLGlob("templates/**/*")
//访问index的时候就执行后面的函数
r.GET("/users/index", func(ctx *gin.Context) {
//http请求
ctx.HTML(http.StatusOK, "users/index.tmpl", gin.H{ //模板渲染
"title": "moreac.top",
})
})
r.GET("/posts/index", func(ctx *gin.Context) {
//http请求
ctx.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ //模板渲染
"title": "moreac.top",
})
})
err := r.Run(":9090")
if err != nil {
return
}
}
{{define "posts/index.tmpl"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>posts/index</title>
</head>
<body>
{{ .title }}
</body>
</html>
{{end}}
静态文件处理
网页上面使用到的样式文件 .css .js pic等
手机扫一扫
移动阅读更方便
你可能感兴趣的文章