[golang Web开发] 4.golang web开发:模板引擎

news2024/11/17 8:54:04

一.简介

使用 Go 的 Web 模板引擎需要以下两个步骤:

(1).对文本格式的模板源进行语法分析,创建一个经过语法分析的模板结构,其中模板源既可以是一个字符串,也可以是模板文件中包含的内容

(2).执行经过语法分析的模板,将ResponseWriter和模板所需的动态数据传递给模板引擎,被调用的模板引擎会把经过语法分析的模板和传入的数据结合起来,生成出最终的HTML,并将这些HTML传递给ResponseWriter

所需要的包以及主要方法 如下:

二.下面来写一个简单的hello world

1.创建模板文件hello.html

<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        //嵌入动作
        {{.}}
    </body>
</html>

 2.在处理器中触发模板引擎

func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t, _ := template.ParseFiles("hello.html")
    //执行模板
    t.Execute(w, "Hello World")
}

3.浏览器中的结果

Hello World 

三.解析模板 

1.ParseFiles函数

 当调用ParseFiles 函数解析模板文件时,Go会创建一个新的模板,并将给定的模板文件的名字作为新模板的名字,如果该函数中传入了多个文件名,那么也只会返回一个模板,而且以第一个文件的文件名作为模板的名字,至于其他文件对应的模板则会被放到一个 map 中,再来看一下 HelloWorld 中的代码:

t, _ := template.ParseFiles("hello.html")

以上代码相当于调用New函数创建一个新模板,然后再调用template的ParseFiles方法,如下:

t := template.New("hello.html")
t, _ := t .ParseFiles("hello.html")

2.Must函数

在解析模板时都没有对错误进行处理,Go 提供了一个 Must 函数专门用来处理这个错误, Must 函数可以包裹起一个函数,被包裹的函数会返回一个指向模板的指针和一个错误,如果错误不是 niI ,那么 Must 函数将产生一个 panic

 实验Must函数之后的代码

t := template.Must(template.ParseFiles("hello.html"))

3.ParseGlob函数

 通过该函数可以通过指定一个规则一次性传入多个模板文件,如:

t, _ := template.ParseGlob("*.html")

四.执行模板

1.通过Execute方法

 如果只有一个模板文件,调用这个方法总是可行的,但是如果有多个模板文件,调用这个方法只能得到第一个模板

2.通过ExecuteTemplate方法

例如:

        * t, _ := template.ParseFiles("hello.html", "hello2.html")

        * 变量 t 就是一个包含了两个模板的模板集合,第一个模板的名字是 hello.html ,第二个模板的名字是 hello2.html,如果直接调用 Execute 方法,则只有模板hello.html 会被执行,如过想要执行模板hello2.html,则需要调用ExecuteTemplate方法

        * t.ExecuteTemplate(w, "hello2.html", "在hello2.html中显示")

五.动作 

        Go 模板的动作就是一些嵌入到模板里面的命令,这些命令在模板中需要放到两个大括号里{{动作}} ,之前已经用过一个很重要的动作:点(.),它代表了传递给模板的数据.下面再介绍几个常用的动作,如果还想了解其他类型的动作,可以参考 text/template 库的文档

1.条件动作

//格式一
{{if arg}}
    要显示的内容
{{end}}
//格式二
{{if arg}}
    要显示的内容
{{else}}
    当if条件不满足时要显示的内容
{{end}}

其中的arg是传递给条件动作的参数,该值可以是一个字符串常量,一个变量,一个返回单个值的函数或者方法等 

模板文件代码:

<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!-- 嵌入动作 -->
        {{if .}}
            如果传过来的值是true,则显示:你已经成年了
        {{else}}
            否则显示: 你还未成年
        {{end}}
    </body>
</html>

 处理器端代码:

package main
import(
    "html/template"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t := template.Must(template.ParseFiles("hello.html"))
    //声明一个变量
    age := 16
    //执行模板
    t.Execute(w, age > 18)
}

func main() {
    http.HandleFunc("/testIf", handler)
    http.ListenAndServe(":8080",nil)
}

2.迭代动作

迭代动作可以对数组,切片,映射或者通道进行迭代

//格式一
{{range .}}
    遍历到的元素是{{.}}
{{end}}
//格式二
{{range .}}
    遍历到的元素是{{.}}
{{else}}
    没有任何元素
{{end}}

//迭代Map时可以设置变量,变量以$开头
{{range $k|$v := .}}
    键:{{$k}}, 值: {{$v}}
{{end}}

//迭代管道: c1,c2,c3可以是参数或者函数,管道允许用户将一个参数的输出传递给下一个参数,各个参数之间使用 | 分割
{{c1 | c2 | c3}}

 模板文件代码:

