Go模板教程展示了如何使用标准库在Golang中创建模板。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
模板引擎或模板处理器是一个库,旨在将模板与数据模型结合起来以生成文档。模板引擎通常用于生成大量电子邮件、源代码预处理或生成动态HTML页面。
我们创建了一个模板引擎,我们在其中定义了静态部分和动态部分。动态部分稍后会被数据替换。呈现功能稍后将模板与数据组合。模板引擎用于将模板与数据模型结合起来以生成文档。
Go包含两个模板包:text/template和html/template。两者共享相同的界面。html/template自动保护HTML输出免受某些攻击。
在模板API中,Parse函数解析程序中存在的模板字符串,ParseFiles加载和解析模板文件,Execute呈现一个使用特定数据字段输出的模板。New函数使用给定的名称分配一个新的、未定义的模板。
与许多其他模板引擎类似,数据评估和控制结构由{{和}}分隔。
Go模板解析
Parse函数解析Go程序中的模板字符串。
package main
import (
"log"
"os"
"text/template"
)
type User struct {
Name string
Occupation string
}
func main() {
user := User{"John Doe", "gardener"}
tmp := template.New("simple")
tmp, err := tmp.Parse("{{.Name}} is a {{.Occupation}}")
if err != nil {
log.Fatal(err)
}
err2 := tmp.Execute(os.Stdout, user)
if err2 != nil {
log.Fatal(err2)
}
}
该示例创建了一条简单的文本消息。
type User struct {
Name string
Occupation string
}
这是模板中使用的数据类型;字段必须导出,即大写。
tmp := template.New("simple")
创建了一个新模板。
tmp, err := tmp.Parse("{{.Name}} is a {{.Occupation}}")
我们使用Parse来解析模板字符串。使用点运算符,我们访问传递给模板引擎的字段。
$ go run main.go John Doe is a gardener
Go模板必须
Must函数是一个辅助函数,负责错误检查。
package main
import (
"log"
"os"
"text/template"
)
type User struct {
Name string
Occupation string
}
func main() {
user := User{"John Doe", "gardener"}
tmp := template.Must(template.New("simple").Parse("{{.Name}} is a {{.Occupation}}"))
f, err := os.Create("output.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
err2 := tmp.Execute(f, user)
if err2 != nil {
log.Fatal(err2)
}
}
在示例中,我们使用模板将消息写入文件。我们还使用了Must函数。
$ go run main.go $ cat output.txt John Doe is a gardener
Go模板ParseFiles
ParseFiles函数创建一个新模板并从给定的文件名中解析模板定义。
{{.Name}} is a {{.Occupation}}
这是模板文件。
package main
import (
"log"
"os"
"text/template"
)
type User struct {
Name string
Occupation string
}
func main() {
user := User{"John Doe", "gardener"}
tmp, err := template.ParseFiles("message.txt")
if err != nil {
log.Fatal(err)
}
err2 := tmp.Execute(os.Stdout, user)
if err2 != nil {
log.Fatal(err2)
}
}
在示例中,我们从模板文件创建了一条简单的消息。
Go模板范围
range指令遍历模板中的数组、切片、映射或通道的项目。
{{range .Words -}}
{{ .}}
{{end}}
在模板中,我们使用range指令遍历Words数据结构的元素。-字符去除空白字符。
package main
import (
"log"
"os"
"text/template"
)
type Data struct {
Words []string
}
func main() {
data := Data{Words: []string{"sky", "blue", "forest", "tavern", "cup", "cloud"}}
tmp, err := template.ParseFiles("words.txt")
if err != nil {
log.Fatal(err)
}
err2 := tmp.Execute(os.Stdout, data)
if err2 != nil {
log.Fatal(err2)
}
}
在程序中,我们将一段单词传递给模板引擎。我们得到一个单词列表作为输出。
$ go run main.go sky blue forest tavern cup cloud
Go模板条件
可以使用if/elseif/else指令创建条件。
{{- range .Todos -}}
{{if .Done}}
{{- .Title -}}
{{end}}
{{end}}
在模板文件中,我们使用if指令只输出已完成的任务。
package main
import (
"log"
"os"
"text/template"
)
type Todo struct {
Title string
Done bool
}
type Data struct {
Todos []Todo
}
func main() {
data := Data{Todos: []Todo{
{Title: "Task 1", Done: false},
{Title: "Task 2", Done: true},
{Title: "Task 3", Done: true},
{Title: "Task 4", Done: false},
{Title: "Task 5", Done: true},
}}
tmp := template.Must(template.ParseFiles("data.txt"))
err2 := tmp.Execute(os.Stdout, data)
if err2 != nil {
log.Fatal(err2)
}
}
我们从一片待办事项中生成输出。只有完成的任务才会包含在输出中。
Go模板服务器示例
以下示例在服务器应用程序中使用模板。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Users</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Name</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
{{ range .Users}}
<tr>
<td>{{.Name}}</td>
<td>{{.Occupation}}</td>
</tr>
{{ end }}
</tbody>
</table>
</body>
</html>
输出是一个HTML文件。数据被插入到HTML表格中。
package main
import (
"html/template"
"log"
"net/http"
)
type User struct {
Name string
Occupation string
}
type Data struct {
Users []User
}
func main() {
tmp := template.Must(template.ParseFiles("layout.html"))
http.HandleFunc("/users", func(w http.ResponseWriter, _ *http.Request) {
data := Data{
Users: []User{
{Name: "John Doe", Occupation: "gardener"},
{Name: "Roger Roe", Occupation: "driver"},
{Name: "Peter Smith", Occupation: "teacher"},
},
}
tmp.Execute(w, data)
})
log.Println("Listening...")
http.ListenAndServe(":8080", nil)
}
Web服务器返回一个HTML页面,其中包含/usersURL路径的用户表。
Go电子邮件模板
在下面的示例中,我们使用电子邮件模板为多个用户生成电子邮件。我们使用Mailtrap电子邮件测试服务。
$ mkdir template $ cd template $ go mod init com/zetcode/TemplateEmail $ go get github.com/shopspring/decimal
我们启动项目并添加外部github.com/shopspring/decimal包。
package main
import (
"bytes"
"fmt"
"log"
"net/smtp"
"text/template"
"github.com/shopspring/decimal"
)
type Mail struct {
Sender string
To string
Subject string
Body bytes.Buffer
}
type User struct {
Name string
Email string
Debt decimal.Decimal
}
func main() {
sender := "john.doe@example.com"
var users = []User{
{"Roger Roe", "roger.roe@example.com", decimal.NewFromFloat(890.50)},
{"Peter Smith", "peter.smith@example.com", decimal.NewFromFloat(350)},
{"Lucia Green", "lucia.green@example.com", decimal.NewFromFloat(120.80)},
}
my_user := "username"
my_password := "password"
addr := "smtp.mailtrap.io:2525"
host := "smtp.mailtrap.io"
subject := "Amount due"
var template_data = `
Dear {{ .Name }}, your debt amount is ${{ .Debt }}.`
for _, user := range users {
t := template.Must(template.New("template_data").Parse(template_data))
var body bytes.Buffer
err := t.Execute(&body, user)
if err != nil {
log.Fatal(err)
}
request := Mail{
Sender: sender,
To: user.Email,
Subject: subject,
Body: body,
}
msg := BuildMessage(request)
auth := smtp.PlainAuth("", my_user, my_password, host)
err2 := smtp.SendMail(addr, auth, sender, []string{user.Email}, []byte(msg))
if err2 != nil {
log.Fatal(err)
}
}
fmt.Println("Emails sent successfully")
}
func BuildMessage(mail Mail) string {
msg := ""
msg += fmt.Sprintf("From: %s\r\n", mail.Sender)
msg += fmt.Sprintf("To: %s\r\n", mail.To)
msg += fmt.Sprintf("Subject: %s\r\n", mail.Subject)
msg += fmt.Sprintf("\r\n%s\r\n", mail.Body.String())
return msg
}
在示例中,我们向多个用户发送电子邮件以提醒他们他们的债务。
var users = []User{
{"Roger Roe", "roger.roe@example.com", decimal.NewFromFloat(890.50)},
{"Peter Smith", "peter.smith@example.com", decimal.NewFromFloat(350)},
{"Lucia Green", "lucia.green@example.com", decimal.NewFromFloat(120.80)},
}
这些是借款人。
var template_data = `
Dear {{ .Name }}, your debt amount is ${{ .Debt }}.`
这是模板;它包含一个通用消息,其中.Name和.Debt占位符被替换为实际值。
for _, user := range users {
t := template.Must(template.New("template_data").Parse(template_data))
var body bytes.Buffer
err := t.Execute(&body, user)
if err != nil {
log.Fatal(err)
}
request := Mail{
Sender: sender,
To: user.Email,
Subject: subject,
Body: body,
}
msg := BuildMessage(request)
auth := smtp.PlainAuth("", my_user, my_password, host)
err2 := smtp.SendMail(addr, auth, sender, []string{user.Email}, []byte(msg))
if err2 != nil {
log.Fatal(err)
}
}
我们遍历借款人切片并为他们每个人生成一封电子邮件。Execute函数将已解析的模板应用于指定的数据对象。消息生成后,用SendMail发送。
在本教程中,我们使用内置模板包创建了动态文档。
列出所有Go教程。
