Go Web 编程入门:创建动态 HTML 和文本文件

简介: 之前的文章学过把模板和视图分离,建立一个 Web 服务器来展现 HTML 模板。我们将学习如何使用 Go 的模板包创建动态 HTML 和文本文件。

建立 Web 服务器


到目前为止,我们一直在向终端输出模板,但是当我们开始深入研究更多 HTML 时,这开始变得不那么有意义了。相反,我们希望可视化在 Web 浏览器中生成的 HTML。为此,我们首先需要设置一个 Web 服务器来呈现我们的 HTML 模板。

package main
import (
  "html/template"
  "net/http"
)
var testTemplate *template.Template
type ViewData struct {
  Name string
}
func main() {
  var err error
  testTemplate, err = template.ParseFiles("hello.gohtml")
  if err != nil {
    panic(err)
  }
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8000", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "text/html")
  vd := ViewData{"Kyrie Jobs"}
  err := testTemplate.Execute(w, vd)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}


创建一个名为 hello.gohtml 的文件并将以下内容添加到其中:

<h1>Hello, {{.Name}}!</h1>

现在通过在终端中输入 go run main.go 来启动服务器。该程序应保持运行并在端口 8000 上侦听 Web 请求,因此您可以在 localhost:8000 查看呈现的 HTML。


网络异常,图片无法展示
|


if...else 块


我们当前的模板很无聊,因为它只打印出一个人的名字。但是如果没有提供名字会发生什么?

让我们试试看。打开你的 main.go 文件并删除你的 handler() 函数中创建 ViewData 实例的代码,而是向 testTemplate.Execute 方法提供 nil 。完成后,您的 handler() 函数应如下所示:

func handler(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "text/html")
  err := testTemplate.Execute(w, nil)
  if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
  }
}


现在重新启动您的服务器(或让新服务器重新启动)并在浏览器中访问该页面 - localhost:8000。您应该看到一个看起来像这样的页面。

网络异常,图片无法展示
|


当我们不提供名称时,模板将使用空字符串代替值呈现。相反,我们希望我们的页面显示一个更通用的字符串,例如“Hello, there!”。让我们继续更新模板以使用我们的第一个操作,即 if/else 块。像这样更新 hello.gohtml:

<h1>Hello, {{if .Name}} {{.Name}} {{else}} there {{end}}!</h1>


如果您在浏览器中查看该页面,您应该会看到这更新了您的模板以显示“Hello, there !”就像我们想要的那样,但不幸的是,这在“there”这个词和感叹号之间增加了一个额外的空格。大多数时候这并不重要,但是在处理文本时,这有时会很烦人。在下一节中,我们将看看两个选项来稍微清理一下。


为了摆脱额外的空白,我们有几个选择:

  1. 从我们的模板中删除它们。
  2. 使用减号 (-) 告诉模板包修剪多余的空白。


第一个选项非常简单。我们只需将 hello.gohtml 文件更新为并删除多余的空格。

<h1>Hello, {{if .Name}}{{.Name}}{{else}}there{{end}}!</h1>

在这个例子中,这很好用,因为它是一段非常短的文本,但是想象一下我们正在生成 python 代码,其中间距很重要 - 这很快就会变得非常烦人。幸运的是,模板包还提供了一种使用减号来修剪不需要的空白的方法。

<h1>
  Hello,
  {{if .Name}}
    {{.Name}}
  {{- else}}
    there
  {{- end}}!
</h1>

在此代码片段中,我们通过将减号字符放在 else 关键字的前面来告诉模板包,我们不希望 Name 变量及其后面的任何内容之间的所有空格,并且我们也对 end 执行相同操作倒数第二行的关键字。重新加载您的页面,您应该会看到该空格不再存在。


对于本教程的其余部分,我将选择使用此处的第一个示例作为我的 hello.html 文件。


范围块

现在让我们假设您想在您的网站上显示所有小部件以及它们的价格。这是动态 Web 应用程序的任务类型,因为没有人愿意为您销售的每件商品手动创建 HTML 并维护它。相反,我们希望对每个项目使用相同的 HTML。在 Go 中,您可以使用模板内的范围块来实现此目的。

{{range .Widgets}}
  <div class="widget">
    <h3 class="name">{{.Name}}</h3>
    <span class="price">${{.Price}}</span>
  </div>
{{end}}


如果你重启你的服务器(或者让新的)并在 localhost:8000 重新加载页面,你现在应该会看到一个 HTML 页面,其中显示了三个小部件,每个小部件都有一个标题和一个价格。如果我们在数组中添加更多小部件,我们会在这里看到更多,如果我们将其保留为空数组,我们将不会在此处看到任何小部件。


range 操作混淆的最常见来源是我们正在访问小部件的各个属性,而无需在 .Widgets 值内使用索引或任何其他访问器。这是因为范围操作会将集合中每个对象的值设置为范围块内的点 (.)。例如,如果您要在范围块内渲染 {{.}},您将看到与在 Widget 对象上使用 fmt.Println() 相同的输出。


嵌套模板


随着您的模板开始增长,您会很快发现您需要在不同的地方重用组件。这就是嵌套模板来拯救这一天的地方。使用 Go 的模板包,您可以声明多个唯一命名的模板,然后当您需要在代码中使用另一个模板时,您只需使用 template 关键字引用它。例如,假设您想为您的网站声明一个页脚,您可以将其包含在多个页面和多个布局中。将以下页脚模板添加到 hello.html 文件中。你把它放在哪里并不重要,但我更喜欢把它放在文件的顶部。