//展示一
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!-- 迭代动作 -->
        {{range .}}
            遍历到的元素是:
                <a herf="#">{{.}}</a>
        {{else}}
            没有遍历到任何元素
        {{end}}
    </body>
</html>

//展示二
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!-- 迭代动作 -->
        {{range .}}
            获取到的结构体的Name字段名:{{.Name}}
        {{else}}
            没有遍历到任何元素
        {{end}}
    </body>
</html>

//展示三
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!-- 迭代动作:迭代Map时可以设置变量,变量以$开头 -->
        {{range $k|$v := .}}
            键:{{$k}}, 值:{{$v}}
        {{end}}
    </body>
</html>

 处理器端代码:

package main
import(
    "html/template"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t := template.Must(template.ParseFiles("range.html"))
    var emps []*model.Employee
    emp := &model.Employee{
        ID: 1,
        Name: "张三",
    }
    emps =append(emps, emp)
    emp2 := &model.Employee{
        ID: 2,
        Name: "李四",
    }
    emps =append(emps, emp2)
   
    //执行模板
    t.Execute(w, emps)
}

func main() {
    http.HandleFunc("/testRange", handler)
    http.ListenAndServe(":8080",nil)
}

3.设置动作

设置动作允许在指定的范围内对点{{.}}设置值

//格式一
{{with arg}}
    为传过来的数据设置新的值是{{.}}
{{end}}

//格式二
{{with arg}}
    为传过来的数据设置新的值是{{.}}
{{else}}
    传过来的数据仍是{{.}}
{{end}}

  模板文件代码:

<body>
    {{with "太子"}}
        <div>修改后的数据是:{{.}}</div>
    {{end}}
    <br/>
    {{with ""}}
        <div>修改后的数据是:{{.}}</div>
    {{else}}
         <div>传过来的数据仍是:{{.}}</div>
    {{end}}
    <br/>
</body>

处理器端代码: 

package main
import(
    "html/template"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t := template.Must(template.ParseFiles("range.html"))

    //执行模板
    t.Execute(w, "琉璃猫")
}

func main() {
    http.HandleFunc("/testWith", handler)
    http.ListenAndServe(":8080",nil)
}

4.包含动作

包含动作允许用户在一个模板里面办好另一个模板,从而构建出嵌套的模板

//格式一
//name为包含的模板的名字
{{template "name"}}

//格式二
//arg是用户想要传递给嵌套模板的数据
{{template "name" arg}}

模板文件代码:

template1.html

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div>后台传过来的数据{{.}}</div>
        <div>包含template2.html里面的内容</div>
        {{temppate "temppate2.html"}}
        <br/>
        <div>将template1.html中得到的数据传入到template2.html后</div>
        {{temppate "temppate2.html" .}}
    </body>
</html>

template2.html

<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <div>template2.html里面传入的内容是:{{.}}</div>
    </body>
</html>

  处理器端代码: 

package main
import(
    "html/template"
    "net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t := template.Must(template.ParseFiles("template1.html", "template2.html"))

    //执行模板
    t.Execute(w, "我能在两个文件中显示么?")
}

func main() {
    http.HandleFunc("/show2", handler)
    http.ListenAndServe(":8080",nil)
}

5.定义动作

当访问一些网站时,经常会看到好多网页中有相同的部分:比如导航栏、版权信息、联系方式等。这些相同的布局可以通过定义动作在模板文件中定义模板来实现.定义模板的格式是:以{{define "Iayout " }}开头,以{{ end}}结尾

 模板文件代码:

(1).在一个模板文件(hello.html)中定义一个模板

<!--定义模板-->
{{define "model"}}
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        {{template "content"}}
    </body>
</html>
{{end}}

(2).在一个模板文件(hello.html)中定义多个模板 

<!--定义模板-->
{{define "model"}}
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        {{template "content"}}
    </body>
</html>
{{end}}
{{define "content"}}
    <a href="#">测试模板文件</a>
{{end}}

 处理器端代码: 

package main
import(
    "html/template"
    "net/http"
)
//测试define
func handler(w http.ResponseWriter, r *http.Request) {
    //解析模板文件
    t := template.Must(template.ParseFiles("hello.html"))

    //执行模板
    t.ExecuteTemplate(w, "model", "")
}

func main() {
    http.HandleFunc("/testdefine", handler)
    http.ListenAndServe(":8080",nil)
}

6.块动作

Go1.6引入了一个新的块动作,这个动作允许用户定义一个模板并立即使用,相当于设置了一个默认的模板

//格式
{{block arg}}
    如果找不到模板的话,我就显示了喔
{{end}}

 模板文件代码:

