Loading

03 Go模板

目录结构如下: image-20220518234138321

1 template模板初识

hello.tmpl

<!DOCTYPE html>
<html lang="zh-CN">
<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>
<hr>

{{/*1   template模板初识*/}}
<p> hello {{ . }} </p>
<hr/>

{{/*2 模板语法详解*/}}
{{/*当我们传入的变量是map或结构体时,可以在模板文件中通过.根据key来取值*/}}
<p> 姓名: {{ .user1.Name }}</p>
<p> 性别: {{ .user1.Gender }}</p>
<p> 年龄: {{ .user1.Age }}</p>
<hr/>

{{/*变量*/}}
{{ $obj := .user1.Name }}
<p>变量: {{ $obj }}</p>
<hr/>

{{/*移除空格*/}}
<p>去除模板内容左侧的所有空白符号 {{- .user1.Age -}} 去除模板内容右侧的所有空白符号</p>
<hr/>

{{/*条件判断*/}}
<p>条件判断:
   {{ $Age := .user1.Age }}
   {{ $Gender := .user1.Gender }}
   {{ if $Gender }}
       {{ $Gender }}
   {{ else if $Age }}
       {{ $Age }}
   {{ else }}
        啥也没有
  {{ end }}
</p>
<hr/>

{{/*比较函数*/}}
{{/*eq     如果arg1 == arg2则返回真 可以比较字符串*/}}
{{/*ne     如果arg1 != arg2则返回真 可以比较字符串*/}}
{{/*lt     如果arg1 < arg2则返回真*/}}
{{/*le     如果arg1 <= arg2则返回真*/}}
{{/*gt     如果arg1 > arg2则返回真*/}}
{{/*ge     如果arg1 >= arg2则返回真*/}}
<p>比较函数:
   {{ if lt .user1.Age 18 }}
        好好学习
  {{ else if  gt .user1.Age 18 }}
        好好工作
  {{ else }}
        好好养老
  {{ end }}
</p>
<hr/>

{{/*with 造一个局部作用域*/}}
{{/*{{with pipeline}} T1 {{end}}*/}}
{{/*如果pipeline为empty不产生输出,否则将dot设为pipeline的值并执行T1。不修改外面的dot。*/}}
{{/*{{with pipeline}} T1 {{else}} T0 {{end}}*/}}
{{/*如果pipeline为empty,不改变dot并执行T0,否则dot设为pipeline的值并执行T1。*/}}
<p>with:局部作用域:</p>
{{ with .user2 }}
    <li>{{ .name }}</li>
    <li>{{ .gender }}</li>
    <li> {{ .age }}</li>
{{ else }}
    没有数据
{{ end }}
<hr/>

{{/*range 其中pipeline的值必须是数组、切片、map或者通道*/}}
{{/*{{range pipeline}} T1 {{end}}*/}}
{{/*如果pipeline的值其长度为0,不会有任何输出*/}}
{{/*{{range pipeline}} T1 {{else}} T0 {{end}}*/}}
{{/*如果pipeline的值其长度为0,则会执行T0。*/}}
<p>range 遍历</p>
{{  $slice := .user2 }}
{{  range $slice }}
    <li> {{ . }} </li>
{{ end }}
<hr/>
<p>range遍历带索引</p>
{{ range $idx,$val := $slice }}
    <p>{{ $idx }} - {{ $val }}</p>
{{ else }}}
没有数据
{{ end }}
<hr/>

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

{{/*自定义函数*/}}

</body>
</html>

main.go

package main

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

//1   template模板初识
//1.1 定义一个hello.tmpl的模板文件
//1.2 解析模板和渲染模板
func sayHello01(w http.ResponseWriter, r *http.Request) {
// 解析指定文件生成模板对象
tmpl, err := template.ParseFiles("./hello.tmpl")
if err != nil {
fmt.Println("create template failed,err:", err)
return
}
// 利用给定数据渲染模板,并将数据写入w
err = tmpl.Execute(w, "go语言")
if err != nil {
fmt.Println(err)
return
}
}