{{define "footer"}}
  <footer>
    <p>
      Copyright 2016 Calhoun.io
    </p>
    <p>
      Contact information: <a href="mailto:jon@calhoun.io">jon@calhoun.io</a>.
    </p>
  </footer>
{{end}}

然后在小部件的范围块之后插入以下行。

{{template "footer"}}

您的 hello.gohtml 文件应如下所示:

{{define "footer"}}
  <footer>
    <p>
      Copyright 2016 Calhoun.io
    </p>
    <p>
      Contact information: <a href="mailto:jon@calhoun.io">jon@calhoun.io</a>.
    </p>
  </footer>
{{end}}
{{range .Widgets}}
  <div class="widget">
    <h3 class="name">{{.Name}}</h3>
    <span class="price">${{.Price}}</span>
  </div>
{{end}}
{{template "footer"}}

现在,如果您查看 localhost:8000,您将看到该页面正在使用您定义的页脚模板。当您定义一个模板时,您可以在任何其他模板中使用它,甚至可以多次使用它。尝试包含页脚模板两次以了解我的意思。


模板变量

我们的上一个示例很棒,但是当您需要在嵌套模板中包含一些数据时会发生什么?幸运的是,模板操作允许您传入第二个参数,该参数将分配给模板内的点 (.) 参数。例如,假设我们想为小部件的名称标题部分编写模板,我们可以使用以下代码来实现。

{{define "widget-header"}}
  <h3 class="name">{{.}}</h3>
{{end}}
{{range .Widgets}}
  <div class="widget">
    {{template "widget-header" .Name}}
    <span class="price">${{.Price}}</span>
  </div>
{{end}}

在这种情况下,.Name 属性被分配给 widget-header 模板内的点 (.) 属性。


带有模板变量的嵌套模板甚至允许您深入多层,这意味着可以从模板内部调用模板。

{{define "widget"}}
  <div class="widget">
    {{template "widget-header" .Name}}
    <span class="price">${{.Price}}</span>
  </div>
{{end}}
{{define "widget-header"}}
  <h3 class="name">{{.}}</h3>
{{end}}
{{range .Widgets}}
  {{template "widget" .}}
{{end}}

这段代码的最终结果是相同的,但是现在我们有了一个小部件模板,我们可以轻松地在 Web 应用程序的其他页面上重用它,而无需重写代码。


接下来


凭借您新学到的模板技能,您应该可以创建可重用的动态模板。在下一篇文章中,我们将介绍如何使用内置的模板函数,如 andeqindex,然后我们将看看如何添加我们自己的自定义函数。我原本打算包括那些听到的,但这篇文章有很多要介绍的行动,我不想卖空任何一个。


在关于函数的帖子之后,我们将介绍如何使用模板来创建 Web 应用程序的视图层。这将包括创建共享布局、定义可以被覆盖的默认模板,以及在不同页面中包含相同的模板,而无需将所有代码放入单个文件中。

相关文章
|
2月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
241 4
|
2月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟蒋星熠Jaxonic,Go语言探索者。深耕云计算、微服务与并发编程,以代码为笔,在二进制星河中书写极客诗篇。分享Go核心原理、性能优化与实战架构,助力开发者掌握云原生时代利器。#Go语言 #并发编程 #性能优化
406 43
Go语言深度解析:从入门到精通的完整指南
|
7月前
|
人工智能 安全 算法
Go入门实战:并发模式的使用
本文详细探讨了Go语言的并发模式,包括Goroutine、Channel、Mutex和WaitGroup等核心概念。通过具体代码实例与详细解释,介绍了这些模式的原理及应用。同时分析了未来发展趋势与挑战,如更高效的并发控制、更好的并发安全及性能优化。Go语言凭借其优秀的并发性能,在现代编程中备受青睐。
233 33
|
3月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
206 19
|
2月前
|
开发框架 前端开发 Go
【GoGin】(0)基于Go的WEB开发框架,GO Gin是什么?怎么启动?本文给你答案
Gin:Go语言编写的Web框架,以更好的性能实现类似Martini框架的APInet/http、Beego:开源的高性能Go语言Web框架、Iris:最快的Go语言Web框架,完备的MVC支持。
361 1
|
3月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟 蒋星熠Jaxonic,执着的星际旅人,用Go语言编写代码诗篇。🚀 Go语言以简洁、高效、并发为核心,助力云计算与微服务革新。📚 本文详解Go语法、并发模型、性能优化与实战案例,助你掌握现代编程精髓。🌌 从goroutine到channel,从内存优化到高并发架构,全面解析Go的强大力量。🔧 实战构建高性能Web服务,展现Go在云原生时代的无限可能。✨ 附技术对比、最佳实践与生态全景,带你踏上Go语言的星辰征途。#Go语言 #并发编程 #云原生 #性能优化
|
6月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
6月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。
|
7月前
|
设计模式 缓存 算法
Go如何进行高质量编程与性能调优实践
本文介绍了Go语言高质量编程与性能调优的实践方法。高质量编程包括良好的编码习惯(如清晰注释、命名规范)、代码风格与设计(如MVC模式)、简洁明了的代码原则,以及单元测试与代码重构的重要性。性能调优方面,涵盖算法优化、数据结构选择、I/O优化、内存管理、并行与并发处理优化及代码层面的改进。通过这些方法,可有效提升代码质量和系统性能。
158 13
|
7月前
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
183 10