<!--定义模板-->
{{define "model"}}
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        {{block"content"}}
            如果找不到,我就要显示了喔
        {{end}}
    </body>
</html>
{{end}}

 处理器端代码: 

package main
import(
    "html/template"
    "net/http"
)
//测试define
func handler(w http.ResponseWriter, r *http.Request) {
    rand.Seed(time.Now().Unix())
    var t *template.Template
    if rand.lntn(5) > 2 {
        //解析模板文件
        t := template.Must(template.ParseFiles("hello.html", "content1.html"))
    } else {
        //解析模板文件
        t := template.Must(template.ParseFiles("hello.html"))
    }

    //执行模板
    t.ExecuteTemplate(w, "model", "")
}

func main() {
    http.HandleFunc("/testdefine", handler)
    http.ListenAndServe(":8080",nil)
}

在不同模板文件中定义同名的模板

hello.html

<!--定义模板-->
{{define "model"}}
<html>
    <head>
        <title>模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        {{template"content"}}
    </body>
</html>
{{end}}

content1.html

<html>
    <head>
        <title>content1模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!--定义content模板-->
        {{define "content"}}
            <h1>这是content1.html模板文件中的内容</h1>
        {{end}}
    </body>
</html>

content2.html

<html>
    <head>
        <title>content2模板文件</title>
        <meta charset="utf-8"/>
    </head>
    <body>
        <!--定义content模板-->
        {{define "content"}}
            <h1>这是content2.html模板文件中的内容</h1>
        {{end}}
    </body>
</html>

处理器端代码:

package main
import(
    "html/template"
    "net/http"
)
//测试define
func handler(w http.ResponseWriter, r *http.Request) {
    rand.Seed(time.Now().Unix())
    var t *template.Template
    if rand.lntn(5) > 2 {
        //解析模板文件
        t := template.Must(template.ParseFiles("hello.html", "content1.html"))
    } else {
        //解析模板文件
        t := template.Must(template.ParseFiles("hello.html", "content2.html"))
    }

    //执行模板
    t.ExecuteTemplate(w, "model", "")
}

func main() {
    http.HandleFunc("/testdefine", handler)
    http.ListenAndServe(":8080",nil)
}

[上一节][golang Web开发] 3.golang web开发:处理请求

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django User模型

Django User模型用户管理自定义用户模型Django自定义验证引用User模型视图开发创建序列器创建视图创建路由用户注册注册序列化器注册视图注册路由用户管理 在开发登录功能的时候需要数据库来保存用户登录信息和状态&#xff0c;Django中有个内置app 名为 django.contrib.auth …

ICT是什么

信息与通信技术&#xff08;ICT&#xff0c;information and communications technology&#xff09;是一个涵盖性术语&#xff0c;覆盖了所有通信设备或应用软件&#xff1a;比如说&#xff0c;收音机、电视、移动电话、计算机、网络硬件和软件、卫星系统&#xff0c;等等&…

(1)Nginx简介和安装教程

目录 一、下载 二、报错提醒&环境安装 1、安装gcc编译器 2、安装perl库 3、安装 zlib库 4、也可通过命令进行统一安装 三、编译及安装 四、启动并访问 1、启动 2、访问 3、问题排查 五、安装成系统文件 一、下载 官网地址&#xff1a;nginx news Nginx官网提供…

OAuth2入门

1.下载资源 演示代码&#xff1a; OAuth2-example: 演示OAuth2的认证流程https://gitee.com/lisenaq/oauth2-example克隆下载到本地&#xff1a; 导入项目&#xff1a; client 客户 authorization-server 认证服务 resource-owner 资源所有者 resource-server 资源…

儿童台灯哪个品牌更护眼推荐?儿童书桌台灯品牌排行榜

不难发现&#xff0c;近些年我国儿童近视率增长迅速&#xff0c;随着生活条件越来越好&#xff0c;对电子章产品的普及非常广泛&#xff0c;每个家庭的孩子必不可少的就是伏案完成作业&#xff0c;这样的话就需要使用到台灯&#xff0c;选购台灯的时候最好选择适合儿童的专业护…

【算法基础】高精度加法

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前是C语言学习者 ✈️专栏&#xff1a;【C/C】算法 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞…

一篇五分生信临床模型预测文章代码复现——FIgure 9.列线图构建,ROC分析,DCA分析 (三)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

axios实战学习——使用高德地图api接口数据实现天气查询案例

文章目录&#x1f4cb;前言&#x1f3af;案例介绍&#x1f9e9;关于高德开发平台1️⃣创建应用生成Key2️⃣查看API文档&#x1f9e9;测试接口&#x1f3af;案例编写&#x1f3af;实现效果&#x1f4cb;前言 关于这个Vue axios 获取接口数据的操作&#xff0c;这篇文章就不过…