//2 模板语法详解
//2.1{{.}}中的点表示当前对象,当我们传入一个结构体对象时,我们可以根据.来访问结构体的对应字段
func sayHello02(w http.ResponseWriter, r *http.Request) {
type UserInfo struct {
Name   string
Gender string
Age    int
}
tmpl, err := template.ParseFiles("./hello.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 结构体字段名必须是大写才能被模板访问到
user1 := UserInfo{
Name: "张三",
//Gender: "男",
Age: 27,
}
// map的key大写或小写都能被模板访问到
user2 := map[string]interface{}{
"name":   "小红",
"gender": "女",
"age":    18,
}

err = tmpl.Execute(w, map[string]interface{}{
"user1": &user1,
"user2": &user2,
})

if err != nil {
fmt.Println(err)
return
}
}

func main() {
//1   template模板初识
http.HandleFunc("/01", sayHello01)
//2 模板语法详解
http.HandleFunc("/02", sayHello02)

// 启动服务端
fmt.Println("server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}

2 模板嵌套

main.go

package main

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

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

func nestTing(w http.ResponseWriter, r *http.Request) {
// 定义模板
// 解析模板
// 在解析模板时,被嵌套的模板一定要在后面解析,t.tmpl模板中嵌套了ul.tmpl,所以ul.tmpl要在t.tmpl后进行解析
tmpl, err := template.ParseFiles("./t.tmpl", "./ul.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 渲染模板
type userInfo struct {
Name   string
Gender string
Age    int
}
user := userInfo{
Name:   "张三",
Gender: "男",
Age:    30,
}

err = tmpl.ExecuteTemplate(w, "t.tmpl", user)
if err != nil {
fmt.Println(err)
return
}
}

func main() {
http.HandleFunc("/", nestTing)
fmt.Println("http server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}

t.tmpl

<!DOCTYPE html>
<html lang="zh-CN" xmlns="http://www.w3.org/1999/html">
<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/>

{{/*单独的文件*/}}
<h3 style="color: blueviolet">ul.tmpl</h3>
{{ template "ul.tmpl" . }}
<hr/>

{{/* 通过define定义的template */}}
<h3 style="color: blueviolet">define ol.tmpl</h3>
{{ template "ol.tmpl" }}
<hr/>

<h3 style="color: blueviolet">传参</h3>
<p> t.tmpl->姓名:{{ .Name }} </p>
<p> t.tmpl->性别:{{ .Gender }} </p>
<p> t.tmpl->年龄:{{ .Age }} </p>
<hr/>

</body>
</html>

{{/* 通过define定义的template */}}
{{ define "ol.tmpl" }}
    <ol>
        <li>ol.tmpl->吃饭{{ .Name }}</li>
        <li>ol.tmpl->睡觉</li>
        <li>ol.tmpl->打豆豆</li>
    </ol>
{{ end }}

ul.tmpl

<li>ul.tmpl->注释{{ .Name }}</li>
<li>ul.tmpl->日志{{ .Gender }}</li>
<li>ul.tmpl->测试{{ .Age }}</li>

3 模板继承

base.tmpl

{{/*定义根模板*/}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>Go Templates</title>
    <style>
        * {
            margin: 0;
       }
        .nav {
            top: 0;
            height: 70px;
            width: 100%;
            position: fixed;
            background-color: bisque;
       }
        .main {
            margin-top: 70px;
       }
        .menu {
            left: 0;
            height: 100%;
            width20%;
            position: fixed;
            background-color: lightcoral;
       }
        .content {
            text-align: center;
       }

    </style>
</head>
<body>

<div class="nav"></div>
<div class="main">
    <div class="menu"></div>
    <div class="content">
       {{/*定义块模板,用于被替换, "."表示将base根模板接收的数据传入当前定义的块 */}}
       {{ block "content" . }} {{ end }}
    </div>
</div>

</body>
</html>

home.tmpl

{{/*继承根模板,"."表示base根模板接收数据*/}}
{{ template "base.tmpl" . }}
{{/*重新定义块模板*/}}
{{ define "content" }}
    <p> 这是home页面 </p>
   {{/* "."表示传入的渲染数据 */}}
    <p> hello {{ . }}</p>
{{ end }}

index.tmpl

{{/*继承根模板,"."表示base根模板接收数据*/}}
{{ template "base.tmpl" . }}
{{/*重新定义块模板*/}}
{{ define "content" }}
    <p> 这是index页面 </p>
   {{/* "."表示传入的渲染数据 */}}
    <p> hello {{ . }}</p>
{{ end }}

main.go

package main

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

// 模板继承 block
func index(w http.ResponseWriter, r *http.Request) {
//定义模板
//解析模板, 根模板base.tmpl优先于index.tmpl被加载
tmpl, err := template.ParseFiles("./templates/base.tmpl", "./templates/index.tmpl")
if err != nil {
fmt.Println(err)
return
}
//渲染模板,通过ExecuteTemplate渲染指定的模板
msg := "this is index pag"
err = tmpl.ExecuteTemplate(w, "index.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}

func home(w http.ResponseWriter, r *http.Request) {
//定义模板
//解析模板, 根模板base.tmpl优先于home.tmpl被加载
tmpl, err := template.ParseFiles("./templates/base.tmpl", "./templates/home.tmpl")
if err != nil {
fmt.Println(err)
return
}
//渲染模板,通过ExecuteTemplate渲染指定的模板
msg := "this is home page"
err = tmpl.ExecuteTemplate(w, "home.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}

func main() {
// 路由匹配
http.HandleFunc("/index", index)
http.HandleFunc("/home", home)
// 启动服务端
fmt.Println("http Server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}

4 模板补充

htmlTemplate.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>Document</title>
</head>
<body>
{{ . }}
</body>
</html>

identifier.tmpl

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

{[/*修改默认的标识符*/]}
{[ . ]}

</body>
</html>

main.go

package main

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

// 1.修改默认的标识符
func identifier(w http.ResponseWriter, r *http.Request) {
//Go标准库的模板引擎使用花括号 {{}} 作为标识,而许多前端框架(如Vue和AngularJS)也使用 {{}} 作为标识符,
//所以当我们同时使用Go语言模板引擎和以上前端框架时就会出现冲突,这个时候我们需要修改标识符,修改前端的或者
//修改Go语言的。这里演示如何修改Go语言模板引擎默认的标识符。
tmpl, err := template.New("identifier").Delims("{[", "]}").ParseFiles("./templates/identifier.tmpl")
if err != nil {
fmt.Println(err)
return
}
msg := "this is a identifier page"
err = tmpl.ExecuteTemplate(w, "identifier.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}

// 2.html/template
func htmlTemplate(w http.ResponseWriter, r *http.Request) {
// html/template(默认)针对的是需要返回HTML内容的场景,在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。
tmpl, err := template.ParseFiles("./templates/htmlTemplate.tmpl")
if err != nil {
fmt.Println(err)
return
}
// 传入JavaScript代码,渲染后会在页面上显示出转义后的JS内容
msg := "<script>alert('hello go 语言')</script>"
err = tmpl.ExecuteTemplate(w, "htmlTemplate.tmpl", msg)
if err != nil {
fmt.Println(err)
return
}
}

func main() {
//路由匹配
//1.修改默认的标识符
http.HandleFunc("/identifier", identifier)
//2.html/template
http.HandleFunc("/htmlTemplate", htmlTemplate)

//启动服务
fmt.Println("http server http://127.0.0.1:9090 start")
err := http.ListenAndServe(":9090", nil)
if err != nil {
fmt.Println(err)
return
}
}


posted @ 2022-05-19 16:17  云起时。  阅读(45)  评论(0编辑  收藏  举报