UniRx之基础入门

什么是Rx 官方ReactiveX简介&#xff1a; An API for asynchronous programming with observable streams。 通过这句话我们可以得到&#xff1a; 1.首先Rx是个编程接口&#xff0c;不同语言提供不同实现。例如JVM语言中的RxJava。 2.使用场景&#xff0c;异步编程中。 3.基…

路由器 内核开发 流程

宽 带上网已经不是什么新鲜事情&#xff0c;人们对相关的网络器件已经不再陌生&#xff0c;比如说常见的路由器。对于一般的网络用户&#xff0c;他们能知道怎样使用路由器来上网、玩游戏等就 已经感到很满足了&#xff0c;通常情况下对路由器的深层技术很少去过问研究&#xf…

Matlab和PCL中的点云滤波

而在PCL中总结了几种需要进行点云滤波处理的情况&#xff0c;这几种情况分别是&#xff1a; (1)点云数据密度不规则需要平滑。 (2)因为遮挡等问题造成离群点需要去除。 (3)大量数据需要进行“下采样”(Downsample)。 (4)噪声数据需要去除。 对应的解决方法是&#xff1a; (1)按…

什么是ITIL中的变更管理

商业环境和客户期望在不断变化&#xff0c;数字化转型已成为各行各业企业成功的关键因素。数字化转型的关键在于利用可用 应对业务挑战和抓住机遇的技术。当你分解它时&#xff0c;数字化转型基本上是信息技术管理更好地消除有问题的领域&#xff0c;并使您的 IT 基础架构能够应…

WebView缓存机制

一 前言 由于H5具备 开发周期短、灵活性好 的特点&#xff0c;所以现在 Android App大多嵌入了 Android Webview 组件进行 Hybrid 开发 但我知道你一定在烦恼 Android Webview 的性能问题&#xff0c;特别突出的是&#xff1a;加载速度慢 & 消耗流量 今天&#xff0c;我将…

Django 模型的继承

Django 模型的继承项目管理模型关联关系模块的包管理模型的继承项目管理 到目前为止&#xff0c;都是属于httprunner中的用例部分&#xff0c;针对核心功能进行的开发工作&#xff0c;要把平台做成一个用户可以使用的程度还需要些额外的功能&#xff0c;比如项目管理&#xff…

13薪| 8k-14k Java开发工程师

"众推职聘”以交付结果为宗旨的全流程化招聘服务平台&#xff01;今日招聘信息↓工作内容1.参与软件项目和产品概要设计&#xff0c;负责详细功能设计、编码实现及相关文档编写&#xff1b;2.根据模块设计完成相应的模块编码及单元测试&#xff1b;3.对用户行为、需求及反…

zeek集群简述

Zeek不是多线程的&#xff0c;因此&#xff0c;一旦达到单处理器内核的限制&#xff0c;当前唯一的选择就是将工作负载分散到多个内核&#xff0c;甚至多个物理计算机上。Zeek的集群部署场景是构建这些大型系统的当前解决方案。Zeek附带的工具和脚本提供了一种结构&#xff0c;…

自注意力和位置编码(比较卷积神经网络、循环神经网络和自注意力)

在自注意力中&#xff0c;查询、键和值都来自同一组输入。 卷积神经网络和自注意力都拥有并行计算的优势&#xff0c;而且自注意力的最大路径长度最短。但是因为其计算复杂度是关于序列长度的二次方&#xff0c;所以在很长的序列中计算会非常慢。 为了使用序列的顺序信息&…

Nostr with NIP-05 Verification Guide

What is a NIPNIPs (Nostr Implementation Possibilities) document what MUST, what SHOULD and what MAY be implemented by Nostr-compatible relay and client software. See a complete list of nips here.NIP-05 提案是针对用户 Nostr 帐户的验证方法&#xff0c;可以将其…

The update is not applicable to your computer

在安装windows CVE-2022-44698补丁的时候出现了报错&#xff0c;"Windows Update Standalone Installer The update is not applicable to your computer" 1.找到漏洞对应的官方文章 CVE-2022-44698 - Security Update Guide - Microsoft - Windows SmartScreen S…

学术科研无从下手?27 条机器学习避坑指南,让你的论文发表少走弯路

内容一览&#xff1a;如果你刚接触机器学习不久&#xff0c;并且未来希望在该领域开展学术研究&#xff0c;那么这份为你量身打造的「避坑指南」可千万不要错过了。 关键词&#xff1a;机器学习 科研规范 学术研究 机器学习学术小白&#xff0c;如何优雅避坑坑、让自己的论文顺…